patch-2.2.8 linux/drivers/scsi/sg.c
Next file: linux/drivers/scsi/sr_ioctl.c
Previous file: linux/drivers/scsi/sd.c
Back to the patch index
Back to the overall index
- Lines: 500
- Date:
Fri May 7 11:05:30 1999
- Orig file:
v2.2.7/linux/drivers/scsi/sg.c
- Orig date:
Fri Apr 16 14:47:31 1999
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
@@ -16,7 +16,7 @@
*
* Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
*/
- static char * sg_version_str = "Version: 2.1.31 (990327)";
+ static char * sg_version_str = "Version: 2.1.32 (990501)";
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
* - scatter list logic replaces previous large atomic SG_BIG_BUFF
@@ -69,8 +69,9 @@
int sg_big_buff = SG_SCATTER_SZ; /* sg_big_buff is ro through sysctl */
/* N.B. This global is here to keep existing software happy. It now holds
- the size of the "first buffer" of the most recent sucessful sg_open(). */
-/* Only available when 'sg' compiled into kernel (rather than a module). */
+ the size of the "first buffer" of the most recent sucessful sg_open().
+ Only available when 'sg' compiled into kernel (rather than a module).
+ This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -146,6 +147,7 @@
char closed; /* 1 -> fd closed but request(s) outstanding */
char my_mem_src; /* heap whereabouts of this sg_fb object */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
+ char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
} Sg_fd; /* around 1192 bytes long on i386 */
typedef struct sg_device /* holds the state of each scsi generic device */
@@ -173,7 +175,7 @@
static char * sg_low_malloc(int rqSz, int lowDma, int mem_src,
int * retSzp);
static void sg_low_free(char * buff, int size, int mem_src);
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev);
+static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved);
static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id);
static Sg_request * sg_add_request(Sg_fd * sfp);
@@ -240,11 +242,14 @@
if (! sdp->headfp) { /* no existing opens on this device */
sdp->sgdebug = 0;
sdp->sg_tablesize = sdp->device->host->sg_tablesize;
- sdp->merge_fd = SG_DEF_MERGE_FD;
+ sdp->merge_fd = 0; /* A little tricky if SG_DEF_MERGE_FD set */
}
- if ((sfp = sg_add_sfp(sdp, dev))) {
+ if ((sfp = sg_add_sfp(sdp, dev, O_RDWR == (flags & O_ACCMODE)))) {
+ filp->private_data = sfp;
+#if SG_DEF_MERGE_FD
if (0 == sdp->merge_fd)
- filp->private_data = sfp;
+ sdp->merge_fd = 1;
+#endif
}
else {
if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */
@@ -322,11 +327,12 @@
return -ERESTARTSYS;
srp = sg_get_request(sfp, req_pack_id);
}
- srp->header.pack_len = srp->header.reply_len; /* Why ????? */
+ if (2 != sfp->underrun_flag)
+ srp->header.pack_len = srp->header.reply_len; /* Why ????? */
/* Now copy the result back to the user buffer. */
if (count >= size_sg_header) {
- copy_to_user(buf, &srp->header, size_sg_header);
+ __copy_to_user(buf, &srp->header, size_sg_header);
buf += size_sg_header;
if (count > srp->header.reply_len)
count = srp->header.reply_len;
@@ -371,7 +377,7 @@
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_READ, buf, count)))
- return k;
+ return k; /* protects following copy_from_user()s + get_user()s */
/* The minimum scsi command length is 6 bytes. If we get anything
* less than this, it is clearly bogus. */
if (count < (size_sg_header + 6))
@@ -382,10 +388,10 @@
SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n"));
return -EDOM;
}
- copy_from_user(&srp->header, buf, size_sg_header);
+ __copy_from_user(&srp->header, buf, size_sg_header);
buf += size_sg_header;
srp->header.pack_len = count;
- get_user(opcode, buf);
+ __get_user(opcode, buf);
cmd_size = COMMAND_SIZE(opcode);
if ((opcode >= 0xc0) && srp->header.twelve_byte)
cmd_size = 12;
@@ -427,7 +433,7 @@
SCpnt->sense_buffer[0] = 0;
SCpnt->cmd_len = cmd_size;
/* Now copy the SCSI command from the user's address space. */
- copy_from_user(cmnd, buf, cmd_size);
+ __copy_from_user(cmnd, buf, cmd_size);
/* Set the LUN field in the command structure. */
cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
@@ -439,11 +445,10 @@
SCpnt->use_sg = srp->data.use_sg;
SCpnt->sglist_len = srp->data.sglist_len;
SCpnt->bufflen = srp->data.bufflen;
- SCpnt->underflow = srp->data.bufflen;
-/* Not many drivers look at this:
- aic7xxx driver gives DID_RETRY_COMMAND on underrun
- seagate comments out its underrun checking code, and the rest ...
-*/
+ if (1 == sfp->underrun_flag)
+ SCpnt->underflow = srp->data.bufflen;
+ else
+ SCpnt->underflow = 0;
SCpnt->buffer = srp->data.buffer;
srp->data.use_sg = 0;
srp->data.sglist_len = 0;
@@ -479,14 +484,10 @@
switch(cmd_in)
{
case SG_SET_TIMEOUT:
- result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
- if (result) return result;
return get_user(sfp->timeout, (int *)arg);
case SG_GET_TIMEOUT:
return sfp->timeout; /* strange ..., for backward compatibility */
case SG_SET_FORCE_LOW_DMA:
- result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
- if (result) return result;
result = get_user(val, (int *)arg);
if (result) return result;
if (val) {
@@ -503,28 +504,23 @@
sfp->low_dma = sdp->device->host->unchecked_isa_dma;
return 0;
case SG_GET_LOW_DMA:
- result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- if (result) return result;
- put_user((int)sfp->low_dma, (int *)arg);
- return 0;
+ return put_user((int)sfp->low_dma, (int *)arg);
case SG_GET_SCSI_ID:
result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(Sg_scsi_id));
if (result) return result;
else {
Sg_scsi_id * sg_idp = (Sg_scsi_id *)arg;
- put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
- put_user((int)sdp->device->channel, &sg_idp->channel);
- put_user((int)sdp->device->id, &sg_idp->scsi_id);
- put_user((int)sdp->device->lun, &sg_idp->lun);
- put_user((int)sdp->device->type, &sg_idp->scsi_type);
- put_user(0, &sg_idp->unused1);
- put_user(0, &sg_idp->unused2);
- put_user(0, &sg_idp->unused3);
+ __put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
+ __put_user((int)sdp->device->channel, &sg_idp->channel);
+ __put_user((int)sdp->device->id, &sg_idp->scsi_id);
+ __put_user((int)sdp->device->lun, &sg_idp->lun);
+ __put_user((int)sdp->device->type, &sg_idp->scsi_type);
+ __put_user(0, &sg_idp->unused1);
+ __put_user(0, &sg_idp->unused2);
+ __put_user(0, &sg_idp->unused3);
return 0;
}
case SG_SET_FORCE_PACK_ID:
- result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
- if (result) return result;
result = get_user(val, (int *)arg);
if (result) return result;
sfp->force_packid = val ? 1 : 0;
@@ -535,16 +531,14 @@
srp = sfp->headrp;
while (srp) {
if (! srp->my_cmdp) {
- put_user(srp->header.pack_id, (int *)arg);
+ __put_user(srp->header.pack_id, (int *)arg);
return 0;
}
srp = srp->nextrp;
}
- put_user(-1, (int *)arg);
+ __put_user(-1, (int *)arg);
return 0;
case SG_GET_NUM_WAITING:
- result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- if (result) return result;
srp = sfp->headrp;
val = 0;
while (srp) {
@@ -552,36 +546,25 @@
++val;
srp = srp->nextrp;
}
- put_user(val, (int *)arg);
- return 0;
+ return put_user(val, (int *)arg);
case SG_GET_SG_TABLESIZE:
- result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- if (result) return result;
- put_user(sdp->sg_tablesize, (int *)arg);
- return 0;
+ return put_user(sdp->sg_tablesize, (int *)arg);
case SG_SET_RESERVED_SIZE:
/* currently ignored, future extension */
if (O_RDWR != (filp->f_flags & O_ACCMODE))
return -EACCES;
- result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
+ result = get_user(val, (int *)arg);
if (result) return result;
+ /* logic should go here */
return 0;
case SG_GET_RESERVED_SIZE:
- result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- if (result) return result;
- put_user(sfp->fb_size, (int *)arg);
- return 0;
+ return put_user(sfp->fb_size, (int *)arg);
case SG_GET_MERGE_FD:
- result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- if (result) return result;
- put_user((int)sdp->merge_fd, (int *)arg);
- return 0;
+ return put_user((int)sdp->merge_fd, (int *)arg);
case SG_SET_MERGE_FD:
if (O_RDWR != (filp->f_flags & O_ACCMODE))
return -EACCES; /* require write access since effect wider
then just this fd */
- result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
- if (result) return result;
result = get_user(val, (int *)arg);
if (result) return result;
val = val ? 1 : 0;
@@ -591,17 +574,19 @@
sdp->merge_fd = val;
return 0;
case SG_SET_COMMAND_Q:
- result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
- if (result) return result;
result = get_user(val, (int *)arg);
if (result) return result;
sfp->cmd_q = val ? 1 : 0;
return 0;
case SG_GET_COMMAND_Q:
- result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+ return put_user((int)sfp->cmd_q, (int *)arg);
+ case SG_SET_UNDERRUN_FLAG:
+ result = get_user(val, (int *)arg);
if (result) return result;
- put_user((int)sfp->cmd_q, (int *)arg);
+ sfp->underrun_flag = val;
return 0;
+ case SG_GET_UNDERRUN_FLAG:
+ return put_user((int)sfp->underrun_flag, (int *)arg);
case SG_EMULATED_HOST:
return put_user(sdp->device->host->hostt->emulated, (int *)arg);
case SCSI_IOCTL_SEND_COMMAND:
@@ -613,8 +598,6 @@
dangerous */
return scsi_ioctl_send_command(sdp->device, (void *)arg);
case SG_SET_DEBUG:
- result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
- if (result) return result;
result = get_user(val, (int *)arg);
if (result) return result;
sdp->sgdebug = (char)val;
@@ -625,6 +608,8 @@
return 0;
case SCSI_IOCTL_GET_IDLUN:
case SCSI_IOCTL_GET_BUS_NUMBER:
+ case SCSI_IOCTL_PROBE_HOST:
+ case SG_GET_TRANSFORM:
return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
default:
if (O_RDWR != (filp->f_flags & O_ACCMODE))
@@ -698,6 +683,7 @@
sdp = &sg_dev_arr[dev];
if (NULL == sdp->device)
return; /* Get out of here quick ... */
+
sfp = sdp->headfp;
while (sfp) {
srp = sfp->headrp;
@@ -721,6 +707,8 @@
srp->data.sglist_len = SCpnt->sglist_len;
srp->data.bufflen = SCpnt->bufflen;
srp->data.buffer = SCpnt->buffer;
+ if (2 == sfp->underrun_flag)
+ srp->header.pack_len = SCpnt->underflow;
sg_clr_scpnt(SCpnt);
srp->my_cmdp = NULL;
@@ -755,7 +743,7 @@
* underrun or overrun should signal an error. Until that can be
* implemented, this kludge allows for returning useful error values
* except in cases that return DID_ERROR that might be due to an
- * underrun. [Underrun on advansys adapter yields DID_ABORT -dpg] */
+ * underrun. */
if (SCpnt->sense_buffer[0] == 0 &&
status_byte(SCpnt->result) == GOOD)
srp->header.result = 0;
@@ -887,8 +875,9 @@
printk(">> Following FD has NULL parent pointer ???\n");
printk(" FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n",
k, fp->timeout, fp->fb_size, (int)fp->cmd_q);
- printk(" low_dma=%d, force_packid=%d, closed=%d\n",
- (int)fp->low_dma, (int)fp->force_packid, (int)fp->closed);
+ printk(" low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n",
+ (int)fp->low_dma, (int)fp->force_packid,
+ (int)fp->underrun_flag, (int)fp->closed);
srp = fp->headrp;
if (NULL == srp)
printk(" No requests active\n");
@@ -1002,7 +991,7 @@
sdp->generic_wait = NULL;
sdp->headfp= NULL;
sdp->exclude = 0;
- sdp->merge_fd = 0;
+ sdp->merge_fd = 0; /* Cope with SG_DEF_MERGE_FD on open */
sdp->sgdebug = 0;
sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
@@ -1120,7 +1109,7 @@
if ((blk_size < 0) || (! srp))
return -EFAULT;
- SCSI_LOG_TIMEOUT(4, printk("sg build: m_b_s=%d, num_write_xfer=%d\n",
+ SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n",
max_buff_size, num_write_xfer));
if (0 == blk_size)
++blk_size; /* don't know why */
@@ -1139,7 +1128,7 @@
srp->data.mem_src = mem_src;
srp->data.b_malloc_len = blk_size;
if (inp && (num_write_xfer > 0))
- copy_from_user(srp->data.buffer, inp, num_write_xfer);
+ __copy_from_user(srp->data.buffer, inp, num_write_xfer);
return 0;
}
}
@@ -1185,17 +1174,17 @@
}
sclp->address = p;
sclp->length = ret_sz;
- sclp->alt_address = (char *)mem_src;
+ sclp->alt_address = (char *)(long)mem_src;
if(inp && (num_write_xfer > 0)) {
num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz;
- copy_from_user(sclp->address, inp, num);
+ __copy_from_user(sclp->address, inp, num);
num_write_xfer -= num;
inp += num;
}
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_build: k=%d, a=0x%x, len=%d, ms=%d\n",
- k, (int)sclp->address, ret_sz, (int)sclp->alt_address));
+ printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n",
+ k, sclp->address, ret_sz, mem_src));
} /* end of for loop */
srp->data.use_sg = k;
SCSI_LOG_TIMEOUT(5,
@@ -1224,20 +1213,20 @@
if (num_read_xfer > 0) {
num = (int)sclp->length;
if (num > num_read_xfer) {
- copy_to_user(outp, sclp->address, num_read_xfer);
+ __copy_to_user(outp, sclp->address, num_read_xfer);
outp += num_read_xfer;
num_read_xfer = 0;
}
else {
- copy_to_user(outp, sclp->address, num);
+ __copy_to_user(outp, sclp->address, num);
outp += num;
num_read_xfer -= num;
}
}
- mem_src = (int)sclp->alt_address;
+ mem_src = (int)(long)sclp->alt_address;
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_undo_rem: k=%d, a=0x%x, len=%d, ms=%d\n",
- k, (int)sclp->address, sclp->length, mem_src));
+ printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n",
+ k, sclp->address, sclp->length, mem_src));
sg_free(srp, sclp->address, sclp->length, mem_src);
}
sg_free(srp, srp->data.buffer, srp->data.sglist_len,
@@ -1245,13 +1234,13 @@
}
else {
if (num_read_xfer > 0)
- copy_to_user(outp, srp->data.buffer, num_read_xfer);
+ __copy_to_user(outp, srp->data.buffer, num_read_xfer);
sg_free(srp, srp->data.buffer, srp->data.b_malloc_len,
srp->data.mem_src);
}
if (0 == sg_remove_request(srp->parentfp, srp)) {
- SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=%d not found\n",
- (int)srp));
+ SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n",
+ srp));
}
return 0;
}
@@ -1336,7 +1325,7 @@
return 0;
}
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev)
+static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved)
{
Sg_fd * sfp;
@@ -1357,8 +1346,12 @@
sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
sdp->device->host->unchecked_isa_dma : 1;
sfp->cmd_q = SG_DEF_COMMAND_Q;
- sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma,
- SG_HEAP_PAGE, &sfp->fb_size);
+ sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG;
+ if (get_reserved)
+ sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma,
+ SG_HEAP_PAGE, &sfp->fb_size);
+ else
+ sfp->fst_buf = NULL;
if (! sfp->fst_buf)
sfp->fb_size = 0;
sfp->parentdp = sdp;
@@ -1371,10 +1364,10 @@
pfp->nextfp = sfp;
}
sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */
- SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%x, m_s=%d\n",
- (int)sfp, (int)sfp->my_mem_src));
- SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: fb_sz=%d, fst_buf=0x%x\n",
- sfp->fb_size, (int)sfp->fst_buf));
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
+ sfp, (int)sfp->my_mem_src));
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: fb_sz=%d, fst_buf=0x%p\n",
+ sfp->fb_size, sfp->fst_buf));
return sfp;
}
@@ -1416,13 +1409,13 @@
prev_fp = fp;
}
}
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: fb_sz=%d, fst_buf=0x%x\n",
- sfp->fb_size, (int)sfp->fst_buf));
+SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: fb_sz=%d, fst_buf=0x%p\n",
+ sfp->fb_size, sfp->fst_buf));
sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
sfp->parentdp = NULL;
sfp->fst_buf = NULL;
sfp->fb_size = 0;
- SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%x\n", (int)sfp));
+ SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp));
sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src);
res = 1;
}
@@ -1573,8 +1566,8 @@
}
if (resp) *mem_srcp = l_ms;
}
- SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%x\n",
- size, *mem_srcp, (int)resp));
+ SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%p\n",
+ size, *mem_srcp, resp));
return resp;
}
@@ -1598,8 +1591,8 @@
free_pages((unsigned long)buff, order);
}
else
- printk("sg_low_free: bad mem_src=%d, buff=0x%x, rqSz=%df\n",
- mem_src, (int)buff, size);
+ printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n",
+ mem_src, buff, size);
}
static void sg_free(Sg_request * srp, char * buff, int size, int mem_src)
@@ -1607,7 +1600,7 @@
Sg_fd * sfp = srp->parentfp;
SCSI_LOG_TIMEOUT(6,
- printk("sg_free: buff=0x%x, size=%d\n", (int)buff, size));
+ printk("sg_free: buff=0x%p, size=%d\n", buff, size));
if ((! sfp) || (! buff) || (size <= 0))
;
else if (sfp->fst_buf == buff) {
@@ -1624,5 +1617,7 @@
SCpnt->sglist_len = 0;
SCpnt->bufflen = 0;
SCpnt->buffer = NULL;
+ SCpnt->underflow = 0;
+ SCpnt->request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)