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