0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/slab.h>
0011 #include <linux/module.h>
0012 #include <scsi/scsi.h>
0013 #include <scsi/scsi_eh.h>
0014 #include <scsi/scsi_dh.h>
0015 #include <scsi/scsi_device.h>
0016
0017 #define CLARIION_NAME "emc"
0018
0019 #define CLARIION_TRESPASS_PAGE 0x22
0020 #define CLARIION_BUFFER_SIZE 0xFC
0021 #define CLARIION_TIMEOUT (60 * HZ)
0022 #define CLARIION_RETRIES 3
0023 #define CLARIION_UNBOUND_LU -1
0024 #define CLARIION_SP_A 0
0025 #define CLARIION_SP_B 1
0026
0027
0028 #define CLARIION_SHORT_TRESPASS 1
0029 #define CLARIION_HONOR_RESERVATIONS 2
0030
0031
0032 #define CLARIION_LUN_UNINITIALIZED -1
0033 #define CLARIION_LUN_UNBOUND 0
0034 #define CLARIION_LUN_BOUND 1
0035 #define CLARIION_LUN_OWNED 2
0036
0037 static unsigned char long_trespass[] = {
0038 0, 0, 0, 0, 0, 0, 0, 0,
0039 CLARIION_TRESPASS_PAGE,
0040 0x09,
0041 0x01,
0042 0xff, 0xff,
0043 0, 0, 0, 0, 0, 0
0044 };
0045
0046 static unsigned char short_trespass[] = {
0047 0, 0, 0, 0,
0048 CLARIION_TRESPASS_PAGE,
0049 0x02,
0050 0x01,
0051 0xff,
0052 };
0053
0054 static const char * lun_state[] =
0055 {
0056 "not bound",
0057 "bound",
0058 "owned",
0059 };
0060
0061 struct clariion_dh_data {
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 unsigned flags;
0073
0074
0075
0076 unsigned char buffer[CLARIION_BUFFER_SIZE];
0077
0078
0079
0080 int lun_state;
0081
0082
0083
0084 int port;
0085
0086
0087
0088
0089 int default_sp;
0090
0091
0092
0093
0094 int current_sp;
0095 };
0096
0097
0098
0099
0100 static int trespass_endio(struct scsi_device *sdev,
0101 struct scsi_sense_hdr *sshdr)
0102 {
0103 int err = SCSI_DH_IO;
0104
0105 sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
0106 "0x%2x, 0x%2x while sending CLARiiON trespass "
0107 "command.\n", CLARIION_NAME, sshdr->sense_key,
0108 sshdr->asc, sshdr->ascq);
0109
0110 if (sshdr->sense_key == 0x05 && sshdr->asc == 0x04 &&
0111 sshdr->ascq == 0x00) {
0112
0113
0114
0115
0116 sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
0117 "progress while sending CLARiiON trespass "
0118 "command.\n", CLARIION_NAME);
0119 err = SCSI_DH_DEV_TEMP_BUSY;
0120 } else if (sshdr->sense_key == 0x02 && sshdr->asc == 0x04 &&
0121 sshdr->ascq == 0x03) {
0122
0123
0124
0125
0126 sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
0127 "ucode upgrade NDU operation while sending "
0128 "CLARiiON trespass command.\n", CLARIION_NAME);
0129 err = SCSI_DH_DEV_TEMP_BUSY;
0130 } else
0131 err = SCSI_DH_DEV_FAILED;
0132 return err;
0133 }
0134
0135 static int parse_sp_info_reply(struct scsi_device *sdev,
0136 struct clariion_dh_data *csdev)
0137 {
0138 int err = SCSI_DH_OK;
0139
0140
0141 if (csdev->buffer[48] != 0) {
0142 sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress "
0143 "ucode upgrade NDU operation while finding "
0144 "current active SP.", CLARIION_NAME);
0145 err = SCSI_DH_DEV_TEMP_BUSY;
0146 goto out;
0147 }
0148 if (csdev->buffer[4] > 2) {
0149
0150 sdev_printk(KERN_NOTICE, sdev,
0151 "%s: invalid VPD page 0xC0 format\n",
0152 CLARIION_NAME);
0153 err = SCSI_DH_NOSYS;
0154 goto out;
0155 }
0156 switch (csdev->buffer[28] & 0x0f) {
0157 case 6:
0158 sdev_printk(KERN_NOTICE, sdev,
0159 "%s: ALUA failover mode detected\n",
0160 CLARIION_NAME);
0161 break;
0162 case 4:
0163
0164 break;
0165 default:
0166 sdev_printk(KERN_WARNING, sdev,
0167 "%s: Invalid failover mode %d\n",
0168 CLARIION_NAME, csdev->buffer[28] & 0x0f);
0169 err = SCSI_DH_NOSYS;
0170 goto out;
0171 }
0172
0173 csdev->default_sp = csdev->buffer[5];
0174 csdev->lun_state = csdev->buffer[4];
0175 csdev->current_sp = csdev->buffer[8];
0176 csdev->port = csdev->buffer[7];
0177 if (csdev->lun_state == CLARIION_LUN_OWNED)
0178 sdev->access_state = SCSI_ACCESS_STATE_OPTIMAL;
0179 else
0180 sdev->access_state = SCSI_ACCESS_STATE_STANDBY;
0181 if (csdev->default_sp == csdev->current_sp)
0182 sdev->access_state |= SCSI_ACCESS_STATE_PREFERRED;
0183 out:
0184 return err;
0185 }
0186
0187 #define emc_default_str "FC (Legacy)"
0188
0189 static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer)
0190 {
0191 unsigned char len = buffer[4] + 5;
0192 char *sp_model = NULL;
0193 unsigned char sp_len, serial_len;
0194
0195 if (len < 160) {
0196 sdev_printk(KERN_WARNING, sdev,
0197 "%s: Invalid information section length %d\n",
0198 CLARIION_NAME, len);
0199
0200 if (!strncmp(buffer + 8, "DGC", 3)) {
0201
0202 sp_model = emc_default_str;
0203 }
0204 goto out;
0205 }
0206
0207
0208
0209
0210 serial_len = buffer[160];
0211 if (serial_len == 0 || serial_len + 161 > len) {
0212 sdev_printk(KERN_WARNING, sdev,
0213 "%s: Invalid array serial number length %d\n",
0214 CLARIION_NAME, serial_len);
0215 goto out;
0216 }
0217 sp_len = buffer[99];
0218 if (sp_len == 0 || serial_len + sp_len + 161 > len) {
0219 sdev_printk(KERN_WARNING, sdev,
0220 "%s: Invalid model number length %d\n",
0221 CLARIION_NAME, sp_len);
0222 goto out;
0223 }
0224 sp_model = &buffer[serial_len + 161];
0225
0226 while (sp_len > 1 && sp_model[sp_len - 1] == ' ')
0227 sp_len--;
0228
0229 sp_model[sp_len] = '\0';
0230
0231 out:
0232 return sp_model;
0233 }
0234
0235 static int send_trespass_cmd(struct scsi_device *sdev,
0236 struct clariion_dh_data *csdev)
0237 {
0238 unsigned char *page22;
0239 unsigned char cdb[MAX_COMMAND_SIZE];
0240 int err, res = SCSI_DH_OK, len;
0241 struct scsi_sense_hdr sshdr;
0242 blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
0243 REQ_FAILFAST_DRIVER;
0244
0245 if (csdev->flags & CLARIION_SHORT_TRESPASS) {
0246 page22 = short_trespass;
0247 if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
0248
0249 page22[6] |= 0x80;
0250 len = sizeof(short_trespass);
0251 cdb[0] = MODE_SELECT;
0252 cdb[1] = 0x10;
0253 cdb[4] = len;
0254 } else {
0255 page22 = long_trespass;
0256 if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
0257
0258 page22[10] |= 0x80;
0259 len = sizeof(long_trespass);
0260 cdb[0] = MODE_SELECT_10;
0261 cdb[8] = len;
0262 }
0263 BUG_ON((len > CLARIION_BUFFER_SIZE));
0264 memcpy(csdev->buffer, page22, len);
0265
0266 err = scsi_execute(sdev, cdb, DMA_TO_DEVICE, csdev->buffer, len, NULL,
0267 &sshdr, CLARIION_TIMEOUT * HZ, CLARIION_RETRIES,
0268 req_flags, 0, NULL);
0269 if (err) {
0270 if (scsi_sense_valid(&sshdr))
0271 res = trespass_endio(sdev, &sshdr);
0272 else {
0273 sdev_printk(KERN_INFO, sdev,
0274 "%s: failed to send MODE SELECT: %x\n",
0275 CLARIION_NAME, err);
0276 res = SCSI_DH_IO;
0277 }
0278 }
0279
0280 return res;
0281 }
0282
0283 static enum scsi_disposition clariion_check_sense(struct scsi_device *sdev,
0284 struct scsi_sense_hdr *sense_hdr)
0285 {
0286 switch (sense_hdr->sense_key) {
0287 case NOT_READY:
0288 if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03)
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 return SUCCESS;
0303 break;
0304 case ILLEGAL_REQUEST:
0305 if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01)
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316 return SUCCESS;
0317 break;
0318 case UNIT_ATTENTION:
0319 if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
0320
0321
0322
0323
0324 return ADD_TO_MLQUEUE;
0325 break;
0326 }
0327
0328 return SCSI_RETURN_NOT_HANDLED;
0329 }
0330
0331 static blk_status_t clariion_prep_fn(struct scsi_device *sdev,
0332 struct request *req)
0333 {
0334 struct clariion_dh_data *h = sdev->handler_data;
0335
0336 if (h->lun_state != CLARIION_LUN_OWNED) {
0337 req->rq_flags |= RQF_QUIET;
0338 return BLK_STS_IOERR;
0339 }
0340
0341 return BLK_STS_OK;
0342 }
0343
0344 static int clariion_std_inquiry(struct scsi_device *sdev,
0345 struct clariion_dh_data *csdev)
0346 {
0347 int err = SCSI_DH_OK;
0348 char *sp_model;
0349
0350 sp_model = parse_sp_model(sdev, sdev->inquiry);
0351 if (!sp_model) {
0352 err = SCSI_DH_DEV_UNSUPP;
0353 goto out;
0354 }
0355
0356
0357
0358
0359 if (!strlen(sp_model) || !strncmp(sp_model, "FC",2))
0360 csdev->flags |= CLARIION_SHORT_TRESPASS;
0361
0362 sdev_printk(KERN_INFO, sdev,
0363 "%s: detected Clariion %s, flags %x\n",
0364 CLARIION_NAME, sp_model, csdev->flags);
0365 out:
0366 return err;
0367 }
0368
0369 static int clariion_send_inquiry(struct scsi_device *sdev,
0370 struct clariion_dh_data *csdev)
0371 {
0372 int err = SCSI_DH_IO;
0373
0374 if (!scsi_get_vpd_page(sdev, 0xC0, csdev->buffer,
0375 CLARIION_BUFFER_SIZE))
0376 err = parse_sp_info_reply(sdev, csdev);
0377
0378 return err;
0379 }
0380
0381 static int clariion_activate(struct scsi_device *sdev,
0382 activate_complete fn, void *data)
0383 {
0384 struct clariion_dh_data *csdev = sdev->handler_data;
0385 int result;
0386
0387 result = clariion_send_inquiry(sdev, csdev);
0388 if (result != SCSI_DH_OK)
0389 goto done;
0390
0391 if (csdev->lun_state == CLARIION_LUN_OWNED)
0392 goto done;
0393
0394 result = send_trespass_cmd(sdev, csdev);
0395 if (result != SCSI_DH_OK)
0396 goto done;
0397 sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n",
0398 CLARIION_NAME,
0399 csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" );
0400
0401
0402 result = clariion_send_inquiry(sdev, csdev);
0403 if (result != SCSI_DH_OK)
0404 goto done;
0405
0406 done:
0407 sdev_printk(KERN_INFO, sdev,
0408 "%s: at SP %c Port %d (%s, default SP %c)\n",
0409 CLARIION_NAME, csdev->current_sp + 'A',
0410 csdev->port, lun_state[csdev->lun_state],
0411 csdev->default_sp + 'A');
0412
0413 if (fn)
0414 fn(data, result);
0415 return 0;
0416 }
0417
0418
0419
0420
0421
0422
0423 static int clariion_set_params(struct scsi_device *sdev, const char *params)
0424 {
0425 struct clariion_dh_data *csdev = sdev->handler_data;
0426 unsigned int hr = 0, st = 0, argc;
0427 const char *p = params;
0428 int result = SCSI_DH_OK;
0429
0430 if ((sscanf(params, "%u", &argc) != 1) || (argc != 2))
0431 return -EINVAL;
0432
0433 while (*p++)
0434 ;
0435 if ((sscanf(p, "%u", &st) != 1) || (st > 1))
0436 return -EINVAL;
0437
0438 while (*p++)
0439 ;
0440 if ((sscanf(p, "%u", &hr) != 1) || (hr > 1))
0441 return -EINVAL;
0442
0443 if (st)
0444 csdev->flags |= CLARIION_SHORT_TRESPASS;
0445 else
0446 csdev->flags &= ~CLARIION_SHORT_TRESPASS;
0447
0448 if (hr)
0449 csdev->flags |= CLARIION_HONOR_RESERVATIONS;
0450 else
0451 csdev->flags &= ~CLARIION_HONOR_RESERVATIONS;
0452
0453
0454
0455
0456
0457
0458 if (csdev->lun_state != CLARIION_LUN_OWNED)
0459 goto done;
0460
0461 csdev->lun_state = CLARIION_LUN_UNINITIALIZED;
0462 result = send_trespass_cmd(sdev, csdev);
0463 if (result != SCSI_DH_OK)
0464 goto done;
0465
0466
0467 result = clariion_send_inquiry(sdev, csdev);
0468
0469 done:
0470 return result;
0471 }
0472
0473 static int clariion_bus_attach(struct scsi_device *sdev)
0474 {
0475 struct clariion_dh_data *h;
0476 int err;
0477
0478 h = kzalloc(sizeof(*h) , GFP_KERNEL);
0479 if (!h)
0480 return SCSI_DH_NOMEM;
0481 h->lun_state = CLARIION_LUN_UNINITIALIZED;
0482 h->default_sp = CLARIION_UNBOUND_LU;
0483 h->current_sp = CLARIION_UNBOUND_LU;
0484
0485 err = clariion_std_inquiry(sdev, h);
0486 if (err != SCSI_DH_OK)
0487 goto failed;
0488
0489 err = clariion_send_inquiry(sdev, h);
0490 if (err != SCSI_DH_OK)
0491 goto failed;
0492
0493 sdev_printk(KERN_INFO, sdev,
0494 "%s: connected to SP %c Port %d (%s, default SP %c)\n",
0495 CLARIION_NAME, h->current_sp + 'A',
0496 h->port, lun_state[h->lun_state],
0497 h->default_sp + 'A');
0498
0499 sdev->handler_data = h;
0500 return SCSI_DH_OK;
0501
0502 failed:
0503 kfree(h);
0504 return err;
0505 }
0506
0507 static void clariion_bus_detach(struct scsi_device *sdev)
0508 {
0509 kfree(sdev->handler_data);
0510 sdev->handler_data = NULL;
0511 }
0512
0513 static struct scsi_device_handler clariion_dh = {
0514 .name = CLARIION_NAME,
0515 .module = THIS_MODULE,
0516 .attach = clariion_bus_attach,
0517 .detach = clariion_bus_detach,
0518 .check_sense = clariion_check_sense,
0519 .activate = clariion_activate,
0520 .prep_fn = clariion_prep_fn,
0521 .set_params = clariion_set_params,
0522 };
0523
0524 static int __init clariion_init(void)
0525 {
0526 int r;
0527
0528 r = scsi_register_device_handler(&clariion_dh);
0529 if (r != 0)
0530 printk(KERN_ERR "%s: Failed to register scsi device handler.",
0531 CLARIION_NAME);
0532 return r;
0533 }
0534
0535 static void __exit clariion_exit(void)
0536 {
0537 scsi_unregister_device_handler(&clariion_dh);
0538 }
0539
0540 module_init(clariion_init);
0541 module_exit(clariion_exit);
0542
0543 MODULE_DESCRIPTION("EMC CX/AX/FC-family driver");
0544 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, Chandra Seetharaman <sekharan@us.ibm.com>");
0545 MODULE_LICENSE("GPL");