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