2 * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be
5 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
6 * Copyright (C) 2006 Mike Christie
7 * Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
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)
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.
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.
24 #include <linux/slab.h>
25 #include <linux/module.h>
26 #include <scsi/scsi.h>
27 #include <scsi/scsi_dbg.h>
28 #include <scsi/scsi_eh.h>
29 #include <scsi/scsi_dh.h>
31 #define HP_SW_NAME "hp_sw"
33 #define HP_SW_TIMEOUT (60 * HZ)
34 #define HP_SW_RETRIES 3
36 #define HP_SW_PATH_UNINITIALIZED -1
37 #define HP_SW_PATH_ACTIVE 0
38 #define HP_SW_PATH_PASSIVE 1
40 struct hp_sw_dh_data
{
44 struct scsi_device
*sdev
;
47 static int hp_sw_start_stop(struct hp_sw_dh_data
*);
50 * tur_done - Handle TEST UNIT READY return status
51 * @sdev: sdev the command has been sent to
52 * @errors: blk error code
54 * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
56 static int tur_done(struct scsi_device
*sdev
, struct hp_sw_dh_data
*h
,
57 struct scsi_sense_hdr
*sshdr
)
61 switch (sshdr
->sense_key
) {
63 ret
= SCSI_DH_IMM_RETRY
;
66 if (sshdr
->asc
== 0x04 && sshdr
->ascq
== 2) {
68 * LUN not ready - Initialization command required
70 * This is the passive path
72 h
->path_state
= HP_SW_PATH_PASSIVE
;
78 sdev_printk(KERN_WARNING
, sdev
,
79 "%s: sending tur failed, sense %x/%x/%x\n",
80 HP_SW_NAME
, sshdr
->sense_key
, sshdr
->asc
,
88 * hp_sw_tur - Send TEST UNIT READY
89 * @sdev: sdev command should be sent to
91 * Use the TEST UNIT READY command to determine
94 static int hp_sw_tur(struct scsi_device
*sdev
, struct hp_sw_dh_data
*h
)
96 unsigned char cmd
[6] = { TEST_UNIT_READY
};
97 struct scsi_sense_hdr sshdr
;
98 int ret
= SCSI_DH_OK
, res
;
99 u64 req_flags
= REQ_FAILFAST_DEV
| REQ_FAILFAST_TRANSPORT
|
103 res
= scsi_execute_req_flags(sdev
, cmd
, DMA_NONE
, NULL
, 0, &sshdr
,
104 HP_SW_TIMEOUT
, HP_SW_RETRIES
,
107 if (scsi_sense_valid(&sshdr
))
108 ret
= tur_done(sdev
, h
, &sshdr
);
110 sdev_printk(KERN_WARNING
, sdev
,
111 "%s: sending tur failed with %x\n",
116 h
->path_state
= HP_SW_PATH_ACTIVE
;
119 if (ret
== SCSI_DH_IMM_RETRY
)
126 * hp_sw_start_stop - Send START STOP UNIT command
127 * @sdev: sdev command should be sent to
129 * Sending START STOP UNIT activates the SP.
131 static int hp_sw_start_stop(struct hp_sw_dh_data
*h
)
133 unsigned char cmd
[6] = { START_STOP
, 0, 0, 0, 1, 0 };
134 struct scsi_sense_hdr sshdr
;
135 struct scsi_device
*sdev
= h
->sdev
;
136 int res
, rc
= SCSI_DH_OK
;
137 int retry_cnt
= HP_SW_RETRIES
;
138 u64 req_flags
= REQ_FAILFAST_DEV
| REQ_FAILFAST_TRANSPORT
|
142 res
= scsi_execute_req_flags(sdev
, cmd
, DMA_NONE
, NULL
, 0, &sshdr
,
143 HP_SW_TIMEOUT
, HP_SW_RETRIES
,
146 if (!scsi_sense_valid(&sshdr
)) {
147 sdev_printk(KERN_WARNING
, sdev
,
148 "%s: sending start_stop_unit failed, "
149 "no sense available\n", HP_SW_NAME
);
152 switch (sshdr
.sense_key
) {
154 if (sshdr
.asc
== 0x04 && sshdr
.ascq
== 3) {
156 * LUN not ready - manual intervention required
158 * Switch-over in progress, retry.
167 sdev_printk(KERN_WARNING
, sdev
,
168 "%s: sending start_stop_unit failed, "
169 "sense %x/%x/%x\n", HP_SW_NAME
,
170 sshdr
.sense_key
, sshdr
.asc
, sshdr
.ascq
);
177 static int hp_sw_prep_fn(struct scsi_device
*sdev
, struct request
*req
)
179 struct hp_sw_dh_data
*h
= sdev
->handler_data
;
180 int ret
= BLKPREP_OK
;
182 if (h
->path_state
!= HP_SW_PATH_ACTIVE
) {
184 req
->rq_flags
|= RQF_QUIET
;
191 * hp_sw_activate - Activate a path
192 * @sdev: sdev on the path to be activated
194 * The HP Active/Passive firmware is pretty simple;
195 * the passive path reports NOT READY with sense codes
196 * 0x04/0x02; a START STOP UNIT command will then
197 * activate the passive path (and deactivate the
198 * previously active one).
200 static int hp_sw_activate(struct scsi_device
*sdev
,
201 activate_complete fn
, void *data
)
203 int ret
= SCSI_DH_OK
;
204 struct hp_sw_dh_data
*h
= sdev
->handler_data
;
206 ret
= hp_sw_tur(sdev
, h
);
208 if (ret
== SCSI_DH_OK
&& h
->path_state
== HP_SW_PATH_PASSIVE
)
209 ret
= hp_sw_start_stop(h
);
216 static int hp_sw_bus_attach(struct scsi_device
*sdev
)
218 struct hp_sw_dh_data
*h
;
221 h
= kzalloc(sizeof(*h
), GFP_KERNEL
);
224 h
->path_state
= HP_SW_PATH_UNINITIALIZED
;
225 h
->retries
= HP_SW_RETRIES
;
228 ret
= hp_sw_tur(sdev
, h
);
229 if (ret
!= SCSI_DH_OK
|| h
->path_state
== HP_SW_PATH_UNINITIALIZED
)
232 sdev_printk(KERN_INFO
, sdev
, "%s: attached to %s path\n",
233 HP_SW_NAME
, h
->path_state
== HP_SW_PATH_ACTIVE
?
236 sdev
->handler_data
= h
;
243 static void hp_sw_bus_detach( struct scsi_device
*sdev
)
245 kfree(sdev
->handler_data
);
246 sdev
->handler_data
= NULL
;
249 static struct scsi_device_handler hp_sw_dh
= {
251 .module
= THIS_MODULE
,
252 .attach
= hp_sw_bus_attach
,
253 .detach
= hp_sw_bus_detach
,
254 .activate
= hp_sw_activate
,
255 .prep_fn
= hp_sw_prep_fn
,
258 static int __init
hp_sw_init(void)
260 return scsi_register_device_handler(&hp_sw_dh
);
263 static void __exit
hp_sw_exit(void)
265 scsi_unregister_device_handler(&hp_sw_dh
);
268 module_init(hp_sw_init
);
269 module_exit(hp_sw_exit
);
271 MODULE_DESCRIPTION("HP Active/Passive driver");
272 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
273 MODULE_LICENSE("GPL");