[SCSI] libsas: dynamic queue depth
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / libsas / sas_scsi_host.c
index eeba76cdf7746c518c49f680d3d2ab9f3a9b863a..ebd1417339e96e5b6ee5c93ca5a0db004ce22940 100644 (file)
@@ -182,79 +182,56 @@ int sas_queue_up(struct sas_task *task)
        return 0;
 }
 
-/**
- * sas_queuecommand -- Enqueue a command for processing
- * @parameters: See SCSI Core documentation
- *
- * Note: XXX: Remove the host unlock/lock pair when SCSI Core can
- * call us without holding an IRQ spinlock...
- */
-static int sas_queuecommand_lck(struct scsi_cmnd *cmd,
-                    void (*scsi_done)(struct scsi_cmnd *))
-       __releases(host->host_lock)
-       __acquires(dev->sata_dev.ap->lock)
-       __releases(dev->sata_dev.ap->lock)
-       __acquires(host->host_lock)
+int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 {
-       int res = 0;
-       struct domain_device *dev = cmd_to_domain_dev(cmd);
-       struct Scsi_Host *host = cmd->device->host;
        struct sas_internal *i = to_sas_internal(host->transportt);
+       struct domain_device *dev = cmd_to_domain_dev(cmd);
+       struct sas_ha_struct *sas_ha = dev->port->ha;
+       struct sas_task *task;
+       int res = 0;
 
-       spin_unlock_irq(host->host_lock);
+       /* If the device fell off, no sense in issuing commands */
+       if (dev->gone) {
+               cmd->result = DID_BAD_TARGET << 16;
+               goto out_done;
+       }
 
-       {
-               struct sas_ha_struct *sas_ha = dev->port->ha;
-               struct sas_task *task;
-
-               /* If the device fell off, no sense in issuing commands */
-               if (dev->gone) {
-                       cmd->result = DID_BAD_TARGET << 16;
-                       scsi_done(cmd);
-                       goto out;
-               }
+       if (dev_is_sata(dev)) {
+               unsigned long flags;
 
-               if (dev_is_sata(dev)) {
-                       unsigned long flags;
+               spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+               res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
+               spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+               return res;
+       }
 
-                       spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
-                       res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
-                       spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
-                       goto out;
-               }
+       task = sas_create_task(cmd, dev, GFP_ATOMIC);
+       if (!task)
+               return SCSI_MLQUEUE_HOST_BUSY;
 
-               res = -ENOMEM;
-               task = sas_create_task(cmd, dev, GFP_ATOMIC);
-               if (!task)
-                       goto out;
+       /* Queue up, Direct Mode or Task Collector Mode. */
+       if (sas_ha->lldd_max_execute_num < 2)
+               res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
+       else
+               res = sas_queue_up(task);
 
-               cmd->scsi_done = scsi_done;
-               /* Queue up, Direct Mode or Task Collector Mode. */
-               if (sas_ha->lldd_max_execute_num < 2)
-                       res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
-               else
-                       res = sas_queue_up(task);
+       if (res)
+               goto out_free_task;
+       return 0;
 
-               /* Examine */
-               if (res) {
-                       SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
-                       ASSIGN_SAS_TASK(cmd, NULL);
-                       sas_free_task(task);
-                       if (res == -SAS_QUEUE_FULL) {
-                               cmd->result = DID_SOFT_ERROR << 16; /* retry */
-                               res = 0;
-                               scsi_done(cmd);
-                       }
-                       goto out;
-               }
-       }
-out:
-       spin_lock_irq(host->host_lock);
-       return res;
+out_free_task:
+       SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+       ASSIGN_SAS_TASK(cmd, NULL);
+       sas_free_task(task);
+       if (res == -SAS_QUEUE_FULL)
+               cmd->result = DID_SOFT_ERROR << 16; /* retry */
+       else
+               cmd->result = DID_ERROR << 16;
+out_done:
+       cmd->scsi_done(cmd);
+       return 0;
 }
 
-DEF_SCSI_QCMD(sas_queuecommand)
-
 static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
 {
        struct sas_task *task = TO_SAS_TASK(cmd);
@@ -784,8 +761,7 @@ int sas_target_alloc(struct scsi_target *starget)
        return 0;
 }
 
-#define SAS_DEF_QD 32
-#define SAS_MAX_QD 64
+#define SAS_DEF_QD 256
 
 int sas_slave_configure(struct scsi_device *scsi_dev)
 {
@@ -828,31 +804,38 @@ void sas_slave_destroy(struct scsi_device *scsi_dev)
                dev->sata_dev.ap->link.device[0].class = ATA_DEV_NONE;
 }
 
-int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth,
-                          int reason)
+int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
 {
-       int res = min(new_depth, SAS_MAX_QD);
+       struct domain_device *dev = sdev_to_domain_dev(sdev);
 
-       if (reason != SCSI_QDEPTH_DEFAULT)
+       if (dev_is_sata(dev))
+               return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth,
+                                               reason);
+
+       switch (reason) {
+       case SCSI_QDEPTH_DEFAULT:
+       case SCSI_QDEPTH_RAMP_UP:
+               if (!sdev->tagged_supported)
+                       depth = 1;
+               scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
+               break;
+       case SCSI_QDEPTH_QFULL:
+               scsi_track_queue_full(sdev, depth);
+               break;
+       default:
                return -EOPNOTSUPP;
-
-       if (scsi_dev->tagged_supported)
-               scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
-                                       res);
-       else {
-               struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
-               sas_printk("device %llx LUN %x queue depth changed to 1\n",
-                          SAS_ADDR(dev->sas_addr),
-                          scsi_dev->lun);
-               scsi_adjust_queue_depth(scsi_dev, 0, 1);
-               res = 1;
        }
 
-       return res;
+       return depth;
 }
 
 int sas_change_queue_type(struct scsi_device *scsi_dev, int qt)
 {
+       struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+       if (dev_is_sata(dev))
+               return -EINVAL;
+
        if (!scsi_dev->tagged_supported)
                return 0;