[SCSI] scsi error: have scsi-ml call change_queue_depth to handle QUEUE_FULL
authorMike Christie <michaelc@cs.wisc.edu>
Fri, 16 Oct 2009 00:46:44 +0000 (17:46 -0700)
committerJames Bottomley <James.Bottomley@suse.de>
Fri, 4 Dec 2009 18:00:42 +0000 (12:00 -0600)
This has scsi-ml call the change_queue_depth functions when
we get a QUEUE_FULL. It will only change the queue depth if
change_queue_depth is set because the LLD may have to
modify some internal resources, so I thought this would
be the safest route.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
-v2
Limits change_queue_depth to only all luns of target by adding
channel check while iterating for all luns of Scsi_Host. This is
same as currently qla2xxx FC HBA does on QUEUE_FULL event.

Signed-off-by: Vasu Dev <vasu.dev@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/scsi_error.c

index 1b0060b791e8dc6fe0b1dd4ace0a1e3f3ea96c7e..7b1e20fee906983298d5aef2c064f17b7da7e12c 100644 (file)
@@ -331,6 +331,28 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
        }
 }
 
+static void scsi_handle_queue_full(struct scsi_device *sdev)
+{
+       struct scsi_host_template *sht = sdev->host->hostt;
+       struct scsi_device *tmp_sdev;
+
+       if (!sht->change_queue_depth)
+               return;
+
+       shost_for_each_device(tmp_sdev, sdev->host) {
+               if (tmp_sdev->channel != sdev->channel ||
+                   tmp_sdev->id != sdev->id)
+                       continue;
+               /*
+                * We do not know the number of commands that were at
+                * the device when we got the queue full so we start
+                * from the highest possible value and work our way down.
+                */
+               sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1,
+                                       SCSI_QDEPTH_QFULL);
+       }
+}
+
 /**
  * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD.
  * @scmd:      SCSI cmd to examine.
@@ -387,8 +409,10 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
                 * let issuer deal with this, it could be just fine
                 */
                return SUCCESS;
-       case BUSY:
        case QUEUE_FULL:
+               scsi_handle_queue_full(scmd->device);
+               /* fall through */
+       case BUSY:
        default:
                return FAILED;
        }
@@ -1387,6 +1411,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
         */
        switch (status_byte(scmd->result)) {
        case QUEUE_FULL:
+               scsi_handle_queue_full(scmd->device);
                /*
                 * the case of trying to send too many commands to a
                 * tagged queueing device.