]> err.no Git - linux-2.6/blobdiff - drivers/md/dm-mpath-hp-sw.c
[ARM] Merge most of the PXA work for initial merge
[linux-2.6] / drivers / md / dm-mpath-hp-sw.c
index 575317037ce2f10056371e1a8c1977a52a29a315..b63a0ab37c538736c9eac9869fdf464105ba0025 100644 (file)
 #include <linux/types.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
 
 #include "dm.h"
 #include "dm-hw-handler.h"
 
 #define DM_MSG_PREFIX "multipath hp-sw"
 #define DM_HP_HWH_NAME "hp-sw"
-#define DM_HP_HWH_VER "0.0.3"
+#define DM_HP_HWH_VER "1.0.0"
 
 struct hp_sw_context {
        unsigned char sense[SCSI_SENSE_BUFFERSIZE];
 };
 
+/*
+ * hp_sw_error_is_retryable - Is an HP-specific check condition retryable?
+ * @req: path activation request
+ *
+ * Examine error codes of request and determine whether the error is retryable.
+ * Some error codes are already retried by scsi-ml (see
+ * scsi_decide_disposition), but some HP specific codes are not.
+ * The intent of this routine is to supply the logic for the HP specific
+ * check conditions.
+ *
+ * Returns:
+ *  1 - command completed with retryable error
+ *  0 - command completed with non-retryable error
+ *
+ * Possible optimizations
+ * 1. More hardware-specific error codes
+ */
+static int hp_sw_error_is_retryable(struct request *req)
+{
+       /*
+        * NOT_READY is known to be retryable
+        * For now we just dump out the sense data and call it retryable
+        */
+       if (status_byte(req->errors) == CHECK_CONDITION)
+               __scsi_print_sense(DM_HP_HWH_NAME, req->sense, req->sense_len);
+
+       /*
+        * At this point we don't have complete information about all the error
+        * codes from this hardware, so we are just conservative and retry
+        * when in doubt.
+        */
+       return 1;
+}
+
 /*
  * hp_sw_end_io - Completion handler for HP path activation.
  * @req: path activation request
@@ -40,23 +75,30 @@ struct hp_sw_context {
  *
  * Context: scsi-ml softirq
  *
- * Possible optimizations
- * 1. Actually check sense data for retryable error (e.g. NOT_READY)
  */
 static void hp_sw_end_io(struct request *req, int error)
 {
        struct dm_path *path = req->end_io_data;
        unsigned err_flags = 0;
 
-       if (!error)
+       if (!error) {
                DMDEBUG("%s path activation command - success",
                        path->dev->name);
-       else {
-               DMWARN("%s path activation command - error=0x%x",
-                      path->dev->name, error);
-               err_flags = MP_FAIL_PATH;
+               goto out;
        }
 
+       if (hp_sw_error_is_retryable(req)) {
+               DMDEBUG("%s path activation command - retry",
+                       path->dev->name);
+               err_flags = MP_RETRY;
+               goto out;
+       }
+
+       DMWARN("%s path activation fail - error=0x%x",
+              path->dev->name, error);
+       err_flags = MP_FAIL_PATH;
+
+out:
        req->end_io_data = NULL;
        __blk_put_request(req->q, req);
        dm_pg_init_complete(path, err_flags);
@@ -95,7 +137,6 @@ static struct request *hp_sw_get_request(struct dm_path *path)
        req->sense = h->sense;
        memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
 
-       memset(&req->cmd, 0, BLK_MAX_CDB);
        req->cmd[0] = START_STOP;
        req->cmd[4] = 1;
        req->cmd_len = COMMAND_SIZE(req->cmd[0]);
@@ -135,7 +176,7 @@ static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed,
        if (!req) {
                DMERR("%s path activation command - allocation fail",
                      path->dev->name);
-               goto fail;
+               goto retry;
        }
 
        DMDEBUG("%s path activation command - sent", path->dev->name);
@@ -143,8 +184,8 @@ static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed,
        blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io);
        return;
 
-fail:
-       dm_pg_init_complete(path, MP_FAIL_PATH);
+retry:
+       dm_pg_init_complete(path, MP_RETRY);
 }
 
 static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv)