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