patch-2.2.16 linux/drivers/scsi/sg.c
Next file: linux/drivers/scsi/sr.c
Previous file: linux/drivers/scsi/seagate.c
Back to the patch index
Back to the overall index
- Lines: 284
- Date:
Wed Jun 7 14:26:43 2000
- Orig file:
v2.2.15/linux/drivers/scsi/sg.c
- Orig date:
Tue Jan 4 10:12:21 2000
diff -urN v2.2.15/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
@@ -7,7 +7,7 @@
* Original driver (sg.c):
* Copyright (C) 1992 Lawrence Foard
* 2.x extensions to driver:
- * Copyright (C) 1998, 1999 Douglas Gilbert
+ * Copyright (C) 1998 - 2000 Douglas Gilbert
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,8 +16,8 @@
*
* Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
*/
- static char * sg_version_str = "Version: 2.1.36 (991218)";
- static int sg_version_num = 20136; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 2.1.38 (20000527)";
+ static int sg_version_num = 20138; /* 2 digits for each component */
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -35,7 +35,7 @@
* # echo "scsi dump 1" > /proc/scsi/scsi
* To dump the state of sg's data structures get the 'sg_debug'
* program from the utilities and enter:
- * # sg_debug /dev/sga
+ * # sg_debug /dev/sg0
* or any valid sg device name. The state of _all_ sg devices
* will be sent to the console and the log.
*
@@ -100,7 +100,7 @@
static void sg_detach(Scsi_Device *);
-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff,
+struct Scsi_Device_Template sg_template = {NULL, "generic", "sg", NULL, 0xff,
SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
sg_detect, sg_init,
sg_finish, sg_attach, sg_detach};
@@ -127,6 +127,7 @@
Sg_scatter_hold data; /* hold buffer, perhaps scatter list */
struct sg_header header; /* scsi command+info, see <scsi/sg.h> */
char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
+ char done; /* 0->before bh, 1->before read, 2->read */
} Sg_request; /* 72 bytes long on i386 */
typedef struct sg_fd /* holds the state of a file descriptor */
@@ -186,7 +187,7 @@
static void sg_low_free(char * buff, int size, int mem_src);
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_get_rq_mark(Sg_fd * sfp, int pack_id);
static Sg_request * sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp);
static int sg_res_in_use(const Sg_fd * sfp);
@@ -319,13 +320,13 @@
copy_from_user(&hdr, buf, size_sg_header);
req_pack_id = hdr.pack_id;
}
- srp = sg_get_request(sfp, req_pack_id);
+ srp = sg_get_rq_mark(sfp, req_pack_id);
if (! srp) { /* now wait on packet to arrive */
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
res = 0; /* following is a macro that beats race condition */
__wait_event_interruptible(sfp->read_wait,
- (srp = sg_get_request(sfp, req_pack_id)),
+ (srp = sg_get_rq_mark(sfp, req_pack_id)),
res);
if (res)
return res; /* -ERESTARTSYS because signal hit process */
@@ -533,7 +534,7 @@
if (result) return result;
srp = sfp->headrp;
while (srp) {
- if (! srp->my_cmdp) {
+ if (1 == srp->done) {
__put_user(srp->header.pack_id, (int *)arg);
return 0;
}
@@ -545,7 +546,7 @@
srp = sfp->headrp;
val = 0;
while (srp) {
- if (! srp->my_cmdp)
+ if (1 == srp->done)
++val;
srp = srp->nextrp;
}
@@ -609,8 +610,29 @@
return -EBUSY;
result = get_user(val, (int *)arg);
if (result) return result;
- /* Don't do anything till scsi mod level visibility */
- return 0;
+ if (SG_SCSI_RESET_NOTHING == val)
+ return 0;
+#ifdef SCSI_TRY_RESET_DEVICE
+ switch (val)
+ {
+ case SG_SCSI_RESET_DEVICE:
+ val = SCSI_TRY_RESET_DEVICE;
+ break;
+ case SG_SCSI_RESET_BUS:
+ val = SCSI_TRY_RESET_BUS;
+ break;
+ case SG_SCSI_RESET_HOST:
+ val = SCSI_TRY_RESET_HOST;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if(! capable(CAP_SYS_ADMIN)) return -EACCES;
+ return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
+#else
+ SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
+ result = -EINVAL;
+#endif
case SCSI_IOCTL_SEND_COMMAND:
/* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
user already has read/write access to the generic device and so
@@ -652,7 +674,7 @@
poll_wait(filp, &sfp->read_wait, wait);
srp = sfp->headrp;
while (srp) { /* if any read waiting, flag it */
- if (! (res || srp->my_cmdp))
+ if ((0 == res) && (1 == srp->done))
res = POLLIN | POLLRDNORM;
++count;
srp = srp->nextrp;
@@ -732,6 +754,7 @@
srp->data.buffer = SCpnt->buffer;
sg_clr_scpnt(SCpnt);
srp->my_cmdp = NULL;
+ srp->done = 1;
SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n",
dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
@@ -864,9 +887,9 @@
dev = MINOR(sdp->i_rdev);
if (part_of)
- printk(" >>> device=%d(sg%c), ", dev, 'a' + dev);
+ printk(" >>> device=%d (sg%d), ", dev, dev);
else
- printk("sg_debug: device=%d(sg%c), ", dev, 'a' + dev);
+ printk("sg_debug: device=%d (sg%d), ", dev, dev);
printk("scsi%d chan=%d id=%d lun=%d em=%d\n", sdp->device->host->host_no,
sdp->device->channel, sdp->device->id, sdp->device->lun,
sdp->device->host->hostt->emulated);
@@ -908,7 +931,8 @@
srp->header.pack_id, srp->my_cmdp->bufflen,
srp->my_cmdp->use_sg);
else
- printk("to_read: pack_id=%d, bufflen=%d, use_sg=%d\n",
+ printk("%s: pack_id=%d, bufflen=%d, use_sg=%d\n",
+ ((1 == srp->done) ? "to_read" : "prior"),
srp->header.pack_id, srp->data.bufflen, srp->data.use_sg);
if (! srp->parentfp)
printk(">> request has NULL parent pointer ???\n");
@@ -945,9 +969,9 @@
case TYPE_WORM:
case TYPE_TAPE: break;
default:
- printk("Detected scsi generic sg%c at scsi%d,"
+ printk("Detected scsi generic sg%d at scsi%d,"
" channel %d, id %d, lun %d\n",
- 'a'+sg_template.dev_noticed,
+ sg_template.dev_noticed,
scsidp->host->host_no, scsidp->channel,
scsidp->id, scsidp->lun);
}
@@ -1124,6 +1148,8 @@
SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n",
max_buff_size));
+ if (max_buff_size <= 0)
+ return 0;
if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
sg_link_reserve(sfp, srp, max_buff_size);
sg_write_xfer(req_schp, inp, num_write_xfer);
@@ -1351,6 +1377,8 @@
Sg_scatter_hold * rsv_schp = &sfp->reserve;
SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
+ /* round request up to next highest SG_SECTOR_SZ byte boundary */
+ size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
if (rsv_schp->use_sg > 0) {
int k, num;
int rem = size;
@@ -1413,15 +1441,17 @@
srp->res_used = 0;
}
-static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id)
+static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id)
{
Sg_request * resp = NULL;
resp = sfp->headrp;
while (resp) {
- if ((! resp->my_cmdp) &&
- ((-1 == pack_id) || (resp->header.pack_id == pack_id)))
+ if ((1 == resp->done) &&
+ ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
+ resp->done = 2;
return resp;
+ }
resp = resp->nextrp;
}
return resp;
@@ -1431,12 +1461,12 @@
static Sg_request * sg_add_request(Sg_fd * sfp)
{
int k;
- Sg_request * resp = NULL;
- Sg_request * rp;
+ Sg_request * resp = sfp->headrp;
+ Sg_request * rp = sfp->req_arr;
- resp = sfp->headrp;
- rp = sfp->req_arr;
if (! resp) {
+ memset(rp, 0, sizeof(Sg_request));
+ rp->parentfp = sfp;
resp = rp;
sfp->headrp = resp;
}
@@ -1444,12 +1474,15 @@
if (0 == sfp->cmd_q)
resp = NULL; /* command queuing disallowed */
else {
- for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) {
+ for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
if (! rp->parentfp)
break;
}
if (k < SG_MAX_QUEUE) {
- while (resp->nextrp) resp = resp->nextrp;
+ memset(rp, 0, sizeof(Sg_request));
+ rp->parentfp = sfp;
+ while (resp->nextrp)
+ resp = resp->nextrp;
resp->nextrp = rp;
resp = rp;
}
@@ -1458,11 +1491,7 @@
}
}
if (resp) {
- resp->parentfp = sfp;
resp->nextrp = NULL;
- resp->res_used = 0;
- memset(&resp->data, 0, sizeof(Sg_scatter_hold));
- memset(&resp->header, 0, sizeof(struct sg_header));
resp->my_cmdp = NULL;
}
return resp;
@@ -1478,14 +1507,14 @@
return 0;
prev_rp = sfp->headrp;
if (srp == prev_rp) {
- prev_rp->parentfp = NULL;
sfp->headrp = prev_rp->nextrp;
+ prev_rp->parentfp = NULL;
return 1;
}
while ((rp = prev_rp->nextrp)) {
if (srp == rp) {
- rp->parentfp = NULL;
prev_rp->nextrp = rp->nextrp;
+ rp->parentfp = NULL;
return 1;
}
prev_rp = rp;
@@ -1551,7 +1580,7 @@
/* Need to stop sg_command_done() playing with this list during this loop */
while (srp) {
tsrp = srp->nextrp;
- if (! srp->my_cmdp)
+ if (srp->done)
sg_finish_rem_req(srp, NULL, 0);
else
++dirty;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)