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  * Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
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 
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>
30 
31 #define HP_SW_NAME			"hp_sw"
32 
33 #define HP_SW_TIMEOUT			(60 * HZ)
34 #define HP_SW_RETRIES			3
35 
36 #define HP_SW_PATH_UNINITIALIZED	-1
37 #define HP_SW_PATH_ACTIVE		0
38 #define HP_SW_PATH_PASSIVE		1
39 
40 struct hp_sw_dh_data {
41 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
42 	int path_state;
43 	int retries;
44 	int retry_cnt;
45 	struct scsi_device *sdev;
46 	activate_complete	callback_fn;
47 	void			*callback_data;
48 };
49 
50 static int hp_sw_start_stop(struct hp_sw_dh_data *);
51 
52 /*
53  * tur_done - Handle TEST UNIT READY return status
54  * @sdev: sdev the command has been sent to
55  * @errors: blk error code
56  *
57  * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
58  */
59 static int tur_done(struct scsi_device *sdev, unsigned char *sense)
60 {
61 	struct scsi_sense_hdr sshdr;
62 	int ret;
63 
64 	ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
65 	if (!ret) {
66 		sdev_printk(KERN_WARNING, sdev,
67 			    "%s: sending tur failed, no sense available\n",
68 			    HP_SW_NAME);
69 		ret = SCSI_DH_IO;
70 		goto done;
71 	}
72 	switch (sshdr.sense_key) {
73 	case UNIT_ATTENTION:
74 		ret = SCSI_DH_IMM_RETRY;
75 		break;
76 	case NOT_READY:
77 		if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) {
78 			/*
79 			 * LUN not ready - Initialization command required
80 			 *
81 			 * This is the passive path
82 			 */
83 			ret = SCSI_DH_DEV_OFFLINED;
84 			break;
85 		}
86 		/* Fallthrough */
87 	default:
88 		sdev_printk(KERN_WARNING, sdev,
89 			   "%s: sending tur failed, sense %x/%x/%x\n",
90 			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
91 			   sshdr.ascq);
92 		break;
93 	}
94 
95 done:
96 	return ret;
97 }
98 
99 /*
100  * hp_sw_tur - Send TEST UNIT READY
101  * @sdev: sdev command should be sent to
102  *
103  * Use the TEST UNIT READY command to determine
104  * the path state.
105  */
106 static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
107 {
108 	struct request *req;
109 	int ret;
110 
111 retry:
112 	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
113 	if (IS_ERR(req))
114 		return SCSI_DH_RES_TEMP_UNAVAIL;
115 
116 	blk_rq_set_block_pc(req);
117 	req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
118 			  REQ_FAILFAST_DRIVER;
119 	req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
120 	req->cmd[0] = TEST_UNIT_READY;
121 	req->timeout = HP_SW_TIMEOUT;
122 	req->sense = h->sense;
123 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
124 	req->sense_len = 0;
125 
126 	ret = blk_execute_rq(req->q, NULL, req, 1);
127 	if (ret == -EIO) {
128 		if (req->sense_len > 0) {
129 			ret = tur_done(sdev, h->sense);
130 		} else {
131 			sdev_printk(KERN_WARNING, sdev,
132 				    "%s: sending tur failed with %x\n",
133 				    HP_SW_NAME, req->errors);
134 			ret = SCSI_DH_IO;
135 		}
136 	} else {
137 		h->path_state = HP_SW_PATH_ACTIVE;
138 		ret = SCSI_DH_OK;
139 	}
140 	if (ret == SCSI_DH_IMM_RETRY) {
141 		blk_put_request(req);
142 		goto retry;
143 	}
144 	if (ret == SCSI_DH_DEV_OFFLINED) {
145 		h->path_state = HP_SW_PATH_PASSIVE;
146 		ret = SCSI_DH_OK;
147 	}
148 
149 	blk_put_request(req);
150 
151 	return ret;
152 }
153 
154 /*
155  * start_done - Handle START STOP UNIT return status
156  * @sdev: sdev the command has been sent to
157  * @errors: blk error code
158  */
159 static int start_done(struct scsi_device *sdev, unsigned char *sense)
160 {
161 	struct scsi_sense_hdr sshdr;
162 	int rc;
163 
164 	rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
165 	if (!rc) {
166 		sdev_printk(KERN_WARNING, sdev,
167 			    "%s: sending start_stop_unit failed, "
168 			    "no sense available\n",
169 			    HP_SW_NAME);
170 		return SCSI_DH_IO;
171 	}
172 	switch (sshdr.sense_key) {
173 	case NOT_READY:
174 		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
175 			/*
176 			 * LUN not ready - manual intervention required
177 			 *
178 			 * Switch-over in progress, retry.
179 			 */
180 			rc = SCSI_DH_RETRY;
181 			break;
182 		}
183 		/* fall through */
184 	default:
185 		sdev_printk(KERN_WARNING, sdev,
186 			   "%s: sending start_stop_unit failed, sense %x/%x/%x\n",
187 			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
188 			   sshdr.ascq);
189 		rc = SCSI_DH_IO;
190 	}
191 
192 	return rc;
193 }
194 
195 static void start_stop_endio(struct request *req, int error)
196 {
197 	struct hp_sw_dh_data *h = req->end_io_data;
198 	unsigned err = SCSI_DH_OK;
199 
200 	if (error || host_byte(req->errors) != DID_OK ||
201 			msg_byte(req->errors) != COMMAND_COMPLETE) {
202 		sdev_printk(KERN_WARNING, h->sdev,
203 			    "%s: sending start_stop_unit failed with %x\n",
204 			    HP_SW_NAME, req->errors);
205 		err = SCSI_DH_IO;
206 		goto done;
207 	}
208 
209 	if (req->sense_len > 0) {
210 		err = start_done(h->sdev, h->sense);
211 		if (err == SCSI_DH_RETRY) {
212 			err = SCSI_DH_IO;
213 			if (--h->retry_cnt) {
214 				blk_put_request(req);
215 				err = hp_sw_start_stop(h);
216 				if (err == SCSI_DH_OK)
217 					return;
218 			}
219 		}
220 	}
221 done:
222 	req->end_io_data = NULL;
223 	__blk_put_request(req->q, req);
224 	if (h->callback_fn) {
225 		h->callback_fn(h->callback_data, err);
226 		h->callback_fn = h->callback_data = NULL;
227 	}
228 	return;
229 
230 }
231 
232 /*
233  * hp_sw_start_stop - Send START STOP UNIT command
234  * @sdev: sdev command should be sent to
235  *
236  * Sending START STOP UNIT activates the SP.
237  */
238 static int hp_sw_start_stop(struct hp_sw_dh_data *h)
239 {
240 	struct request *req;
241 
242 	req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
243 	if (IS_ERR(req))
244 		return SCSI_DH_RES_TEMP_UNAVAIL;
245 
246 	blk_rq_set_block_pc(req);
247 	req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
248 			  REQ_FAILFAST_DRIVER;
249 	req->cmd_len = COMMAND_SIZE(START_STOP);
250 	req->cmd[0] = START_STOP;
251 	req->cmd[4] = 1;	/* Start spin cycle */
252 	req->timeout = HP_SW_TIMEOUT;
253 	req->sense = h->sense;
254 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
255 	req->sense_len = 0;
256 	req->end_io_data = h;
257 
258 	blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio);
259 	return SCSI_DH_OK;
260 }
261 
262 static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
263 {
264 	struct hp_sw_dh_data *h = sdev->handler_data;
265 	int ret = BLKPREP_OK;
266 
267 	if (h->path_state != HP_SW_PATH_ACTIVE) {
268 		ret = BLKPREP_KILL;
269 		req->cmd_flags |= REQ_QUIET;
270 	}
271 	return ret;
272 
273 }
274 
275 /*
276  * hp_sw_activate - Activate a path
277  * @sdev: sdev on the path to be activated
278  *
279  * The HP Active/Passive firmware is pretty simple;
280  * the passive path reports NOT READY with sense codes
281  * 0x04/0x02; a START STOP UNIT command will then
282  * activate the passive path (and deactivate the
283  * previously active one).
284  */
285 static int hp_sw_activate(struct scsi_device *sdev,
286 				activate_complete fn, void *data)
287 {
288 	int ret = SCSI_DH_OK;
289 	struct hp_sw_dh_data *h = sdev->handler_data;
290 
291 	ret = hp_sw_tur(sdev, h);
292 
293 	if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
294 		h->retry_cnt = h->retries;
295 		h->callback_fn = fn;
296 		h->callback_data = data;
297 		ret = hp_sw_start_stop(h);
298 		if (ret == SCSI_DH_OK)
299 			return 0;
300 		h->callback_fn = h->callback_data = NULL;
301 	}
302 
303 	if (fn)
304 		fn(data, ret);
305 	return 0;
306 }
307 
308 static int hp_sw_bus_attach(struct scsi_device *sdev)
309 {
310 	struct hp_sw_dh_data *h;
311 	int ret;
312 
313 	h = kzalloc(sizeof(*h), GFP_KERNEL);
314 	if (!h)
315 		return -ENOMEM;
316 	h->path_state = HP_SW_PATH_UNINITIALIZED;
317 	h->retries = HP_SW_RETRIES;
318 	h->sdev = sdev;
319 
320 	ret = hp_sw_tur(sdev, h);
321 	if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
322 		goto failed;
323 
324 	sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
325 		    HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
326 		    "active":"passive");
327 
328 	sdev->handler_data = h;
329 	return 0;
330 failed:
331 	kfree(h);
332 	return -EINVAL;
333 }
334 
335 static void hp_sw_bus_detach( struct scsi_device *sdev )
336 {
337 	kfree(sdev->handler_data);
338 	sdev->handler_data = NULL;
339 }
340 
341 static struct scsi_device_handler hp_sw_dh = {
342 	.name		= HP_SW_NAME,
343 	.module		= THIS_MODULE,
344 	.attach		= hp_sw_bus_attach,
345 	.detach		= hp_sw_bus_detach,
346 	.activate	= hp_sw_activate,
347 	.prep_fn	= hp_sw_prep_fn,
348 };
349 
350 static int __init hp_sw_init(void)
351 {
352 	return scsi_register_device_handler(&hp_sw_dh);
353 }
354 
355 static void __exit hp_sw_exit(void)
356 {
357 	scsi_unregister_device_handler(&hp_sw_dh);
358 }
359 
360 module_init(hp_sw_init);
361 module_exit(hp_sw_exit);
362 
363 MODULE_DESCRIPTION("HP Active/Passive driver");
364 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
365 MODULE_LICENSE("GPL");
366