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