These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / scsi / device_handler / scsi_dh_hp_sw.c
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");