diff options
Diffstat (limited to 'drivers/md/dm-mpath-hp-sw.c')
-rw-r--r-- | drivers/md/dm-mpath-hp-sw.c | 247 |
1 files changed, 0 insertions, 247 deletions
diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c deleted file mode 100644 index b63a0ab37c53..000000000000 --- a/drivers/md/dm-mpath-hp-sw.c +++ /dev/null | |||
@@ -1,247 +0,0 @@ | |||
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 | #include <scsi/scsi_dbg.h> | ||
22 | |||
23 | #include "dm.h" | ||
24 | #include "dm-hw-handler.h" | ||
25 | |||
26 | #define DM_MSG_PREFIX "multipath hp-sw" | ||
27 | #define DM_HP_HWH_NAME "hp-sw" | ||
28 | #define DM_HP_HWH_VER "1.0.0" | ||
29 | |||
30 | struct hp_sw_context { | ||
31 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * hp_sw_error_is_retryable - Is an HP-specific check condition retryable? | ||
36 | * @req: path activation request | ||
37 | * | ||
38 | * Examine error codes of request and determine whether the error is retryable. | ||
39 | * Some error codes are already retried by scsi-ml (see | ||
40 | * scsi_decide_disposition), but some HP specific codes are not. | ||
41 | * The intent of this routine is to supply the logic for the HP specific | ||
42 | * check conditions. | ||
43 | * | ||
44 | * Returns: | ||
45 | * 1 - command completed with retryable error | ||
46 | * 0 - command completed with non-retryable error | ||
47 | * | ||
48 | * Possible optimizations | ||
49 | * 1. More hardware-specific error codes | ||
50 | */ | ||
51 | static int hp_sw_error_is_retryable(struct request *req) | ||
52 | { | ||
53 | /* | ||
54 | * NOT_READY is known to be retryable | ||
55 | * For now we just dump out the sense data and call it retryable | ||
56 | */ | ||
57 | if (status_byte(req->errors) == CHECK_CONDITION) | ||
58 | __scsi_print_sense(DM_HP_HWH_NAME, req->sense, req->sense_len); | ||
59 | |||
60 | /* | ||
61 | * At this point we don't have complete information about all the error | ||
62 | * codes from this hardware, so we are just conservative and retry | ||
63 | * when in doubt. | ||
64 | */ | ||
65 | return 1; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * hp_sw_end_io - Completion handler for HP path activation. | ||
70 | * @req: path activation request | ||
71 | * @error: scsi-ml error | ||
72 | * | ||
73 | * Check sense data, free request structure, and notify dm that | ||
74 | * pg initialization has completed. | ||
75 | * | ||
76 | * Context: scsi-ml softirq | ||
77 | * | ||
78 | */ | ||
79 | static void hp_sw_end_io(struct request *req, int error) | ||
80 | { | ||
81 | struct dm_path *path = req->end_io_data; | ||
82 | unsigned err_flags = 0; | ||
83 | |||
84 | if (!error) { | ||
85 | DMDEBUG("%s path activation command - success", | ||
86 | path->dev->name); | ||
87 | goto out; | ||
88 | } | ||
89 | |||
90 | if (hp_sw_error_is_retryable(req)) { | ||
91 | DMDEBUG("%s path activation command - retry", | ||
92 | path->dev->name); | ||
93 | err_flags = MP_RETRY; | ||
94 | goto out; | ||
95 | } | ||
96 | |||
97 | DMWARN("%s path activation fail - error=0x%x", | ||
98 | path->dev->name, error); | ||
99 | err_flags = MP_FAIL_PATH; | ||
100 | |||
101 | out: | ||
102 | req->end_io_data = NULL; | ||
103 | __blk_put_request(req->q, req); | ||
104 | dm_pg_init_complete(path, err_flags); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * hp_sw_get_request - Allocate an HP specific path activation request | ||
109 | * @path: path on which request will be sent (needed for request queue) | ||
110 | * | ||
111 | * The START command is used for path activation request. | ||
112 | * These arrays are controller-based failover, not LUN based. | ||
113 | * One START command issued to a single path will fail over all | ||
114 | * LUNs for the same controller. | ||
115 | * | ||
116 | * Possible optimizations | ||
117 | * 1. Make timeout configurable | ||
118 | * 2. Preallocate request | ||
119 | */ | ||
120 | static struct request *hp_sw_get_request(struct dm_path *path) | ||
121 | { | ||
122 | struct request *req; | ||
123 | struct block_device *bdev = path->dev->bdev; | ||
124 | struct request_queue *q = bdev_get_queue(bdev); | ||
125 | struct hp_sw_context *h = path->hwhcontext; | ||
126 | |||
127 | req = blk_get_request(q, WRITE, GFP_NOIO); | ||
128 | if (!req) | ||
129 | goto out; | ||
130 | |||
131 | req->timeout = 60 * HZ; | ||
132 | |||
133 | req->errors = 0; | ||
134 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
135 | req->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
136 | req->end_io_data = path; | ||
137 | req->sense = h->sense; | ||
138 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
139 | |||
140 | req->cmd[0] = START_STOP; | ||
141 | req->cmd[4] = 1; | ||
142 | req->cmd_len = COMMAND_SIZE(req->cmd[0]); | ||
143 | |||
144 | out: | ||
145 | return req; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * hp_sw_pg_init - HP path activation implementation. | ||
150 | * @hwh: hardware handler specific data | ||
151 | * @bypassed: unused; is the path group bypassed? (see dm-mpath.c) | ||
152 | * @path: path to send initialization command | ||
153 | * | ||
154 | * Send an HP-specific path activation command on 'path'. | ||
155 | * Do not try to optimize in any way, just send the activation command. | ||
156 | * More than one path activation command may be sent to the same controller. | ||
157 | * This seems to work fine for basic failover support. | ||
158 | * | ||
159 | * Possible optimizations | ||
160 | * 1. Detect an in-progress activation request and avoid submitting another one | ||
161 | * 2. Model the controller and only send a single activation request at a time | ||
162 | * 3. Determine the state of a path before sending an activation request | ||
163 | * | ||
164 | * Context: kmpathd (see process_queued_ios() in dm-mpath.c) | ||
165 | */ | ||
166 | static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, | ||
167 | struct dm_path *path) | ||
168 | { | ||
169 | struct request *req; | ||
170 | struct hp_sw_context *h; | ||
171 | |||
172 | path->hwhcontext = hwh->context; | ||
173 | h = hwh->context; | ||
174 | |||
175 | req = hp_sw_get_request(path); | ||
176 | if (!req) { | ||
177 | DMERR("%s path activation command - allocation fail", | ||
178 | path->dev->name); | ||
179 | goto retry; | ||
180 | } | ||
181 | |||
182 | DMDEBUG("%s path activation command - sent", path->dev->name); | ||
183 | |||
184 | blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); | ||
185 | return; | ||
186 | |||
187 | retry: | ||
188 | dm_pg_init_complete(path, MP_RETRY); | ||
189 | } | ||
190 | |||
191 | static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) | ||
192 | { | ||
193 | struct hp_sw_context *h; | ||
194 | |||
195 | h = kmalloc(sizeof(*h), GFP_KERNEL); | ||
196 | if (!h) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | hwh->context = h; | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static void hp_sw_destroy(struct hw_handler *hwh) | ||
205 | { | ||
206 | struct hp_sw_context *h = hwh->context; | ||
207 | |||
208 | kfree(h); | ||
209 | } | ||
210 | |||
211 | static struct hw_handler_type hp_sw_hwh = { | ||
212 | .name = DM_HP_HWH_NAME, | ||
213 | .module = THIS_MODULE, | ||
214 | .create = hp_sw_create, | ||
215 | .destroy = hp_sw_destroy, | ||
216 | .pg_init = hp_sw_pg_init, | ||
217 | }; | ||
218 | |||
219 | static int __init hp_sw_init(void) | ||
220 | { | ||
221 | int r; | ||
222 | |||
223 | r = dm_register_hw_handler(&hp_sw_hwh); | ||
224 | if (r < 0) | ||
225 | DMERR("register failed %d", r); | ||
226 | else | ||
227 | DMINFO("version " DM_HP_HWH_VER " loaded"); | ||
228 | |||
229 | return r; | ||
230 | } | ||
231 | |||
232 | static void __exit hp_sw_exit(void) | ||
233 | { | ||
234 | int r; | ||
235 | |||
236 | r = dm_unregister_hw_handler(&hp_sw_hwh); | ||
237 | if (r < 0) | ||
238 | DMERR("unregister failed %d", r); | ||
239 | } | ||
240 | |||
241 | module_init(hp_sw_init); | ||
242 | module_exit(hp_sw_exit); | ||
243 | |||
244 | MODULE_DESCRIPTION("DM Multipath HP StorageWorks / FSC FibreCat (A/P) support"); | ||
245 | MODULE_AUTHOR("Mike Christie, Dave Wysochanski <dm-devel@redhat.com>"); | ||
246 | MODULE_LICENSE("GPL"); | ||
247 | MODULE_VERSION(DM_HP_HWH_VER); | ||