]> git.hungrycats.org Git - linux/commitdiff
Restore device command queue functionality
authorJames Bottomley <jejb@raven.il.steeleye.com>
Sun, 9 Feb 2003 03:36:18 +0000 (21:36 -0600)
committerJames Bottomley <jejb@raven.il.steeleye.com>
Sun, 9 Feb 2003 03:36:18 +0000 (21:36 -0600)
The recent slab allocation changes mean that we no longer keep a
permanent list of commands on the device_queue list.  However,
certain pieces of SCSI code relied on being able to traverse this
list to find details of all outstanding commands (the error handler
being the prime example).  This code adds back a new dynamic cmd_list
which keeps the list of commands currently allocated to the device.
Since the list is dynamic, it is protected by a lock (list_lock).

drivers/scsi/dpt_i2o.c
drivers/scsi/hosts.c
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_error.c
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_scan.c

index 31461b46fc2201f7a194f5d1114670b8efd28e4a..b35c75e1b62f8eae095a0913b38e62a73316609f 100644 (file)
@@ -2510,13 +2510,16 @@ static void adpt_fail_posted_scbs(adpt_hba* pHba)
        Scsi_Device*    d = NULL;
 
        list_for_each_entry(d, &pHba->host->my_devices, siblings) {
-               for(cmd = d->device_queue; cmd ; cmd = cmd->next){
+               unsigned long flags;
+               spin_lock_irqsave(&d->list_lock, flags);
+               list_for_each_entry(cmd, &d->cmd_list, list) {
                        if(cmd->serial_number == 0){
                                continue;
                        }
                        cmd->result = (DID_OK << 16) | (QUEUE_FULL <<1);
                        cmd->scsi_done(cmd);
                }
+               spin_unlock_irqrestore(&d->list_lock, flags);
        }
 }
 
index ca7185175eb2ae6525f75ea0a86bc66464bde63e..16c5c4ac76ffff5acd3a1331f193ff25132a363c 100644 (file)
@@ -205,13 +205,15 @@ static int scsi_check_device_busy(struct scsi_device *sdev)
 {
        struct Scsi_Host *shost = sdev->host;
        struct scsi_cmnd *scmd;
+       unsigned long flags;
 
        /*
         * Loop over all of the commands associated with the
         * device.  If any of them are busy, then set the state
         * back to inactive and bail.
         */
-       for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
+       spin_lock_irqsave(&sdev->list_lock, flags);
+       list_for_each_entry(scmd, &sdev->cmd_list, list) {
                if (scmd->request && scmd->request->rq_status != RQ_INACTIVE)
                        goto active;
 
@@ -223,6 +225,7 @@ static int scsi_check_device_busy(struct scsi_device *sdev)
                if (scmd->request)
                        scmd->request->rq_status = RQ_SCSI_DISCONNECTING;
        }
+       spin_unlock_irqrestore(&sdev->list_lock, flags);
 
        return 0;
 
@@ -233,12 +236,13 @@ active:
                        scmd->pid, scmd->state, scmd->owner);
 
        list_for_each_entry(sdev, &shost->my_devices, siblings) {
-               for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
+               list_for_each_entry(scmd, &sdev->cmd_list, list) {
                        if (scmd->request->rq_status == RQ_SCSI_DISCONNECTING)
                                scmd->request->rq_status = RQ_INACTIVE;
                }
        }
 
+       spin_unlock_irqrestore(&sdev->list_lock, flags);
        printk(KERN_ERR "Device busy???\n");
        return 1;
 }
index cc8ff7cf49bed0a8dc51aa607d2a54efb35ad8c2..3d15efce2b9b9c2dc6f4f130500b46e8b671e60e 100644 (file)
@@ -403,12 +403,17 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask)
        struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
 
        if (likely(cmd != NULL)) {
+               unsigned long flags;
+
                memset(cmd, 0, sizeof(*cmd));
                cmd->device = dev;
                cmd->state = SCSI_STATE_UNUSED;
                cmd->owner = SCSI_OWNER_NOBODY;
                init_timer(&cmd->eh_timeout);
                INIT_LIST_HEAD(&cmd->list);
+               spin_lock_irqsave(&dev->list_lock, flags);
+               list_add(&dev->cmd_list, &cmd->list);
+               spin_unlock_irqrestore(&dev->list_lock, flags);
        }
 
        return cmd;
@@ -430,7 +435,13 @@ void scsi_put_command(struct scsi_cmnd *cmd)
        struct Scsi_Host *shost = cmd->device->host;
        unsigned long flags;
        
