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