Subject: scsi_dh: add scsi device handler to dm

From: Mike Anderson <[EMAIL PROTECTED]>

This patch adds a dm hardware handler that can control SCSI device
handlers.

SCSI Hardware handler for a specific device type can be invokes by using
this handler.

For example, to use the lsi_rdac SCSI hardware handler, one would specify
        hardware_handler        "2 scsi_dh lsi_rdac"
in the device section of /etc/multipath.conf.

Signed-off-by: Mike Anderson <[EMAIL PROTECTED]>
Signed-off-by: Chandra Seetharaman <[EMAIL PROTECTED]>
---

 drivers/md/Kconfig            |    6   6 +     0 -     0 !
 drivers/md/Makefile           |    2   2 +     0 -     0 !
 drivers/md/dm-mpath-scsi-dh.c |  185   185 +   0 -     0 !
 3 files changed, 193 insertions(+)

Index: linux-2.6.24-rc8/drivers/md/Kconfig
===================================================================
--- linux-2.6.24-rc8.orig/drivers/md/Kconfig
+++ linux-2.6.24-rc8/drivers/md/Kconfig
@@ -273,6 +273,12 @@ config DM_MULTIPATH_HP
         ---help---
           Multipath support for HP MSA (Active/Passive) series hardware.
 
+config DM_MULTIPATH_SCSI_DH
+        tristate "SCSI Device Handler support (EXPERIMENTAL)"
+        depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL
+        ---help---
+          Multipath support for SCSI Device Handlers.
+
 config DM_DELAY
        tristate "I/O delaying target (EXPERIMENTAL)"
        depends on BLK_DEV_DM && EXPERIMENTAL
Index: linux-2.6.24-rc8/drivers/md/Makefile
===================================================================
--- linux-2.6.24-rc8.orig/drivers/md/Makefile
+++ linux-2.6.24-rc8/drivers/md/Makefile
@@ -9,6 +9,7 @@ dm-snapshot-objs := dm-snap.o dm-excepti
 dm-mirror-objs := dm-log.o dm-raid1.o
 dm-rdac-objs   := dm-mpath-rdac.o
 dm-hp-sw-objs  := dm-mpath-hp-sw.o
+dm-scsi-dh-objs := dm-mpath-scsi-dh.o
 md-mod-objs     := md.o bitmap.o
 raid456-objs   := raid5.o raid6algos.o raid6recov.o raid6tables.o \
                   raid6int1.o raid6int2.o raid6int4.o \
@@ -38,6 +39,7 @@ obj-$(CONFIG_DM_MULTIPATH)    += dm-multipa
 obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o
 obj-$(CONFIG_DM_MULTIPATH_HP)  += dm-hp-sw.o
 obj-$(CONFIG_DM_MULTIPATH_RDAC)        += dm-rdac.o
+obj-$(CONFIG_DM_MULTIPATH_SCSI_DH) += dm-scsi-dh.o
 obj-$(CONFIG_DM_SNAPSHOT)      += dm-snapshot.o
 obj-$(CONFIG_DM_MIRROR)                += dm-mirror.o
 obj-$(CONFIG_DM_ZERO)          += dm-zero.o
