]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/scsi_lib.c
scsi: Only add commands to the device command list if required by the LLD
[karo-tx-linux.git] / drivers / scsi / scsi_lib.c
index f0eb55744513fb9f0cfa49f6c5d2cfec18ce179f..1470c93a87e7f4024618fed3a8ee0570ade04485 100644 (file)
@@ -584,19 +584,9 @@ static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd)
 
 static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd)
 {
-       struct scsi_device *sdev = cmd->device;
-       struct Scsi_Host *shost = sdev->host;
-       unsigned long flags;
-
        scsi_mq_free_sgtables(cmd);
        scsi_uninit_cmd(cmd);
-
-       if (shost->use_cmd_list) {
-               BUG_ON(list_empty(&cmd->list));
-               spin_lock_irqsave(&sdev->list_lock, flags);
-               list_del_init(&cmd->list);
-               spin_unlock_irqrestore(&sdev->list_lock, flags);
-       }
+       scsi_del_cmd_from_list(cmd);
 }
 
 /*
@@ -1134,12 +1124,40 @@ err_exit:
 }
 EXPORT_SYMBOL(scsi_init_io);
 
+/* Add a command to the list used by the aacraid and dpt_i2o drivers */
+void scsi_add_cmd_to_list(struct scsi_cmnd *cmd)
+{
+       struct scsi_device *sdev = cmd->device;
+       struct Scsi_Host *shost = sdev->host;
+       unsigned long flags;
+
+       if (shost->use_cmd_list) {
+               spin_lock_irqsave(&sdev->list_lock, flags);
+               list_add_tail(&cmd->list, &sdev->cmd_list);
+               spin_unlock_irqrestore(&sdev->list_lock, flags);
+       }
+}
+
+/* Remove a command from the list used by the aacraid and dpt_i2o drivers */
+void scsi_del_cmd_from_list(struct scsi_cmnd *cmd)
+{
+       struct scsi_device *sdev = cmd->device;
+       struct Scsi_Host *shost = sdev->host;
+       unsigned long flags;
+
+       if (shost->use_cmd_list) {
+               spin_lock_irqsave(&sdev->list_lock, flags);
+               BUG_ON(list_empty(&cmd->list));
+               list_del_init(&cmd->list);
+               spin_unlock_irqrestore(&sdev->list_lock, flags);
+       }
+}
+
 void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
 {
        void *buf = cmd->sense_buffer;
        void *prot = cmd->prot_sdb;
        unsigned int unchecked_isa_dma = cmd->flags & SCMD_UNCHECKED_ISA_DMA;
-       unsigned long flags;
 
        /* zero out the cmd, except for the embedded scsi_request */
        memset((char *)cmd + sizeof(cmd->req), 0,
@@ -1152,9 +1170,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
        INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
        cmd->jiffies_at_alloc = jiffies;
 
-       spin_lock_irqsave(&dev->list_lock, flags);
-       list_add_tail(&cmd->list, &dev->cmd_list);
-       spin_unlock_irqrestore(&dev->list_lock, flags);
+       scsi_add_cmd_to_list(cmd);
 }
 
 static int scsi_setup_scsi_cmnd(struct scsi_device *sdev, struct request *req)
@@ -1871,11 +1887,7 @@ static int scsi_mq_prep_fn(struct request *req)
        INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
        cmd->jiffies_at_alloc = jiffies;
 
-       if (shost->use_cmd_list) {
-               spin_lock_irq(&sdev->list_lock);
-               list_add_tail(&cmd->list, &sdev->cmd_list);
-               spin_unlock_irq(&sdev->list_lock);
-       }
+       scsi_add_cmd_to_list(cmd);
 
        sg = (void *)cmd + sizeof(struct scsi_cmnd) + shost->hostt->cmd_size;
        cmd->sdb.table.sgl = sg;
@@ -2625,7 +2637,6 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
                case SDEV_QUIESCE:
                case SDEV_OFFLINE:
                case SDEV_TRANSPORT_OFFLINE:
-               case SDEV_BLOCK:
                        break;
                default:
                        goto illegal;
@@ -2639,6 +2650,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
                case SDEV_OFFLINE:
                case SDEV_TRANSPORT_OFFLINE:
                case SDEV_CANCEL:
+               case SDEV_BLOCK:
                case SDEV_CREATED_BLOCK:
                        break;
                default:
@@ -2882,7 +2894,12 @@ static void scsi_wait_for_queuecommand(struct scsi_device *sdev)
 int
 scsi_device_quiesce(struct scsi_device *sdev)
 {
-       int err = scsi_device_set_state(sdev, SDEV_QUIESCE);
+       int err;
+
+       mutex_lock(&sdev->state_mutex);
+       err = scsi_device_set_state(sdev, SDEV_QUIESCE);
+       mutex_unlock(&sdev->state_mutex);
+
        if (err)
                return err;
 
@@ -2910,10 +2927,11 @@ void scsi_device_resume(struct scsi_device *sdev)
         * so assume the state is being managed elsewhere (for example
         * device deleted during suspend)
         */
-       if (sdev->sdev_state != SDEV_QUIESCE ||
-           scsi_device_set_state(sdev, SDEV_RUNNING))
-               return;
-       scsi_run_queue(sdev->request_queue);
+       mutex_lock(&sdev->state_mutex);
+       if (sdev->sdev_state == SDEV_QUIESCE &&
+           scsi_device_set_state(sdev, SDEV_RUNNING) == 0)
+               scsi_run_queue(sdev->request_queue);
+       mutex_unlock(&sdev->state_mutex);
 }
 EXPORT_SYMBOL(scsi_device_resume);
 
@@ -3012,6 +3030,7 @@ static int scsi_internal_device_block(struct scsi_device *sdev)
        struct request_queue *q = sdev->request_queue;
        int err;
 
+       mutex_lock(&sdev->state_mutex);
        err = scsi_internal_device_block_nowait(sdev);
        if (err == 0) {
                if (q->mq_ops)
@@ -3019,9 +3038,25 @@ static int scsi_internal_device_block(struct scsi_device *sdev)
                else
                        scsi_wait_for_queuecommand(sdev);
        }
+       mutex_unlock(&sdev->state_mutex);
+
        return err;
 }
  
