aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/device_handler
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-07-18 05:39:39 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-18 05:39:39 -0400
commit49997d75152b3d23c53b0fa730599f2f74c92c65 (patch)
tree46e93126170d02cfec9505172e545732c1b69656 /drivers/scsi/device_handler
parenta0c80b80e0fb48129e4e9d6a9ede914f9ff1850d (diff)
parent5b664cb235e97afbf34db9c4d77f08ebd725335e (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: Documentation/powerpc/booting-without-of.txt drivers/atm/Makefile drivers/net/fs_enet/fs_enet-main.c drivers/pci/pci-acpi.c net/8021q/vlan.c net/iucv/iucv.c
Diffstat (limited to 'drivers/scsi/device_handler')
-rw-r--r--drivers/scsi/device_handler/Kconfig32
-rw-r--r--drivers/scsi/device_handler/Makefile7
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c162
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c504
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c207
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c696
6 files changed, 1608 insertions, 0 deletions
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig
new file mode 100644
index 000000000000..2adc0f666b68
--- /dev/null
+++ b/drivers/scsi/device_handler/Kconfig
@@ -0,0 +1,32 @@
1#
2# SCSI Device Handler configuration
3#
4
5menuconfig SCSI_DH
6 tristate "SCSI Device Handlers"
7 depends on SCSI
8 default n
9 help
10 SCSI Device Handlers provide device specific support for
11 devices utilized in multipath configurations. Say Y here to
12 select support for specific hardware.
13
14config SCSI_DH_RDAC
15 tristate "LSI RDAC Device Handler"
16 depends on SCSI_DH
17 help
18 If you have a LSI RDAC select y. Otherwise, say N.
19
20config SCSI_DH_HP_SW
21 tristate "HP/COMPAQ MSA Device Handler"
22 depends on SCSI_DH
23 help
24 If you have a HP/COMPAQ MSA device that requires START_STOP to
25 be sent to start it and cannot upgrade the firmware then select y.
26 Otherwise, say N.
27
28config SCSI_DH_EMC
29 tristate "EMC CLARiiON Device Handler"
30 depends on SCSI_DH
31 help
32 If you have a EMC CLARiiON select y. Otherwise, say N.
diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile
new file mode 100644
index 000000000000..35272e93b1c8
--- /dev/null
+++ b/drivers/scsi/device_handler/Makefile
@@ -0,0 +1,7 @@
1#
2# SCSI Device Handler
3#
4obj-$(CONFIG_SCSI_DH) += scsi_dh.o
5obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o
6obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o
7obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
new file mode 100644
index 000000000000..ab6c21cd9689
--- /dev/null
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -0,0 +1,162 @@
1/*
2 * SCSI device handler infrastruture.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Copyright IBM Corporation, 2007
19 * Authors:
20 * Chandra Seetharaman <sekharan@us.ibm.com>
21 * Mike Anderson <andmike@linux.vnet.ibm.com>
22 */
23
24#include <scsi/scsi_dh.h>
25#include "../scsi_priv.h"
26
27static DEFINE_SPINLOCK(list_lock);
28static LIST_HEAD(scsi_dh_list);
29
30static struct scsi_device_handler *get_device_handler(const char *name)
31{
32 struct scsi_device_handler *tmp, *found = NULL;
33
34 spin_lock(&list_lock);
35 list_for_each_entry(tmp, &scsi_dh_list, list) {
36 if (!strcmp(tmp->name, name)) {
37 found = tmp;
38 break;
39 }
40 }
41 spin_unlock(&list_lock);
42 return found;
43}
44
45static int scsi_dh_notifier_add(struct device *dev, void *data)
46{
47 struct scsi_device_handler *scsi_dh = data;
48
49 scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev);
50 return 0;
51}
52
53/*
54 * scsi_register_device_handler - register a device handler personality
55 * module.
56 * @scsi_dh - device handler to be registered.
57 *
58 * Returns 0 on success, -EBUSY if handler already registered.
59 */
60int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
61{
62 int ret = -EBUSY;
63 struct scsi_device_handler *tmp;
64
65 tmp = get_device_handler(scsi_dh->name);
66 if (tmp)
67 goto done;
68
69 ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb);
70
71 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
72 spin_lock(&list_lock);
73 list_add(&scsi_dh->list, &scsi_dh_list);
74 spin_unlock(&list_lock);
75
76done:
77 return ret;
78}
79EXPORT_SYMBOL_GPL(scsi_register_device_handler);
80
81static int scsi_dh_notifier_remove(struct device *dev, void *data)
82{
83 struct scsi_device_handler *scsi_dh = data;
84
85 scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev);
86 return 0;
87}
88
89/*
90 * scsi_unregister_device_handler - register a device handler personality
91 * module.
92 * @scsi_dh - device handler to be unregistered.
93 *
94 * Returns 0 on success, -ENODEV if handler not registered.
95 */
96int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
97{
98 int ret = -ENODEV;
99 struct scsi_device_handler *tmp;
100
101 tmp = get_device_handler(scsi_dh->name);
102 if (!tmp)
103 goto done;
104
105 ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb);
106
107 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
108 scsi_dh_notifier_remove);
109 spin_lock(&list_lock);
110 list_del(&scsi_dh->list);
111 spin_unlock(&list_lock);
112
113done:
114 return ret;
115}
116EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
117
118/*
119 * scsi_dh_activate - activate the path associated with the scsi_device
120 * corresponding to the given request queue.
121 * @q - Request queue that is associated with the scsi_device to be
122 * activated.
123 */
124int scsi_dh_activate(struct request_queue *q)
125{
126 int err = 0;
127 unsigned long flags;
128 struct scsi_device *sdev;
129 struct scsi_device_handler *scsi_dh = NULL;
130
131 spin_lock_irqsave(q->queue_lock, flags);
132 sdev = q->queuedata;
133 if (sdev && sdev->scsi_dh_data)
134 scsi_dh = sdev->scsi_dh_data->scsi_dh;
135 if (!scsi_dh || !get_device(&sdev->sdev_gendev))
136 err = SCSI_DH_NOSYS;
137 spin_unlock_irqrestore(q->queue_lock, flags);
138
139 if (err)
140 return err;
141
142 if (scsi_dh->activate)
143 err = scsi_dh->activate(sdev);
144 put_device(&sdev->sdev_gendev);
145 return err;
146}
147EXPORT_SYMBOL_GPL(scsi_dh_activate);
148
149/*
150 * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for
151 * the given name. FALSE(0) otherwise.
152 * @name - name of the device handler.
153 */
154int scsi_dh_handler_exist(const char *name)
155{
156 return (get_device_handler(name) != NULL);
157}
158EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
159
160MODULE_DESCRIPTION("SCSI device handler");
161MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
162MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
new file mode 100644
index 000000000000..f2467e936e55
--- /dev/null
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -0,0 +1,504 @@
1/*
2 * Target driver for EMC CLARiiON AX/CX-series hardware.
3 * Based on code from Lars Marowsky-Bree <lmb@suse.de>
4 * and Ed Goggin <egoggin@emc.com>.
5 *
6 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
7 * Copyright (C) 2006 Mike Christie
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; see the file COPYING. If not, write to
21 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23#include <scsi/scsi.h>
24#include <scsi/scsi_eh.h>
25#include <scsi/scsi_dh.h>
26#include <scsi/scsi_device.h>
27
28#define CLARIION_NAME "emc_clariion"
29
30#define CLARIION_TRESPASS_PAGE 0x22
31#define CLARIION_BUFFER_SIZE 0x80
32#define CLARIION_TIMEOUT (60 * HZ)
33#define CLARIION_RETRIES 3
34#define CLARIION_UNBOUND_LU -1
35
36static unsigned char long_trespass[] = {
37 0, 0, 0, 0,
38 CLARIION_TRESPASS_PAGE, /* Page code */
39 0x09, /* Page length - 2 */
40 0x81, /* Trespass code + Honor reservation bit */
41 0xff, 0xff, /* Trespass target */
42 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
43};
44
45static unsigned char long_trespass_hr[] = {
46 0, 0, 0, 0,
47 CLARIION_TRESPASS_PAGE, /* Page code */
48 0x09, /* Page length - 2 */
49 0x01, /* Trespass code + Honor reservation bit */
50 0xff, 0xff, /* Trespass target */
51 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */
52};
53
54static unsigned char short_trespass[] = {
55 0, 0, 0, 0,
56 CLARIION_TRESPASS_PAGE, /* Page code */
57 0x02, /* Page length - 2 */
58 0x81, /* Trespass code + Honor reservation bit */
59 0xff, /* Trespass target */
60};
61
62static unsigned char short_trespass_hr[] = {
63 0, 0, 0, 0,
64 CLARIION_TRESPASS_PAGE, /* Page code */
65 0x02, /* Page length - 2 */
66 0x01, /* Trespass code + Honor reservation bit */
67 0xff, /* Trespass target */
68};
69
70struct clariion_dh_data {
71 /*
72 * Use short trespass command (FC-series) or the long version
73 * (default for AX/CX CLARiiON arrays).
74 */
75 unsigned short_trespass;
76 /*
77 * Whether or not (default) to honor SCSI reservations when
78 * initiating a switch-over.
79 */
80 unsigned hr;
81 /* I/O buffer for both MODE_SELECT and INQUIRY commands. */
82 char buffer[CLARIION_BUFFER_SIZE];
83 /*
84 * SCSI sense buffer for commands -- assumes serial issuance
85 * and completion sequence of all commands for same multipath.
86 */
87 unsigned char sense[SCSI_SENSE_BUFFERSIZE];
88 /* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */
89 int default_sp;
90 /* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */
91 int current_sp;
92};
93
94static inline struct clariion_dh_data
95 *get_clariion_data(struct scsi_device *sdev)
96{
97 struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
98 BUG_ON(scsi_dh_data == NULL);
99 return ((struct clariion_dh_data *) scsi_dh_data->buf);
100}
101
102/*
103 * Parse MODE_SELECT cmd reply.
104 */
105static int trespass_endio(struct scsi_device *sdev, int result)
106{
107 int err = SCSI_DH_OK;
108 struct scsi_sense_hdr sshdr;
109 struct clariion_dh_data *csdev = get_clariion_data(sdev);
110 char *sense = csdev->sense;
111
112 if (status_byte(result) == CHECK_CONDITION &&
113 scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
114 sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, "
115 "0x%2x, 0x%2x while sending CLARiiON trespass "
116 "command.\n", sshdr.sense_key, sshdr.asc,
117 sshdr.ascq);
118
119 if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
120 (sshdr.ascq == 0x00)) {
121 /*
122 * Array based copy in progress -- do not send
123 * mode_select or copy will be aborted mid-stream.
124 */
125 sdev_printk(KERN_INFO, sdev, "Array Based Copy in "
126 "progress while sending CLARiiON trespass "
127 "command.\n");
128 err = SCSI_DH_DEV_TEMP_BUSY;
129 } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
130 (sshdr.ascq == 0x03)) {
131 /*
132 * LUN Not Ready - Manual Intervention Required
133 * indicates in-progress ucode upgrade (NDU).
134 */
135 sdev_printk(KERN_INFO, sdev, "Detected in-progress "
136 "ucode upgrade NDU operation while sending "
137 "CLARiiON trespass command.\n");
138 err = SCSI_DH_DEV_TEMP_BUSY;
139 } else
140 err = SCSI_DH_DEV_FAILED;
141 } else if (result) {
142 sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending "
143 "CLARiiON trespass command.\n", result);
144 err = SCSI_DH_IO;
145 }
146
147 return err;
148}
149
150static int parse_sp_info_reply(struct scsi_device *sdev, int result,
151 int *default_sp, int *current_sp, int *new_current_sp)
152{
153 int err = SCSI_DH_OK;
154 struct clariion_dh_data *csdev = get_clariion_data(sdev);
155
156 if (result == 0) {
157 /* check for in-progress ucode upgrade (NDU) */
158 if (csdev->buffer[48] != 0) {
159 sdev_printk(KERN_NOTICE, sdev, "Detected in-progress "
160 "ucode upgrade NDU operation while finding "
161 "current active SP.");
162 err = SCSI_DH_DEV_TEMP_BUSY;
163 } else {
164 *default_sp = csdev->buffer[5];
165
166 if (csdev->buffer[4] == 2)
167 /* SP for path is current */
168 *current_sp = csdev->buffer[8];
169 else {
170 if (csdev->buffer[4] == 1)
171 /* SP for this path is NOT current */
172 if (csdev->buffer[8] == 0)
173 *current_sp = 1;
174 else
175 *current_sp = 0;
176 else
177 /* unbound LU or LUNZ */
178 *current_sp = CLARIION_UNBOUND_LU;
179 }
180 *new_current_sp = csdev->buffer[8];
181 }
182 } else {
183 struct scsi_sense_hdr sshdr;
184
185 err = SCSI_DH_IO;
186
187 if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
188 &sshdr))
189 sdev_printk(KERN_ERR, sdev, "Found valid sense data "
190 "0x%2x, 0x%2x, 0x%2x while finding current "
191 "active SP.", sshdr.sense_key, sshdr.asc,
192 sshdr.ascq);
193 else
194 sdev_printk(KERN_ERR, sdev, "Error 0x%x finding "
195 "current active SP.", result);
196 }
197
198 return err;
199}
200
201static int sp_info_endio(struct scsi_device *sdev, int result,
202 int mode_select_sent, int *done)
203{
204 struct clariion_dh_data *csdev = get_clariion_data(sdev);
205 int err_flags, default_sp, current_sp, new_current_sp;
206
207 err_flags = parse_sp_info_reply(sdev, result, &default_sp,
208 &current_sp, &new_current_sp);
209
210 if (err_flags != SCSI_DH_OK)
211 goto done;
212
213 if (mode_select_sent) {
214 csdev->default_sp = default_sp;
215 csdev->current_sp = current_sp;
216 } else {
217 /*
218 * Issue the actual module_selec request IFF either
219 * (1) we do not know the identity of the current SP OR
220 * (2) what we think we know is actually correct.
221 */
222 if ((current_sp != CLARIION_UNBOUND_LU) &&
223 (new_current_sp != current_sp)) {
224
225 csdev->default_sp = default_sp;
226 csdev->current_sp = current_sp;
227
228 sdev_printk(KERN_INFO, sdev, "Ignoring path group "
229 "switch-over command for CLARiiON SP%s since "
230 " mapped device is already initialized.",
231 current_sp ? "B" : "A");
232 if (done)
233 *done = 1; /* as good as doing it */
234 }
235 }
236done:
237 return err_flags;
238}
239
240/*
241* Get block request for REQ_BLOCK_PC command issued to path. Currently
242* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
243*
244* Uses data and sense buffers in hardware handler context structure and
245* assumes serial servicing of commands, both issuance and completion.
246*/
247static struct request *get_req(struct scsi_device *sdev, int cmd)
248{
249 struct clariion_dh_data *csdev = get_clariion_data(sdev);
250 struct request *rq;
251 unsigned char *page22;
252 int len = 0;
253
254 rq = blk_get_request(sdev->request_queue,
255 (cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC);
256 if (!rq) {
257 sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
258 return NULL;
259 }
260
261 memset(&rq->cmd, 0, BLK_MAX_CDB);
262 rq->cmd[0] = cmd;
263 rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
264
265 switch (cmd) {
266 case MODE_SELECT:
267 if (csdev->short_trespass) {
268 page22 = csdev->hr ? short_trespass_hr : short_trespass;
269 len = sizeof(short_trespass);
270 } else {
271 page22 = csdev->hr ? long_trespass_hr : long_trespass;
272 len = sizeof(long_trespass);
273 }
274 /*
275 * Can't DMA from kernel BSS -- must copy selected trespass
276 * command mode page contents to context buffer which is
277 * allocated by kmalloc.
278 */
279 BUG_ON((len > CLARIION_BUFFER_SIZE));
280 memcpy(csdev->buffer, page22, len);
281 rq->cmd_flags |= REQ_RW;
282 rq->cmd[1] = 0x10;
283 break;
284 case INQUIRY:
285 rq->cmd[1] = 0x1;
286 rq->cmd[2] = 0xC0;
287 len = CLARIION_BUFFER_SIZE;
288 memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE);
289 break;
290 default:
291 BUG_ON(1);
292 break;
293 }
294
295 rq->cmd[4] = len;
296 rq->cmd_type = REQ_TYPE_BLOCK_PC;
297 rq->cmd_flags |= REQ_FAILFAST;
298 rq->timeout = CLARIION_TIMEOUT;
299 rq->retries = CLARIION_RETRIES;
300
301 rq->sense = csdev->sense;
302 memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
303 rq->sense_len = 0;
304
305 if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer,
306 len, GFP_ATOMIC)) {
307 __blk_put_request(rq->q, rq);
308 return NULL;
309 }
310
311 return rq;
312}
313
314static int send_cmd(struct scsi_device *sdev, int cmd)
315{
316 struct request *rq = get_req(sdev, cmd);
317
318 if (!rq)
319 return SCSI_DH_RES_TEMP_UNAVAIL;
320
321 return blk_execute_rq(sdev->request_queue, NULL, rq, 1);
322}
323
324static int clariion_activate(struct scsi_device *sdev)
325{
326 int result, done = 0;
327
328 result = send_cmd(sdev, INQUIRY);
329 result = sp_info_endio(sdev, result, 0, &done);
330 if (result || done)
331 goto done;
332
333 result = send_cmd(sdev, MODE_SELECT);
334 result = trespass_endio(sdev, result);
335 if (result)
336 goto done;
337
338 result = send_cmd(sdev, INQUIRY);
339 result = sp_info_endio(sdev, result, 1, NULL);
340done:
341 return result;
342}
343
344static int clariion_check_sense(struct scsi_device *sdev,
345 struct scsi_sense_hdr *sense_hdr)
346{
347 switch (sense_hdr->sense_key) {
348 case NOT_READY:
349 if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03)
350 /*
351 * LUN Not Ready - Manual Intervention Required
352 * indicates this is a passive path.
353 *
354 * FIXME: However, if this is seen and EVPD C0
355 * indicates that this is due to a NDU in
356 * progress, we should set FAIL_PATH too.
357 * This indicates we might have to do a SCSI
358 * inquiry in the end_io path. Ugh.
359 *
360 * Can return FAILED only when we want the error
361 * recovery process to kick in.
362 */
363 return SUCCESS;
364 break;
365 case ILLEGAL_REQUEST:
366 if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01)
367 /*
368 * An array based copy is in progress. Do not
369 * fail the path, do not bypass to another PG,
370 * do not retry. Fail the IO immediately.
371 * (Actually this is the same conclusion as in
372 * the default handler, but lets make sure.)
373 *
374 * Can return FAILED only when we want the error
375 * recovery process to kick in.
376 */
377 return SUCCESS;
378 break;
379 case UNIT_ATTENTION:
380 if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
381 /*
382 * Unit Attention Code. This is the first IO
383 * to the new path, so just retry.
384 */
385 return NEEDS_RETRY;
386 break;
387 }
388
389 /* success just means we do not care what scsi-ml does */
390 return SUCCESS;
391}
392
393static const struct {
394 char *vendor;
395 char *model;
396} clariion_dev_list[] = {
397 {"DGC", "RAID"},
398 {"DGC", "DISK"},
399 {NULL, NULL},
400};
401
402static int clariion_bus_notify(struct notifier_block *, unsigned long, void *);
403
404static struct scsi_device_handler clariion_dh = {
405 .name = CLARIION_NAME,
406 .module = THIS_MODULE,
407 .nb.notifier_call = clariion_bus_notify,
408 .check_sense = clariion_check_sense,
409 .activate = clariion_activate,
410};
411
412/*
413 * TODO: need some interface so we can set trespass values
414 */
415static int clariion_bus_notify(struct notifier_block *nb,
416 unsigned long action, void *data)
417{
418 struct device *dev = data;
419 struct scsi_device *sdev;
420 struct scsi_dh_data *scsi_dh_data;
421 struct clariion_dh_data *h;
422 int i, found = 0;
423 unsigned long flags;
424
425 if (!scsi_is_sdev_device(dev))
426 return 0;
427
428 sdev = to_scsi_device(dev);
429
430 if (action == BUS_NOTIFY_ADD_DEVICE) {
431 for (i = 0; clariion_dev_list[i].vendor; i++) {
432 if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
433 strlen(clariion_dev_list[i].vendor)) &&
434 !strncmp(sdev->model, clariion_dev_list[i].model,
435 strlen(clariion_dev_list[i].model))) {
436 found = 1;
437 break;
438 }
439 }
440 if (!found)
441 goto out;
442
443 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
444 + sizeof(*h) , GFP_KERNEL);
445 if (!scsi_dh_data) {
446 sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
447 CLARIION_NAME);
448 goto out;
449 }
450
451 scsi_dh_data->scsi_dh = &clariion_dh;
452 h = (struct clariion_dh_data *) scsi_dh_data->buf;
453 h->default_sp = CLARIION_UNBOUND_LU;
454 h->current_sp = CLARIION_UNBOUND_LU;
455
456 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
457 sdev->scsi_dh_data = scsi_dh_data;
458 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
459
460 sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME);
461 try_module_get(THIS_MODULE);
462
463 } else if (action == BUS_NOTIFY_DEL_DEVICE) {
464 if (sdev->scsi_dh_data == NULL ||
465 sdev->scsi_dh_data->scsi_dh != &clariion_dh)
466 goto out;
467
468 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
469 scsi_dh_data = sdev->scsi_dh_data;
470 sdev->scsi_dh_data = NULL;
471 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
472
473 sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n",
474 CLARIION_NAME);
475
476 kfree(scsi_dh_data);
477 module_put(THIS_MODULE);
478 }
479
480out:
481 return 0;
482}
483
484static int __init clariion_init(void)
485{
486 int r;
487
488 r = scsi_register_device_handler(&clariion_dh);
489 if (r != 0)
490 printk(KERN_ERR "Failed to register scsi device handler.");
491 return r;
492}
493
494static void __exit clariion_exit(void)
495{
496 scsi_unregister_device_handler(&clariion_dh);
497}
498
499module_init(clariion_init);
500module_exit(clariion_exit);
501
502MODULE_DESCRIPTION("EMC CX/AX/FC-family driver");
503MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, Chandra Seetharaman <sekharan@us.ibm.com>");
504MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
new file mode 100644
index 000000000000..ae6be87d6a83
--- /dev/null
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -0,0 +1,207 @@
1/*
2 * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be
3 * upgraded.
4 *
5 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
6 * Copyright (C) 2006 Mike Christie
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <scsi/scsi.h>
24#include <scsi/scsi_dbg.h>
25#include <scsi/scsi_eh.h>
26#include <scsi/scsi_dh.h>
27
28#define HP_SW_NAME "hp_sw"
29
30#define HP_SW_TIMEOUT (60 * HZ)
31#define HP_SW_RETRIES 3
32
33struct hp_sw_dh_data {
34 unsigned char sense[SCSI_SENSE_BUFFERSIZE];
35 int retries;
36};
37
38static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
39{
40 struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
41 BUG_ON(scsi_dh_data == NULL);
42 return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
43}
44
45static int hp_sw_done(struct scsi_device *sdev)
46{
47 struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
48 struct scsi_sense_hdr sshdr;
49 int rc;
50
51 sdev_printk(KERN_INFO, sdev, "hp_sw_done\n");
52
53 rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
54 if (!rc)
55 goto done;
56 switch (sshdr.sense_key) {
57 case NOT_READY:
58 if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
59 rc = SCSI_DH_RETRY;
60 h->retries++;
61 break;
62 }
63 /* fall through */
64 default:
65 h->retries++;
66 rc = SCSI_DH_IMM_RETRY;
67 }
68
69done:
70 if (rc == SCSI_DH_OK || rc == SCSI_DH_IO)
71 h->retries = 0;
72 else if (h->retries > HP_SW_RETRIES) {
73 h->retries = 0;
74 rc = SCSI_DH_IO;
75 }
76 return rc;
77}
78
79static int hp_sw_activate(struct scsi_device *sdev)
80{
81 struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
82 struct request *req;
83 int ret = SCSI_DH_RES_TEMP_UNAVAIL;
84
85 req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
86 if (!req)
87 goto done;
88
89 sdev_printk(KERN_INFO, sdev, "sending START_STOP.");
90
91 req->cmd_type = REQ_TYPE_BLOCK_PC;
92 req->cmd_flags |= REQ_FAILFAST;
93 req->cmd_len = COMMAND_SIZE(START_STOP);
94 memset(req->cmd, 0, MAX_COMMAND_SIZE);
95 req->cmd[0] = START_STOP;
96 req->cmd[4] = 1; /* Start spin cycle */
97 req->timeout = HP_SW_TIMEOUT;
98 req->sense = h->sense;
99 memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
100 req->sense_len = 0;
101
102 ret = blk_execute_rq(req->q, NULL, req, 1);
103 if (!ret) /* SUCCESS */
104 ret = hp_sw_done(sdev);
105 else
106 ret = SCSI_DH_IO;
107done:
108 return ret;
109}
110
111static const struct {
112 char *vendor;
113 char *model;
114} hp_sw_dh_data_list[] = {
115 {"COMPAQ", "MSA"},
116 {"HP", "HSV"},
117 {"DEC", "HSG80"},
118 {NULL, NULL},
119};
120
121static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *);
122
123static struct scsi_device_handler hp_sw_dh = {
124 .name = HP_SW_NAME,
125 .module = THIS_MODULE,
126 .nb.notifier_call = hp_sw_bus_notify,
127 .activate = hp_sw_activate,
128};
129
130static int hp_sw_bus_notify(struct notifier_block *nb,
131 unsigned long action, void *data)
132{
133 struct device *dev = data;
134 struct scsi_device *sdev;
135 struct scsi_dh_data *scsi_dh_data;
136 int i, found = 0;
137 unsigned long flags;
138
139 if (!scsi_is_sdev_device(dev))
140 return 0;
141
142 sdev = to_scsi_device(dev);
143
144 if (action == BUS_NOTIFY_ADD_DEVICE) {
145 for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
146 if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
147 strlen(hp_sw_dh_data_list[i].vendor)) &&
148 !strncmp(sdev->model, hp_sw_dh_data_list[i].model,
149 strlen(hp_sw_dh_data_list[i].model))) {
150 found = 1;
151 break;
152 }
153 }
154 if (!found)
155 goto out;
156
157 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
158 + sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
159 if (!scsi_dh_data) {
160 sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
161 HP_SW_NAME);
162 goto out;
163 }
164
165 scsi_dh_data->scsi_dh = &hp_sw_dh;
166 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
167 sdev->scsi_dh_data = scsi_dh_data;
168 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
169 try_module_get(THIS_MODULE);
170
171 sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
172 } else if (action == BUS_NOTIFY_DEL_DEVICE) {
173 if (sdev->scsi_dh_data == NULL ||
174 sdev->scsi_dh_data->scsi_dh != &hp_sw_dh)
175 goto out;
176
177 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
178 scsi_dh_data = sdev->scsi_dh_data;
179 sdev->scsi_dh_data = NULL;
180 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
181 module_put(THIS_MODULE);
182
183 sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME);
184
185 kfree(scsi_dh_data);
186 }
187
188out:
189 return 0;
190}
191
192static int __init hp_sw_init(void)
193{
194 return scsi_register_device_handler(&hp_sw_dh);
195}
196
197static void __exit hp_sw_exit(void)
198{
199 scsi_unregister_device_handler(&hp_sw_dh);
200}
201
202module_init(hp_sw_init);
203module_exit(hp_sw_exit);
204
205MODULE_DESCRIPTION("HP MSA 1000");
206MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
207MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
new file mode 100644
index 000000000000..fdf34b0ec6e1
--- /dev/null
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -0,0 +1,696 @@
1/*
2 * Engenio/LSI RDAC SCSI Device Handler
3 *
4 * Copyright (C) 2005 Mike Christie. All rights reserved.
5 * Copyright (C) Chandra Seetharaman, IBM Corp. 2007
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 */
22#include <scsi/scsi.h>
23#include <scsi/scsi_eh.h>
24#include <scsi/scsi_dh.h>
25
26#define RDAC_NAME "rdac"
27
28/*
29 * LSI mode page stuff
30 *
31 * These struct definitions and the forming of the
32 * mode page were taken from the LSI RDAC 2.4 GPL'd
33 * driver, and then converted to Linux conventions.
34 */
35#define RDAC_QUIESCENCE_TIME 20;
36/*
37 * Page Codes
38 */
39#define RDAC_PAGE_CODE_REDUNDANT_CONTROLLER 0x2c
40
41/*
42 * Controller modes definitions
43 */
44#define RDAC_MODE_TRANSFER_SPECIFIED_LUNS 0x02
45
46/*
47 * RDAC Options field
48 */
49#define RDAC_FORCED_QUIESENCE 0x02
50
51#define RDAC_TIMEOUT (60 * HZ)
52#define RDAC_RETRIES 3
53
54struct rdac_mode_6_hdr {
55 u8 data_len;
56 u8 medium_type;
57 u8 device_params;
58 u8 block_desc_len;
59};
60
61struct rdac_mode_10_hdr {
62 u16 data_len;
63 u8 medium_type;
64 u8 device_params;
65 u16 reserved;
66 u16 block_desc_len;
67};
68
69struct rdac_mode_common {
70 u8 controller_serial[16];
71 u8 alt_controller_serial[16];
72 u8 rdac_mode[2];
73 u8 alt_rdac_mode[2];
74 u8 quiescence_timeout;
75 u8 rdac_options;
76};
77
78struct rdac_pg_legacy {
79 struct rdac_mode_6_hdr hdr;
80 u8 page_code;
81 u8 page_len;
82 struct rdac_mode_common common;
83#define MODE6_MAX_LUN 32
84 u8 lun_table[MODE6_MAX_LUN];
85 u8 reserved2[32];
86 u8 reserved3;
87 u8 reserved4;
88};
89
90struct rdac_pg_expanded {
91 struct rdac_mode_10_hdr hdr;
92 u8 page_code;
93 u8 subpage_code;
94 u8 page_len[2];
95 struct rdac_mode_common common;
96 u8 lun_table[256];
97 u8 reserved3;
98 u8 reserved4;
99};
100
101struct c9_inquiry {
102 u8 peripheral_info;
103 u8 page_code; /* 0xC9 */
104 u8 reserved1;
105 u8 page_len;
106 u8 page_id[4]; /* "vace" */
107 u8 avte_cvp;
108 u8 path_prio;
109 u8 reserved2[38];
110};
111
112#define SUBSYS_ID_LEN 16
113#define SLOT_ID_LEN 2
114
115struct c4_inquiry {
116 u8 peripheral_info;
117 u8 page_code; /* 0xC4 */
118 u8 reserved1;
119 u8 page_len;
120 u8 page_id[4]; /* "subs" */
121 u8 subsys_id[SUBSYS_ID_LEN];
122 u8 revision[4];
123 u8 slot_id[SLOT_ID_LEN];
124 u8 reserved[2];
125};
126
127struct rdac_controller {
128 u8 subsys_id[SUBSYS_ID_LEN];
129 u8 slot_id[SLOT_ID_LEN];
130 int use_ms10;
131 struct kref kref;
132 struct list_head node; /* list of all controllers */
133 union {
134 struct rdac_pg_legacy legacy;
135 struct rdac_pg_expanded expanded;
136 } mode_select;
137};
138struct c8_inquiry {
139 u8 peripheral_info;
140 u8 page_code; /* 0xC8 */
141 u8 reserved1;
142 u8 page_len;
143 u8 page_id[4]; /* "edid" */
144 u8 reserved2[3];
145 u8 vol_uniq_id_len;
146 u8 vol_uniq_id[16];
147 u8 vol_user_label_len;
148 u8 vol_user_label[60];
149 u8 array_uniq_id_len;
150 u8 array_unique_id[16];
151 u8 array_user_label_len;
152 u8 array_user_label[60];
153 u8 lun[8];
154};
155
156struct c2_inquiry {
157 u8 peripheral_info;
158 u8 page_code; /* 0xC2 */
159 u8 reserved1;
160 u8 page_len;
161 u8 page_id[4]; /* "swr4" */
162 u8 sw_version[3];
163 u8 sw_date[3];
164 u8 features_enabled;
165 u8 max_lun_supported;
166 u8 partitions[239]; /* Total allocation length should be 0xFF */
167};
168
169struct rdac_dh_data {
170 struct rdac_controller *ctlr;
171#define UNINITIALIZED_LUN (1 << 8)
172 unsigned lun;
173#define RDAC_STATE_ACTIVE 0
174#define RDAC_STATE_PASSIVE 1
175 unsigned char state;
176 unsigned char sense[SCSI_SENSE_BUFFERSIZE];
177 union {
178 struct c2_inquiry c2;
179 struct c4_inquiry c4;
180 struct c8_inquiry c8;
181 struct c9_inquiry c9;
182 } inq;
183};
184
185static LIST_HEAD(ctlr_list);
186static DEFINE_SPINLOCK(list_lock);
187
188static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
189{
190 struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
191 BUG_ON(scsi_dh_data == NULL);
192 return ((struct rdac_dh_data *) scsi_dh_data->buf);
193}
194
195static struct request *get_rdac_req(struct scsi_device *sdev,
196 void *buffer, unsigned buflen, int rw)
197{
198 struct request *rq;
199 struct request_queue *q = sdev->request_queue;
200 struct rdac_dh_data *h = get_rdac_data(sdev);
201
202 rq = blk_get_request(q, rw, GFP_KERNEL);
203
204 if (!rq) {
205 sdev_printk(KERN_INFO, sdev,
206 "get_rdac_req: blk_get_request failed.\n");
207 return NULL;
208 }
209
210 if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) {
211 blk_put_request(rq);
212 sdev_printk(KERN_INFO, sdev,
213 "get_rdac_req: blk_rq_map_kern failed.\n");
214 return NULL;
215 }
216
217 memset(&rq->cmd, 0, BLK_MAX_CDB);
218 rq->sense = h->sense;
219 memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
220 rq->sense_len = 0;
221
222 rq->cmd_type = REQ_TYPE_BLOCK_PC;
223 rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
224 rq->retries = RDAC_RETRIES;
225 rq->timeout = RDAC_TIMEOUT;
226
227 return rq;
228}
229
230static struct request *rdac_failover_get(struct scsi_device *sdev)
231{
232 struct request *rq;
233 struct rdac_mode_common *common;
234 unsigned data_size;
235 struct rdac_dh_data *h = get_rdac_data(sdev);
236
237 if (h->ctlr->use_ms10) {
238 struct rdac_pg_expanded *rdac_pg;
239
240 data_size = sizeof(struct rdac_pg_expanded);
241 rdac_pg = &h->ctlr->mode_select.expanded;
242 memset(rdac_pg, 0, data_size);
243 common = &rdac_pg->common;
244 rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40;
245 rdac_pg->subpage_code = 0x1;
246 rdac_pg->page_len[0] = 0x01;
247 rdac_pg->page_len[1] = 0x28;
248 rdac_pg->lun_table[h->lun] = 0x81;
249 } else {
250 struct rdac_pg_legacy *rdac_pg;
251
252 data_size = sizeof(struct rdac_pg_legacy);
253 rdac_pg = &h->ctlr->mode_select.legacy;
254 memset(rdac_pg, 0, data_size);
255 common = &rdac_pg->common;
256 rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
257 rdac_pg->page_len = 0x68;
258 rdac_pg->lun_table[h->lun] = 0x81;
259 }
260 common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS;
261 common->quiescence_timeout = RDAC_QUIESCENCE_TIME;
262 common->rdac_options = RDAC_FORCED_QUIESENCE;
263
264 /* get request for block layer packet command */
265 rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE);
266 if (!rq)
267 return NULL;
268
269 /* Prepare the command. */
270 if (h->ctlr->use_ms10) {
271 rq->cmd[0] = MODE_SELECT_10;
272 rq->cmd[7] = data_size >> 8;
273 rq->cmd[8] = data_size & 0xff;
274 } else {
275 rq->cmd[0] = MODE_SELECT;
276 rq->cmd[4] = data_size;
277 }
278 rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
279
280 return rq;
281}
282
283static void release_controller(struct kref *kref)
284{
285 struct rdac_controller *ctlr;
286 ctlr = container_of(kref, struct rdac_controller, kref);
287
288 spin_lock(&list_lock);
289 list_del(&ctlr->node);
290 spin_unlock(&list_lock);
291 kfree(ctlr);
292}
293
294static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id)
295{
296 struct rdac_controller *ctlr, *tmp;
297
298 spin_lock(&list_lock);
299
300 list_for_each_entry(tmp, &ctlr_list, node) {
301 if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) &&
302 (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) {
303 kref_get(&tmp->kref);
304 spin_unlock(&list_lock);
305 return tmp;
306 }
307 }
308 ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC);
309 if (!ctlr)
310 goto done;
311
312 /* initialize fields of controller */
313 memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN);
314 memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);
315 kref_init(&ctlr->kref);
316 ctlr->use_ms10 = -1;
317 list_add(&ctlr->node, &ctlr_list);
318done:
319 spin_unlock(&list_lock);
320 return ctlr;
321}
322
323static int submit_inquiry(struct scsi_device *sdev, int page_code,
324 unsigned int len)
325{
326 struct request *rq;
327 struct request_queue *q = sdev->request_queue;
328 struct rdac_dh_data *h = get_rdac_data(sdev);
329 int err = SCSI_DH_RES_TEMP_UNAVAIL;
330
331 rq = get_rdac_req(sdev, &h->inq, len, READ);
332 if (!rq)
333 goto done;
334
335 /* Prepare the command. */
336 rq->cmd[0] = INQUIRY;
337 rq->cmd[1] = 1;
338 rq->cmd[2] = page_code;
339 rq->cmd[4] = len;
340 rq->cmd_len = COMMAND_SIZE(INQUIRY);
341 err = blk_execute_rq(q, NULL, rq, 1);
342 if (err == -EIO)
343 err = SCSI_DH_IO;
344done:
345 return err;
346}
347
348static int get_lun(struct scsi_device *sdev)
349{
350 int err;
351 struct c8_inquiry *inqp;
352 struct rdac_dh_data *h = get_rdac_data(sdev);
353
354 err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry));
355 if (err == SCSI_DH_OK) {
356 inqp = &h->inq.c8;
357 h->lun = inqp->lun[7]; /* currently it uses only one byte */
358 }
359 return err;
360}
361
362#define RDAC_OWNED 0
363#define RDAC_UNOWNED 1
364#define RDAC_FAILED 2
365static int check_ownership(struct scsi_device *sdev)
366{
367 int err;
368 struct c9_inquiry *inqp;
369 struct rdac_dh_data *h = get_rdac_data(sdev);
370
371 err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry));
372 if (err == SCSI_DH_OK) {
373 err = RDAC_UNOWNED;
374 inqp = &h->inq.c9;
375 /*
376 * If in AVT mode or if the path already owns the LUN,
377 * return RDAC_OWNED;
378 */
379 if (((inqp->avte_cvp >> 7) == 0x1) ||
380 ((inqp->avte_cvp & 0x1) != 0))
381 err = RDAC_OWNED;
382 } else
383 err = RDAC_FAILED;
384 return err;
385}
386
387static int initialize_controller(struct scsi_device *sdev)
388{
389 int err;
390 struct c4_inquiry *inqp;
391 struct rdac_dh_data *h = get_rdac_data(sdev);
392
393 err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry));
394 if (err == SCSI_DH_OK) {
395 inqp = &h->inq.c4;
396 h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
397 if (!h->ctlr)
398 err = SCSI_DH_RES_TEMP_UNAVAIL;
399 }
400 return err;
401}
402
403static int set_mode_select(struct scsi_device *sdev)
404{
405 int err;
406 struct c2_inquiry *inqp;
407 struct rdac_dh_data *h = get_rdac_data(sdev);
408
409 err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry));
410 if (err == SCSI_DH_OK) {
411 inqp = &h->inq.c2;
412 /*
413 * If more than MODE6_MAX_LUN luns are supported, use
414 * mode select 10
415 */
416 if (inqp->max_lun_supported >= MODE6_MAX_LUN)
417 h->ctlr->use_ms10 = 1;
418 else
419 h->ctlr->use_ms10 = 0;
420 }
421 return err;
422}
423
424static int mode_select_handle_sense(struct scsi_device *sdev)
425{
426 struct scsi_sense_hdr sense_hdr;
427 struct rdac_dh_data *h = get_rdac_data(sdev);
428 int sense, err = SCSI_DH_IO, ret;
429
430 ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
431 if (!ret)
432 goto done;
433
434 err = SCSI_DH_OK;
435 sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) |
436 sense_hdr.ascq;
437 /* If it is retryable failure, submit the c9 inquiry again */
438 if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 ||
439 sense == 0x62900) {
440 /* 0x59136 - Command lock contention
441 * 0x[6b]8b02 - Quiesense in progress or achieved
442 * 0x62900 - Power On, Reset, or Bus Device Reset
443 */
444 err = SCSI_DH_RETRY;
445 }
446
447 if (sense)
448 sdev_printk(KERN_INFO, sdev,
449 "MODE_SELECT failed with sense 0x%x.\n", sense);
450done:
451 return err;
452}
453
454static int send_mode_select(struct scsi_device *sdev)
455{
456 struct request *rq;
457 struct request_queue *q = sdev->request_queue;
458 struct rdac_dh_data *h = get_rdac_data(sdev);
459 int err = SCSI_DH_RES_TEMP_UNAVAIL;
460
461 rq = rdac_failover_get(sdev);
462 if (!rq)
463 goto done;
464
465 sdev_printk(KERN_INFO, sdev, "queueing MODE_SELECT command.\n");
466
467 err = blk_execute_rq(q, NULL, rq, 1);
468 if (err != SCSI_DH_OK)
469 err = mode_select_handle_sense(sdev);
470 if (err == SCSI_DH_OK)
471 h->state = RDAC_STATE_ACTIVE;
472done:
473 return err;
474}
475
476static int rdac_activate(struct scsi_device *sdev)
477{
478 struct rdac_dh_data *h = get_rdac_data(sdev);
479 int err = SCSI_DH_OK;
480
481 if (h->lun == UNINITIALIZED_LUN) {
482 err = get_lun(sdev);
483 if (err != SCSI_DH_OK)
484 goto done;
485 }
486
487 err = check_ownership(sdev);
488 switch (err) {
489 case RDAC_UNOWNED:
490 break;
491 case RDAC_OWNED:
492 err = SCSI_DH_OK;
493 goto done;
494 case RDAC_FAILED:
495 default:
496 err = SCSI_DH_IO;
497 goto done;
498 }
499
500 if (!h->ctlr) {
501 err = initialize_controller(sdev);
502 if (err != SCSI_DH_OK)
503 goto done;
504 }
505
506 if (h->ctlr->use_ms10 == -1) {
507 err = set_mode_select(sdev);
508 if (err != SCSI_DH_OK)
509 goto done;
510 }
511
512 err = send_mode_select(sdev);
513done:
514 return err;
515}
516
517static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
518{
519 struct rdac_dh_data *h = get_rdac_data(sdev);
520 int ret = BLKPREP_OK;
521
522 if (h->state != RDAC_STATE_ACTIVE) {
523 ret = BLKPREP_KILL;
524 req->cmd_flags |= REQ_QUIET;
525 }
526 return ret;
527
528}
529
530static int rdac_check_sense(struct scsi_device *sdev,
531 struct scsi_sense_hdr *sense_hdr)
532{
533 struct rdac_dh_data *h = get_rdac_data(sdev);
534 switch (sense_hdr->sense_key) {
535 case NOT_READY:
536 if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81)
537 /* LUN Not Ready - Storage firmware incompatible
538 * Manual code synchonisation required.
539 *
540 * Nothing we can do here. Try to bypass the path.
541 */
542 return SUCCESS;
543 if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0xA1)
544 /* LUN Not Ready - Quiescense in progress
545 *
546 * Just retry and wait.
547 */
548 return NEEDS_RETRY;
549 break;
550 case ILLEGAL_REQUEST:
551 if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) {
552 /* Invalid Request - Current Logical Unit Ownership.
553 * Controller is not the current owner of the LUN,
554 * Fail the path, so that the other path be used.
555 */
556 h->state = RDAC_STATE_PASSIVE;
557 return SUCCESS;
558 }
559 break;
560 case UNIT_ATTENTION:
561 if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
562 /*
563 * Power On, Reset, or Bus Device Reset, just retry.
564 */
565 return NEEDS_RETRY;
566 break;
567 }
568 /* success just means we do not care what scsi-ml does */
569 return SCSI_RETURN_NOT_HANDLED;
570}
571
572static const struct {
573 char *vendor;
574 char *model;
575} rdac_dev_list[] = {
576 {"IBM", "1722"},
577 {"IBM", "1724"},
578 {"IBM", "1726"},
579 {"IBM", "1742"},
580 {"IBM", "1814"},
581 {"IBM", "1815"},
582 {"IBM", "1818"},
583 {"IBM", "3526"},
584 {"SGI", "TP9400"},
585 {"SGI", "TP9500"},
586 {"SGI", "IS"},
587 {"STK", "OPENstorage D280"},
588 {"SUN", "CSM200_R"},
589 {"SUN", "LCSM100_F"},
590 {NULL, NULL},
591};
592
593static int rdac_bus_notify(struct notifier_block *, unsigned long, void *);
594
595static struct scsi_device_handler rdac_dh = {
596 .name = RDAC_NAME,
597 .module = THIS_MODULE,
598 .nb.notifier_call = rdac_bus_notify,
599 .prep_fn = rdac_prep_fn,
600 .check_sense = rdac_check_sense,
601 .activate = rdac_activate,
602};
603
604/*
605 * TODO: need some interface so we can set trespass values
606 */
607static int rdac_bus_notify(struct notifier_block *nb,
608 unsigned long action, void *data)
609{
610 struct device *dev = data;
611 struct scsi_device *sdev;
612 struct scsi_dh_data *scsi_dh_data;
613 struct rdac_dh_data *h;
614 int i, found = 0;
615 unsigned long flags;
616
617 if (!scsi_is_sdev_device(dev))
618 return 0;
619
620 sdev = to_scsi_device(dev);
621
622 if (action == BUS_NOTIFY_ADD_DEVICE) {
623 for (i = 0; rdac_dev_list[i].vendor; i++) {
624 if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
625 strlen(rdac_dev_list[i].vendor)) &&
626 !strncmp(sdev->model, rdac_dev_list[i].model,
627 strlen(rdac_dev_list[i].model))) {
628 found = 1;
629 break;
630 }
631 }
632 if (!found)
633 goto out;
634
635 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
636 + sizeof(*h) , GFP_KERNEL);
637 if (!scsi_dh_data) {
638 sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
639 RDAC_NAME);
640 goto out;
641 }
642
643 scsi_dh_data->scsi_dh = &rdac_dh;
644 h = (struct rdac_dh_data *) scsi_dh_data->buf;
645 h->lun = UNINITIALIZED_LUN;
646 h->state = RDAC_STATE_ACTIVE;
647 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
648 sdev->scsi_dh_data = scsi_dh_data;
649 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
650 try_module_get(THIS_MODULE);
651
652 sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME);
653
654 } else if (action == BUS_NOTIFY_DEL_DEVICE) {
655 if (sdev->scsi_dh_data == NULL ||
656 sdev->scsi_dh_data->scsi_dh != &rdac_dh)
657 goto out;
658
659 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
660 scsi_dh_data = sdev->scsi_dh_data;
661 sdev->scsi_dh_data = NULL;
662 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
663
664 h = (struct rdac_dh_data *) scsi_dh_data->buf;
665 if (h->ctlr)
666 kref_put(&h->ctlr->kref, release_controller);
667 kfree(scsi_dh_data);
668 module_put(THIS_MODULE);
669 sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME);
670 }
671
672out:
673 return 0;
674}
675
676static int __init rdac_init(void)
677{
678 int r;
679
680 r = scsi_register_device_handler(&rdac_dh);
681 if (r != 0)
682 printk(KERN_ERR "Failed to register scsi device handler.");
683 return r;
684}
685
686static void __exit rdac_exit(void)
687{
688 scsi_unregister_device_handler(&rdac_dh);
689}
690
691module_init(rdac_init);
692module_exit(rdac_exit);
693
694MODULE_DESCRIPTION("Multipath LSI/Engenio RDAC driver");
695MODULE_AUTHOR("Mike Christie, Chandra Seetharaman");
696MODULE_LICENSE("GPL");