]> Pileus Git - ~andy/linux/commitdiff
[SCSI] ipr: Support new device queueing model
authorbrking@us.ibm.com <brking@us.ibm.com>
Tue, 1 Nov 2005 23:02:22 +0000 (17:02 -0600)
committerJames Bottomley <jejb@mulgrave.(none)>
Sun, 6 Nov 2005 19:09:47 +0000 (13:09 -0600)
New ipr adapters support a new device queueing model in the
adapter firmware. The queueing model is the NACA queueing model,
but it does not mean use of NACA is required. The new model removes
some of the adapter firmware queue state that made handling QERR=0
almost impossible. The queueing model on older adapters included the
concept of a queue frozen state, which would freeze the response
queue in the adapter when a check condition occurred, requiring a
a primitive to resume the queue. The new queueing model removes this
complexity.

Signed-off-by: Brian King <brking@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/ipr.c
drivers/scsi/ipr.h

index cca4972735be724c2da8a8fc4cf18c70506d9a8c..2f84f26624bf8778e49f2d82d4ce21e15f5e73d3 100644 (file)
@@ -814,7 +814,7 @@ static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type,
  **/
 static void ipr_init_res_entry(struct ipr_resource_entry *res)
 {
-       res->needs_sync_complete = 1;
+       res->needs_sync_complete = 0;
        res->in_erp = 0;
        res->add_to_ml = 0;
        res->del_from_ml = 0;
@@ -3251,7 +3251,8 @@ static int ipr_slave_alloc(struct scsi_device *sdev)
                        res->add_to_ml = 0;
                        res->in_erp = 0;
                        sdev->hostdata = res;
-                       res->needs_sync_complete = 1;
+                       if (!ipr_is_naca_model(res))
+                               res->needs_sync_complete = 1;
                        rc = 0;
                        break;
                }
@@ -3515,7 +3516,8 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
        }
 
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
-       res->needs_sync_complete = 1;
+       if (!ipr_is_naca_model(res))
+               res->needs_sync_complete = 1;
 
        LEAVE;
        return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS);
@@ -3819,7 +3821,8 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
        }
 
        if (res) {
-               res->needs_sync_complete = 1;
+               if (!ipr_is_naca_model(res))
+                       res->needs_sync_complete = 1;
                res->in_erp = 0;
        }
        ipr_unmap_sglist(ioa_cfg, ipr_cmd);
@@ -4088,6 +4091,30 @@ static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd)
        }
 }
 
+/**
+ * ipr_get_autosense - Copy autosense data to sense buffer
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function copies the autosense buffer to the buffer
+ * in the scsi_cmd, if there is autosense available.
+ *
+ * Return value:
+ *     1 if autosense was available / 0 if not
+ **/
+static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+
+       if ((be32_to_cpu(ioasa->ioasc_specific) &
+            (IPR_ADDITIONAL_STATUS_FMT | IPR_AUTOSENSE_VALID)) == 0)
+               return 0;
+
+       memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data,
+              min_t(u16, be16_to_cpu(ioasa->auto_sense.auto_sense_len),
+                  SCSI_SENSE_BUFFERSIZE));
+       return 1;
+}
+
 /**
  * ipr_erp_start - Process an error response for a SCSI op
  * @ioa_cfg:   ioa config struct
@@ -4118,7 +4145,10 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
 
        switch (ioasc & IPR_IOASC_IOASC_MASK) {
        case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
-               scsi_cmd->result |= (DID_IMM_RETRY << 16);
+               if (ipr_is_naca_model(res))
+                       scsi_cmd->result |= (DID_ABORT << 16);
+               else
+                       scsi_cmd->result |= (DID_IMM_RETRY << 16);
                break;
        case IPR_IOASC_IR_RESOURCE_HANDLE:
        case IPR_IOASC_IR_NO_CMDS_TO_2ND_IOA:
@@ -4126,7 +4156,8 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
                break;
        case IPR_IOASC_HW_SEL_TIMEOUT:
                scsi_cmd->result |= (DID_NO_CONNECT << 16);
-               res->needs_sync_complete = 1;
+               if (!ipr_is_naca_model(res))
+                       res->needs_sync_complete = 1;
                break;
        case IPR_IOASC_SYNC_REQUIRED:
                if (!res->in_erp)
@@ -4146,21 +4177,27 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
                if (!res->resetting_device)
                        scsi_report_bus_reset(ioa_cfg->host, scsi_cmd->device->channel);
                scsi_cmd->result |= (DID_ERROR << 16);
-               res->needs_sync_complete = 1;
+               if (!ipr_is_naca_model(res))
+                       res->needs_sync_complete = 1;
                break;
        case IPR_IOASC_HW_DEV_BUS_STATUS:
                scsi_cmd->result |= IPR_IOASC_SENSE_STATUS(ioasc);
                if (IPR_IOASC_SENSE_STATUS(ioasc) == SAM_STAT_CHECK_CONDITION) {
-                       ipr_erp_cancel_all(ipr_cmd);
-                       return;
+                       if (!ipr_get_autosense(ipr_cmd)) {
+                               if (!ipr_is_naca_model(res)) {
+                                       ipr_erp_cancel_all(ipr_cmd);
+                                       return;
+                               }
+                       }
                }
-               res->needs_sync_complete = 1;
+               if (!ipr_is_naca_model(res))
+                       res->needs_sync_complete = 1;
                break;
        case IPR_IOASC_NR_INIT_CMD_REQUIRED:
                break;
        default:
                scsi_cmd->result |= (DID_ERROR << 16);
-               if (!ipr_is_vset_device(res))
+               if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res))
                        res->needs_sync_complete = 1;
                break;
        }
index f7fa8cd2ecadacb62c55cd3a903f22c3f5acdce3..c9cc40e5db2418145f7c301499b97993e0d5f867 100644 (file)
@@ -302,6 +302,10 @@ struct ipr_config_table_entry {
 #define IPR_SUBTYPE_GENERIC_SCSI       1
 #define IPR_SUBTYPE_VOLUME_SET         2
 
+#define IPR_QUEUEING_MODEL(res)        ((((res)->cfgte.flags) & 0x70) >> 4)
+#define IPR_QUEUE_FROZEN_MODEL 0
+#define IPR_QUEUE_NACA_MODEL           1
+
        struct ipr_res_addr res_addr;
        __be32 res_handle;
        __be32 reserved4[2];
@@ -1293,6 +1297,20 @@ static inline int ipr_is_gscsi(struct ipr_resource_entry *res)
                return 0;
 }
 
+/**
+ * ipr_is_naca_model - Determine if a resource is using NACA queueing model
+ * @res:       resource entry struct
+ *
+ * Return value:
+ *     1 if NACA queueing model / 0 if not NACA queueing model
+ **/
+static inline int ipr_is_naca_model(struct ipr_resource_entry *res)
+{
+       if (ipr_is_gscsi(res) && IPR_QUEUEING_MODEL(res) == IPR_QUEUE_NACA_MODEL)
+               return 1;
+       return 0;
+}
+
 /**
  * ipr_is_device - Determine if resource address is that of a device
  * @res_addr:  resource address struct