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 	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
111 	if (!req)
112 		return SCSI_DH_RES_TEMP_UNAVAIL;
113 
114 	req->cmd_type = REQ_TYPE_BLOCK_PC;
115 	req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
116 			  REQ_FAILFAST_DRIVER;
117 	req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
118 	req->cmd[0] = TEST_UNIT_READY;
119 	req->timeout = HP_SW_TIMEOUT;
120 	req->sense = h->sense;
121 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
122 	req->sense_len = 0;
123 
124 retry:
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 		goto retry;
141 	if (ret == SCSI_DH_DEV_OFFLINED) {
142 		h->path_state = HP_SW_PATH_PASSIVE;
143 		ret = SCSI_DH_OK;
144 	}
145 
146 	blk_put_request(req);
147 
148 	return ret;
149 }
150 
151 /*
152  * start_done - Handle START STOP UNIT return status
153  * @sdev: sdev the command has been sent to
154  * @errors: blk error code
155  */
156 static int start_done(struct scsi_device *sdev, unsigned char *sense)
157 {
158 	struct scsi_sense_hdr sshdr;
159 	int rc;
160 
161 	rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
162 	if (!rc) {
163 		sdev_printk(KERN_WARNING, sdev,
164 			    "%s: sending start_stop_unit failed, "
165 			    "no sense available\n",
166 			    HP_SW_NAME);
167 		return SCSI_DH_IO;
168 	}
169 	switch (sshdr.sense_key) {
170 	case NOT_READY:
171 		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
172 			/*
173 			 * LUN not ready - manual intervention required
174 			 *
175 			 * Switch-over in progress, retry.
176 			 */
177 			rc = SCSI_DH_RETRY;
178 			break;
179 		}
180 		/* fall through */
181 	default:
182 		sdev_printk(KERN_WARNING, sdev,
183 			   "%s: sending start_stop_unit failed, sense %x/%x/%x\n",
184 			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
185 			   sshdr.ascq);
186 		rc = SCSI_DH_IO;
187 	}
188 
189 	return rc;
190 }
191 
192 /*
193  * hp_sw_start_stop - Send START STOP UNIT command
194  * @sdev: sdev command should be sent to
195  *
196  * Sending START STOP UNIT activates the SP.
197  */
198 static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h)
199 {
200 	struct request *req;
201 	int ret, retry;
202 
203 	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
204 	if (!req)
205 		return SCSI_DH_RES_TEMP_UNAVAIL;
206 
207 	req->cmd_type = REQ_TYPE_BLOCK_PC;
208 	req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
209 			  REQ_FAILFAST_DRIVER;
210 	req->cmd_len = COMMAND_SIZE(START_STOP);
211 	req->cmd[0] = START_STOP;
212 	req->cmd[4] = 1;	/* Start spin cycle */
213 	req->timeout = HP_SW_TIMEOUT;
214 	req->sense = h->sense;
215 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
216 	req->sense_len = 0;
217 	retry = h->retries;
218 
219 retry:
220 	ret = blk_execute_rq(req->q, NULL, req, 1);
221 	if (ret == -EIO) {
222 		if (req->sense_len > 0) {
223 			ret = start_done(sdev, h->sense);
224 		} else {
225 			sdev_printk(KERN_WARNING, sdev,
226 				    "%s: sending start_stop_unit failed with %x\n",
227 				    HP_SW_NAME, req->errors);
228 			ret = SCSI_DH_IO;
229 		}
230 	} else
231 		ret = SCSI_DH_OK;
232 
233 	if (ret == SCSI_DH_RETRY) {
234 		if (--retry)
235 			goto retry;
236 		ret = SCSI_DH_IO;
237 	}
238 
239 	blk_put_request(req);
240 
241 	return ret;
242 }
243 
244 static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
245 {
246 	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
247 	int ret = BLKPREP_OK;
248 
249 	if (h->path_state != HP_SW_PATH_ACTIVE) {
250 		ret = BLKPREP_KILL;
251 		req->cmd_flags |= REQ_QUIET;
252 	}
253 	return ret;
254 
255 }
256 
257 /*
258  * hp_sw_activate - Activate a path
259  * @sdev: sdev on the path to be activated
260  *
261  * The HP Active/Passive firmware is pretty simple;
262  * the passive path reports NOT READY with sense codes
263  * 0x04/0x02; a START STOP UNIT command will then
264  * activate the passive path (and deactivate the
265  * previously active one).
266  */
267 static int hp_sw_activate(struct scsi_device *sdev)
268 {
269 	int ret = SCSI_DH_OK;
270 	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
271 
272 	ret = hp_sw_tur(sdev, h);
273 
274 	if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
275 		ret = hp_sw_start_stop(sdev, h);
276 		if (ret == SCSI_DH_OK)
277 			sdev_printk(KERN_INFO, sdev,
278 				    "%s: activated path\n",
279 				    HP_SW_NAME);
280 	}
281 
282 	return ret;
283 }
284 
285 static const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
286 	{"COMPAQ", "MSA1000 VOLUME"},
287 	{"COMPAQ", "HSV110"},
288 	{"HP", "HSV100"},
289 	{"DEC", "HSG80"},
290 	{NULL, NULL},
291 };
292 
293 static int hp_sw_bus_attach(struct scsi_device *sdev);
294 static void hp_sw_bus_detach(struct scsi_device *sdev);
295 
296 static struct scsi_device_handler hp_sw_dh = {
297 	.name		= HP_SW_NAME,
298 	.module		= THIS_MODULE,
299 	.devlist	= hp_sw_dh_data_list,
300 	.attach		= hp_sw_bus_attach,
301 	.detach		= hp_sw_bus_detach,
302 	.activate	= hp_sw_activate,
303 	.prep_fn	= hp_sw_prep_fn,
304 };
305 
306 static int hp_sw_bus_attach(struct scsi_device *sdev)
307 {
308 	struct scsi_dh_data *scsi_dh_data;
309 	struct hp_sw_dh_data *h;
310 	unsigned long flags;
311 	int ret;
312 
313 	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
314 			       + sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
315 	if (!scsi_dh_data) {
316 		sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
317 			    HP_SW_NAME);
318 		return 0;
319 	}
320 
321 	scsi_dh_data->scsi_dh = &hp_sw_dh;
322 	h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
323 	h->path_state = HP_SW_PATH_UNINITIALIZED;
324 	h->retries = HP_SW_RETRIES;
325 
326 	ret = hp_sw_tur(sdev, h);
327 	if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
328 		goto failed;
329 
330 	if (!try_module_get(THIS_MODULE))
331 		goto failed;
332 
333 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
334 	sdev->scsi_dh_data = scsi_dh_data;
335 	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
336 
337 	sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
338 		    HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
339 		    "active":"passive");
340 
341 	return 0;
342 
343 failed:
344 	kfree(scsi_dh_data);
345 	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
346 		    HP_SW_NAME);
347 	return -EINVAL;
348 }
349 
350 static void hp_sw_bus_detach( struct scsi_device *sdev )
351 {
352 	struct scsi_dh_data *scsi_dh_data;
353 	unsigned long flags;
354 
355 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
356 	scsi_dh_data = sdev->scsi_dh_data;
357 	sdev->scsi_dh_data = NULL;
358 	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
359 	module_put(THIS_MODULE);
360 
361 	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME);
362 
363 	kfree(scsi_dh_data);
364 }
365 
366 static int __init hp_sw_init(void)
367 {
368 	return scsi_register_device_handler(&hp_sw_dh);
369 }
370 
371 static void __exit hp_sw_exit(void)
372 {
373 	scsi_unregister_device_handler(&hp_sw_dh);
374 }
375 
376 module_init(hp_sw_init);
377 module_exit(hp_sw_exit);
378 
379 MODULE_DESCRIPTION("HP Active/Passive driver");
380 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
381 MODULE_LICENSE("GPL");
382