Index: linux-2.6.24-rc8/drivers/md/dm-mpath-scsi-dh.c
===================================================================
--- /dev/null
+++ linux-2.6.24-rc8/drivers/md/dm-mpath-scsi-dh.c
@@ -0,0 +1,185 @@
+/*
+ * SCSI Device handler
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ *     Author: Mike Anderson <[EMAIL PROTECTED]>
+ */
+
+#define DM_MSG_PREFIX "multipath scsi_dh"
+
+#include "dm.h"
+#include "dm-hw-handler.h"
+
+struct scsi_dh_context {
+       char            *hw_handler_name;
+       struct dm_path  *path;
+};
+
+static int scsi_dh_create(struct hw_handler *hwh, unsigned argc, char **argv)
+{
+       struct scsi_dh_context *c;
+
+       c = kzalloc(sizeof(*c), GFP_KERNEL);
+       if (!c)
+               return -ENOMEM;
+       if (argc == 1) {
+               c->hw_handler_name = kstrdup(argv[0], GFP_KERNEL);
+               if (c->hw_handler_name)
+                       request_module("scsi_dh_%s", c->hw_handler_name);
+       }
+
+       hwh->context = c;
+
+       return 0;
+}
+
+static void scsi_dh_destroy(struct hw_handler *hwh)
+{
+       struct scsi_dh_context *c = hwh->context;
+       kfree(c->hw_handler_name);
+       kfree(c);
+       hwh->context = NULL;
+       return;
+}
+
+static unsigned scsi_dh_error(struct hw_handler *hwh, struct bio *bio)
+{
+       /* Try default handler */
+       return dm_scsi_err_handler(hwh, bio);
+}
+
+
+static void pg_init_done(struct request *req, int err)
+{
+       struct scsi_dh_context *c = req->end_io_data;
+       int ret = 0;
+
+       if (blkerr_transport_err(req->errors)) {
+               /*
+                * Old dm behavior had us fail a path on any error.
+                * In future patches, since we have finer grained errors now,
+                * we do not have to fail the path on the first transient
+                * error.
+                */
+               ret = MP_FAIL_PATH;
+               goto out;
+       }
+
+       /* device or driver problems */
+       switch (req->errors) {
+       case BLKERR_OK:
+               break;
+       case BLKERR_NOSYS:
+               if (!c->hw_handler_name)
+                       break;
+               DMERR("Cannot failover device because hw-%s may not be "
+                     "loaded.", c->hw_handler_name);
+               /*
+                * Fail path for now, so we do not ping poing
+                */
+               ret = MP_FAIL_PATH;
+               break;
+       case BLKERR_DEV_TEMP_BUSY:
+               /*
+                * Probably doing something like FW upgrade on the
+                * controller so try the other pg.
+                */
+               ret = MP_BYPASS_PG;
+               break;
+       /* TODO: For BLKERR_RETRY we should wait a couple seconds */
+       case BLKERR_RETRY:
+       case BLKERR_IMM_RETRY:
+       case BLKERR_RES_TEMP_UNAVAIL:
+               break;
+       default:
+               /*
+                * We probably do not want to fail the path for a device
+                * error, but this is what the old dm did. In future
+                * patches we can do more advanced handling.
+                */
+               ret = MP_FAIL_PATH;
+       }
+
+out:
+       dm_pg_init_complete(c->path, ret);
+       __blk_put_request(req->q, req);
+       return;
+}
+
+static void scsi_dh_pg_init(struct hw_handler *hwh, unsigned bypassed,
+                       struct dm_path *path)
+{
+       struct scsi_dh_context *c = hwh->context;
+       struct request *req;
+
+       req = blk_get_request(bdev_get_queue(path->dev->bdev), 1, GFP_NOIO);
+       if (!req) {
+               /* FIXME: Add retry */
+               dm_pg_init_complete(path, MP_FAIL_PATH);
+               return;
+       }
+
+       req->cmd[0] = REQ_LB_OP_TRANSITION;
+       req->cmd_type = REQ_TYPE_LINUX_BLOCK;
+       c->path = path;
+       req->end_io_data = c;
+       /* TODO: does this need to be configurable or is it HW specific? */
+       req->retries = 5;
+       blk_execute_rq_nowait(req->q, NULL, req, 1, pg_init_done);
+}
+
+#define SCSI_DH_NAME "scsi_dh"
+#define SCSI_DH_VER "0.1"
+
+static struct hw_handler_type scsi_dh_handler = {
+       .name = SCSI_DH_NAME,
+       .module = THIS_MODULE,
+       .create = scsi_dh_create,
+       .destroy = scsi_dh_destroy,
+       .pg_init = scsi_dh_pg_init,
+       .error = scsi_dh_error,
+};
+
+static int __init scsi_dh_init(void)
+{
+       int r;
+
+       r = dm_register_hw_handler(&scsi_dh_handler);
+       if (r < 0) {
+               DMERR("%s: register failed %d", SCSI_DH_NAME, r);
+               return r;
+       }
+
+       DMINFO("%s: version %s loaded", SCSI_DH_NAME, SCSI_DH_VER);
+       return 0;
+}
+
+static void __exit scsi_dh_exit(void)
+{
+       int r = dm_unregister_hw_handler(&scsi_dh_handler);
+
+       if (r < 0)
+               DMERR("%s: unregister failed %d", SCSI_DH_NAME, r);
+}
+
+module_init(scsi_dh_init);
+module_exit(scsi_dh_exit);
+
+MODULE_DESCRIPTION("DM Multipath SCSI Device Handler support");
+MODULE_AUTHOR("Mike Anderson <[EMAIL PROTECTED]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SCSI_DH_VER);

-- 

----------------------------------------------------------------------
    Chandra Seetharaman               | Be careful what you choose....
              - [EMAIL PROTECTED]   |      .......you may get it.
----------------------------------------------------------------------
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to