diff options
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/Kconfig | 6 | ||||
-rw-r--r-- | drivers/md/Makefile | 2 | ||||
-rw-r--r-- | drivers/md/dm-mpath-hp-sw.c | 206 |
3 files changed, 214 insertions, 0 deletions
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 34a8c60a254a..a99af8978203 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -267,6 +267,12 @@ config DM_MULTIPATH_RDAC | |||
267 | ---help--- | 267 | ---help--- |
268 | Multipath support for LSI/Engenio RDAC. | 268 | Multipath support for LSI/Engenio RDAC. |
269 | 269 | ||
270 | config DM_MULTIPATH_HP | ||
271 | tristate "HP MSA multipath support (EXPERIMENTAL)" | ||
272 | depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL | ||
273 | ---help--- | ||
274 | Multipath support for HP MSA (Active/Passive) series hardware. | ||
275 | |||
270 | config DM_DELAY | 276 | config DM_DELAY |
271 | tristate "I/O delaying target (EXPERIMENTAL)" | 277 | tristate "I/O delaying target (EXPERIMENTAL)" |
272 | depends on BLK_DEV_DM && EXPERIMENTAL | 278 | depends on BLK_DEV_DM && EXPERIMENTAL |
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index c49366cdc05d..fded842edeb1 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
@@ -8,6 +8,7 @@ dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o | |||
8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o | 8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o |
9 | dm-mirror-objs := dm-log.o dm-raid1.o | 9 | dm-mirror-objs := dm-log.o dm-raid1.o |
10 | dm-rdac-objs := dm-mpath-rdac.o | 10 | dm-rdac-objs := dm-mpath-rdac.o |
11 | dm-hp-sw-objs := dm-mpath-hp-sw.o | ||
11 | md-mod-objs := md.o bitmap.o | 12 | md-mod-objs := md.o bitmap.o |
12 | raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \ | 13 | raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \ |
13 | raid6int1.o raid6int2.o raid6int4.o \ | 14 | raid6int1.o raid6int2.o raid6int4.o \ |
@@ -35,6 +36,7 @@ obj-$(CONFIG_DM_CRYPT) += dm-crypt.o | |||
35 | obj-$(CONFIG_DM_DELAY) += dm-delay.o | 36 | obj-$(CONFIG_DM_DELAY) += dm-delay.o |
36 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o | 37 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o |
37 | obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o | 38 | obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o |
39 | obj-$(CONFIG_DM_MULTIPATH_HP) += dm-hp-sw.o | ||
38 | obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o | 40 | obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o |
39 | obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o | 41 | obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o |
40 | obj-$(CONFIG_DM_MIRROR) += dm-mirror.o | 42 | obj-$(CONFIG_DM_MIRROR) += dm-mirror.o |
diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c new file mode 100644 index 000000000000..575317037ce2 --- /dev/null +++ b/drivers/md/dm-mpath-hp-sw.c | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Mike Christie, All rights reserved. | ||
3 | * Copyright (C) 2007 Red Hat, Inc. All rights reserved. | ||
4 | * Authors: Mike Christie | ||
5 | * Dave Wysochanski | ||
6 | * | ||
7 | * This file is released under the GPL. | ||
8 | * | ||
9 | * This module implements the specific path activation code for | ||
10 | * HP StorageWorks and FSC FibreCat Asymmetric (Active/Passive) | ||
11 | * storage arrays. | ||
12 | * These storage arrays have controller-based failover, not | ||
13 | * LUN-based failover. However, LUN-based failover is the design | ||
14 | * of dm-multipath. Thus, this module is written for LUN-based failover. | ||
15 | */ | ||
16 | #include <linux/blkdev.h> | ||
17 | #include <linux/list.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <scsi/scsi.h> | ||
20 | #include <scsi/scsi_cmnd.h> | ||
21 | |||
22 | #include "dm.h" | ||
23 | #include "dm-hw-handler.h" | ||
24 | |||
25 | #define DM_MSG_PREFIX "multipath hp-sw" | ||
26 | #define DM_HP_HWH_NAME "hp-sw" | ||
27 | #define DM_HP_HWH_VER "0.0.3" | ||
28 | |||
29 | struct hp_sw_context { | ||
30 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * hp_sw_end_io - Completion handler for HP path activation. | ||
35 | * @req: path activation request | ||
36 | * @error: scsi-ml error | ||
37 | * | ||
38 | * Check sense data, free request structure, and notify dm that | ||
39 | * pg initialization has completed. | ||
40 | * | ||
41 | * Context: scsi-ml softirq | ||
42 | * | ||
43 | * Possible optimizations | ||
44 | * 1. Actually check sense data for retryable error (e.g. NOT_READY) | ||
45 | */ | ||
46 | static void hp_sw_end_io(struct request *req, int error) | ||
47 | { | ||
48 | struct dm_path *path = req->end_io_data; | ||
49 | unsigned err_flags = 0; | ||
50 | |||
51 | if (!error) | ||
52 | DMDEBUG("%s path activation command - success", | ||
53 | path->dev->name); | ||
54 | else { | ||
55 | DMWARN("%s path activation command - error=0x%x", | ||
56 | path->dev->name, error); | ||
57 | err_flags = MP_FAIL_PATH; | ||
58 | } | ||
59 | |||
60 | req->end_io_data = NULL; | ||
61 | __blk_put_request(req->q, req); | ||
62 | dm_pg_init_complete(path, err_flags); | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * hp_sw_get_request - Allocate an HP specific path activation request | ||
67 | * @path: path on which request will be sent (needed for request queue) | ||
68 | * | ||
69 | * The START command is used for path activation request. | ||
70 | * These arrays are controller-based failover, not LUN based. | ||
71 | * One START command issued to a single path will fail over all | ||
72 | * LUNs for the same controller. | ||
73 | * | ||
74 | * Possible optimizations | ||
75 | * 1. Make timeout configurable | ||
76 | * 2. Preallocate request | ||
77 | */ | ||
78 | static struct request *hp_sw_get_request(struct dm_path *path) | ||
79 | { | ||
80 | struct request *req; | ||
81 | struct block_device *bdev = path->dev->bdev; | ||
82 | struct request_queue *q = bdev_get_queue(bdev); | ||
83 | struct hp_sw_context *h = path->hwhcontext; | ||
84 | |||
85 | req = blk_get_request(q, WRITE, GFP_NOIO); | ||
86 | if (!req) | ||
87 | goto out; | ||
88 | |||
89 | req->timeout = 60 * HZ; | ||
90 | |||
91 | req->errors = 0; | ||
92 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
93 | req->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
94 | req->end_io_data = path; | ||
95 | req->sense = h->sense; | ||
96 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
97 | |||
98 | memset(&req->cmd, 0, BLK_MAX_CDB); | ||
99 | req->cmd[0] = START_STOP; | ||
100 | req->cmd[4] = 1; | ||
101 | req->cmd_len = COMMAND_SIZE(req->cmd[0]); | ||
102 | |||
103 | out: | ||
104 | return req; | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * hp_sw_pg_init - HP path activation implementation. | ||
109 | * @hwh: hardware handler specific data | ||
110 | * @bypassed: unused; is the path group bypassed? (see dm-mpath.c) | ||
111 | * @path: path to send initialization command | ||
112 | * | ||
113 | * Send an HP-specific path activation command on 'path'. | ||
114 | * Do not try to optimize in any way, just send the activation command. | ||
115 | * More than one path activation command may be sent to the same controller. | ||
116 | * This seems to work fine for basic failover support. | ||
117 | * | ||
118 | * Possible optimizations | ||
119 | * 1. Detect an in-progress activation request and avoid submitting another one | ||
120 | * 2. Model the controller and only send a single activation request at a time | ||
121 | * 3. Determine the state of a path before sending an activation request | ||
122 | * | ||
123 | * Context: kmpathd (see process_queued_ios() in dm-mpath.c) | ||
124 | */ | ||
125 | static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, | ||
126 | struct dm_path *path) | ||
127 | { | ||
128 | struct request *req; | ||
129 | struct hp_sw_context *h; | ||
130 | |||
131 | path->hwhcontext = hwh->context; | ||
132 | h = hwh->context; | ||
133 | |||
134 | req = hp_sw_get_request(path); | ||
135 | if (!req) { | ||
136 | DMERR("%s path activation command - allocation fail", | ||
137 | path->dev->name); | ||
138 | goto fail; | ||
139 | } | ||
140 | |||
141 | DMDEBUG("%s path activation command - sent", path->dev->name); | ||
142 | |||
143 | blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); | ||
144 | return; | ||
145 | |||
146 | fail: | ||
147 | dm_pg_init_complete(path, MP_FAIL_PATH); | ||
148 | } | ||
149 | |||
150 | static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) | ||
151 | { | ||
152 | struct hp_sw_context *h; | ||
153 | |||
154 | h = kmalloc(sizeof(*h), GFP_KERNEL); | ||
155 | if (!h) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | hwh->context = h; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static void hp_sw_destroy(struct hw_handler *hwh) | ||
164 | { | ||
165 | struct hp_sw_context *h = hwh->context; | ||
166 | |||
167 | kfree(h); | ||
168 | } | ||
169 | |||
170 | static struct hw_handler_type hp_sw_hwh = { | ||
171 | .name = DM_HP_HWH_NAME, | ||
172 | .module = THIS_MODULE, | ||
173 | .create = hp_sw_create, | ||
174 | .destroy = hp_sw_destroy, | ||
175 | .pg_init = hp_sw_pg_init, | ||
176 | }; | ||
177 | |||
178 | static int __init hp_sw_init(void) | ||
179 | { | ||
180 | int r; | ||
181 | |||
182 | r = dm_register_hw_handler(&hp_sw_hwh); | ||
183 | if (r < 0) | ||
184 | DMERR("register failed %d", r); | ||
185 | else | ||
186 | DMINFO("version " DM_HP_HWH_VER " loaded"); | ||
187 | |||
188 | return r; | ||
189 | } | ||
190 | |||
191 | static void __exit hp_sw_exit(void) | ||
192 | { | ||
193 | int r; | ||
194 | |||
195 | r = dm_unregister_hw_handler(&hp_sw_hwh); | ||
196 | if (r < 0) | ||
197 | DMERR("unregister failed %d", r); | ||
198 | } | ||
199 | |||
200 | module_init(hp_sw_init); | ||
201 | module_exit(hp_sw_exit); | ||
202 | |||
203 | MODULE_DESCRIPTION("DM Multipath HP StorageWorks / FSC FibreCat (A/P) support"); | ||
204 | MODULE_AUTHOR("Mike Christie, Dave Wysochanski <dm-devel@redhat.com>"); | ||
205 | MODULE_LICENSE("GPL"); | ||
206 | MODULE_VERSION(DM_HP_HWH_VER); | ||