* Move dm hw handlers to lower level subsystems
@ 2007-06-09 19:07 michaelc
2007-06-09 19:07 ` [PATCH 1/7] scsi-hw-handler: add REQ_LB_OP_TRANSITION and errors michaelc
0 siblings, 1 reply; 10+ messages in thread
From: michaelc @ 2007-06-09 19:07 UTC (permalink / raw)
To: linux-scsi, dm-devel
The following patches remove the dm hw handlers and move them
to scsi (there is only one hw handler dm-emc, but I also added
one for old hp boxes which cannot be upgraded).
Why move this piece of code to the scsi layer or dasd layer
or wherever they are needed?
- dm is only a BIO mapper/router. It does not know anything about
scsi and it would be nice that it did not have to.
- In the future we can use the scsi hw handlers for more advanced
things. For example, during scanning they can check a devices
state (check it if is a passive path using whatever vendor specific
checks it needs to), then we can set some bits or do
some magic so that when we get commands to passive devices later
(like from partition scanning or userspace app scanning) we
can avoid retries and filling the logs with noisey error messages.
The drawbacks?
- I think sending REQ_TYPE_BLOCK_PC from dm hw handlers is very
simple. There is no needed for the REQ_TYPE_LINUX_BLOCK/REQ_LB_OP_TRANSITION
abstraction.
The patches I am sending converts what is in mainline. In the past
I was converting every patch that has been sent to dm-devel, so I could
make sure it all work or was going to work or was just as horrible as
dm :), but I think it would be an easier transition to just get what
is in mainline coverted so we can began doing more advanced things like
Ed and Chandra's patches (I am working on patches for that once this
is done).
The patches should work with the existing multipath tools. The dm multipath
argument code, will load the scsi hw handler when it see the dm one.
The only thing we do not handle in a nice backward compat way in the
kernel is the dm hw handler specific arguments. Because the hw handlers
move to a different subsytem, there was not nice way to do some sort
of compat code in the kernel. And there was actually only one hw handler,
and I guess Hannes or Ed, in a previous thread said the defaults for it
should be fine most of the time initially so I did not worry.
I did testing on the code, but I do not actaully have any of this hardware,
so I hacked up scsi_debug. This was nice because I can test all the code
paths, but I am not really sure how realistic the testing is. So if you
have a old hp/compaq hsv/msa box where the firmware cannot be upgraded
or a emc clariion box try it out.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/7] scsi-hw-handler: add REQ_LB_OP_TRANSITION and errors
2007-06-09 19:07 Move dm hw handlers to lower level subsystems michaelc
@ 2007-06-09 19:07 ` michaelc
2007-06-09 19:07 ` [PATCH 2/7] scsi-hw-handler: scsi handling of REQ_LB_OP_TRANSITION michaelc
0 siblings, 1 reply; 10+ messages in thread
From: michaelc @ 2007-06-09 19:07 UTC (permalink / raw)
To: linux-scsi, dm-devel; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This patch adds REQ_LB_OP_TRANSITION which is a REQ_TYPE_LINUX_BLOCK
type of command. It also adds the error codes which are used by
REQ_LB_OP_TRANSITION to blkdev.h.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
block/ll_rw_blk.c | 2 +-
include/linux/blkdev.h | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 1 deletions(-)
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 6b5173a..c063792 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -3396,7 +3396,7 @@ static int __end_that_request_first(stru
* for a REQ_BLOCK_PC request, we want to carry any eventual
* sense key with us all the way through
*/
- if (!blk_pc_request(req))
+ if (!blk_pc_request(req) && !blk_linux_request(req))
req->errors = 0;
if (!uptodate) {
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index db5b00a..e02e208 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -175,8 +175,48 @@ enum {
*/
REQ_LB_OP_EJECT = 0x40, /* eject request */
REQ_LB_OP_FLUSH = 0x41, /* flush device */
+ REQ_LB_OP_TRANSITION = 0x42, /* failover/failback a device */
};
+enum {
+ BLKERR_OK = 0,
+ /*
+ * device errors
+ */
+ BLKERR_DEV_FAILED, /* generic device error */
+ BLKERR_DEV_TEMP_BUSY,
+ BLKERR_DEVICE_MAX, /* max device blkerr definition */
+
+ /*
+ * transport errors
+ */
+ BLKERR_NOTCONN = BLKERR_DEVICE_MAX + 1,
+ BLKERR_CONN_FAILURE,
+ BLKERR_TRANSPORT_MAX, /* max transport blkerr definition */
+
+ /*
+ * driver and generic errors
+ */
+ BLKERR_IO = BLKERR_TRANSPORT_MAX + 1, /* generic error */
+ BLKERR_INVALID_IO,
+ BLKERR_RETRY, /* retry the req, but not immediately */
+ BLKERR_IMM_RETRY, /* immediately retry the req */
+ BLKERR_TIMED_OUT,
+ BLKERR_RES_TEMP_UNAVAIL,
+ BLKERR_DEV_OFFLINED,
+ BLKERR_NOSYS,
+ BLKERR_DRIVER_MAX,
+};
+
+#define blk_dev_err(_err) \
+ (_err > BLKERR_OK && _err < BLKERR_DEVICE_MAX)
+
+ #define blkerr_transport_err(_err) \
+ (_err > BLKERR_DEVICE_MAX && _err < BLKERR_TRANSPORT_MAX)
+
+#define blkerr_driver_err(_err) \
+ (_err > BLKERR_TRANSPORT_MAX)
+
/*
* request type modified bits. first three bits match BIO_RW* bits, important
*/
@@ -529,6 +569,7 @@ #define blk_fs_request(rq) ((rq)->cmd_ty
#define blk_pc_request(rq) ((rq)->cmd_type == REQ_TYPE_BLOCK_PC)
#define blk_special_request(rq) ((rq)->cmd_type == REQ_TYPE_SPECIAL)
#define blk_sense_request(rq) ((rq)->cmd_type == REQ_TYPE_SENSE)
+#define blk_linux_request(rq) ((rq)->cmd_type == REQ_TYPE_LINUX_BLOCK)
#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST)
#define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED)
--
1.4.1.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/7] scsi-hw-handler: scsi handling of REQ_LB_OP_TRANSITION
2007-06-09 19:07 ` [PATCH 1/7] scsi-hw-handler: add REQ_LB_OP_TRANSITION and errors michaelc
@ 2007-06-09 19:07 ` michaelc
2007-06-09 19:08 ` [PATCH 3/7] scsi-hw-handler: add hp sw handler michaelc
0 siblings, 1 reply; 10+ messages in thread
From: michaelc @ 2007-06-09 19:07 UTC (permalink / raw)
To: linux-scsi, dm-devel; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This patch adds a scsi handler for REQ_LB_OP_TRANSITION commands.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/Kconfig | 5 ++
drivers/scsi/scsi_error.c | 10 ++++
drivers/scsi/scsi_lib.c | 113 +++++++++++++++++++++++++++++++++++++++++++-
include/scsi/scsi_cmnd.h | 1
include/scsi/scsi_device.h | 14 +++++
5 files changed, 141 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index aac9cd9..e4372da 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -285,6 +285,11 @@ source "drivers/scsi/libsas/Kconfig"
endmenu
+menu "SCSI Device Info Drivers"
+ depends on SCSI
+
+endmenu
+
menu "SCSI low-level drivers"
depends on SCSI!=n
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 9adb64a..99e526d 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -297,6 +297,7 @@ #endif
**/
static int scsi_check_sense(struct scsi_cmnd *scmd)
{
+ struct scsi_device *sdev = scmd->device;
struct scsi_sense_hdr sshdr;
if (! scsi_command_normalize_sense(scmd, &sshdr))
@@ -305,6 +306,15 @@ static int scsi_check_sense(struct scsi_
if (scsi_sense_is_deferred(&sshdr))
return NEEDS_RETRY;
+ if (sdev->sdevt && sdev->sdevt->check_sense) {
+ int rc;
+
+ rc = sdev->sdevt->check_sense(&sshdr);
+ if (rc)
+ return rc;
+ /* hw module does not care. Drop down to default handling */
+ }
+
/*
* Previous logic looked for FILEMARK, EOM or ILI which are
* mainly associated with tapes and returned SUCCESS.
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 70454b4..e96a9a0 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1075,6 +1075,37 @@ static struct scsi_cmnd *scsi_get_cmd_fr
return cmd;
}
+static int scsi_setup_blk_linux_cmnd(struct scsi_device *sdev,
+ struct request *rq)
+{
+ if (!get_device(&sdev->sdev_gendev)) {
+ rq->errors = BLKERR_DEV_OFFLINED;
+ goto kill;
+ }
+
+ switch (rq->cmd[0]) {
+ case REQ_LB_OP_TRANSITION:
+ if (!sdev->sdevt || !sdev->sdevt->transition) {
+ /* set REQ_LB_OP_TRANSITION specific error */
+ rq->errors = BLKERR_NOSYS;
+ goto kill;
+ }
+ if (!try_module_get(sdev->sdevt->module)) {
+ rq->errors = BLKERR_DEV_OFFLINED;
+ goto kill;
+ }
+
+ break;
+ default:
+ rq->errors = BLKERR_INVALID_IO;
+ goto kill;
+ }
+ return BLKPREP_OK;
+
+kill:
+ return BLKPREP_KILL;
+}
+
static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
{
BUG_ON(!blk_pc_request(cmd->request));
@@ -1233,6 +1264,8 @@ static int scsi_prep_fn(struct request_q
case REQ_TYPE_FS:
ret = scsi_setup_fs_cmnd(sdev, req);
break;
+ case REQ_TYPE_LINUX_BLOCK:
+ return scsi_setup_blk_linux_cmnd(sdev, req);
default:
/*
* All other command types are not supported.
@@ -1376,9 +1409,24 @@ static void scsi_kill_request(struct req
static void scsi_softirq_done(struct request *rq)
{
struct scsi_cmnd *cmd = rq->completion_data;
- unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+ struct request_queue *q;
+ unsigned long wait_for, flags;
int disposition;
+ if (blk_linux_request(rq)) {
+ q = rq->q;
+ spin_lock_irqsave(q->queue_lock, flags);
+ /*
+ * we always return 1 and the caller should
+ * check rq->errors for the complete status
+ */
+ end_that_request_last(rq, 1);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ return;
+ }
+
+
+ wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
INIT_LIST_HEAD(&cmd->eh_entry);
disposition = scsi_decide_disposition(cmd);
@@ -1408,6 +1456,51 @@ static void scsi_softirq_done(struct req
}
}
+/**
+ * scsi_blk_linux_cmd_done - Complete a REQ_TYPE_LINUX_BLOCK request.
+ * @req: REQ_TYPE_LINUX_BLOCK request being processed
+ * @err: return value
+ *
+ * This function should be called by the REQ_TYPE_LINUX_BLOCK handler
+ * to return the request to its caller. This function queues the
+ * the completion to the blk softirq so the queue lock does not have
+ * to be held here.
+ */
+void scsi_blk_linux_cmd_done(struct request *rq, int err)
+{
+ struct scsi_device *sdev = rq->q->queuedata;
+
+ switch (rq->cmd[0]) {
+ case REQ_LB_OP_TRANSITION:
+ module_put(sdev->sdevt->module);
+ break;
+ }
+
+ put_device(&sdev->sdev_gendev);
+ rq->errors = err;
+ rq->completion_data = NULL;
+ blk_complete_request(rq);
+}
+EXPORT_SYMBOL_GPL(scsi_blk_linux_cmd_done);
+
+static void scsi_execute_blk_linux_cmd(struct request *rq)
+{
+ struct request_queue *q = rq->q;
+ struct scsi_device *sdev = q->queuedata;
+
+ switch (rq->cmd[0]) {
+ case REQ_LB_OP_TRANSITION:
+ spin_unlock_irq(q->queue_lock);
+ sdev->sdevt->transition(rq);
+ spin_lock_irq(q->queue_lock);
+ break;
+ default:
+ /* should have checked in scsi_prep_fn already */
+ BUG();
+ }
+}
+
+
/*
* Function: scsi_request_fn()
*
@@ -1450,7 +1543,23 @@ static void scsi_request_fn(struct reque
* accept it.
*/
req = elv_next_request(q);
- if (!req || !scsi_dev_queue_ready(q, sdev))
+ if (!req)
+ break;
+
+ /*
+ * We do not account for linux blk req in the device
+ * or host busy accounting because it is not necessarily
+ * a scsi command that is sent to some object. The lower
+ * level can translate it into a request/scsi_cmnd, if
+ * necessary, and then queue that up using REQ_TYPE_BLOCK_PC.
+ */
+ if (blk_linux_request(req)) {
+ blkdev_dequeue_request(req);
+ scsi_execute_blk_linux_cmd(req);
+ continue;
+ }
+
+ if (!scsi_dev_queue_ready(q, sdev))
break;
if (unlikely(!scsi_device_online(sdev))) {
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 53e1705..5344b44 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -127,6 +127,7 @@ extern void __scsi_put_command(struct Sc
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_finish_command(struct scsi_cmnd *cmd);
extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
+extern void scsi_blk_linux_cmd_done(struct request *req, int err);
extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
size_t *offset, size_t *len);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 2f3c5b8..1db6808 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -9,6 +9,7 @@ #include <linux/blkdev.h>
#include <asm/atomic.h>
struct request_queue;
+struct request;
struct scsi_cmnd;
struct scsi_lun;
struct scsi_sense_hdr;
@@ -143,9 +144,22 @@ #define SCSI_DEFAULT_DEVICE_BLOCKED 3
struct execute_work ew; /* used to get process context on put */
+ struct scsi_device_template *sdevt;
+ void *sdevt_data;
enum scsi_device_state sdev_state;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
+
+#define SCSI_MAX_SDEV_TEMPLATE_NAME 16
+
+struct scsi_device_template {
+ struct module *module;
+ const char *name;
+
+ int (* check_sense)(struct scsi_sense_hdr *);
+ void (* transition)(struct request *);
+};
+
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)
#define class_to_sdev(d) \
--
1.4.1.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/7] scsi-hw-handler: add hp sw handler
2007-06-09 19:07 ` [PATCH 2/7] scsi-hw-handler: scsi handling of REQ_LB_OP_TRANSITION michaelc
@ 2007-06-09 19:08 ` michaelc
2007-06-09 19:08 ` [PATCH 4/7] scsi-hw-handler: add emc clariion handler michaelc
0 siblings, 1 reply; 10+ messages in thread
From: michaelc @ 2007-06-09 19:08 UTC (permalink / raw)
To: linux-scsi, dm-devel; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This patch adds a very basic scsi hw handler for older
hp boxes which cannot be upgraded.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/Kconfig | 8 ++
drivers/scsi/Makefile | 1
drivers/scsi/hw_hp_sw.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 224 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index e4372da..3122346 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -288,6 +288,14 @@ endmenu
menu "SCSI Device Info Drivers"
depends on SCSI
+config SCSI_HP_SW
+ tristate "HP/COMPAQ MSA Driver"
+ depends on SCSI
+ help
+ If you have a HP/COMPAQ MSA device that requires START_STOP to
+ be sent to start it and cannot upgrade the firmware then select y.
+ Otherwise, say N.
+
endmenu
menu "SCSI low-level drivers"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index cba3967..c86e3c0 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
obj-$(CONFIG_SCSI_STEX) += stex.o
+obj-$(CONFIG_SCSI_HP_SW) += hw_hp_sw.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/hw_hp_sw.c b/drivers/scsi/hw_hp_sw.c
new file mode 100644
index 0000000..190ea0a
--- /dev/null
+++ b/drivers/scsi/hw_hp_sw.c
@@ -0,0 +1,215 @@
+/*
+ * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be
+ * upgraded.
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2006 Mike Christie
+ *
+ * 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, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_driver.h>
+
+#define HP_SW_TIMEOUT 30
+#define HP_SW_RETRIES 3
+
+struct hp_sw_dev {
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+ int retries;
+};
+
+static void hp_sw_done(struct request *req, int uptodate)
+{
+ struct request *act_req = req->end_io_data;
+ struct request_queue *q = req->q;
+ struct scsi_device *sdev = q->queuedata;
+ struct hp_sw_dev *hp_sw_dev = sdev->sdevt_data;
+ struct scsi_sense_hdr sshdr;
+ int rc = BLKERR_OK;
+
+ sdev_printk(KERN_INFO, sdev, "hp_sw_done %d\n", req->errors);
+
+ /*
+ * This will at least get us going. Let Dave do the details.
+ */
+ if (status_byte(req->errors) == CHECK_CONDITION &&
+ scsi_normalize_sense(req->sense, req->sense_len, &sshdr)) {
+ /* tmp debug output */
+ __scsi_print_sense("hp_sw_done", req->sense, req->sense_len);
+
+ switch (sshdr.sense_key) {
+ case NOT_READY:
+ if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
+ rc = BLKERR_RETRY;
+ hp_sw_dev->retries++;
+ break;
+ }
+ /* fall through */
+ default:
+ hp_sw_dev->retries++;
+ rc = BLKERR_IMM_RETRY;
+ }
+ } else if (req->errors)
+ rc = BLKERR_IO;
+
+ if (rc == BLKERR_OK)
+ hp_sw_dev->retries = 0;
+ else if (hp_sw_dev->retries > HP_SW_RETRIES) {
+ hp_sw_dev->retries = 0;
+ rc = BLKERR_IO;
+ }
+
+ __blk_put_request(req->q, req);
+ scsi_blk_linux_cmd_done(act_req, rc);
+}
+
+static void hp_sw_transition(struct request *act_req)
+{
+ struct scsi_device *sdev = act_req->q->queuedata;
+ struct hp_sw_dev *hp_sw_dev = sdev->sdevt_data;
+ struct request *req;
+
+ sdev_printk(KERN_INFO, sdev, "hp_sw_done send START_STOP retries %d.\n",
+ act_req->retries);
+
+ req = blk_get_request(sdev->request_queue, 0, GFP_ATOMIC);
+ if (!req) {
+ scsi_blk_linux_cmd_done(req, BLKERR_RES_TEMP_UNAVAIL);
+ return;
+ }
+
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_FAILFAST;
+ req->cmd_len = COMMAND_SIZE(START_STOP);
+ memset(req->cmd, 0, MAX_COMMAND_SIZE);
+ req->cmd[0] = START_STOP;
+ req->cmd[4] = 1; /* Start spin cycle */
+ req->timeout = HP_SW_TIMEOUT;
+ req->retries = HP_SW_RETRIES;
+ req->end_io_data = act_req;
+ req->sense = hp_sw_dev->sense;
+ memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
+ req->sense_len = 0;
+
+ blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_done);
+}
+
+static struct scsi_device_template hp_sw_template = {
+ .name = "hp_sw",
+ .module = THIS_MODULE,
+ .transition = hp_sw_transition,
+};
+
+static const struct {
+ char *vendor;
+ char *model;
+} hp_sw_dev_list[] = {
+ {"COMPAQ", "MSA1000"},
+ {"HP", "HSV100"},
+ {NULL, NULL},
+};
+
+static int hp_sw_add(struct class_device *clsdev,
+ struct class_interface *interface)
+{
+ struct scsi_device *sdev = to_scsi_device(clsdev->dev);
+ struct hp_sw_dev *hp_sw_dev;
+ int i, found = 0;
+ unsigned long flags;
+
+ for (i = 0; hp_sw_dev_list[i].vendor; i++) {
+ if (!strncmp(sdev->vendor, hp_sw_dev_list[i].vendor,
+ strlen(hp_sw_dev_list[i].vendor)) &&
+ !strncmp(sdev->model, hp_sw_dev_list[i].model,
+ strlen(hp_sw_dev_list[i].model))) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return -ENODEV;
+
+ hp_sw_dev = kzalloc(sizeof(*hp_sw_dev), GFP_KERNEL);
+ if (!hp_sw_dev)
+ return -ENOMEM;
+
+ spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+ sdev->sdevt = &hp_sw_template;
+ sdev->sdevt_data = hp_sw_dev;
+ spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+ sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n",
+ hp_sw_template.name);
+ return 0;
+}
+
+static void hp_sw_remove(struct class_device *clsdev,
+ struct class_interface *interface)
+{
+ struct scsi_device *sdev = to_scsi_device(clsdev->dev);
+ struct hp_sw_dev *hp_sw_dev = sdev->sdevt_data;
+ int i, found = 0;
+ unsigned long flags;
+
+ for (i = 0; hp_sw_dev_list[i].vendor; i++) {
+ if (!strncmp(sdev->vendor, hp_sw_dev_list[i].vendor,
+ strlen(hp_sw_dev_list[i].vendor)) &&
+ !strncmp(sdev->model, hp_sw_dev_list[i].model,
+ strlen(hp_sw_dev_list[i].model))) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return;
+
+ spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+ sdev->sdevt = NULL;
+ sdev->sdevt_data = NULL;
+ spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+ sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n",
+ hp_sw_template.name);
+
+ kfree(hp_sw_dev);
+}
+
+static struct class_interface hp_sw_interface = {
+ .add = hp_sw_add,
+ .remove = hp_sw_remove,
+};
+
+static int __init hp_sw_init(void)
+{
+ return scsi_register_interface(&hp_sw_interface);
+}
+
+static void __exit hp_sw_exit(void)
+{
+ scsi_unregister_interface(&hp_sw_interface);
+}
+
+module_init(hp_sw_init);
+module_exit(hp_sw_exit);
+
+MODULE_DESCRIPTION("HP MSA 1000");
+MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
+MODULE_LICENSE("GPL");
--
1.4.1.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/7] scsi-hw-handler: add emc clariion handler
2007-06-09 19:08 ` [PATCH 3/7] scsi-hw-handler: add hp sw handler michaelc
@ 2007-06-09 19:08 ` michaelc
2007-06-09 19:08 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers michaelc
0 siblings, 1 reply; 10+ messages in thread
From: michaelc @ 2007-06-09 19:08 UTC (permalink / raw)
To: linux-scsi, dm-devel; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This adds support for clarrions. It is just a port of what
is in mainline. Ed's patches will be intergrated in a
different patch which adds more advanced functionality.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/Kconfig | 6 +
drivers/scsi/Makefile | 1
drivers/scsi/hw_emc.c | 362 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 369 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3122346..f8bf5ce 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -296,6 +296,12 @@ config SCSI_HP_SW
be sent to start it and cannot upgrade the firmware then select y.
Otherwise, say N.
+config SCSI_CLARIION
+ tristate "EMC CLARiiON Driver"
+ depends on SCSI
+ help
+ If you have a EMC CLARiiON select y. Otherwise, say N.
+
endmenu
menu "SCSI low-level drivers"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index c86e3c0..ceffe0e 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
obj-$(CONFIG_SCSI_STEX) += stex.o
obj-$(CONFIG_SCSI_HP_SW) += hw_hp_sw.o
+obj-$(CONFIG_SCSI_CLARIION) += hw_emc.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/hw_emc.c b/drivers/scsi/hw_emc.c
new file mode 100644
index 0000000..1095aee
--- /dev/null
+++ b/drivers/scsi/hw_emc.c
@@ -0,0 +1,362 @@
+/*
+ * Target driver for EMC CLARiiON AX/CX-series hardware.
+ * Based on code from Lars Marowsky-Bree <lmb@suse.de>
+ * and Ed Goggin <egoggin@emc.com>.
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2006 Mike Christie
+ *
+ * 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, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+
+#define CLARIION_NAME "emc_clarrion"
+
+#define CLARIION_TRESPASS_PAGE 0x22
+#define CLARIION_BUFFER_SIZE 0x80
+#define CLARIION_TIMEOUT (60 * HZ)
+#define CLARIION_UNBOUND_LU -1
+#define CLARIION_RETRIES 3
+
+struct clariion_sdev {
+ /*
+ * Use short trespass command (FC-series) or the long version
+ * (default for AX/CX CLARiiON arrays).
+ */
+ unsigned short_trespass;
+ /*
+ * Whether or not (default) to honor SCSI reservations when
+ * initiating a switch-over.
+ */
+ unsigned hr;
+ /* I/O buffer for both MODE_SELECT and INQUIRY commands. */
+ char buffer[CLARIION_BUFFER_SIZE];
+ /*
+ * SCSI sense buffer for commands -- assumes serial issuance
+ * and completion sequence of all commands for same multipath.
+ */
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+};
+
+static unsigned char long_trespass[] = {
+ 0, 0, 0, 0,
+ CLARIION_TRESPASS_PAGE, /* Page code */
+ 0x09, /* Page length - 2 */
+ 0x81, /* Trespass code + Honor reservation bit */
+ 0xff, 0xff, /* Trespass target */
+ 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
+};
+
+static unsigned char long_trespass_hr[] = {
+ 0, 0, 0, 0,
+ CLARIION_TRESPASS_PAGE, /* Page code */
+ 0x09, /* Page length - 2 */
+ 0x01, /* Trespass code + Honor reservation bit */
+ 0xff, 0xff, /* Trespass target */
+ 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
+};
+
+static unsigned char short_trespass[] = {
+ 0, 0, 0, 0,
+ CLARIION_TRESPASS_PAGE, /* Page code */
+ 0x02, /* Page length - 2 */
+ 0x81, /* Trespass code + Honor reservation bit */
+ 0xff, /* Trespass target */
+};
+
+static unsigned char short_trespass_hr[] = {
+ 0, 0, 0, 0,
+ CLARIION_TRESPASS_PAGE, /* Page code */
+ 0x02, /* Page length - 2 */
+ 0x01, /* Trespass code + Honor reservation bit */
+ 0xff, /* Trespass target */
+};
+
+/*
+ * Parse MODE_SELECT cmd reply.
+ */
+static int parse_trespass_rsp(struct scsi_device *sdev, char *sense,
+ int result)
+{
+ struct scsi_sense_hdr sshdr;
+ int err = 0;
+
+ if (status_byte(result) == CHECK_CONDITION &&
+ scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
+ sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, "
+ "0x%2x, 0x%2x while sending CLARiiON trespass "
+ "command.\n", sshdr.sense_key, sshdr.asc,
+ sshdr.ascq);
+
+ if ((sshdr.sense_key = 0x05) && (sshdr.asc = 0x04) &&
+ (sshdr.ascq = 0x00)) {
+ /*
+ * Array based copy in progress -- do not send
+ * pg_init or copy will be aborted mid-stream.
+ */
+ sdev_printk(KERN_INFO, sdev, "Array Based Copy in "
+ "progress while sending CLARiiON trespass "
+ "command.\n");
+ err = BLKERR_DEV_TEMP_BUSY;
+ } else if ((sshdr.sense_key = 0x02) && (sshdr.asc = 0x04) &&
+ (sshdr.ascq = 0x03)) {
+ /*
+ * LUN Not Ready - Manual Intervention Required
+ * indicates in-progress ucode upgrade (NDU).
+ */
+ sdev_printk(KERN_INFO, sdev, "Detected in-progress "
+ "ucode upgrade NDU operation while sending "
+ "CLARiiON trespass command.\n");
+ err = BLKERR_DEV_TEMP_BUSY;
+ } else
+ err = BLKERR_DEV_FAILED;
+ } else if (result) {
+ sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending "
+ "CLARiiON trespass command.\n", result);
+ err = BLKERR_IO;
+ }
+
+ return err;
+}
+
+static void trespass_done(struct request *req, int uptodate)
+{
+ struct request *act_req = req->end_io_data;
+ struct scsi_device *sdev = req->q->queuedata;
+ int err_flags, result = req->errors;
+ char *sense = req->sense;
+
+ sdev_printk(KERN_NOTICE, sdev, "Trespass compeleted. Uptodate %d error "
+ "%d.\n", uptodate, req->errors);
+
+ __blk_put_request(req->q, req);
+
+ err_flags = parse_trespass_rsp(sdev, sense, result);
+ if (err_flags) {
+ scsi_blk_linux_cmd_done(act_req, err_flags);
+ return;
+ }
+
+ scsi_blk_linux_cmd_done(act_req, BLKERR_OK);
+}
+
+static int execute_trespass(struct request *act_req)
+{
+ struct scsi_device *sdev = act_req->q->queuedata;
+ struct clariion_sdev *csdev = sdev->sdevt_data;
+ struct request *req;
+ unsigned char *page22;
+ unsigned size;
+
+ if (csdev->short_trespass) {
+ page22 = csdev->hr ? short_trespass_hr : short_trespass;
+ size = sizeof(short_trespass);
+ } else {
+ page22 = csdev->hr ? long_trespass_hr : long_trespass;
+ size = sizeof(long_trespass);
+ }
+
+ req = blk_get_request(sdev->request_queue, 1, GFP_ATOMIC);
+ if (!req)
+ return BLKERR_RES_TEMP_UNAVAIL;
+
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_FAILFAST;
+ req->timeout = CLARIION_TIMEOUT;
+ req->retries = CLARIION_RETRIES;
+ req->end_io_data = act_req;
+ req->sense = csdev->sense;
+ memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
+ req->sense_len = 0;
+
+ memset(req->cmd, 0, MAX_COMMAND_SIZE);
+ req->cmd[0] = MODE_SELECT;
+ req->cmd[1] = 0x10;
+ req->cmd[4] = size;
+ req->cmd_len = COMMAND_SIZE(MODE_SELECT);
+ memcpy(csdev->buffer, page22, size);
+
+ if (blk_rq_map_kern(sdev->request_queue, req, csdev->buffer,
+ size, GFP_ATOMIC)) {
+ __blk_put_request(req->q, req);
+ return BLKERR_RES_TEMP_UNAVAIL;
+ }
+
+ sdev_printk(KERN_NOTICE, sdev, "Failing over device\n.");
+ blk_execute_rq_nowait(req->q, NULL, req, 1, trespass_done);
+ return BLKERR_OK;
+}
+
+static void clariion_transition(struct request *req)
+{
+ int err;
+
+ err = execute_trespass(req);
+ if (err)
+ scsi_blk_linux_cmd_done(req, err);
+}
+
+static int clariion_check_sense(struct scsi_sense_hdr *sense_hdr)
+{
+ switch (sense_hdr->sense_key) {
+ case NOT_READY:
+ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03)
+ /*
+ * LUN Not Ready - Manual Intervention Required
+ * indicates this is a passive path.
+ *
+ * FIXME: However, if this is seen and EVPD C0
+ * indicates that this is due to a NDU in
+ * progress, we should set FAIL_PATH too.
+ * This indicates we might have to do a SCSI
+ * inquiry in the end_io path. Ugh.
+ */
+ return FAILED;
+ break;
+ case ILLEGAL_REQUEST:
+ if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01)
+ /*
+ * An array based copy is in progress. Do not
+ * fail the path, do not bypass to another PG,
+ * do not retry. Fail the IO immediately.
+ * (Actually this is the same conclusion as in
+ * the default handler, but lets make sure.)
+ */
+ return FAILED;
+ break;
+ case UNIT_ATTENTION:
+ if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+ /*
+ * Unit Attention Code. This is the first IO
+ * to the new path, so just retry.
+ */
+ return NEEDS_RETRY;
+ break;
+ }
+
+ /* success just means we do not care what scsi-ml does */
+ return SUCCESS;
+}
+
+static struct scsi_device_template clariion_template = {
+ .name = CLARIION_NAME,
+ .module = THIS_MODULE,
+ .check_sense = clariion_check_sense,
+ .transition = clariion_transition,
+};
+
+static const struct {
+ char *vendor;
+ char *model;
+} clariion_dev_list[] = {
+ {"DGC", "RAID"},
+ {"DGC", "DISK"},
+ {NULL, NULL},
+};
+
+/*
+ * TODO: need some interface so we can set trespass values
+ */
+static int clariion_add(struct class_device *clsdev,
+ struct class_interface *interface)
+{
+ struct scsi_device *sdev = to_scsi_device(clsdev->dev);
+ struct clariion_sdev *csdev;
+ int i, found = 0;
+ unsigned long flags;
+
+ for (i = 0; clariion_dev_list[i].vendor; i++) {
+ if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
+ strlen(clariion_dev_list[i].vendor)) &&
+ !strncmp(sdev->model, clariion_dev_list[i].model,
+ strlen(clariion_dev_list[i].model))) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return -ENODEV;
+
+ csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
+ if (!csdev)
+ return -ENOMEM;
+
+ spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+ sdev->sdevt_data = csdev;
+ sdev->sdevt = &clariion_template;
+ spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+ sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n",
+ clariion_template.name);
+ return 0;
+}
+
+static void clariion_remove(struct class_device *clsdev,
+ struct class_interface *interface)
+{
+ struct scsi_device *sdev = to_scsi_device(clsdev->dev);
+ struct clariion_sdev *csdev = sdev->sdevt_data;
+ int i, found = 0;
+ unsigned long flags;
+
+ for (i = 0; clariion_dev_list[i].vendor; i++) {
+ if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
+ strlen(clariion_dev_list[i].vendor)) &&
+ !strncmp(sdev->model, clariion_dev_list[i].model,
+ strlen(clariion_dev_list[i].model))) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return;
+
+ spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+ sdev->sdevt_data = NULL;
+ sdev->sdevt = NULL;
+ spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+ sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n",
+ clariion_template.name);
+
+ kfree(csdev);
+}
+
+static struct class_interface clariion_interface = {
+ .add = clariion_add,
+ .remove = clariion_remove,
+};
+
+static int __init clariion_init(void)
+{
+ return scsi_register_interface(&clariion_interface);
+}
+
+static void __exit clariion_exit(void)
+{
+ scsi_unregister_interface(&clariion_interface);
+}
+
+module_init(clariion_init);
+module_exit(clariion_exit);
+
+MODULE_DESCRIPTION("EMC CX/AX/FC-family driver");
+MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
+MODULE_LICENSE("GPL");
--
1.4.1.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers
2007-06-09 19:08 ` [PATCH 4/7] scsi-hw-handler: add emc clariion handler michaelc
@ 2007-06-09 19:08 ` michaelc
2007-06-09 19:08 ` [PATCH 6/7] scsi-hw-handler: rm dm-hw-handler code michaelc
2007-06-09 19:18 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers Mike Christie
0 siblings, 2 replies; 10+ messages in thread
From: michaelc @ 2007-06-09 19:08 UTC (permalink / raw)
To: linux-scsi, dm-devel; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This patch converts dm-mpath to scsi hw handlers. It does
not add any new functionality and old behaviors and userspace
tools should be supported except we use the safe clariion
default instead of using the userspace setting.
This is just the dm-mpath parts which are necessary to use
REQ_TYPE_LINUX_BLOCK and REQ_LB_OP_TRANSITION. In later mails
I will send patches which remove old code and add more
functionality.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/md/dm-mpath.c | 199 +++++++++++++++++++++++++++----------------------
1 files changed, 111 insertions(+), 88 deletions(-)
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index de54b39..5655d16 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -7,7 +7,6 @@
#include "dm.h"
#include "dm-path-selector.h"
-#include "dm-hw-handler.h"
#include "dm-bio-list.h"
#include "dm-bio-record.h"
@@ -60,9 +59,9 @@ struct multipath {
spinlock_t lock;
- struct hw_handler hw_handler;
unsigned nr_priority_groups;
struct list_head priority_groups;
+ char *hw_handler_name;
unsigned pg_init_required; /* pg_init needs calling? */
unsigned pg_init_in_progress; /* Only one pg_init allowed at once */
@@ -106,6 +105,9 @@ static struct kmem_cache *_mpio_cache;
struct workqueue_struct *kmultipathd;
static void process_queued_ios(struct work_struct *work);
static void trigger_event(struct work_struct *work);
+static void bypass_pg(struct multipath *m, struct priority_group *pg,
+ int bypassed);
+static int fail_path(struct pgpath *pgpath);
/*-----------------------------------------------
@@ -190,18 +192,13 @@ static struct multipath *alloc_multipath
static void free_multipath(struct multipath *m)
{
struct priority_group *pg, *tmp;
- struct hw_handler *hwh = &m->hw_handler;
list_for_each_entry_safe(pg, tmp, &m->priority_groups, list) {
list_del(&pg->list);
free_priority_group(pg, m->ti);
}
- if (hwh->type) {
- hwh->type->destroy(hwh);
- dm_put_hw_handler(hwh->type);
- }
-
+ kfree(m->hw_handler_name);
mempool_destroy(m->mpio_pool);
kfree(m);
}
@@ -213,12 +210,10 @@ static void free_multipath(struct multip
static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
{
- struct hw_handler *hwh = &m->hw_handler;
-
m->current_pg = pgpath->pg;
/* Must we initialise the PG first, and queue I/O till it's ready? */
- if (hwh->type && hwh->type->pg_init) {
+ if (m->hw_handler_name) {
m->pg_init_required = 1;
m->queue_io = 1;
} else {
@@ -400,11 +395,106 @@ static void dispatch_queued_ios(struct m
}
}
+static void __pg_init_done(struct dm_path *path, int errors)
+{
+ struct pgpath *pgpath = path_to_pgpath(path);
+ struct priority_group *pg = pgpath->pg;
+ struct multipath *m = pg->m;
+ unsigned long flags;
+
+ if (blkerr_transport_err(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.
+ */
+ fail_path(pgpath);
+ goto cleanup;
+ }
+
+ /* device or driver problems */
+ switch (errors) {
+ case BLKERR_OK:
+ break;
+ case BLKERR_NOSYS:
+ if (!m->hw_handler_name) {
+ errors = 0;
+ break;
+ }
+ DMERR("Cannot failover device because hw-%s may not be "
+ "loaded.", m->hw_handler_name);
+ /*
+ * Fail path for now, so we do not ping poing
+ */
+ fail_path(pgpath);
+ break;
+ case BLKERR_DEV_TEMP_BUSY:
+ /*
+ * Probably doing something like FW upgrade on the
+ * controller so try the other pg.
+ */
+ bypass_pg(m, pg, 1);
+ 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.
+ */
+ fail_path(pgpath);
+ }
+
+cleanup:
+ spin_lock_irqsave(&m->lock, flags);
+ if (errors) {
+ DMERR("Could not failover device. Error %d.", errors);
+ m->current_pgpath = NULL;
+ m->current_pg = NULL;
+ } else if (!m->pg_init_required) {
+ m->queue_io = 0;
+ pg->bypassed = 0;
+ }
+
+ m->pg_init_in_progress = 0;
+ queue_work(kmultipathd, &m->process_queued_ios);
+ spin_unlock_irqrestore(&m->lock, flags);
+}
+
+static void pg_init_done(struct request *req, int err)
+{
+ __pg_init_done(req->end_io_data, req->errors);
+ __blk_put_request(req->q, req);
+}
+
+static void pg_init(struct dm_path *path)
+{
+ struct request *req;
+
+ req = blk_get_request(bdev_get_queue(path->dev->bdev), 1, GFP_NOIO);
+ if (!req) {
+ /* retry later */
+ __pg_init_done(path, BLKERR_RES_TEMP_UNAVAIL);
+ return;
+ }
+
+ req->cmd[0] = REQ_LB_OP_TRANSITION;
+ req->cmd_type = REQ_TYPE_LINUX_BLOCK;
+ req->end_io_data = path;
+ /* 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);
+}
+
static void process_queued_ios(struct work_struct *work)
{
struct multipath *m =
container_of(work, struct multipath, process_queued_ios);
- struct hw_handler *hwh = &m->hw_handler;
struct pgpath *pgpath = NULL;
unsigned init_required = 0, must_queue = 1;
unsigned long flags;
@@ -433,7 +523,7 @@ out:
spin_unlock_irqrestore(&m->lock, flags);
if (init_required)
- hwh->type->pg_init(hwh, pgpath->pg->bypassed, &pgpath->path);
+ pg_init(&pgpath->path);
if (!must_queue)
dispatch_queued_ios(m);
@@ -646,10 +736,9 @@ static struct priority_group *parse_prio
static int parse_hw_handler(struct arg_set *as, struct multipath *m)
{
+ struct dm_target *ti = m->ti;
int r;
- struct hw_handler_type *hwht;
unsigned hw_argc;
- struct dm_target *ti = m->ti;
static struct param _params[] = {
{0, 1024, "invalid number of hardware handler args"},
@@ -662,25 +751,9 @@ static int parse_hw_handler(struct arg_s
if (!hw_argc)
return 0;
- hwht = dm_get_hw_handler(shift(as));
- if (!hwht) {
- ti->error = "unknown hardware handler type";
- return -EINVAL;
- }
-
- m->hw_handler.md = dm_table_get_md(ti->table);
- dm_put(m->hw_handler.md);
-
- r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
- if (r) {
- dm_put_hw_handler(hwht);
- ti->error = "hardware handler constructor failed";
- return r;
- }
-
- m->hw_handler.type = hwht;
+ m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL);
+ request_module("hw-%s", m->hw_handler_name);
consume(as, hw_argc - 1);
-
return 0;
}
@@ -979,45 +1052,11 @@ static int bypass_pg_num(struct multipat
}
/*
- * pg_init must call this when it has completed its initialisation
- */
-void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
-{
- struct pgpath *pgpath = path_to_pgpath(path);
- struct priority_group *pg = pgpath->pg;
- struct multipath *m = pg->m;
- unsigned long flags;
-
- /* We insist on failing the path if the PG is already bypassed. */
- if (err_flags && pg->bypassed)
- err_flags |= MP_FAIL_PATH;
-
- if (err_flags & MP_FAIL_PATH)
- fail_path(pgpath);
-
- if (err_flags & MP_BYPASS_PG)
- bypass_pg(m, pg, 1);
-
- spin_lock_irqsave(&m->lock, flags);
- if (err_flags) {
- m->current_pgpath = NULL;
- m->current_pg = NULL;
- } else if (!m->pg_init_required)
- m->queue_io = 0;
-
- m->pg_init_in_progress = 0;
- queue_work(kmultipathd, &m->process_queued_ios);
- spin_unlock_irqrestore(&m->lock, flags);
-}
-
-/*
* end_io handling
*/
static int do_end_io(struct multipath *m, struct bio *bio,
int error, struct mpath_io *mpio)
{
- struct hw_handler *hwh = &m->hw_handler;
- unsigned err_flags = MP_FAIL_PATH; /* Default behavior */
unsigned long flags;
if (!error)
@@ -1044,19 +1083,8 @@ static int do_end_io(struct multipath *m
}
spin_unlock_irqrestore(&m->lock, flags);
- if (hwh->type && hwh->type->error)
- err_flags = hwh->type->error(hwh, bio);
-
- if (mpio->pgpath) {
- if (err_flags & MP_FAIL_PATH)
- fail_path(mpio->pgpath);
-
- if (err_flags & MP_BYPASS_PG)
- bypass_pg(m, mpio->pgpath->pg, 1);
- }
-
- if (err_flags & MP_ERROR_IO)
- return -EIO;
+ if (mpio->pgpath)
+ fail_path(mpio->pgpath);
requeue:
dm_bio_restore(&mpio->details, bio);
@@ -1141,7 +1169,6 @@ static int multipath_status(struct dm_ta
int sz = 0;
unsigned long flags;
struct multipath *m = (struct multipath *) ti->private;
- struct hw_handler *hwh = &m->hw_handler;
struct priority_group *pg;
struct pgpath *p;
unsigned pg_num;
@@ -1157,12 +1184,10 @@ static int multipath_status(struct dm_ta
else
DMEMIT("0 ");
- if (hwh->type && hwh->type->status)
- sz += hwh->type->status(hwh, type, result + sz, maxlen - sz);
- else if (!hwh->type || type == STATUSTYPE_INFO)
- DMEMIT("0 ");
+ if (m->hw_handler_name)
+ DMEMIT("1 %s ", m->hw_handler_name);
else
- DMEMIT("1 %s ", hwh->type->name);
+ DMEMIT("0 ");
DMEMIT("%u ", m->nr_priority_groups);
@@ -1387,8 +1412,6 @@ static void __exit dm_multipath_exit(voi
kmem_cache_destroy(_mpio_cache);
}
-EXPORT_SYMBOL_GPL(dm_pg_init_complete);
-
module_init(dm_multipath_init);
module_exit(dm_multipath_exit);
--
1.4.1.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/7] scsi-hw-handler: rm dm-hw-handler code
2007-06-09 19:08 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers michaelc
@ 2007-06-09 19:08 ` michaelc
2007-06-09 19:08 ` [PATCH 7/7] scsi-hw-handler: rm dm-emc code michaelc
2007-06-09 19:18 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers Mike Christie
1 sibling, 1 reply; 10+ messages in thread
From: michaelc @ 2007-06-09 19:08 UTC (permalink / raw)
To: linux-scsi, dm-devel; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
dm-hw-handler is no longer used.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/md/Makefile | 2
drivers/md/dm-hw-handler.c | 215 --------------------------------------------
drivers/md/dm-hw-handler.h | 62 -------------
3 files changed, 1 insertions(+), 278 deletions(-)
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 3875408..d2ccc48 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -4,7 +4,7 @@ #
dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
dm-ioctl.o dm-io.o kcopyd.o
-dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o
+dm-multipath-objs := dm-path-selector.o dm-mpath.o
dm-snapshot-objs := dm-snap.o dm-exception-store.o
dm-mirror-objs := dm-log.o dm-raid1.o
md-mod-objs := md.o bitmap.o
diff --git a/drivers/md/dm-hw-handler.c b/drivers/md/dm-hw-handler.c
deleted file mode 100644
index baafaab..0000000
--- a/drivers/md/dm-hw-handler.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is released under the GPL.
- *
- * Multipath hardware handler registration.
- */
-
-#include "dm.h"
-#include "dm-hw-handler.h"
-
-#include <linux/slab.h>
-
-struct hwh_internal {
- struct hw_handler_type hwht;
-
- struct list_head list;
- long use;
-};
-
-#define hwht_to_hwhi(__hwht) container_of((__hwht), struct hwh_internal, hwht)
-
-static LIST_HEAD(_hw_handlers);
-static DECLARE_RWSEM(_hwh_lock);
-
-static struct hwh_internal *__find_hw_handler_type(const char *name)
-{
- struct hwh_internal *hwhi;
-
- list_for_each_entry(hwhi, &_hw_handlers, list) {
- if (!strcmp(name, hwhi->hwht.name))
- return hwhi;
- }
-
- return NULL;
-}
-
-static struct hwh_internal *get_hw_handler(const char *name)
-{
- struct hwh_internal *hwhi;
-
- down_read(&_hwh_lock);
- hwhi = __find_hw_handler_type(name);
- if (hwhi) {
- if ((hwhi->use == 0) && !try_module_get(hwhi->hwht.module))
- hwhi = NULL;
- else
- hwhi->use++;
- }
- up_read(&_hwh_lock);
-
- return hwhi;
-}
-
-struct hw_handler_type *dm_get_hw_handler(const char *name)
-{
- struct hwh_internal *hwhi;
-
- if (!name)
- return NULL;
-
- hwhi = get_hw_handler(name);
- if (!hwhi) {
- request_module("dm-%s", name);
- hwhi = get_hw_handler(name);
- }
-
- return hwhi ? &hwhi->hwht : NULL;
-}
-
-void dm_put_hw_handler(struct hw_handler_type *hwht)
-{
- struct hwh_internal *hwhi;
-
- if (!hwht)
- return;
-
- down_read(&_hwh_lock);
- hwhi = __find_hw_handler_type(hwht->name);
- if (!hwhi)
- goto out;
-
- if (--hwhi->use == 0)
- module_put(hwhi->hwht.module);
-
- BUG_ON(hwhi->use < 0);
-
- out:
- up_read(&_hwh_lock);
-}
-
-static struct hwh_internal *_alloc_hw_handler(struct hw_handler_type *hwht)
-{
- struct hwh_internal *hwhi = kmalloc(sizeof(*hwhi), GFP_KERNEL);
-
- if (hwhi) {
- memset(hwhi, 0, sizeof(*hwhi));
- hwhi->hwht = *hwht;
- }
-
- return hwhi;
-}
-
-int dm_register_hw_handler(struct hw_handler_type *hwht)
-{
- int r = 0;
- struct hwh_internal *hwhi = _alloc_hw_handler(hwht);
-
- if (!hwhi)
- return -ENOMEM;
-
- down_write(&_hwh_lock);
-
- if (__find_hw_handler_type(hwht->name)) {
- kfree(hwhi);
- r = -EEXIST;
- } else
- list_add(&hwhi->list, &_hw_handlers);
-
- up_write(&_hwh_lock);
-
- return r;
-}
-
-int dm_unregister_hw_handler(struct hw_handler_type *hwht)
-{
- struct hwh_internal *hwhi;
-
- down_write(&_hwh_lock);
-
- hwhi = __find_hw_handler_type(hwht->name);
- if (!hwhi) {
- up_write(&_hwh_lock);
- return -EINVAL;
- }
-
- if (hwhi->use) {
- up_write(&_hwh_lock);
- return -ETXTBSY;
- }
-
- list_del(&hwhi->list);
-
- up_write(&_hwh_lock);
-
- kfree(hwhi);
-
- return 0;
-}
-
-unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio)
-{
-#if 0
- int sense_key, asc, ascq;
-
- if (bio->bi_error & BIO_SENSE) {
- /* FIXME: This is just an initial guess. */
- /* key / asc / ascq */
- sense_key = (bio->bi_error >> 16) & 0xff;
- asc = (bio->bi_error >> 8) & 0xff;
- ascq = bio->bi_error & 0xff;
-
- switch (sense_key) {
- /* This block as a whole comes from the device.
- * So no point retrying on another path. */
- case 0x03: /* Medium error */
- case 0x05: /* Illegal request */
- case 0x07: /* Data protect */
- case 0x08: /* Blank check */
- case 0x0a: /* copy aborted */
- case 0x0c: /* obsolete - no clue ;-) */
- case 0x0d: /* volume overflow */
- case 0x0e: /* data miscompare */
- case 0x0f: /* reserved - no idea either. */
- return MP_ERROR_IO;
-
- /* For these errors it's unclear whether they
- * come from the device or the controller.
- * So just lets try a different path, and if
- * it eventually succeeds, user-space will clear
- * the paths again... */
- case 0x02: /* Not ready */
- case 0x04: /* Hardware error */
- case 0x09: /* vendor specific */
- case 0x0b: /* Aborted command */
- return MP_FAIL_PATH;
-
- case 0x06: /* Unit attention - might want to decode */
- if (asc == 0x04 && ascq == 0x01)
- /* "Unit in the process of
- * becoming ready" */
- return 0;
- return MP_FAIL_PATH;
-
- /* FIXME: For Unit Not Ready we may want
- * to have a generic pg activation
- * feature (START_UNIT). */
-
- /* Should these two ever end up in the
- * error path? I don't think so. */
- case 0x00: /* No sense */
- case 0x01: /* Recovered error */
- return 0;
- }
- }
-#endif
-
- /* We got no idea how to decode the other kinds of errors ->
- * assume generic error condition. */
- return MP_FAIL_PATH;
-}
-
-EXPORT_SYMBOL_GPL(dm_register_hw_handler);
-EXPORT_SYMBOL_GPL(dm_unregister_hw_handler);
-EXPORT_SYMBOL_GPL(dm_scsi_err_handler);
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
deleted file mode 100644
index e0832e6..0000000
--- a/drivers/md/dm-hw-handler.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is released under the GPL.
- *
- * Multipath hardware handler registration.
- */
-
-#ifndef DM_HW_HANDLER_H
-#define DM_HW_HANDLER_H
-
-#include <linux/device-mapper.h>
-
-#include "dm-mpath.h"
-
-struct hw_handler_type;
-struct hw_handler {
- struct hw_handler_type *type;
- struct mapped_device *md;
- void *context;
-};
-
-/*
- * Constructs a hardware handler object, takes custom arguments
- */
-/* Information about a hardware handler type */
-struct hw_handler_type {
- char *name;
- struct module *module;
-
- int (*create) (struct hw_handler *handler, unsigned int argc,
- char **argv);
- void (*destroy) (struct hw_handler *hwh);
-
- void (*pg_init) (struct hw_handler *hwh, unsigned bypassed,
- struct dm_path *path);
- unsigned (*error) (struct hw_handler *hwh, struct bio *bio);
- int (*status) (struct hw_handler *hwh, status_type_t type,
- char *result, unsigned int maxlen);
-};
-
-/* Register a hardware handler */
-int dm_register_hw_handler(struct hw_handler_type *type);
-
-/* Unregister a hardware handler */
-int dm_unregister_hw_handler(struct hw_handler_type *type);
-
-/* Returns a registered hardware handler type */
-struct hw_handler_type *dm_get_hw_handler(const char *name);
-
-/* Releases a hardware handler */
-void dm_put_hw_handler(struct hw_handler_type *hwht);
-
-/* Default err function */
-unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio);
-
-/* Error flags for err and dm_pg_init_complete */
-#define MP_FAIL_PATH 1
-#define MP_BYPASS_PG 2
-#define MP_ERROR_IO 4 /* Don't retry this I/O */
-
-#endif
--
1.4.1.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/7] scsi-hw-handler: rm dm-emc code
2007-06-09 19:08 ` [PATCH 6/7] scsi-hw-handler: rm dm-hw-handler code michaelc
@ 2007-06-09 19:08 ` michaelc
0 siblings, 0 replies; 10+ messages in thread
From: michaelc @ 2007-06-09 19:08 UTC (permalink / raw)
To: linux-scsi, dm-devel; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
dm-emc.c is no longer used and is replaced by
drivers/scsi/hw_emc.c.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/md/Kconfig | 6 -
drivers/md/Makefile | 1
drivers/md/dm-emc.c | 362 ---------------------------------------------------
3 files changed, 0 insertions(+), 369 deletions(-)
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 7df934d..35968f9 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -256,12 +256,6 @@ config DM_MULTIPATH
---help---
Allow volume managers to support multipath hardware.
-config DM_MULTIPATH_EMC
- tristate "EMC CX/AX multipath support (EXPERIMENTAL)"
- depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL
- ---help---
- Multipath support for EMC CX/AX series hardware.
-
config DM_DELAY
tristate "I/O delaying target (EXPERIMENTAL)"
depends on BLK_DEV_DM && EXPERIMENTAL
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index d2ccc48..0ca8f2f 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -33,7 +33,6 @@ obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
obj-$(CONFIG_DM_DELAY) += dm-delay.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
-obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
deleted file mode 100644
index 265c467..0000000
--- a/drivers/md/dm-emc.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2004 SUSE LINUX Products GmbH. All rights reserved.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is released under the GPL.
- *
- * Multipath support for EMC CLARiiON AX/CX-series hardware.
- */
-
-#include "dm.h"
-#include "dm-hw-handler.h"
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-
-#define DM_MSG_PREFIX "multipath emc"
-
-struct emc_handler {
- spinlock_t lock;
-
- /* Whether we should send the short trespass command (FC-series)
- * or the long version (default for AX/CX CLARiiON arrays). */
- unsigned short_trespass;
- /* Whether or not to honor SCSI reservations when initiating a
- * switch-over. Default: Don't. */
- unsigned hr;
-
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
-};
-
-#define TRESPASS_PAGE 0x22
-#define EMC_FAILOVER_TIMEOUT (60 * HZ)
-
-/* Code borrowed from dm-lsi-rdac by Mike Christie */
-
-static inline void free_bio(struct bio *bio)
-{
- __free_page(bio->bi_io_vec[0].bv_page);
- bio_put(bio);
-}
-
-static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
-{
- struct dm_path *path = bio->bi_private;
-
- if (bio->bi_size)
- return 1;
-
- /* We also need to look at the sense keys here whether or not to
- * switch to the next PG etc.
- *
- * For now simple logic: either it works or it doesn't.
- */
- if (error)
- dm_pg_init_complete(path, MP_FAIL_PATH);
- else
- dm_pg_init_complete(path, 0);
-
- /* request is freed in block layer */
- free_bio(bio);
-
- return 0;
-}
-
-static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size)
-{
- struct bio *bio;
- struct page *page;
-
- bio = bio_alloc(GFP_ATOMIC, 1);
- if (!bio) {
- DMERR("get_failover_bio: bio_alloc() failed.");
- return NULL;
- }
-
- bio->bi_rw |= (1 << BIO_RW);
- bio->bi_bdev = path->dev->bdev;
- bio->bi_sector = 0;
- bio->bi_private = path;
- bio->bi_end_io = emc_endio;
-
- page = alloc_page(GFP_ATOMIC);
- if (!page) {
- DMERR("get_failover_bio: alloc_page() failed.");
- bio_put(bio);
- return NULL;
- }
-
- if (bio_add_page(bio, page, data_size, 0) != data_size) {
- DMERR("get_failover_bio: alloc_page() failed.");
- __free_page(page);
- bio_put(bio);
- return NULL;
- }
-
- return bio;
-}
-
-static struct request *get_failover_req(struct emc_handler *h,
- struct bio *bio, struct dm_path *path)
-{
- struct request *rq;
- struct block_device *bdev = bio->bi_bdev;
- struct request_queue *q = bdev_get_queue(bdev);
-
- /* FIXME: Figure out why it fails with GFP_ATOMIC. */
- rq = blk_get_request(q, WRITE, __GFP_WAIT);
- if (!rq) {
- DMERR("get_failover_req: blk_get_request failed");
- return NULL;
- }
-
- rq->bio = rq->biotail = bio;
- blk_rq_bio_prep(q, rq, bio);
-
- rq->rq_disk = bdev->bd_contains->bd_disk;
-
- /* bio backed don't set data */
- rq->buffer = rq->data = NULL;
- /* rq data_len used for pc cmd's request_bufflen */
- rq->data_len = bio->bi_size;
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = 0;
-
- memset(&rq->cmd, 0, BLK_MAX_CDB);
-
- rq->timeout = EMC_FAILOVER_TIMEOUT;
- rq->cmd_type = REQ_TYPE_BLOCK_PC;
- rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
-
- return rq;
-}
-
-static struct request *emc_trespass_get(struct emc_handler *h,
- struct dm_path *path)
-{
- struct bio *bio;
- struct request *rq;
- unsigned char *page22;
- unsigned char long_trespass_pg[] = {
- 0, 0, 0, 0,
- TRESPASS_PAGE, /* Page code */
- 0x09, /* Page length - 2 */
- h->hr ? 0x01 : 0x81, /* Trespass code + Honor reservation bit */
- 0xff, 0xff, /* Trespass target */
- 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
- };
- unsigned char short_trespass_pg[] = {
- 0, 0, 0, 0,
- TRESPASS_PAGE, /* Page code */
- 0x02, /* Page length - 2 */
- h->hr ? 0x01 : 0x81, /* Trespass code + Honor reservation bit */
- 0xff, /* Trespass target */
- };
- unsigned data_size = h->short_trespass ? sizeof(short_trespass_pg) :
- sizeof(long_trespass_pg);
-
- /* get bio backing */
- if (data_size > PAGE_SIZE)
- /* this should never happen */
- return NULL;
-
- bio = get_failover_bio(path, data_size);
- if (!bio) {
- DMERR("emc_trespass_get: no bio");
- return NULL;
- }
-
- page22 = (unsigned char *)bio_data(bio);
- memset(page22, 0, data_size);
-
- memcpy(page22, h->short_trespass ?
- short_trespass_pg : long_trespass_pg, data_size);
-
- /* get request for block layer packet command */
- rq = get_failover_req(h, bio, path);
- if (!rq) {
- DMERR("emc_trespass_get: no rq");
- free_bio(bio);
- return NULL;
- }
-
- /* Prepare the command. */
- rq->cmd[0] = MODE_SELECT;
- rq->cmd[1] = 0x10;
- rq->cmd[4] = data_size;
- rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
-
- return rq;
-}
-
-static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed,
- struct dm_path *path)
-{
- struct request *rq;
- struct request_queue *q = bdev_get_queue(path->dev->bdev);
-
- /*
- * We can either blindly init the pg (then look at the sense),
- * or we can send some commands to get the state here (then
- * possibly send the fo cmnd), or we can also have the
- * initial state passed into us and then get an update here.
- */
- if (!q) {
- DMINFO("emc_pg_init: no queue");
- goto fail_path;
- }
-
- /* FIXME: The request should be pre-allocated. */
- rq = emc_trespass_get(hwh->context, path);
- if (!rq) {
- DMERR("emc_pg_init: no rq");
- goto fail_path;
- }
-
- DMINFO("emc_pg_init: sending switch-over command");
- elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
- return;
-
-fail_path:
- dm_pg_init_complete(path, MP_FAIL_PATH);
-}
-
-static struct emc_handler *alloc_emc_handler(void)
-{
- struct emc_handler *h = kmalloc(sizeof(*h), GFP_KERNEL);
-
- if (h) {
- memset(h, 0, sizeof(*h));
- spin_lock_init(&h->lock);
- }
-
- return h;
-}
-
-static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv)
-{
- struct emc_handler *h;
- unsigned hr, short_trespass;
-
- if (argc == 0) {
- /* No arguments: use defaults */
- hr = 0;
- short_trespass = 0;
- } else if (argc != 2) {
- DMWARN("incorrect number of arguments");
- return -EINVAL;
- } else {
- if ((sscanf(argv[0], "%u", &short_trespass) != 1)
- || (short_trespass > 1)) {
- DMWARN("invalid trespass mode selected");
- return -EINVAL;
- }
-
- if ((sscanf(argv[1], "%u", &hr) != 1)
- || (hr > 1)) {
- DMWARN("invalid honor reservation flag selected");
- return -EINVAL;
- }
- }
-
- h = alloc_emc_handler();
- if (!h)
- return -ENOMEM;
-
- hwh->context = h;
-
- if ((h->short_trespass = short_trespass))
- DMWARN("short trespass command will be send");
- else
- DMWARN("long trespass command will be send");
-
- if ((h->hr = hr))
- DMWARN("honor reservation bit will be set");
- else
- DMWARN("honor reservation bit will not be set (default)");
-
- return 0;
-}
-
-static void emc_destroy(struct hw_handler *hwh)
-{
- struct emc_handler *h = (struct emc_handler *) hwh->context;
-
- kfree(h);
- hwh->context = NULL;
-}
-
-static unsigned emc_error(struct hw_handler *hwh, struct bio *bio)
-{
- /* FIXME: Patch from axboe still missing */
-#if 0
- int sense;
-
- if (bio->bi_error & BIO_SENSE) {
- sense = bio->bi_error & 0xffffff; /* sense key / asc / ascq */
-
- if (sense == 0x020403) {
- /* LUN Not Ready - Manual Intervention Required
- * indicates this is a passive path.
- *
- * FIXME: However, if this is seen and EVPD C0
- * indicates that this is due to a NDU in
- * progress, we should set FAIL_PATH too.
- * This indicates we might have to do a SCSI
- * inquiry in the end_io path. Ugh. */
- return MP_BYPASS_PG | MP_RETRY_IO;
- } else if (sense == 0x052501) {
- /* An array based copy is in progress. Do not
- * fail the path, do not bypass to another PG,
- * do not retry. Fail the IO immediately.
- * (Actually this is the same conclusion as in
- * the default handler, but lets make sure.) */
- return 0;
- } else if (sense == 0x062900) {
- /* Unit Attention Code. This is the first IO
- * to the new path, so just retry. */
- return MP_RETRY_IO;
- }
- }
-#endif
-
- /* Try default handler */
- return dm_scsi_err_handler(hwh, bio);
-}
-
-static struct hw_handler_type emc_hwh = {
- .name = "emc",
- .module = THIS_MODULE,
- .create = emc_create,
- .destroy = emc_destroy,
- .pg_init = emc_pg_init,
- .error = emc_error,
-};
-
-static int __init dm_emc_init(void)
-{
- int r = dm_register_hw_handler(&emc_hwh);
-
- if (r < 0)
- DMERR("register failed %d", r);
-
- DMINFO("version 0.0.3 loaded");
-
- return r;
-}
-
-static void __exit dm_emc_exit(void)
-{
- int r = dm_unregister_hw_handler(&emc_hwh);
-
- if (r < 0)
- DMERR("unregister failed %d", r);
-}
-
-module_init(dm_emc_init);
-module_exit(dm_emc_exit);
-
-MODULE_DESCRIPTION(DM_NAME " EMC CX/AX/FC-family multipath");
-MODULE_AUTHOR("Lars Marowsky-Bree <lmb@suse.de>");
-MODULE_LICENSE("GPL");
--
1.4.1.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers
2007-06-09 19:08 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers michaelc
2007-06-09 19:08 ` [PATCH 6/7] scsi-hw-handler: rm dm-hw-handler code michaelc
@ 2007-06-09 19:18 ` Mike Christie
2007-06-09 19:39 ` [dm-devel] " Mike Christie
1 sibling, 1 reply; 10+ messages in thread
From: Mike Christie @ 2007-06-09 19:18 UTC (permalink / raw)
To: michaelc; +Cc: dm-devel, Alasdair Graeme Kergon, linux-scsi
michaelc@cs.wisc.edu wrote:
> From: Mike Christie <michaelc@cs.wisc.edu>
>
> This patch converts dm-mpath to scsi hw handlers. It does
> not add any new functionality and old behaviors and userspace
> tools should be supported except we use the safe clariion
> default instead of using the userspace setting.
>
> This is just the dm-mpath parts which are necessary to use
> REQ_TYPE_LINUX_BLOCK and REQ_LB_OP_TRANSITION. In later mails
> I will send patches which remove old code and add more
> functionality.
> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Alasdair, I took out all the new functionality. This patch is just the
basic conversion. I can try to break it down even more if and do a patch
for every hw handler callout that gets removed (all the callouts end up
getting removed), but that may not buy much since the bulk of the patch
is the REQ_TYPE_LINUX_BLOCK code.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [dm-devel] Re: [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers
2007-06-09 19:18 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers Mike Christie
@ 2007-06-09 19:39 ` Mike Christie
0 siblings, 0 replies; 10+ messages in thread
From: Mike Christie @ 2007-06-09 19:39 UTC (permalink / raw)
To: device-mapper development; +Cc: Alasdair Graeme Kergon, linux-scsi
Mike Christie wrote:
> michaelc@cs.wisc.edu wrote:
>> From: Mike Christie <michaelc@cs.wisc.edu>
>>
>> This patch converts dm-mpath to scsi hw handlers. It does
>> not add any new functionality and old behaviors and userspace
>> tools should be supported except we use the safe clariion
>> default instead of using the userspace setting.
>>
>> This is just the dm-mpath parts which are necessary to use
>> REQ_TYPE_LINUX_BLOCK and REQ_LB_OP_TRANSITION. In later mails
>> I will send patches which remove old code and add more
>> functionality.
>> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
>
> Alasdair, I took out all the new functionality. This patch is just the
> basic conversion. I can try to break it down even more if and do a patch
> for every hw handler callout that gets removed (all the callouts end up
> getting removed), but that may not buy much since the bulk of the patch
> is the REQ_TYPE_LINUX_BLOCK code.
>
Just in case, I broke the patch in this mail down here
http://www.cs.wisc.edu/~michaelc/block/dm/mpath/
It basically breaks it up into removing the creation/destruction
callbacks. Then adds the new pg init code. And finally removes the old
pg_init code. Each patch is not compilable by itself so it is not
git-revertable, but maybe it will be easier for you to read.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2007-06-09 19:39 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-09 19:07 Move dm hw handlers to lower level subsystems michaelc
2007-06-09 19:07 ` [PATCH 1/7] scsi-hw-handler: add REQ_LB_OP_TRANSITION and errors michaelc
2007-06-09 19:07 ` [PATCH 2/7] scsi-hw-handler: scsi handling of REQ_LB_OP_TRANSITION michaelc
2007-06-09 19:08 ` [PATCH 3/7] scsi-hw-handler: add hp sw handler michaelc
2007-06-09 19:08 ` [PATCH 4/7] scsi-hw-handler: add emc clariion handler michaelc
2007-06-09 19:08 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers michaelc
2007-06-09 19:08 ` [PATCH 6/7] scsi-hw-handler: rm dm-hw-handler code michaelc
2007-06-09 19:08 ` [PATCH 7/7] scsi-hw-handler: rm dm-emc code michaelc
2007-06-09 19:18 ` [PATCH 5/7] scsi-hw-handler: convert dm-mpath to scsi hw handlers Mike Christie
2007-06-09 19:39 ` [dm-devel] " Mike Christie
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).