scsi_dh: Move hardware handlers from dm to SCSI
Subsystems (3)
cover scsi_dh: Move hardware handlers from dm to SCSI
Hello,
This is the latest version of the patchset that was posted on Apr 17:
http://marc.info/?l=linux-scsi&m=120847097122545&w=2
Following are the changes made since last post:
Based on Alasdair's comments:
- Split the dm-mpath patch into 4 patches to enhance readabilty
- Added comments to patch header and inline
- Added an interface scsi_dh_handler_exist() and used it to verify the availability of a hardware handler
- Do not accept arguments with the hardware handler parameter
- Make the workqueue single threaded, and change its name
- removed the usage of path_to_activate and used an existing field -renamed activate_passive_path to activate_path
- Bring back the pg_init_retries.
Others:
- Added additional devices to the device list
- removed few erroneous BUG assertions
- Fixed an erroneous return code from scsi_dh_rdac.c.
This patch set applies on 2.6.25-mm1.
This patch set has been tested on a DS4800.
Testing has been done earlier with the following storage devices:
- IBM DS4800 storage device for the lsi_rdac hardware handler
- HP storage device for the hp_sw hardware handler.
Thanks to Dave([email protected])
- EMC storage device for the EMC hardware handler.
Thanks to Arthur([email protected]) and Ronald([email protected])
In effect all hardware handlers are tested.
-------------------- Comment from Patch 01/10 --------------------- Some of the storage devices (that can be accessed through multiple paths), do need some special handling for
1. Activating the passive path of the storage access.
2. Decode and handle the special sense codes returned by the devices.
3. Handle the I/Os being sent to the passive path, especially during the device probe time.
when accessed through multiple paths.
As of today this special device handling is done at the dm-multipath layer using dm-handlers. That works well for (1); for (2) to be handled at dm layer, scsi sense information need to be exported from SCSI to dm-layer, which is not very attractive; (3) cannot be done at all at the dm layer.
Device handler has been moved to SCSI mainly to handle (2) and (3) properly.
----------------------
Thanks,
chandra
PATCH 1/10 scsi_dh: add infrastructure for SCSI Device Handlers
Subject: [PATCH 01/10] scsi_dh: add infrastructure for SCSI Device Handlers
From: Chandra Seetharaman <[email protected]>
Some of the storage devices (that can be accessed through multiple paths), do need some special handling for
1. Activating the passive path of the storage access.
2. Decode and handle the special sense codes returned by the devices.
3. Handle the I/Os being sent to the passive path, especially during the device probe time.
when accessed through multiple paths.
As of today this special device handling is done at the dm-multipath layer using dm-handlers. That works well for (1); for (2) to be handled at dm layer, scsi sense information need to be exported from SCSI to dm-layer, which is not very attractive; (3) cannot be done at all at the dm layer.
Device handler has been moved to SCSI mainly to handle (2) and (3) properly.
--
This patch provides the infrastructure for moving the feature over to SCSI.
---
drivers/scsi/Kconfig | 2 2 + 0 - 0 ! drivers/scsi/Makefile | 1 1 + 0 - 0 ! drivers/scsi/device_handler/Kconfig | 12 12 + 0 - 0 ! drivers/scsi/device_handler/Makefile | 4 4 + 0 - 0 ! drivers/scsi/device_handler/scsi_dh.c | 151 151 + 0 - 0 ! drivers/scsi/scsi_error.c | 11 11 + 0 - 0 ! drivers/scsi/scsi_lib.c | 8 8 + 0 - 0 ! drivers/scsi/scsi_sysfs.c | 1 1 + 0 - 0 ! include/scsi/scsi.h | 1 1 + 0 - 0 ! include/scsi/scsi_device.h | 22 22 + 0 - 0 ! include/scsi/scsi_dh.h | 58 58 + 0 - 0 ! 11 files changed, 271 insertions(+)
drivers/scsi/Kconfig +2 -0
@@ -1761,4 +1761,6 @@ endif # SCSI_LOWLEVEL source "drivers/scsi/pcmcia/Kconfig" +source "drivers/scsi/device_handler/Kconfig" + endmenu
drivers/scsi/Makefile +1 -0
@@ -34,6 +34,7 @@ obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_t obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o +obj-$(CONFIG_SCSI_DH) += device_handler/ obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
drivers/scsi/device_handler/Kconfig new file +12 -0
@@ -0,0 +1,12 @@ +# +# SCSI Device Handler configuration +# + +menuconfig SCSI_DH + tristate "SCSI Device Handlers" + depends on SCSI + default n + help + SCSI Device Handlers provide device specific support for + devices utilized in multipath configurations. Say Y here to + select support for specific hardware.
drivers/scsi/device_handler/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +# +# SCSI Device Handler +# +obj-$(CONFIG_SCSI_DH) += scsi_dh.o
drivers/scsi/scsi_error.c +11 -0
@@ -298,6 +298,7 @@ static inline void scsi_eh_prt_fail_stat*/ 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))
@@ -306,6 +307,16 @@ static int scsi_check_sense(struct scsi_if (scsi_sense_is_deferred (&sshdr))return NEEDS_RETRY ; +if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh && + sdev->scsi_dh_data->scsi_dh->check_sense) { +int rc; + + rc = sdev->scsi_dh_data->scsi_dh->check_sense (sdev, &sshdr); +if (rc !=SCSI_RETURN_NOT_HANDLED ) +return rc; +/* handler 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.
include/scsi/scsi_device.h +22 -0
@@ -161,9 +161,29 @@ struct scsi_device {struct execute_work ew;/* used to get process context on put */ +struct scsi_dh_data *scsi_dh_data;enum scsi_device_state sdev_state;unsigned long sdev_data[0 ]; } __attribute__((aligned(sizeof(unsigned long)))); + +struct scsi_device_handler { +/* Used by the infrastructure */ +struct list_head list;/* list of scsi_device_handlers */ +struct notifier_block nb; + +/* Filled by the hardware handler */ +struct module *module; +const char *name; +int (*check_sense)(struct scsi_device *,struct scsi_sense_hdr *); +int (*activate)(struct scsi_device *); +int (*prep_fn)(struct scsi_device *,struct request *); +}; + +struct scsi_dh_data { +struct scsi_device_handler *scsi_dh; +char buf[0 ]; +}; +#define to_scsi_device (d) \ container_of(d, struct scsi_device, sdev_gendev)#define class_to_sdev (d) \
@@ -229,7 +249,9 @@ extern struct scsi_device *__scsi_add_de uint, uint, uint, void *hostdata);extern int scsi_add_device (struct Scsi_Host *host,uint channel,uint target,uint lun); +extern int scsi_register_device_handler (struct scsi_device_handler *scsi_dh);extern void scsi_remove_device (struct scsi_device *); +extern int scsi_unregister_device_handler (struct scsi_device_handler *scsi_dh);extern int scsi_device_get (struct scsi_device *);extern void scsi_device_put (struct scsi_device *);
drivers/scsi/device_handler/scsi_dh.c new file +162 -0
162 lines not on this page · raw message
include/scsi/scsi_dh.h new file +59 -0
59 lines not on this page · raw message
drivers/scsi/scsi_lib.c +8 -0
@@ -1156,6 +1156,14 @@ int scsi_setup_fs_cmnd(struct scsi_devicif (ret !=BLKPREP_OK )return ret; + +if (unlikely (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh + && sdev->scsi_dh_data->scsi_dh->prep_fn)) { + ret = sdev->scsi_dh_data->scsi_dh->prep_fn (sdev, req); +if (ret !=BLKPREP_OK ) +return ret; + } +/* * Filesystem requests must transfer data. */
include/scsi/scsi.h +1 -0
@@ -374,6 +374,7 @@ struct scsi_lun {#define SOFT_ERROR 0x2005#define ADD_TO_MLQUEUE 0x2006#define TIMEOUT_ERROR 0x2007 +#define SCSI_RETURN_NOT_HANDLED 0x2008/* * Midlevel queue return values.
drivers/scsi/scsi_sysfs.c +1 -0
@@ -406,6 +406,7 @@ struct bus_type scsi_bus_type = { .resume = scsi_bus_resume, .remove = scsi_bus_remove, }; +EXPORT_SYMBOL_GPL (scsi_bus_type);int scsi_sysfs_register (void ) {
PATCH 2/10 scsi_dh: add lsi rdac device handler
In reply to Chandra SeetharamanSubject: [PATCH 02/10] scsi_dh: add lsi rdac device handler
From: Chandra Seetharaman <[email protected]>
This patch provides the device handler to support the LSI RDAC SCSI based storage devices.
---
drivers/scsi/device_handler/Kconfig | 6 6 + 0 - 0 ! drivers/scsi/device_handler/Makefile | 1 1 + 0 - 0 ! drivers/scsi/device_handler/scsi_dh_rdac.c | 678 678 + 0 - 0 ! 3 files changed, 685 insertions(+)
drivers/scsi/device_handler/Kconfig +6 -0
@@ -10,3 +10,9 @@ menuconfig SCSI_DH SCSI Device Handlers provide device specific support for devices utilized in multipath configurations. Say Y here to select support for specific hardware. + +config SCSI_DH_RDAC + tristate "LSI RDAC Device Handler" + depends on SCSI_DH + help + If you have a LSI RDAC select y. Otherwise, say N.
drivers/scsi/device_handler/scsi_dh_rdac.c new file +691 -0
691 lines not on this page · raw message
drivers/scsi/device_handler/Makefile +1 -0
@@ -2,3 +2,4 @@ # SCSI Device Handler # obj-$(CONFIG_SCSI_DH) += scsi_dh.o +obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o
PATCH 3/10 scsi_dh: add hp sw device handler
In reply to Chandra SeetharamanSubject: [PATCH 03/10] scsi_dh: add hp sw device handler
From: Mike Christie <[email protected]>
This patch provides the device handler to support the older hp boxes which cannot be upgraded.
---
drivers/scsi/device_handler/Kconfig | 8 8 + 0 - 0 ! drivers/scsi/device_handler/Makefile | 1 1 + 0 - 0 ! drivers/scsi/device_handler/scsi_dh_hp_sw.c | 201 201 + 0 - 0 ! 3 files changed, 210 insertions(+)
drivers/scsi/device_handler/Kconfig +8 -0
@@ -16,3 +16,11 @@ config SCSI_DH_RDAC depends on SCSI_DH help If you have a LSI RDAC select y. Otherwise, say N. + +config SCSI_DH_HP_SW + tristate "HP/COMPAQ MSA Device Handler" + depends on SCSI_DH + 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.
drivers/scsi/device_handler/Makefile +1 -0
@@ -3,3 +3,4 @@ # obj-$(CONFIG_SCSI_DH) += scsi_dh.o obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o +obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o
drivers/scsi/device_handler/scsi_dh_hp_sw.c new file +202 -0
202 lines not on this page · raw message
PATCH 4/10 scsi_dh: add EMC Clariion device handler
In reply to Chandra SeetharamanSubject: [PATCH 04/10] scsi_dh: add EMC Clariion device handler
From: Chandra Seetharaman <[email protected]>
This adds support for EMC Clariions. This patch has the features that currently exists in mainline and advanced features from Ed's patches.
---
drivers/scsi/device_handler/Kconfig | 6 6 + 0 - 0 ! drivers/scsi/device_handler/Makefile | 1 1 + 0 - 0 ! drivers/scsi/device_handler/scsi_dh_emc.c | 499 499 + 0 - 0 ! 3 files changed, 506 insertions(+)
drivers/scsi/device_handler/Kconfig +6 -0
@@ -24,3 +24,9 @@ config SCSI_DH_HP_SW 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. + +config SCSI_DH_EMC + tristate "EMC CLARiiON Device Handler" + depends on SCSI_DH + help + If you have a EMC CLARiiON select y. Otherwise, say N.
drivers/scsi/device_handler/scsi_dh_emc.c new file +499 -0
499 lines not on this page · raw message
drivers/scsi/device_handler/Makefile +1 -0
@@ -4,3 +4,4 @@ obj-$(CONFIG_SCSI_DH) += scsi_dh.o obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o +obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o
PATCH 5/10 scsi_dh: Use SCSI device handler in dm-multipath
In reply to Chandra SeetharamanSubject: [PATCH 05/10] scsi_dh: Use SCSI device handler in dm-multipath
From: Chandra Seetharaman <[email protected]>
This patch converts dm-mpath to use scsi device handlers instead of dm's hardware handlers.
This patch does not add any new functionality. Old behaviors remain and userspace tools work as is except that arguments supplied with hardware handler are ignored.
One behavioral exception is: Activation of a path is synchronous in this patch, opposed to the older behavior of being asynchronous (changed in patch 07: scsi_dh: Add a single threaded workqueue for initializing a path)
Note: There is no need to get a reference for the device handler module (as it was done in the dm hardware handler case) here as the reference is held when the device was first found. Instead we check and make sure that support for the specified device is present at table load time.
---
drivers/md/Kconfig | 1 1 + 0 - 0 !
drivers/md/dm-mpath.c | 226 111 + 115 - 0 !
2 files changed, 112 insertions(+), 115 deletions(-)
drivers/md/dm-mpath.c +80 -51
@@ -20,6 +20,7 @@#include <linux/slab.h> #include <linux/time.h> #include <linux/workqueue.h> +#include <scsi/scsi_dh.h> #include <asm/atomic.h> #define DM_MSG_PREFIX "multipath"
@@ -61,7 +62,7 @@ struct multipath {spinlock_t lock; -struct hw_handler hw_handler; +const char *hw_handler_name;unsigned nr_priority_groups;struct list_head priority_groups;unsigned pg_init_required;/* pg_init needs calling? */
@@ -109,6 +110,7 @@ static struct kmem_cache *_mpio_cache;static struct workqueue_struct *kmultipathd;static void process_queued_ios (struct work_struct *work);static void trigger_event (struct work_struct *work); +static void pg_init_done (struct dm_path *,int );/*-----------------------------------------------
@@ -193,18 +195,13 @@ static struct multipath *alloc_multipathstatic 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); }
@@ -216,12 +213,10 @@ static void free_multipath(struct multipstatic 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 {
@@ -409,7 +404,6 @@ static void process_queued_ios(struct wo {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;
@@ -438,8 +432,11 @@ static void process_queued_ios(struct wo out:spin_unlock_irqrestore (&m->lock, flags); -if (init_required) - hwh->type->pg_init (hwh, pgpath->pg->bypassed, &pgpath->path); +if (init_required) { +struct dm_path *path = &pgpath->path; +int ret =scsi_dh_activate (bdev_get_queue (path->dev->bdev)); +pg_init_done (path, ret); + }if (!must_queue)dispatch_queued_ios (m);
@@ -652,8 +649,6 @@ static struct priority_group *parse_priostatic int parse_hw_handler (struct arg_set *as,struct multipath *m) { -int r; -struct hw_handler_type *hwht;unsigned hw_argc;struct dm_target *ti = m->ti;
@@ -661,30 +656,18 @@ static int parse_hw_handler(struct arg_s {0, 1024, "invalid number of hardware handler args"}, }; - r =read_param (_params,shift (as), &hw_argc, &ti->error); -if (r) +if (read_param (_params,shift (as), &hw_argc, &ti->error))return -EINVAL ;if (!hw_argc)return 0 ; - hwht =dm_get_hw_handler (shift (as)); -if (!hwht) { + m->hw_handler_name =kstrdup (shift (as),GFP_KERNEL ); +request_module ("scsi_dh_%s" , m->hw_handler_name); +if (scsi_dh_handler_exist (m->hw_handler_name) ==0 ) { 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;consume (as, hw_argc -1 );return 0 ;
@@ -1063,14 +1046,74 @@ void dm_pg_init_complete(struct dm_pathspin_unlock_irqrestore (&m->lock, flags); } +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; + +/* device or driver problems */ +switch (errors) { +case SCSI_DH_OK : +break ; +case SCSI_DH_NOSYS : +if (!m->hw_handler_name) { + errors =0 ; +break ; + } +DMERR ("Cannot failover device because scsi_dh_%s was not " +"loaded." , m->hw_handler_name); +/* +* Fail path for now, so we do not ping pong +*/ +fail_path (pgpath); +break ; +case SCSI_DH_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 SCSI_DH_RETRY we should wait a couple seconds */ +case SCSI_DH_RETRY : +case SCSI_DH_IMM_RETRY : +case SCSI_DH_RES_TEMP_UNAVAIL : +if (pg_init_limit_reached (m, pgpath)) +fail_path (pgpath); + errors =0 ; +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); + } + +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); +} +/* * end_io handling */ static int do_end_io (struct multipath *m,struct bio *bio,int error,struct dm_mpath_io *mpio) { -struct hw_handler *hwh = &m->hw_handler; -unsigned err_flags =MP_FAIL_PATH ;/* Default behavior */ unsigned long flags;if (!error)
@@ -1097,19 +1140,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);
@@ -1194,7 +1226,6 @@ static int multipath_status(struct dm_taint 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;
@@ -1214,12 +1245,10 @@ static int multipath_status(struct dm_taDMEMIT ("pg_init_retries %u " , m->pg_init_retries); } -if (hwh->type && hwh->type->status) - sz += hwh->type->status (hwh, type, result + sz, maxlen - sz); -else if (!hwh->type || type ==STATUSTYPE_INFO ) +if (!m->hw_handler_name || type ==STATUSTYPE_INFO )DMEMIT ("0 " );else -DMEMIT ("1 %s " , hwh->type->name); +DMEMIT ("1 %s " , m->hw_handler_name);DMEMIT ("%u " , m->nr_priority_groups);
drivers/md/Kconfig +1 -0
@@ -252,6 +252,7 @@ config DM_ZERO config DM_MULTIPATH tristate "Multipath target" depends on BLK_DEV_DM + select SCSI_DH ---help--- Allow volume managers to support multipath hardware.
PATCH 6/10 scsi_dh: Do not allow arguments for hardware handlers
In reply to Chandra SeetharamanSubject: [PATCH 06/10] scsi_dh: Do not allow arguments for hardware handlers
From: Chandra Seetharaman <[email protected]>
The new implementation does not use the arguments provided with the hardware handler. This patch makes the change visible to the user by failing table load when arguments are provided with the hardware handler.
---
drivers/md/dm-mpath.c +6 -2
@@ -653,11 +653,15 @@ static int parse_hw_handler(struct arg_sstruct dm_target *ti = m->ti;static struct param _params[] = { - {0 ,1024 ,"invalid number of hardware handler args" }, + {0 ,1 ,"invalid number of hardware handler args" }, }; -if (read_param (_params,shift (as), &hw_argc, &ti->error)) +if (read_param (_params,shift (as), &hw_argc, &ti->error)) { +if (hw_argc >1 ) + ti->error ="no arguments accepted for hardware" +" handler" ;return -EINVAL ; + }if (!hw_argc)return 0 ;
Alasdair G Kergon
maintainerRe: [PATCH 06/10] scsi_dh: Do not allow arguments for hardware handlers
Quoted 5 lines · Chandra Seetharaman
Subject: [PATCH 06/10]
scsi_dh: Do not allow arguments for hardware handlers
From: Chandra Seetharaman <[email protected]>
The new implementation does not use the arguments provided with the hardware handler. This patch makes the change visible to the user by failing table load when arguments are provided with the hardware handler.
But then someone supplying such an arg may need to update their userspace multipath config file before they can use this new kernel.
Past experience suggests that changes like that usually come back and bite us. Let's instead just have the kernel log a message noting that the args have been ignored and allow people to deal with it at their leisure.
Alasdair
Signature · 1 line
[email protected]
Re: [dm-devel] [PATCH 06/10] scsi_dh: Do not allow arguments for hardware handlers
Quoted 7 lines · Alasdair G Kergon
Quoted 5 lines · Chandra Seetharaman
Subject: [PATCH 06/10]
scsi_dh: Do not allow arguments for hardware handlers
From: Chandra Seetharaman <[email protected]>
The new implementation does not use the arguments provided with the hardware handler. This patch makes the change visible to the user by failing table load when arguments are provided with the hardware handler.
Quoted 7 lines
But then someone supplying such an arg may need to update their userspace multipath config file before they can use this new kernel.
Past experience suggests that changes like that usually come back and bite us. Let's instead just have the kernel log a message noting that the args have been ignored and allow people to deal with it at their leisure.
Understand.
How does the following patch look ?
--------------------
Subject: [PATCH 06/10] scsi_dh: Print warning when arguments were provided for hardware handlers
From: Chandra Seetharaman <[email protected]>
The new implementation does not use the arguments provided with the hardware handler. This patch makes the change visible to the user by printing a warning to the kernel log.
---
drivers/md/dm-mpath.c +5 -2
@@ -656,8 +656,11 @@ static int parse_hw_handler(struct arg_s {0, 1024, "invalid number of hardware handler args"}, }; -if (read_param (_params,shift (as), &hw_argc, &ti->error)) -return -EINVAL ; +if (read_param (_params,shift (as), &hw_argc, &ti->error)) { +if (hw_argc >1 ) +printk (KERN_WARN "Additional arguments provided to " +"hardware handler were ignored\n" ); + }if (!hw_argc)return 0 ;
------------------------
Quoted 2 lines
Alasdair
PATCH 7/10 scsi_dh: Add a single threaded workqueue for initializing paths
In reply to Chandra SeetharamanSubject: [PATCH 07/10] scsi_dh: Add a single threaded workqueue for initializing paths
From: Chandra Seetharaman <[email protected]>
Before this patch set (SCSI hardware handlers), initialization of a path was done asynchronously. Doing that requires a workqueue in each device/hardware handler module and leads to unneccessary complication in the device handler code, making it difficult to read the code and follow the state diagram.
Moving that workqueue to this level makes the device handler code simpler. Hence, the workqueue is moved to dm level.
A new workqueue is added instead of adding it to the existing workqueue (kmpathd) for the following reasons:
1. Device activation has to happen faster, stacking them along with the other workqueue might lead to unnecessary delay in the activation of the path.
2. The effect could be felt the other way too. i.e the current events that are handled by the existing workqueue might get a delayed response.
---
drivers/md/dm-mpath.c +34 -7
@@ -63,6 +63,7 @@ struct multipath {spinlock_t lock;const char *hw_handler_name; +struct work_struct activate_path;unsigned nr_priority_groups;struct list_head priority_groups;unsigned pg_init_required;/* pg_init needs calling? */
@@ -107,10 +108,10 @@ typedef int (*action_fn) (struct pgpathstatic struct kmem_cache *_mpio_cache; -static struct workqueue_struct *kmultipathd; +static struct workqueue_struct *kmultipathd, *kmpath_handlerd;static void process_queued_ios (struct work_struct *work);static void trigger_event (struct work_struct *work); -static void pg_init_done (struct dm_path *,int ); +static void activate_path (struct work_struct *work);/*-----------------------------------------------
@@ -180,6 +181,7 @@ static struct multipath *alloc_multipath m->queue_io =1 ;INIT_WORK (&m->process_queued_ios, process_queued_ios);INIT_WORK (&m->trigger_event, trigger_event); +INIT_WORK (&m->activate_path, activate_path); m->mpio_pool =mempool_create_slab_pool (MIN_IOS , _mpio_cache);if (!m->mpio_pool) {kfree (m);
@@ -432,11 +434,8 @@ static void process_queued_ios(struct wo out:spin_unlock_irqrestore (&m->lock, flags); -if (init_required) { -struct dm_path *path = &pgpath->path; -int ret =scsi_dh_activate (bdev_get_queue (path->dev->bdev)); -pg_init_done (path, ret); - } +if (init_required) +queue_work (kmpath_handlerd, &m->activate_path);if (!must_queue)dispatch_queued_ios (m);
@@ -795,6 +794,7 @@ static void multipath_dtr(struct dm_targ {struct multipath *m = (struct multipath *) ti->private; +flush_workqueue (kmpath_handlerd);flush_workqueue (kmultipathd);free_multipath (m); }
@@ -1112,6 +1112,17 @@ static void pg_init_done(struct dm_pathspin_unlock_irqrestore (&m->lock, flags); } +static void activate_path (struct work_struct *work) +{ +int ret; +struct multipath *m = + container_of(work, struct multipath, activate_path); +struct dm_path *path = &m->current_pgpath->path; + + ret =scsi_dh_activate (bdev_get_queue (path->dev->bdev)); +pg_init_done (path, ret); +} +/* * end_io handling */
@@ -1455,6 +1466,21 @@ static int __init dm_multipath_init(voidreturn -ENOMEM ; } +/* +* A separate workqueue is used to handle the device handlers +* to avoid overloading existing workqueue. Overloading the +* old workqueue would also create a bottleneck in the +* path of the storage hardware device activation. +*/ + kmpath_handlerd =create_singlethread_workqueue ("kmpath_handlerd" ); +if (!kmpath_handlerd) { +DMERR ("failed to create workqueue kmpath_handlerd" ); +destroy_workqueue (kmultipathd); +dm_unregister_target (&multipath_target); +kmem_cache_destroy (_mpio_cache); +return -ENOMEM ; + } +DMINFO ("version %u.%u.%u loaded" , multipath_target.version[0 ], multipath_target.version[1 ], multipath_target.version[2 ]);
@@ -1466,6 +1492,7 @@ static void __exit dm_multipath_exit(voi {int r; +destroy_workqueue (kmpath_handlerd);destroy_workqueue (kmultipathd); r =dm_unregister_target (&multipath_target);
PATCH 8/10 scsi_dh: Remove dm_pg_init_complete
In reply to Chandra SeetharamanSubject: [PATCH 08/10] scsi_dh: Remove dm_pg_init_complete
From: Chandra Seetharaman <[email protected]>
This patch just removes the dm layer's path initialization completion routine. This is separated from the other patch(scsi_dh: Use SCSI device handler in dm-multipath) Just to make that patch more readable.
---
drivers/md/dm-mpath.c +0 -41
@@ -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" #include "dm-uevent.h"
@@ -1012,44 +1011,6 @@ static int pg_init_limit_reached(structreturn limit_reached; } -/* -* 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; - -/* -* If requested, retry pg_init until maximum number of retries exceeded. -* If retry not requested and PG already bypassed, always fail the path. -*/ -if (err_flags &MP_RETRY ) { -if (pg_init_limit_reached (m, pgpath)) - err_flags |=MP_FAIL_PATH ; - }else 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 & ~MP_RETRY ) { - 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); -} -static void pg_init_done (struct dm_path *path,int errors) {struct pgpath *pgpath =path_to_pgpath (path);
@@ -1501,8 +1462,6 @@ static void __exit dm_multipath_exit(voikmem_cache_destroy (_mpio_cache); } -EXPORT_SYMBOL_GPL (dm_pg_init_complete); -module_init (dm_multipath_init);module_exit (dm_multipath_exit);
PATCH 9/10 scsi_dh: Remove hardware handlers from dm
In reply to Chandra SeetharamanSubject: [PATCH 09/10] scsi_dh: Remove hardware handlers from dm
From: Chandra Seetharaman <[email protected]>
This patch removes the 3 hardware handlers that currently exist under dm as the functionality is moved to SCSI layer in the earlier patches.
---
drivers/md/Kconfig | 18 0 + 18 - 0 ! drivers/md/Makefile | 3 0 + 3 - 0 ! drivers/md/dm-emc.c | 347 0 + 347 - 0 ! drivers/md/dm-mpath-hp-sw.c | 248 0 + 248 - 0 ! drivers/md/dm-mpath-rdac.c | 701 0 + 701 - 0 ! 5 files changed, 1317 deletions(-)
drivers/md/Kconfig +0 -18
@@ -256,24 +256,6 @@ config DM_MULTIPATH ---help--- Allow volume managers to support multipath hardware. -config DM_MULTIPATH_EMC - tristate "EMC CX/AX multipath support" - depends on DM_MULTIPATH && BLK_DEV_DM - ---help--- - Multipath support for EMC CX/AX series hardware. - -config DM_MULTIPATH_RDAC - tristate "LSI/Engenio RDAC multipath support (EXPERIMENTAL)" - depends on DM_MULTIPATH && BLK_DEV_DM && SCSI && EXPERIMENTAL - ---help--- - Multipath support for LSI/Engenio RDAC. - -config DM_MULTIPATH_HP - tristate "HP MSA multipath support (EXPERIMENTAL)" - depends on DM_MULTIPATH && BLK_DEV_DM && SCSI && EXPERIMENTAL - ---help--- - Multipath support for HP MSA (Active/Passive) series hardware. - config DM_DELAY tristate "I/O delaying target (EXPERIMENTAL)" depends on BLK_DEV_DM && EXPERIMENTAL
drivers/md/Makefile +0 -3
@@ -35,9 +35,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_MULTIPATH_HP) += dm-hp-sw.o -obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o obj-$(CONFIG_DM_ZERO) += dm-zero.o
drivers/md/dm-emc.c deleted +0 -347
347 lines not on this page · raw message
drivers/md/dm-mpath-hp-sw.c deleted +0 -248
248 lines not on this page · raw message
drivers/md/dm-mpath-rdac.c deleted +0 -701
701 lines not on this page · raw message
PATCH 10/10 scsi_dh: Remove hardware handler infrastructure from dm
In reply to Chandra SeetharamanSubject: [PATCH 10/10] scsi_dh: Remove hardware handler infrastructure from dm
From: Chandra Seetharaman <[email protected]>
This patch just removes infrastructure that provided support for hardware handlers in the dm layer as it is not needed anymore.
---
drivers/md/Makefile | 2 1 + 1 - 0 ! drivers/md/dm-hw-handler.c | 213 0 + 213 - 0 ! drivers/md/dm-hw-handler.h | 63 0 + 63 - 0 ! drivers/md/dm-mpath.h | 1 0 + 1 - 0 ! 4 files changed, 1 insertion(+), 278 deletions(-)
drivers/md/dm-hw-handler.c deleted +0 -213
@@ -1,213 +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 =kzalloc (sizeof (*hwhi),GFP_KERNEL ); - -if (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);
drivers/md/dm-hw-handler.h deleted +0 -63
63 lines not on this page · raw message
drivers/md/Makefile +1 -1
@@ -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 dm-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-raid1.o dm-rdac-objs := dm-mpath-rdac.o
drivers/md/dm-mpath.h +0 -1
@@ -16,7 +16,6 @@ struct dm_path {unsigned is_active;/* Read-only */ void *pscontext;/* For path-selector use */ -void *hwhcontext;/* For hw-handler use */ };/* Callback for hwh_pg_init_fn to use when complete */