Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 148204 Details for
Bug 195685
RFE: Add dm-hp-sw to kernel to allow use of active/passive sans with dm multipathing
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
Latest upstream patch against 2.6.20
dm-hp-sw-v0.974.patch (text/x-patch), 16.22 KB, created by
Dave Wysochanski
on 2007-02-16 16:15:37 UTC
(
hide
)
Description:
Latest upstream patch against 2.6.20
Filename:
MIME Type:
Creator:
Dave Wysochanski
Created:
2007-02-16 16:15:37 UTC
Size:
16.22 KB
patch
obsolete
>Index: linux-2.6.20/drivers/md/Makefile >=================================================================== >--- linux-2.6.20.orig/drivers/md/Makefile 2007-02-15 17:38:58.000000000 -0500 >+++ linux-2.6.20/drivers/md/Makefile 2007-02-15 17:39:27.000000000 -0500 >@@ -33,6 +33,7 @@ obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o > obj-$(CONFIG_DM_CRYPT) += dm-crypt.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_SNAPSHOT) += dm-snapshot.o > obj-$(CONFIG_DM_MIRROR) += dm-mirror.o > obj-$(CONFIG_DM_ZERO) += dm-zero.o >Index: linux-2.6.20/drivers/md/dm-hp-sw.c >=================================================================== >--- /dev/null 1970-01-01 00:00:00.000000000 +0000 >+++ linux-2.6.20/drivers/md/dm-hp-sw.c 2007-02-15 18:15:53.000000000 -0500 >@@ -0,0 +1,524 @@ >+/* >+ * Copyright (C) 2005 Mike Christie, All rights reserved. >+ * Copyright © 2006 Red Hat, Inc. All rights reserved. >+ * Authors: Mike Christie >+ * Dave Wysochanski >+ * >+ * This file is released under the GPL. >+ * >+ * Basic, very basic, support for HP StorageWorks and FSC FibreCat Asymmetric >+ * (Active/Passive) controllers. These devices need a START_STOP command >+ * issued to the passive path in order to activate it (trigger failover from >+ * active path to passive one). This module implements this functionality. >+ */ >+#include <scsi/scsi.h> >+#include <scsi/scsi_cmnd.h> >+#include <scsi/scsi_dbg.h> >+#include <scsi/scsi_device.h> >+#include <scsi/scsi_host.h> >+#include <scsi/scsi_transport_fc.h> >+#include <linux/list.h> >+#include <linux/types.h> >+ >+/* XXX - for periodic pseudorandom failure */ >+#include <linux/jiffies.h> >+ >+#include "dm.h" >+#include "dm-hw-handler.h" >+ >+#define DM_MSG_PREFIX "multipath hp" >+#define MIN_CMD_RETRIES 5 >+static int cmd_retries=MIN_CMD_RETRIES; >+module_param_named(cmd_retries, cmd_retries, int, S_IRUGO|S_IWUSR); >+MODULE_PARM_DESC(cmd_retries, >+ "Number of times to retry path activation command " >+ "before failing"); >+ >+/* >+ * NOTE: The time it takes the failover command to complete may vary depending >+ * on the number of LUNs, the number of dirty buffers, etc. >+ * Set a minimum value to ensure the user does not cause failover to not work. >+ */ >+#define MIN_CMD_TIMEOUT 30 >+static int cmd_timeout=MIN_CMD_TIMEOUT; >+module_param_named(cmd_timeout, cmd_timeout, int, S_IRUGO|S_IWUSR); >+MODULE_PARM_DESC(cmd_timeout, >+ "Time (in seconds) to wait for path activation " >+ "command completion"); >+ >+ >+struct hp_sw_context { >+ /* >+ * # of times dm layer has called pg_init for one activation sequence >+ */ >+ unsigned pg_init_count; >+ unsigned char sense[SCSI_SENSE_BUFFERSIZE]; >+ u64 node_name; >+}; >+ >+/* >+ * Define the maximum # of MSA1000s we will track for in-progress pg inits. >+ * If you go past this value the code should still work but you may get >+ * multiple pg_inits (unnecessary) on the same controller. We preallocate >+ * here so we don't allocate memory in the I/O path. The normal case is >+ * probably 1 HP MSA1000 connected to a Linux box - gut feel is anything >+ * above 4 is probably a pathalogical case. >+ */ >+#define MAX_HP_MSA 4 >+static unsigned max_hp_msa=MAX_HP_MSA; >+module_param_named(max_hp_msa, max_hp_msa, int, S_IRUGO|S_IWUSR); >+MODULE_PARM_DESC(max_hp_msa, >+ "Maximum number of HP MSA1000s connected - for purposes " >+ "of avoiding duplicate failover commands"); >+/* >+ * We use the FC WWNN to identify a single MSA1000. Note that this is _not_ >+ * a controller within the MSA, but the whole MSA. >+ */ >+struct hp_msa1000 { >+ struct list_head list; >+ u64 node_name; >+}; >+ >+/* >+ * Array used to keep track of HP MSAs connected to this system. >+ * At init time, we allocate an array of structs then add them all to the >+ * free list. Then when we get a pg_init() command, we check the list of >+ * MSAs that have in progress commands. If we don't find a match, then >+ * we grab one from the free list, add the MSA WWNN to it, and move it >+ * from the free list to the in progress list. When the pg_init command >+ * completes, we move it back to the free list. >+ * >+ * We do the preallocation to avoid memory alloc in the I/O path. >+ */ >+static struct hp_msa1000 *hp_msa; >+ >+/* MSAs with pg_init commands in progress */ >+static struct list_head hp_msa_inits_in_progress; >+ >+/* Free MSA structures */ >+static struct list_head hp_msa_free_list; >+ >+/* Protects both free and in-progress lists */ >+static spinlock_t hp_msa_lock; >+ >+ >+/* >+ * Determine whether a pg_init is already in progress on the specified >+ * MSA, identified by 'node_name' >+ * >+ * Returns: >+ * 0 - pg_init not in progress >+ * 1 - pg_init in progress >+ */ >+static int hp_sw_pg_init_in_progress(u64 node_name) >+{ >+ unsigned long flags; >+ struct hp_msa1000 *hp; >+ >+ spin_lock_irqsave(&hp_msa_lock, flags); >+ list_for_each_entry(hp, &hp_msa_inits_in_progress, list) >+ if (hp->node_name == node_name) { >+ spin_unlock_irqrestore(&hp_msa_lock, flags); >+ return 1; >+ } >+ spin_unlock_irqrestore(&hp_msa_lock, flags); >+ return 0; >+} >+ >+ >+/* >+ * Add an entry from the free list to hp_msa_inits_in_progress >+ * for the given value of 'node_name'. >+ * >+ * Returns: >+ * 0 - success >+ * non-zero - failure >+ */ >+static int hp_sw_pg_init_in_progress_add(u64 node_name) >+{ >+ unsigned long flags; >+ struct hp_msa1000 *hp; >+ >+ spin_lock_irqsave(&hp_msa_lock, flags); >+ if (list_empty(&hp_msa_free_list)) { >+ DMINFO ("hp_sw: consider increasing max_hp_msa " >+ "module param "); >+ spin_unlock_irqrestore(&hp_msa_lock, flags); >+ return -ENOMEM; >+ } >+ hp = list_entry(hp_msa_free_list.next, >+ struct hp_msa1000, list); >+ hp->node_name = node_name; >+ list_move(hp_msa_free_list.next, &hp_msa_inits_in_progress); >+ spin_unlock_irqrestore(&hp_msa_lock, flags); >+ return 0; >+} >+ >+/* >+ * Remove the entry from hp_msa_inits_in_progress list that corresponds >+ * to 'node_name'. >+ * >+ * Returns: >+ * 0 - success >+ * non-zero - failure >+ */ >+static int hp_sw_pg_init_in_progress_del(u64 node_name) >+{ >+ unsigned long flags; >+ struct hp_msa1000 *hp; >+ >+ spin_lock_irqsave(&hp_msa_lock, flags); >+ list_for_each_entry(hp, &hp_msa_inits_in_progress, list) >+ if (hp->node_name == node_name) { >+ list_move(&hp->list, &hp_msa_free_list); >+ spin_unlock_irqrestore(&hp_msa_lock, flags); >+ return 0; >+ } >+ spin_unlock_irqrestore(&hp_msa_lock, flags); >+ return -ENOENT; >+} >+ >+ >+/* >+ * Description: HP hardware specific error code checking >+ * Examing error codes and determine whether the error is retryable. >+ * Some error conditions are already retried by scsi-ml (see >+ * scsi_decide_disposition), but some HP specific codes are not. >+ * The intent of this routine is to supply the logic for the HP specific >+ * values. >+ * >+ * Arguments: req - req to be checked for retryable error codes >+ * >+ * Context: scsi-ml softirq >+ * >+ * Lock Status: none >+ * >+ * Returns: >+ * 1 - command completed with retryable error >+ * 0 - command completed with non-retryable error >+ */ >+static int hp_sw_error_is_retryable(struct request *req) >+{ >+ /* >+ * If we get CHECK_CONDITION with NOT_READY, just retry the >+ * command. It may be that the command succeeded, or it may >+ * have truly failed. Either way, it should be safe to retry. >+ */ >+ /* >+ if ((status_byte(req->errors) == CHECK_CONDITION)&& >+ (req->sense[2] & 0xf) == NOT_READY) { >+ */ >+ if (status_byte(req->errors) == CHECK_CONDITION) { >+ if ( driver_byte(req->errors) & DRIVER_SENSE) { >+ DMINFO("hp_sw: sense data"); >+ __scsi_print_sense("hp_sw", req->sense, >+ req->sense_len); >+ } >+ } >+ >+ /* >+ * At this point we don't have complete information about all the error >+ * codes from this hardware, so we are just conservative and retry >+ * when in doubt. >+ */ >+ return 1; >+} >+ >+ >+/* >+ * Description: Completion handler for HP path activation. >+ * Check sense data, free request structure, and notify dm that >+ * pg initialization has completed. >+ * >+ * Arguments: req - completed request >+ * error - blk error value >+ * >+ * Context: scsi-ml softirq >+ * >+ * Lock Status: n/a >+ * >+ * Returns: None >+ */ >+static void hp_sw_end_io(struct request *req, int error) >+{ >+ struct dm_path *path = req->end_io_data; >+ struct hp_sw_context *h = path->hwhcontext; >+ unsigned err_flags; >+ >+ /* TODO: fixup error return */ >+ /* TODO: difference between 'error' arg and req->errors */ >+ if (error == 0) { >+ h->pg_init_count = 0; >+ err_flags = 0; >+ /* >+ * XXX - Probably should remove this log message >+ */ >+ DMINFO("hp_sw: START_STOP on %s completed successfully", >+ path->dev->name); >+ } >+ >+ else { /* If error, we might need to tell dm layer to retry. */ >+ DMINFO("hp_sw: START_STOP on %s completed with error=0x%x", >+ path->dev->name, error); >+ if (hp_sw_error_is_retryable(req)) { >+ /* >+ * NOTE: These retries are in addition to scsi-ml's >+ * retries, because scsi-ml does not handle HP >+ * specific codes. We could just fail here and >+ * rely on multipathd and dm to retry eventually; >+ * however that would have the downside of an >+ * "all paths down" scenario in cases where it may >+ * just take a little while for the pg_init command >+ * to succeed. In essence here we are buying a >+ * little more time here to avoid an "all paths down" >+ * scenario. >+ */ >+ if (h->pg_init_count <= cmd_retries) { >+ DMINFO("hp_sw: %s pg_init pg_init_count=%d", >+ path->dev->name, h->pg_init_count); >+ err_flags = MP_RETRY_PG_INIT; >+ goto exit; >+ } else { >+ DMINFO("hp_sw: %s pg_init out of retries", >+ path->dev->name); >+ } >+ } >+ DMINFO("hp_sw: %s pg_init fail", path->dev->name); >+ h->pg_init_count = 0; >+ err_flags = MP_FAIL_PATH; >+ } >+ >+ exit: >+ hp_sw_pg_init_in_progress_del(h->node_name); >+ req->end_io_data = NULL; >+ __blk_put_request(req->q, req); >+ >+ dm_pg_init_complete(path, err_flags); >+} >+ >+/* >+ * Description: Get a scsi_request structure to be used for path >+ * initialization command (SCSI START_STOP), and fill in scsi cdb >+ * >+ * Arguments: path - path on which to allocate the scsi command for pg init >+ * >+ * Context: local >+ * >+ * Lock Status: n/a >+ * >+ * Returns: request* - pointer to allocated structure (success), >+ * or NULL (failure) >+ */ >+static struct request *hp_sw_get_request(struct dm_path *path) >+{ >+ struct request *req=NULL; >+ struct block_device *bdev = path->dev->bdev; >+ struct request_queue *q = bdev_get_queue(bdev); >+ struct hp_sw_context *h = path->hwhcontext; >+ >+ /* >+ * XXX - fake request fail every so often >+ */ >+#if 0 >+ if ((jiffies & 0xf) == 1) { >+ DMERR("dm-hp-sw: hp_sw_get_request: " >+ "hp_sw_get_request() failed."); >+ goto exit; >+ } >+#endif >+ >+ /* TODO: verify function args, esp GFP_ATOMIC */ >+ req = blk_get_request(q, WRITE, GFP_ATOMIC); >+ if (req == NULL) { >+ DMERR("dm-hp-sw: hp_sw_get_request: " >+ "blk_get_request() failed."); >+ goto exit; >+ } >+ >+ /* TODO: Check timeout unit values */ >+ req->timeout = cmd_timeout*HZ; >+ >+ /* TODO: Double check flags and cmd_type */ >+ req->errors = 0; >+ req->cmd_type = REQ_TYPE_BLOCK_PC; >+ req->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; >+ req->end_io = hp_sw_end_io; >+ req->end_io_data = path; >+ req->sense = h->sense; >+ memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); >+ >+ memset(&req->cmd, 0, BLK_MAX_CDB); >+ req->cmd[0] = START_STOP; >+ req->cmd[4] = 1; >+ req->cmd_len = COMMAND_SIZE(req->cmd[0]); >+exit: >+ return req; >+} >+ >+/* >+ * Description: Entry point for HP path activation. >+ * Just blindly initialize the path and rely on the upper layers to know >+ * whether the path is good or not (don't check the state before sending >+ * the activation request - just send it and do a best-effort). >+ * >+ * Arguments: hwh - hardware handler structure >+ * bypassed - >+ * path - path to initialize >+ * >+ * Context: kmpathd context (see process_queued_ios() in dm-mpath.c) >+ * >+ * Lock Status: n/a >+ * >+ * Returns: None >+ */ >+static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, >+ struct dm_path *path) >+{ >+ struct request *req; >+ struct hp_sw_context *h; >+ struct scsi_device *sdev; >+ struct fc_host_attrs *fc_host; >+ unsigned err_flags; >+ >+ /* >+ * HP MSA1000 is per-controller failover. So grab the FC WWNN >+ * here since it uniquely identifies an MSA1000. >+ * Check to see if there's already a pg_init() in progress to >+ * this particular MSA already. This can happen quite >+ * often if there are multiple luns and a lot of I/O going on when >+ * a path failure occurs. To avoid firing off START_STOP >+ * commands on the same controller needlessly, we save the >+ * WWNN here and do the check. >+ */ >+ sdev = to_scsi_device(path->dev->bdev->bd_disk->driverfs_dev); >+ fc_host = shost_to_fc_host(sdev->host); >+ if (!hp_sw_pg_init_in_progress(fc_host->node_name)) { >+ hp_sw_pg_init_in_progress_add(fc_host->node_name); >+ } else { >+ /* MDW XXX - remove */ >+ DMINFO("hp_sw: skipping START_STOP command on %s, " >+ "pg_init in progress ", path->dev->name); >+ err_flags = 0; >+ goto exit; >+ } >+ >+ /* >+ * FIXME: only one hp_sw_context allocated for the hardware handler >+ * and here were're saving it and using it for every path. In >+ * theory this should be ok since only one pg_init() should be >+ * in progress at a time on any given multipath map >+ */ >+ path->hwhcontext = hwh->context; >+ h = (struct hp_sw_context *) hwh->context; >+ h->pg_init_count++; >+ >+ /* >+ * FIXME: hwhcontext not safe ??? >+ */ >+ h->node_name = fc_host->node_name; >+ >+ req = hp_sw_get_request(path); >+ if (!req) { >+ DMERR("hp_sw: could not allocate request for START_STOP"); >+ goto fail; >+ } >+ >+ DMINFO("hp_sw: queueing START_STOP command on %s, pg_init_count=%d", >+ path->dev->name, h->pg_init_count); >+ >+ elv_add_request(req->q, req, ELEVATOR_INSERT_FRONT, 1); >+ return; >+ >+ fail: >+ /* >+ * FIXME: Not sure what we should do here. >+ * For now, just signal a retry if we are within the retry count. >+ */ >+ if (h->pg_init_count <= cmd_retries) >+ err_flags = MP_RETRY_PG_INIT; >+ else >+ err_flags = MP_FAIL_PATH; >+ >+ exit: >+ dm_pg_init_complete(path, err_flags); >+} >+ >+static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) >+{ >+ struct hp_sw_context *h; >+ >+ /* >+ * FIXME: Maybe here we allocate active/passive controller memory? >+ */ >+ h = kmalloc(sizeof(*h), GFP_KERNEL); >+ if (!h) { >+ DMERR("hp_sw: could not allocate hw_handler context"); >+ return -ENOMEM; >+ } >+ hwh->context = h; >+ h->pg_init_count=0; >+ return 0; >+} >+ >+static void hp_sw_destroy(struct hw_handler *hwh) >+{ >+ struct hp_sw_context *h = hwh->context; >+ >+ kfree(h); >+ hwh->context = NULL; >+} >+ >+static struct hw_handler_type hp_sw_hwh = { >+ .name = "hp_sw", >+ .module = THIS_MODULE, >+ .create = hp_sw_create, >+ .destroy = hp_sw_destroy, >+ .pg_init = hp_sw_pg_init, >+}; >+ >+static int __init hp_sw_init(void) >+{ >+ int r; >+ >+ if (cmd_timeout < MIN_CMD_TIMEOUT) >+ cmd_timeout = MIN_CMD_TIMEOUT; >+ if (cmd_retries < MIN_CMD_RETRIES) >+ cmd_retries = MIN_CMD_RETRIES; >+ >+ hp_msa = (struct hp_msa1000 *) >+ kzalloc(sizeof(struct hp_msa1000)*max_hp_msa, GFP_KERNEL); >+ if (!hp_msa) >+ return -ENOMEM; >+ INIT_LIST_HEAD(&hp_msa_free_list); >+ INIT_LIST_HEAD(&hp_msa_inits_in_progress); >+ for (r=0; r<max_hp_msa; r++) >+ list_add(&hp_msa[r].list, &hp_msa_free_list); >+ spin_lock_init(&hp_msa_lock); >+ >+ r = dm_register_hw_handler(&hp_sw_hwh); >+ if (r < 0) >+ DMERR("hp_sw: register failed %d", r); >+ >+ DMINFO("hp_sw version 0.974 loaded"); >+ >+ return r; >+} >+ >+static void __exit hp_sw_exit(void) >+{ >+ int r; >+ >+ /* FIXME: what about outstanding pg_inits? */ >+ kfree(hp_msa); >+ >+ r = dm_unregister_hw_handler(&hp_sw_hwh); >+ if (r < 0) >+ DMERR("hp_sw: unregister failed %d", r); >+} >+ >+module_init(hp_sw_init); >+module_exit(hp_sw_exit); >+ >+MODULE_DESCRIPTION("HP StorageWorks and FSC FibreCat (A/P) support for dm-multipath"); >+MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>"); >+MODULE_LICENSE("GPL"); >Index: linux-2.6.20/drivers/md/Kconfig >=================================================================== >--- linux-2.6.20.orig/drivers/md/Kconfig 2007-02-15 17:38:58.000000000 -0500 >+++ linux-2.6.20/drivers/md/Kconfig 2007-02-15 17:39:27.000000000 -0500 >@@ -262,6 +262,12 @@ config DM_MULTIPATH_EMC > ---help--- > Multipath support for EMC CX/AX series hardware. > >+config DM_MULTIPATH_HP >+ tristate "HP MSA multipath support (EXPERIMENTAL)" >+ depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL >+ ---help--- >+ Multipath support for HP MSA (Active/Passive) series hardware. >+ > endmenu > > endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 195685
:
131053
|
131073
|
131074
|
132388
|
140056
|
140721
|
140741
|
142204
|
142207
|
148162
| 148204 |
155210
|
292333
|
292553