--- linux/include/scsi/sg.h.orig Sat Apr 11 00:22:21 1998 +++ linux/include/scsi/sg.h Wed Oct 14 13:10:04 1998 @@ -3,17 +3,82 @@ Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user process control of SCSI devices. Development Sponsored by Killy Corp. NY NY + Enhancements for portable SCSI transport library written by + Heiko Eißfeldt and Jörg Schilling */ #ifndef _SCSI_GENERIC_H #define _SCSI_GENERIC_H +/* + * ioctl's + * + * Note that all timeouts are multiples of of a clock tick (HZ). + * Hz is usually 100 but it is 1024 on DEC alpha! + */ +#define SG_SET_TIMEOUT 0x2201 /* set timeout *(int *)arg==timeout in clock ticks*/ +#define SG_GET_TIMEOUT 0x2202 /* get timeout return timeout in clock ticks */ +#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */ + +/* Used to configure SCSI command transformation layer for ATAPI devices */ +#define SG_SET_TRANSFORM 0x2204 +#define SG_GET_TRANSFORM 0x2205 +#define SG_GET_BUFSIZE 0x2206 /* get buffer size return actual SG_BIG_BUFF */ + + +#define SG_MAX_SENSE 16 /* Size of auto-request-sense buffer */ + /* An SG device is accessed by writing "packets" to it, the replies are then read using the read call. The same header is used for reply, just ignore reply_len field. */ +#ifdef SG_GET_BUFSIZE +/* + * This is the new version of the data structure. + * It tries to make the best approach without breaking the old behaviour. + * This version is intended to make 'sg' usable for developing SCSI user + * applications until a better driver is included into Linux. + * this version of the driver is still not able to return the amount of + * sense data that is required by CCS (18 bytes). + * + * The new version is granted to be present if SG_GET_BUFSIZE is defined. + * The fields pack_len, reply_len and sense_len are used for different + * purpose when sending / receiving packets. + * + * On return: + * pack_len is the cmd_status ->DONE + * reply_len is the actual DMA transfer count ->FUTURE + * sense_len is the number of bytes acually returned in sense_buffer ->FUTURE + * + * Only old code that does not clear the unused 31 bits of the + * old data structure breaks with the new version of the driver. + */ +struct sg_header { + int pack_len; /* length of incoming packet (including header) / */ + int reply_len; /* maximum length of expected reply / actual transfer count */ + int pack_id; /* id number of packet */ + int result; /* 0==ok, otherwise refer to errno codes */ + unsigned int twelve_byte :1; /* Force 12 byte command length (unused if want_new is set) */ + unsigned int want_new :1; /* User requests new behaviour */ + unsigned int grant_new :1; /* Driver grants new behaviour */ + unsigned int cdb_len :5; /* Command descriptor block length 6..31 (mandatory) */ + unsigned int sense_len :5; /* Set max / get actual sense length 0..31 (mandatory) */ + unsigned int other_flags :19; /* for future use */ + unsigned char sense_buffer[SG_MAX_SENSE];/* used only by reads */ + /* command follows then data for command */ + }; +/* + * cmd_status contains: + * driver_byte << 24 | host_byte << 16 | msg_byte << 8 | status_byte + */ +#define sg_cmd_status pack_len +#else +/* + * This is the old version of the data structure it is included to + * help developers to migrate to the new interface. + */ struct sg_header { int pack_len; /* length of incoming packet <4096 (including header) */ @@ -25,16 +90,7 @@ unsigned char sense_buffer[16]; /* used only by reads */ /* command follows then data for command */ }; - -/* ioctl's */ -#define SG_SET_TIMEOUT 0x2201 /* set timeout *(int *)arg==timeout */ -#define SG_GET_TIMEOUT 0x2202 /* get timeout return timeout */ - -#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */ - -/* Used to configure SCSI command transformation layer for ATAPI devices */ -#define SG_SET_TRANSFORM 0x2204 -#define SG_GET_TRANSFORM 0x2205 +#endif #define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */ #define SG_DEFAULT_RETRIES 1 --- linux/kernel/sysctl.c.orig Wed Sep 30 19:15:03 1998 +++ linux/kernel/sysctl.c Wed Oct 14 13:11:41 1998 @@ -45,9 +45,6 @@ #ifdef CONFIG_KMOD extern char modprobe_path[]; #endif -#ifdef CONFIG_CHR_DEV_SG -extern int sg_big_buff; -#endif #ifdef __sparc__ extern char reboot_command []; @@ -188,10 +185,6 @@ #ifdef CONFIG_KMOD {KERN_MODPROBE, "modprobe", &modprobe_path, 256, 0644, NULL, &proc_dostring, &sysctl_string }, -#endif -#ifdef CONFIG_CHR_DEV_SG - {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int), - 0444, NULL, &proc_dointvec}, #endif {0} }; --- linux/drivers/scsi/sg.c.orig Mon Aug 24 22:14:10 1998 +++ linux/drivers/scsi/sg.c Wed Oct 14 13:11:41 1998 @@ -5,6 +5,14 @@ * Development Sponsored by Killy Corp. NY NY * * Borrows code from st driver. + * + * Heiko Eißfeldt, 08.01.1998 + * Changed buffer allocation to a lazy kmalloc scheme in order to allow + * multiple requests in parallel on different devices. For example reading + * from a cdrom and writing on a cd burner. + * + * NOTE: SG_BIG_BUFF is kept for compatibility, but has no effect anymore. + * The corresponding sysctl entry is gone. */ #include @@ -28,8 +36,6 @@ #include #include -int sg_big_buff = SG_BIG_BUFF; /* for now, sg_big_buff is read-only through sysctl */ - static int sg_init(void); static int sg_attach(Scsi_Device *); static int sg_detect(Scsi_Device *); @@ -41,12 +47,6 @@ sg_detect, sg_init, NULL, sg_attach, sg_detach}; -#ifdef SG_BIG_BUFF -static char *big_buff = NULL; -static struct wait_queue *big_wait; /* wait for buffer available */ -static int big_inuse=0; -#endif - struct scsi_generic { Scsi_Device *device; @@ -64,7 +64,6 @@ }; static struct scsi_generic *scsi_generics=NULL; -static void sg_free(char *buff,int size); static int sg_ioctl(struct inode * inode,struct file * file, unsigned int cmd_in, unsigned long arg) @@ -97,6 +96,12 @@ return scsi_generics[dev].timeout; case SG_EMULATED_HOST: return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg); + case SG_GET_BUFSIZE: +#ifdef SG_BIG_BUFF + return SG_BIG_BUFF; +#else + return 4096; +#endif case SCSI_IOCTL_SEND_COMMAND: /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the @@ -109,6 +114,47 @@ } } +static char *sg_lazy_malloc(int bsize, int *buff_len, + const struct scsi_generic *s_dev) +{ + void * retval; + int chunksize; + + /* if we have enough space in last buffer, recycle buffer */ + if (s_dev->buff != NULL && *buff_len >= bsize) + return s_dev->buff; + + /* we don't have enough space. Forget the old buffer, + then get a bigger one */ + if (s_dev->buff != NULL) + kfree(s_dev->buff); + + /* quantify block size: 32K or 64K or 128K or more, if possible */ + if (bsize <= 32 * 1024) { + chunksize = 32 * 1024; + } else if (bsize <= 64 * 1024) { + chunksize = 64 * 1024; + } else if (bsize <= 128 * 1024) { + chunksize = 128 * 1024; + } else { + /* for future extensions */ + chunksize = bsize; + } + + /* alloc a new block */ + retval = kmalloc(chunksize, GFP_KERNEL | GFP_DMA); + + /* if the kmalloc failed, let the size be zero */ + if (retval == NULL) { + chunksize = 0; + } + + /* register size of allocated block */ + *buff_len = chunksize; + + return (char *) retval; +} + static int sg_open(struct inode * inode, struct file * filp) { int dev=MINOR(inode->i_rdev); @@ -127,6 +173,9 @@ /* * If we want exclusive access, then wait until the device is not * busy, and then set the flag to prevent anyone else from using it. + * + * FIXME (HE): The device can be used through another driver! + * This goes currently unnoticed. Add a check for this. */ if (flags & O_EXCL) { @@ -164,7 +213,7 @@ && scsi_generics[dev].complete) { if (scsi_generics[dev].buff != NULL) - sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len); + kfree(scsi_generics[dev].buff); scsi_generics[dev].buff=NULL; scsi_generics[dev].pending=0; } @@ -181,6 +230,10 @@ static int sg_close(struct inode * inode, struct file * filp) { int dev=MINOR(inode->i_rdev); + if (scsi_generics[dev].buff != NULL) { + kfree(scsi_generics[dev].buff); + scsi_generics[dev].buff = NULL; + } scsi_generics[dev].users--; if (scsi_generics[dev].device->host->hostt->module) __MOD_DEC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); @@ -191,38 +244,6 @@ return 0; } -static char *sg_malloc(int size) -{ - if (size<=4096) - return (char *) scsi_malloc(size); -#ifdef SG_BIG_BUFF - if (size<=SG_BIG_BUFF) - { - while(big_inuse) - { - interruptible_sleep_on(&big_wait); - if (signal_pending(current)) - return NULL; - } - big_inuse=1; - return big_buff; - } -#endif - return NULL; -} - -static void sg_free(char *buff,int size) -{ -#ifdef SG_BIG_BUFF - if (buff==big_buff) - { - big_inuse=0; - wake_up(&big_wait); - return; - } -#endif - scsi_free(buff,size); -} /* * Read back the results of a previous command. We use the pending and @@ -274,14 +295,16 @@ /* * Now copy the result back to the user buffer. */ - device->header.pack_len=device->header.reply_len; + if (device->header.want_new == 0) { + device->header.pack_len=device->header.reply_len; + } if (count>=sizeof(struct sg_header)) { copy_to_user(buf,&device->header,sizeof(struct sg_header)); buf+=sizeof(struct sg_header); - if (count>device->header.pack_len) - count=device->header.pack_len; + if (count>device->header.reply_len) + count=device->header.reply_len; if (count > sizeof(struct sg_header)) { copy_to_user(buf,device->buff,count-sizeof(struct sg_header)); } @@ -293,8 +316,6 @@ * Clean up, and release the device so that we can send another * command. */ - sg_free(device->buff,device->buff_len); - device->buff = NULL; device->pending=0; wake_up(&device->write_wait); return count; @@ -323,6 +344,10 @@ */ memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); + if (device->header.want_new) { + device->header.grant_new = 1; + device->header.pack_len = SCpnt->result; + } switch (host_byte(SCpnt->result)) { case DID_OK: device->header.result = 0; @@ -355,6 +380,17 @@ break; } + if (driver_byte(SCpnt->result) != 0 + && (SCpnt->sense_buffer[0] & 0x7f) == 0x70 + && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION + && device->device->removable) + { + /* + * detected disc change. Set the bit - this may be used if there + * are filesystems using this device. + */ + device->device->changed = 1; + } /* * Now wake up the process that is waiting for the * result. @@ -435,7 +471,11 @@ */ get_user(opcode, buf); size=COMMAND_SIZE(opcode); - if (opcode >= 0xc0 && device->header.twelve_byte) size = 12; + if (device->header.want_new) { + size = device->header.cdb_len; + } else { + if (opcode >= 0xc0 && device->header.twelve_byte) size = 12; + } /* * Determine buffer size. @@ -466,18 +506,17 @@ /* * Allocate a buffer that is large enough to hold the data - * that has been requested. Round up to an even number of sectors, - * since scsi_malloc allocates in chunks of 512 bytes. + * that has been requested. */ amt=bsize; if (!bsize) bsize++; - bsize=(bsize+511) & ~511; /* * If we cannot allocate the buffer, report an error. */ - if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize))) + if ((bsize<0) + || !(device->buff=sg_lazy_malloc(bsize, &device->buff_len, device))) { device->pending=0; wake_up(&device->write_wait); @@ -496,8 +535,6 @@ { device->pending=0; wake_up(&device->write_wait); - sg_free(device->buff,device->buff_len); - device->buff = NULL; return -EAGAIN; } #ifdef DEBUG @@ -621,10 +658,6 @@ printk("sg: Init generic device.\n"); #endif -#ifdef SG_BIG_BUFF - big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA); -#endif - scsi_generics = (struct scsi_generic *) scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) * sizeof(struct scsi_generic), GFP_ATOMIC); @@ -704,10 +737,6 @@ * sizeof(struct scsi_generic)); } sg_template.dev_max = 0; -#ifdef SG_BIG_BUFF - if(big_buff != NULL) - scsi_init_free(big_buff, SG_BIG_BUFF); -#endif } #endif /* MODULE */