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(sdev
, cmd
, DMA_NONE
, NULL
, 0, NULL
, &sshdr
,
104 HP_SW_TIMEOUT
, HP_SW_RETRIES
, req_flags
, 0, NULL
);
106 if (scsi_sense_valid(&sshdr
))
107 ret
= tur_done(sdev
, h
, &sshdr
);
109 sdev_printk(KERN_WARNING
, sdev
,
110 "%s: sending tur failed with %x\n",
115 h
->path_state
= HP_SW_PATH_ACTIVE
;
118 if (ret
== SCSI_DH_IMM_RETRY
)
125 * hp_sw_start_stop - Send START STOP UNIT command
126 * @sdev: sdev command should be sent to
128 * Sending START STOP UNIT activates the SP.
130 static int hp_sw_start_stop(struct hp_sw_dh_data
*h
)
132 unsigned char cmd
[6] = { START_STOP
, 0, 0, 0, 1, 0 };
133 struct scsi_sense_hdr sshdr
;
134 struct scsi_device
*sdev
= h
->sdev
;
135 int res
, rc
= SCSI_DH_OK
;
136 int retry_cnt
= HP_SW_RETRIES
;
137 u64 req_flags
= REQ_FAILFAST_DEV
| REQ_FAILFAST_TRANSPORT
|
141 res
= scsi_execute(sdev
, cmd
, DMA_NONE
, NULL
, 0, NULL
, &sshdr
,
142 HP_SW_TIMEOUT
, HP_SW_RETRIES
, req_flags
, 0, NULL
);
144 if (!scsi_sense_valid(&sshdr
)) {
145 sdev_printk(KERN_WARNING
, sdev
,
146 "%s: sending start_stop_unit failed, "
147 "no sense available\n", HP_SW_NAME
);
150 switch (sshdr
.sense_key
) {
152 if (sshdr
.asc
== 0x04 && sshdr
.ascq
== 3) {
154 * LUN not ready - manual intervention required
156 * Switch-over in progress, retry.
165 sdev_printk(KERN_WARNING
, sdev
,
166 "%s: sending start_stop_unit failed, "
167 "sense %x/%x/%x\n", HP_SW_NAME
,
168 sshdr
.sense_key
, sshdr
.asc
, sshdr
.ascq
);
175 static int hp_sw_prep_fn(struct scsi_device
*sdev
, struct request
*req
)
177 struct hp_sw_dh_data
*h
= sdev
->handler_data
;
178 int ret
= BLKPREP_OK
;
180 if (h
->path_state
!= HP_SW_PATH_ACTIVE
) {
182 req
->rq_flags
|= RQF_QUIET
;
189 * hp_sw_activate - Activate a path
190 * @sdev: sdev on the path to be activated
192 * The HP Active/Passive firmware is pretty simple;
193 * the passive path reports NOT READY with sense codes
194 * 0x04/0x02; a START STOP UNIT command will then
195 * activate the passive path (and deactivate the
196 * previously active one).
198 static int hp_sw_activate(struct scsi_device
*sdev
,
199 activate_complete fn
, void *data
)
201 int ret
= SCSI_DH_OK
;
202 struct hp_sw_dh_data
*h
= sdev
->handler_data
;
204 ret
= hp_sw_tur(sdev
, h
);
206 if (ret
== SCSI_DH_OK
&& h
->path_state
== HP_SW_PATH_PASSIVE
)
207 ret
= hp_sw_start_stop(h
);
214 static int hp_sw_bus_attach(struct scsi_device
*sdev
)
216 struct hp_sw_dh_data
*h
;
219 h
= kzalloc(sizeof(*h
), GFP_KERNEL
);
222 h
->path_state
= HP_SW_PATH_UNINITIALIZED
;
223 h
->retries
= HP_SW_RETRIES
;
226 ret
= hp_sw_tur(sdev
, h
);
227 if (ret
!= SCSI_DH_OK
|| h
->path_state
== HP_SW_PATH_UNINITIALIZED
)
230 sdev_printk(KERN_INFO
, sdev
, "%s: attached to %s path\n",
231 HP_SW_NAME
, h
->path_state
== HP_SW_PATH_ACTIVE
?
234 sdev
->handler_data
= h
;
241 static void hp_sw_bus_detach( struct scsi_device
*sdev
)
243 kfree(sdev
->handler_data
);
244 sdev
->handler_data
= NULL
;
247 static struct scsi_device_handler hp_sw_dh
= {
249 .module
= THIS_MODULE
,
250 .attach
= hp_sw_bus_attach
,
251 .detach
= hp_sw_bus_detach
,
252 .activate
= hp_sw_activate
,
253 .prep_fn
= hp_sw_prep_fn
,
256 static int __init
hp_sw_init(void)
258 return scsi_register_device_handler(&hp_sw_dh
);
261 static void __exit
hp_sw_exit(void)
263 scsi_unregister_device_handler(&hp_sw_dh
);
266 module_init(hp_sw_init
);
267 module_exit(hp_sw_exit
);
269 MODULE_DESCRIPTION("HP Active/Passive driver");
270 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
271 MODULE_LICENSE("GPL");