1 /* 2 * Target driver for EMC CLARiiON AX/CX-series hardware. 3 * Based on code from Lars Marowsky-Bree <lmb@suse.de> 4 * and Ed Goggin <egoggin@emc.com>. 5 * 6 * Copyright (C) 2006 Red Hat, Inc. All rights reserved. 7 * Copyright (C) 2006 Mike Christie 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 #include <linux/slab.h> 24 #include <linux/module.h> 25 #include <scsi/scsi.h> 26 #include <scsi/scsi_eh.h> 27 #include <scsi/scsi_dh.h> 28 #include <scsi/scsi_device.h> 29 30 #define CLARIION_NAME "emc" 31 32 #define CLARIION_TRESPASS_PAGE 0x22 33 #define CLARIION_BUFFER_SIZE 0xFC 34 #define CLARIION_TIMEOUT (60 * HZ) 35 #define CLARIION_RETRIES 3 36 #define CLARIION_UNBOUND_LU -1 37 #define CLARIION_SP_A 0 38 #define CLARIION_SP_B 1 39 40 /* Flags */ 41 #define CLARIION_SHORT_TRESPASS 1 42 #define CLARIION_HONOR_RESERVATIONS 2 43 44 /* LUN states */ 45 #define CLARIION_LUN_UNINITIALIZED -1 46 #define CLARIION_LUN_UNBOUND 0 47 #define CLARIION_LUN_BOUND 1 48 #define CLARIION_LUN_OWNED 2 49 50 static unsigned char long_trespass[] = { 51 0, 0, 0, 0, 0, 0, 0, 0, 52 CLARIION_TRESPASS_PAGE, /* Page code */ 53 0x09, /* Page length - 2 */ 54 0x01, /* Trespass code */ 55 0xff, 0xff, /* Trespass target */ 56 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ 57 }; 58 59 static unsigned char short_trespass[] = { 60 0, 0, 0, 0, 61 CLARIION_TRESPASS_PAGE, /* Page code */ 62 0x02, /* Page length - 2 */ 63 0x01, /* Trespass code */ 64 0xff, /* Trespass target */ 65 }; 66 67 static const char * lun_state[] = 68 { 69 "not bound", 70 "bound", 71 "owned", 72 }; 73 74 struct clariion_dh_data { 75 /* 76 * Flags: 77 * CLARIION_SHORT_TRESPASS 78 * Use short trespass command (FC-series) or the long version 79 * (default for AX/CX CLARiiON arrays). 80 * 81 * CLARIION_HONOR_RESERVATIONS 82 * Whether or not (default) to honor SCSI reservations when 83 * initiating a switch-over. 84 */ 85 unsigned flags; 86 /* 87 * I/O buffer for both MODE_SELECT and INQUIRY commands. 88 */ 89 unsigned char buffer[CLARIION_BUFFER_SIZE]; 90 /* 91 * LUN state 92 */ 93 int lun_state; 94 /* 95 * SP Port number 96 */ 97 int port; 98 /* 99 * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this 100 * path's mapped LUN 101 */ 102 int default_sp; 103 /* 104 * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this 105 * path's mapped LUN 106 */ 107 int current_sp; 108 }; 109 110 /* 111 * Parse MODE_SELECT cmd reply. 112 */ 113 static int trespass_endio(struct scsi_device *sdev, 114 struct scsi_sense_hdr *sshdr) 115 { 116 int err = SCSI_DH_IO; 117 118 sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, " 119 "0x%2x, 0x%2x while sending CLARiiON trespass " 120 "command.\n", CLARIION_NAME, sshdr->sense_key, 121 sshdr->asc, sshdr->ascq); 122 123 if (sshdr->sense_key == 0x05 && sshdr->asc == 0x04 && 124 sshdr->ascq == 0x00) { 125 /* 126 * Array based copy in progress -- do not send 127 * mode_select or copy will be aborted mid-stream. 128 */ 129 sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in " 130 "progress while sending CLARiiON trespass " 131 "command.\n", CLARIION_NAME); 132 err = SCSI_DH_DEV_TEMP_BUSY; 133 } else if (sshdr->sense_key == 0x02 && sshdr->asc == 0x04 && 134 sshdr->ascq == 0x03) { 135 /* 136 * LUN Not Ready - Manual Intervention Required 137 * indicates in-progress ucode upgrade (NDU). 138 */ 139 sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress " 140 "ucode upgrade NDU operation while sending " 141 "CLARiiON trespass command.\n", CLARIION_NAME); 142 err = SCSI_DH_DEV_TEMP_BUSY; 143 } else 144 err = SCSI_DH_DEV_FAILED; 145 return err; 146 } 147 148 static int parse_sp_info_reply(struct scsi_device *sdev, 149 struct clariion_dh_data *csdev) 150 { 151 int err = SCSI_DH_OK; 152 153 /* check for in-progress ucode upgrade (NDU) */ 154 if (csdev->buffer[48] != 0) { 155 sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress " 156 "ucode upgrade NDU operation while finding " 157 "current active SP.", CLARIION_NAME); 158 err = SCSI_DH_DEV_TEMP_BUSY; 159 goto out; 160 } 161 if (csdev->buffer[4] > 2) { 162 /* Invalid buffer format */ 163 sdev_printk(KERN_NOTICE, sdev, 164 "%s: invalid VPD page 0xC0 format\n", 165 CLARIION_NAME); 166 err = SCSI_DH_NOSYS; 167 goto out; 168 } 169 switch (csdev->buffer[28] & 0x0f) { 170 case 6: 171 sdev_printk(KERN_NOTICE, sdev, 172 "%s: ALUA failover mode detected\n", 173 CLARIION_NAME); 174 break; 175 case 4: 176 /* Linux failover */ 177 break; 178 default: 179 sdev_printk(KERN_WARNING, sdev, 180 "%s: Invalid failover mode %d\n", 181 CLARIION_NAME, csdev->buffer[28] & 0x0f); 182 err = SCSI_DH_NOSYS; 183 goto out; 184 } 185 186 csdev->default_sp = csdev->buffer[5]; 187 csdev->lun_state = csdev->buffer[4]; 188 csdev->current_sp = csdev->buffer[8]; 189 csdev->port = csdev->buffer[7]; 190 if (csdev->lun_state == CLARIION_LUN_OWNED) 191 sdev->access_state = SCSI_ACCESS_STATE_OPTIMAL; 192 else 193 sdev->access_state = SCSI_ACCESS_STATE_STANDBY; 194 if (csdev->default_sp == csdev->current_sp) 195 sdev->access_state |= SCSI_ACCESS_STATE_PREFERRED; 196 out: 197 return err; 198 } 199 200 #define emc_default_str "FC (Legacy)" 201 202 static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer) 203 { 204 unsigned char len = buffer[4] + 5; 205 char *sp_model = NULL; 206 unsigned char sp_len, serial_len; 207 208 if (len < 160) { 209 sdev_printk(KERN_WARNING, sdev, 210 "%s: Invalid information section length %d\n", 211 CLARIION_NAME, len); 212 /* Check for old FC arrays */ 213 if (!strncmp(buffer + 8, "DGC", 3)) { 214 /* Old FC array, not supporting extended information */ 215 sp_model = emc_default_str; 216 } 217 goto out; 218 } 219 220 /* 221 * Parse extended information for SP model number 222 */ 223 serial_len = buffer[160]; 224 if (serial_len == 0 || serial_len + 161 > len) { 225 sdev_printk(KERN_WARNING, sdev, 226 "%s: Invalid array serial number length %d\n", 227 CLARIION_NAME, serial_len); 228 goto out; 229 } 230 sp_len = buffer[99]; 231 if (sp_len == 0 || serial_len + sp_len + 161 > len) { 232 sdev_printk(KERN_WARNING, sdev, 233 "%s: Invalid model number length %d\n", 234 CLARIION_NAME, sp_len); 235 goto out; 236 } 237 sp_model = &buffer[serial_len + 161]; 238 /* Strip whitespace at the end */ 239 while (sp_len > 1 && sp_model[sp_len - 1] == ' ') 240 sp_len--; 241 242 sp_model[sp_len] = '\0'; 243 244 out: 245 return sp_model; 246 } 247 248 static int send_trespass_cmd(struct scsi_device *sdev, 249 struct clariion_dh_data *csdev) 250 { 251 unsigned char *page22; 252 unsigned char cdb[MAX_COMMAND_SIZE]; 253 int err, res = SCSI_DH_OK, len; 254 struct scsi_sense_hdr sshdr; 255 u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | 256 REQ_FAILFAST_DRIVER; 257 258 if (csdev->flags & CLARIION_SHORT_TRESPASS) { 259 page22 = short_trespass; 260 if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) 261 /* Set Honor Reservations bit */ 262 page22[6] |= 0x80; 263 len = sizeof(short_trespass); 264 cdb[0] = MODE_SELECT; 265 cdb[1] = 0x10; 266 cdb[4] = len; 267 } else { 268 page22 = long_trespass; 269 if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) 270 /* Set Honor Reservations bit */ 271 page22[10] |= 0x80; 272 len = sizeof(long_trespass); 273 cdb[0] = MODE_SELECT_10; 274 cdb[8] = len; 275 } 276 BUG_ON((len > CLARIION_BUFFER_SIZE)); 277 memcpy(csdev->buffer, page22, len); 278 279 err = scsi_execute(sdev, cdb, DMA_TO_DEVICE, csdev->buffer, len, NULL, 280 &sshdr, CLARIION_TIMEOUT * HZ, CLARIION_RETRIES, 281 req_flags, 0, NULL); 282 if (err) { 283 if (scsi_sense_valid(&sshdr)) 284 res = trespass_endio(sdev, &sshdr); 285 else { 286 sdev_printk(KERN_INFO, sdev, 287 "%s: failed to send MODE SELECT: %x\n", 288 CLARIION_NAME, err); 289 res = SCSI_DH_IO; 290 } 291 } 292 293 return res; 294 } 295 296 static int clariion_check_sense(struct scsi_device *sdev, 297 struct scsi_sense_hdr *sense_hdr) 298 { 299 switch (sense_hdr->sense_key) { 300 case NOT_READY: 301 if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03) 302 /* 303 * LUN Not Ready - Manual Intervention Required 304 * indicates this is a passive path. 305 * 306 * FIXME: However, if this is seen and EVPD C0 307 * indicates that this is due to a NDU in 308 * progress, we should set FAIL_PATH too. 309 * This indicates we might have to do a SCSI 310 * inquiry in the end_io path. Ugh. 311 * 312 * Can return FAILED only when we want the error 313 * recovery process to kick in. 314 */ 315 return SUCCESS; 316 break; 317 case ILLEGAL_REQUEST: 318 if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01) 319 /* 320 * An array based copy is in progress. Do not 321 * fail the path, do not bypass to another PG, 322 * do not retry. Fail the IO immediately. 323 * (Actually this is the same conclusion as in 324 * the default handler, but lets make sure.) 325 * 326 * Can return FAILED only when we want the error 327 * recovery process to kick in. 328 */ 329 return SUCCESS; 330 break; 331 case UNIT_ATTENTION: 332 if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) 333 /* 334 * Unit Attention Code. This is the first IO 335 * to the new path, so just retry. 336 */ 337 return ADD_TO_MLQUEUE; 338 break; 339 } 340 341 return SCSI_RETURN_NOT_HANDLED; 342 } 343 344 static int clariion_prep_fn(struct scsi_device *sdev, struct request *req) 345 { 346 struct clariion_dh_data *h = sdev->handler_data; 347 int ret = BLKPREP_OK; 348 349 if (h->lun_state != CLARIION_LUN_OWNED) { 350 ret = BLKPREP_KILL; 351 req->rq_flags |= RQF_QUIET; 352 } 353 return ret; 354 355 } 356 357 static int clariion_std_inquiry(struct scsi_device *sdev, 358 struct clariion_dh_data *csdev) 359 { 360 int err = SCSI_DH_OK; 361 char *sp_model; 362 363 sp_model = parse_sp_model(sdev, sdev->inquiry); 364 if (!sp_model) { 365 err = SCSI_DH_DEV_UNSUPP; 366 goto out; 367 } 368 369 /* 370 * FC Series arrays do not support long trespass 371 */ 372 if (!strlen(sp_model) || !strncmp(sp_model, "FC",2)) 373 csdev->flags |= CLARIION_SHORT_TRESPASS; 374 375 sdev_printk(KERN_INFO, sdev, 376 "%s: detected Clariion %s, flags %x\n", 377 CLARIION_NAME, sp_model, csdev->flags); 378 out: 379 return err; 380 } 381 382 static int clariion_send_inquiry(struct scsi_device *sdev, 383 struct clariion_dh_data *csdev) 384 { 385 int err = SCSI_DH_IO; 386 387 if (!scsi_get_vpd_page(sdev, 0xC0, csdev->buffer, 388 CLARIION_BUFFER_SIZE)) 389 err = parse_sp_info_reply(sdev, csdev); 390 391 return err; 392 } 393 394 static int clariion_activate(struct scsi_device *sdev, 395 activate_complete fn, void *data) 396 { 397 struct clariion_dh_data *csdev = sdev->handler_data; 398 int result; 399 400 result = clariion_send_inquiry(sdev, csdev); 401 if (result != SCSI_DH_OK) 402 goto done; 403 404 if (csdev->lun_state == CLARIION_LUN_OWNED) 405 goto done; 406 407 result = send_trespass_cmd(sdev, csdev); 408 if (result != SCSI_DH_OK) 409 goto done; 410 sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n", 411 CLARIION_NAME, 412 csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" ); 413 414 /* Update status */ 415 result = clariion_send_inquiry(sdev, csdev); 416 if (result != SCSI_DH_OK) 417 goto done; 418 419 done: 420 sdev_printk(KERN_INFO, sdev, 421 "%s: at SP %c Port %d (%s, default SP %c)\n", 422 CLARIION_NAME, csdev->current_sp + 'A', 423 csdev->port, lun_state[csdev->lun_state], 424 csdev->default_sp + 'A'); 425 426 if (fn) 427 fn(data, result); 428 return 0; 429 } 430 /* 431 * params - parameters in the following format 432 * "no_of_params\0param1\0param2\0param3\0...\0" 433 * for example, string for 2 parameters with value 10 and 21 434 * is specified as "2\010\021\0". 435 */ 436 static int clariion_set_params(struct scsi_device *sdev, const char *params) 437 { 438 struct clariion_dh_data *csdev = sdev->handler_data; 439 unsigned int hr = 0, st = 0, argc; 440 const char *p = params; 441 int result = SCSI_DH_OK; 442 443 if ((sscanf(params, "%u", &argc) != 1) || (argc != 2)) 444 return -EINVAL; 445 446 while (*p++) 447 ; 448 if ((sscanf(p, "%u", &st) != 1) || (st > 1)) 449 return -EINVAL; 450 451 while (*p++) 452 ; 453 if ((sscanf(p, "%u", &hr) != 1) || (hr > 1)) 454 return -EINVAL; 455 456 if (st) 457 csdev->flags |= CLARIION_SHORT_TRESPASS; 458 else 459 csdev->flags &= ~CLARIION_SHORT_TRESPASS; 460 461 if (hr) 462 csdev->flags |= CLARIION_HONOR_RESERVATIONS; 463 else 464 csdev->flags &= ~CLARIION_HONOR_RESERVATIONS; 465 466 /* 467 * If this path is owned, we have to send a trespass command 468 * with the new parameters. If not, simply return. Next trespass 469 * command would use the parameters. 470 */ 471 if (csdev->lun_state != CLARIION_LUN_OWNED) 472 goto done; 473 474 csdev->lun_state = CLARIION_LUN_UNINITIALIZED; 475 result = send_trespass_cmd(sdev, csdev); 476 if (result != SCSI_DH_OK) 477 goto done; 478 479 /* Update status */ 480 result = clariion_send_inquiry(sdev, csdev); 481 482 done: 483 return result; 484 } 485 486 static int clariion_bus_attach(struct scsi_device *sdev) 487 { 488 struct clariion_dh_data *h; 489 int err; 490 491 h = kzalloc(sizeof(*h) , GFP_KERNEL); 492 if (!h) 493 return SCSI_DH_NOMEM; 494 h->lun_state = CLARIION_LUN_UNINITIALIZED; 495 h->default_sp = CLARIION_UNBOUND_LU; 496 h->current_sp = CLARIION_UNBOUND_LU; 497 498 err = clariion_std_inquiry(sdev, h); 499 if (err != SCSI_DH_OK) 500 goto failed; 501 502 err = clariion_send_inquiry(sdev, h); 503 if (err != SCSI_DH_OK) 504 goto failed; 505 506 sdev_printk(KERN_INFO, sdev, 507 "%s: connected to SP %c Port %d (%s, default SP %c)\n", 508 CLARIION_NAME, h->current_sp + 'A', 509 h->port, lun_state[h->lun_state], 510 h->default_sp + 'A'); 511 512 sdev->handler_data = h; 513 return SCSI_DH_OK; 514 515 failed: 516 kfree(h); 517 return err; 518 } 519 520 static void clariion_bus_detach(struct scsi_device *sdev) 521 { 522 kfree(sdev->handler_data); 523 sdev->handler_data = NULL; 524 } 525 526 static struct scsi_device_handler clariion_dh = { 527 .name = CLARIION_NAME, 528 .module = THIS_MODULE, 529 .attach = clariion_bus_attach, 530 .detach = clariion_bus_detach, 531 .check_sense = clariion_check_sense, 532 .activate = clariion_activate, 533 .prep_fn = clariion_prep_fn, 534 .set_params = clariion_set_params, 535 }; 536 537 static int __init clariion_init(void) 538 { 539 int r; 540 541 r = scsi_register_device_handler(&clariion_dh); 542 if (r != 0) 543 printk(KERN_ERR "%s: Failed to register scsi device handler.", 544 CLARIION_NAME); 545 return r; 546 } 547 548 static void __exit clariion_exit(void) 549 { 550 scsi_unregister_device_handler(&clariion_dh); 551 } 552 553 module_init(clariion_init); 554 module_exit(clariion_exit); 555 556 MODULE_DESCRIPTION("EMC CX/AX/FC-family driver"); 557 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, Chandra Seetharaman <sekharan@us.ibm.com>"); 558 MODULE_LICENSE("GPL"); 559