-       spin_lock_irqsave(&shost->free_list_lock, flags);
+       /* serious error if the command hasn't come from a device list */
+       spin_lock_irqsave(&cmd->device->list_lock, flags);
+       BUG_ON(list_empty(&cmd->list));
+       list_del_init(&cmd->list);
+       spin_unlock(&cmd->device->list_lock);
+       /* changing locks here, don't need to restore the irq state */
+       spin_lock(&shost->free_list_lock);
        if (unlikely(list_empty(&shost->free_list))) {
                list_add(&cmd->list, &shost->free_list);
                cmd = NULL;
index b5a77c9254a9a720b590ce9e2780a4e6cac25780..48eb1bb2f54c7ca1cf3a205bd7442adfbc2d87a3 100644 (file)
@@ -571,9 +571,8 @@ struct scsi_device {
        struct Scsi_Host *host;
        request_queue_t *request_queue;
        volatile unsigned short device_busy;    /* commands actually active on low-level */
-       struct list_head free_cmnds;    /* list of available Scsi_Cmnd structs */
-       struct list_head busy_cmnds;    /* list of Scsi_Cmnd structs in use */
-       Scsi_Cmnd *device_queue;        /* queue of SCSI Command structures */
+       spinlock_t list_lock;
+       struct list_head cmd_list;      /* queue of in use SCSI Command structures */
         Scsi_Cmnd *current_cmnd;       /* currently active command */
        unsigned short queue_depth;     /* How deep of a queue we want */
        unsigned short last_queue_full_depth; /* These two are used by */
@@ -724,7 +723,6 @@ struct scsi_cmnd {
        unsigned short state;
        unsigned short owner;
        Scsi_Request *sc_request;
-       struct scsi_cmnd *next;
        struct scsi_cmnd *reset_chain;
 
        struct list_head list;  /* scsi_cmnd participates in queue lists */
index f21af2d1c1e29b8986e42fa4235438a794bcd767..c0bb52aaa3bd79ad3427e17464e2de80805b2f31 100644 (file)
@@ -233,7 +233,10 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
 
        found = 0;
        list_for_each_entry(sdev, &shost->my_devices, siblings) {
-               for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&sdev->list_lock, flags);
+               list_for_each_entry(scmd, &sdev->cmd_list, list) {
                        if (scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
                                scmd->bh_next = *sc_list;
                                *sc_list = scmd;
@@ -266,6 +269,7 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
                                }
                        }
                }
+               spin_unlock_irqrestore(&sdev->list_lock, flags);
        }
 
        SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost));
@@ -1739,25 +1743,13 @@ scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt)
 int
 scsi_reset_provider(Scsi_Device *dev, int flag)
 {
-       struct scsi_cmnd SC, *SCpnt = &SC;
+       struct scsi_cmnd *SCpnt = scsi_get_command(dev, GFP_KERNEL);
        struct request req;
        int rtn;
 
        SCpnt->request = &req;
        memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
-       SCpnt->device                   = dev;
        SCpnt->request->rq_status       = RQ_SCSI_BUSY;
-       SCpnt->request->waiting         = NULL;
-       SCpnt->use_sg                   = 0;
-       SCpnt->old_use_sg               = 0;
-       SCpnt->old_cmd_len              = 0;
-       SCpnt->underflow                = 0;
-       SCpnt->transfersize             = 0;
-       SCpnt->resid                    = 0;
-       SCpnt->serial_number            = 0;
-       SCpnt->serial_number_at_timeout = 0;
-       SCpnt->host_scribble            = NULL;
-       SCpnt->next                     = NULL;
        SCpnt->state                    = SCSI_STATE_INITIALIZING;
        SCpnt->owner                    = SCSI_OWNER_MIDLEVEL;
     
@@ -1790,5 +1782,6 @@ scsi_reset_provider(Scsi_Device *dev, int flag)
        rtn = scsi_new_reset(SCpnt, flag);
 
        scsi_delete_timer(SCpnt);
+       scsi_put_command(SCpnt);
        return rtn;
 }
index 173cce3c39ba292b9d7af6a7d1d2c59f84c29451..075956e8bdda744fad5f85174b0f2055983183b4 100644 (file)
@@ -359,7 +359,10 @@ static void scsi_dump_status(int level)
                printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) "
                        "(ret all flg) (to/cmd to ito) cmd snse result\n");
                list_for_each_entry(SDpnt, &shpnt->my_devices, siblings) {
-                       for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&SDpnt->list_lock, flags);
+                       list_for_each_entry(SCpnt, &SDpnt->cmd_list, list) {
                                /*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
                                printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
                                       i++,
@@ -389,6 +392,7 @@ static void scsi_dump_status(int level)
                                       SCpnt->sense_buffer[2],
                                       SCpnt->result);
                        }
+                       spin_unlock_irqrestore(&SDpnt->list_lock, flags);
                }
        }
 }
index ba43ec82d8e7ddec2fa6f8573ad8e24ee3f921e8..2688a56fe0d42ff3c29bbb5e3d1ba617a9374689 100644 (file)
@@ -449,6 +449,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
                sdev->online = TRUE;
                INIT_LIST_HEAD(&sdev->siblings);
                INIT_LIST_HEAD(&sdev->same_target_siblings);
+               spin_lock_init(&sdev->list_lock);
                /*
                 * Some low level driver could use device->type
                 */