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

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)