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