+void scsi_start_queue(struct scsi_device *sdev)
+{
+       struct request_queue *q = sdev->request_queue;
+       unsigned long flags;
+
+       if (q->mq_ops) {
+               blk_mq_start_stopped_hw_queues(q, false);
+       } else {
+               spin_lock_irqsave(q->queue_lock, flags);
+               blk_start_queue(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+       }
+}
+
 /**
  * scsi_internal_device_unblock_nowait - resume a device after a block request
  * @sdev:      device to resume
@@ -3040,9 +3075,6 @@ static int scsi_internal_device_block(struct scsi_device *sdev)
 int scsi_internal_device_unblock_nowait(struct scsi_device *sdev,
                                        enum scsi_device_state new_state)
 {
-       struct request_queue *q = sdev->request_queue; 
-       unsigned long flags;
-
        /*
         * Try to transition the scsi device to SDEV_RUNNING or one of the
         * offlined states and goose the device queue if successful.
@@ -3060,13 +3092,7 @@ int scsi_internal_device_unblock_nowait(struct scsi_device *sdev,
                 sdev->sdev_state != SDEV_OFFLINE)
                return -EINVAL;
 
-       if (q->mq_ops) {
-               blk_mq_start_stopped_hw_queues(q, false);
-       } else {
-               spin_lock_irqsave(q->queue_lock, flags);
-               blk_start_queue(q);
-               spin_unlock_irqrestore(q->queue_lock, flags);
-       }
+       scsi_start_queue(sdev);
 
        return 0;
 }
@@ -3089,7 +3115,13 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_unblock_nowait);
 static int scsi_internal_device_unblock(struct scsi_device *sdev,
                                        enum scsi_device_state new_state)
 {
-       return scsi_internal_device_unblock_nowait(sdev, new_state);
+       int ret;
+
+       mutex_lock(&sdev->state_mutex);
+       ret = scsi_internal_device_unblock_nowait(sdev, new_state);
+       mutex_unlock(&sdev->state_mutex);
+
+       return ret;
 }
 
 static void