diff options
author | scameron@beardog.cca.cpqcorp.net <scameron@beardog.cca.cpqcorp.net> | 2008-09-19 21:27:47 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-10-09 02:56:18 -0400 |
commit | 905bd78f2188da69e74966918e3d71df3dff382b (patch) | |
tree | bfe96fedd70cf56a9a7c1585bc7f5965c3fb47e3 /drivers/block | |
parent | 79eb014578b79fcfb9d9e7dc979d1316079220aa (diff) |
cciss: Fix cciss SCSI rescan code to better notice device changes
Fix cciss SCSI rescan code to better notice device changes.
If you hot-unplug a tape drive, then hot-plug a different
tape drive into the same slot in a storage enclosure,
the cciss driver wouldn't notice anything had changed, as
it was only looking at the LUN address and device type.
Now it looks at the inquiry page 0x83 device identifier,
and vendor and model strings as well.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cca.cpqcorp.net>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/cciss_scsi.c | 151 | ||||
-rw-r--r-- | drivers/block/cciss_scsi.h | 4 |
2 files changed, 102 insertions, 53 deletions
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e1233aabda77..a3fd87b41444 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -365,7 +365,7 @@ struct scsi2map { | |||
365 | 365 | ||
366 | static int | 366 | static int |
367 | cciss_scsi_add_entry(int ctlr, int hostno, | 367 | cciss_scsi_add_entry(int ctlr, int hostno, |
368 | unsigned char *scsi3addr, int devtype, | 368 | struct cciss_scsi_dev_t *device, |
369 | struct scsi2map *added, int *nadded) | 369 | struct scsi2map *added, int *nadded) |
370 | { | 370 | { |
371 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ | 371 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ |
@@ -384,12 +384,12 @@ cciss_scsi_add_entry(int ctlr, int hostno, | |||
384 | lun = 0; | 384 | lun = 0; |
385 | /* Is this device a non-zero lun of a multi-lun device */ | 385 | /* Is this device a non-zero lun of a multi-lun device */ |
386 | /* byte 4 of the 8-byte LUN addr will contain the logical unit no. */ | 386 | /* byte 4 of the 8-byte LUN addr will contain the logical unit no. */ |
387 | if (scsi3addr[4] != 0) { | 387 | if (device->scsi3addr[4] != 0) { |
388 | /* Search through our list and find the device which */ | 388 | /* Search through our list and find the device which */ |
389 | /* has the same 8 byte LUN address, excepting byte 4. */ | 389 | /* has the same 8 byte LUN address, excepting byte 4. */ |
390 | /* Assign the same bus and target for this new LUN. */ | 390 | /* Assign the same bus and target for this new LUN. */ |
391 | /* Use the logical unit number from the firmware. */ | 391 | /* Use the logical unit number from the firmware. */ |
392 | memcpy(addr1, scsi3addr, 8); | 392 | memcpy(addr1, device->scsi3addr, 8); |
393 | addr1[4] = 0; | 393 | addr1[4] = 0; |
394 | for (i = 0; i < n; i++) { | 394 | for (i = 0; i < n; i++) { |
395 | sd = &ccissscsi[ctlr].dev[i]; | 395 | sd = &ccissscsi[ctlr].dev[i]; |
@@ -399,7 +399,7 @@ cciss_scsi_add_entry(int ctlr, int hostno, | |||
399 | if (memcmp(addr1, addr2, 8) == 0) { | 399 | if (memcmp(addr1, addr2, 8) == 0) { |
400 | bus = sd->bus; | 400 | bus = sd->bus; |
401 | target = sd->target; | 401 | target = sd->target; |
402 | lun = scsi3addr[4]; | 402 | lun = device->scsi3addr[4]; |
403 | break; | 403 | break; |
404 | } | 404 | } |
405 | } | 405 | } |
@@ -420,8 +420,12 @@ cciss_scsi_add_entry(int ctlr, int hostno, | |||
420 | added[*nadded].lun = sd->lun; | 420 | added[*nadded].lun = sd->lun; |
421 | (*nadded)++; | 421 | (*nadded)++; |
422 | 422 | ||
423 | memcpy(&sd->scsi3addr[0], scsi3addr, 8); | 423 | memcpy(sd->scsi3addr, device->scsi3addr, 8); |
424 | sd->devtype = devtype; | 424 | memcpy(sd->vendor, device->vendor, sizeof(sd->vendor)); |
425 | memcpy(sd->revision, device->revision, sizeof(sd->revision)); | ||
426 | memcpy(sd->device_id, device->device_id, sizeof(sd->device_id)); | ||
427 | sd->devtype = device->devtype; | ||
428 | |||
425 | ccissscsi[ctlr].ndevices++; | 429 | ccissscsi[ctlr].ndevices++; |
426 | 430 | ||
427 | /* initially, (before registering with scsi layer) we don't | 431 | /* initially, (before registering with scsi layer) we don't |
@@ -487,6 +491,22 @@ static void fixup_botched_add(int ctlr, char *scsi3addr) | |||
487 | CPQ_TAPE_UNLOCK(ctlr, flags); | 491 | CPQ_TAPE_UNLOCK(ctlr, flags); |
488 | } | 492 | } |
489 | 493 | ||
494 | static int device_is_the_same(struct cciss_scsi_dev_t *dev1, | ||
495 | struct cciss_scsi_dev_t *dev2) | ||
496 | { | ||
497 | return dev1->devtype == dev2->devtype && | ||
498 | memcmp(dev1->scsi3addr, dev2->scsi3addr, | ||
499 | sizeof(dev1->scsi3addr)) == 0 && | ||
500 | memcmp(dev1->device_id, dev2->device_id, | ||
501 | sizeof(dev1->device_id)) == 0 && | ||
502 | memcmp(dev1->vendor, dev2->vendor, | ||
503 | sizeof(dev1->vendor)) == 0 && | ||
504 | memcmp(dev1->model, dev2->model, | ||
505 | sizeof(dev1->model)) == 0 && | ||
506 | memcmp(dev1->revision, dev2->revision, | ||
507 | sizeof(dev1->revision)) == 0; | ||
508 | } | ||
509 | |||
490 | static int | 510 | static int |
491 | adjust_cciss_scsi_table(int ctlr, int hostno, | 511 | adjust_cciss_scsi_table(int ctlr, int hostno, |
492 | struct cciss_scsi_dev_t sd[], int nsds) | 512 | struct cciss_scsi_dev_t sd[], int nsds) |
@@ -532,7 +552,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
532 | for (j=0;j<nsds;j++) { | 552 | for (j=0;j<nsds;j++) { |
533 | if (SCSI3ADDR_EQ(sd[j].scsi3addr, | 553 | if (SCSI3ADDR_EQ(sd[j].scsi3addr, |
534 | csd->scsi3addr)) { | 554 | csd->scsi3addr)) { |
535 | if (sd[j].devtype == csd->devtype) | 555 | if (device_is_the_same(&sd[j], csd)) |
536 | found=2; | 556 | found=2; |
537 | else | 557 | else |
538 | found=1; | 558 | found=1; |
@@ -548,22 +568,26 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
548 | cciss_scsi_remove_entry(ctlr, hostno, i, | 568 | cciss_scsi_remove_entry(ctlr, hostno, i, |
549 | removed, &nremoved); | 569 | removed, &nremoved); |
550 | /* remove ^^^, hence i not incremented */ | 570 | /* remove ^^^, hence i not incremented */ |
551 | } | 571 | } else if (found == 1) { /* device is different in some way */ |
552 | else if (found == 1) { /* device is different kind */ | ||
553 | changes++; | 572 | changes++; |
554 | printk("cciss%d: device c%db%dt%dl%d type changed " | 573 | printk("cciss%d: device c%db%dt%dl%d has changed.\n", |
555 | "(device type now %s).\n", | 574 | ctlr, hostno, csd->bus, csd->target, csd->lun); |
556 | ctlr, hostno, csd->bus, csd->target, csd->lun, | ||
557 | scsi_device_type(csd->devtype)); | ||
558 | cciss_scsi_remove_entry(ctlr, hostno, i, | 575 | cciss_scsi_remove_entry(ctlr, hostno, i, |
559 | removed, &nremoved); | 576 | removed, &nremoved); |
560 | /* remove ^^^, hence i not incremented */ | 577 | /* remove ^^^, hence i not incremented */ |
561 | if (cciss_scsi_add_entry(ctlr, hostno, | 578 | if (cciss_scsi_add_entry(ctlr, hostno, &sd[j], |
562 | &sd[j].scsi3addr[0], sd[j].devtype, | ||
563 | added, &nadded) != 0) | 579 | added, &nadded) != 0) |
564 | /* we just removed one, so add can't fail. */ | 580 | /* we just removed one, so add can't fail. */ |
565 | BUG(); | 581 | BUG(); |
566 | csd->devtype = sd[j].devtype; | 582 | csd->devtype = sd[j].devtype; |
583 | memcpy(csd->device_id, sd[j].device_id, | ||
584 | sizeof(csd->device_id)); | ||
585 | memcpy(csd->vendor, sd[j].vendor, | ||
586 | sizeof(csd->vendor)); | ||
587 | memcpy(csd->model, sd[j].model, | ||
588 | sizeof(csd->model)); | ||
589 | memcpy(csd->revision, sd[j].revision, | ||
590 | sizeof(csd->revision)); | ||
567 | } else /* device is same as it ever was, */ | 591 | } else /* device is same as it ever was, */ |
568 | i++; /* so just move along. */ | 592 | i++; /* so just move along. */ |
569 | } | 593 | } |
@@ -577,7 +601,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
577 | csd = &ccissscsi[ctlr].dev[j]; | 601 | csd = &ccissscsi[ctlr].dev[j]; |
578 | if (SCSI3ADDR_EQ(sd[i].scsi3addr, | 602 | if (SCSI3ADDR_EQ(sd[i].scsi3addr, |
579 | csd->scsi3addr)) { | 603 | csd->scsi3addr)) { |
580 | if (sd[i].devtype == csd->devtype) | 604 | if (device_is_the_same(&sd[i], csd)) |
581 | found=2; /* found device */ | 605 | found=2; /* found device */ |
582 | else | 606 | else |
583 | found=1; /* found a bug. */ | 607 | found=1; /* found a bug. */ |
@@ -586,16 +610,14 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
586 | } | 610 | } |
587 | if (!found) { | 611 | if (!found) { |
588 | changes++; | 612 | changes++; |
589 | if (cciss_scsi_add_entry(ctlr, hostno, | 613 | if (cciss_scsi_add_entry(ctlr, hostno, &sd[i], |
590 | |||
591 | &sd[i].scsi3addr[0], sd[i].devtype, | ||
592 | added, &nadded) != 0) | 614 | added, &nadded) != 0) |
593 | break; | 615 | break; |
594 | } else if (found == 1) { | 616 | } else if (found == 1) { |
595 | /* should never happen... */ | 617 | /* should never happen... */ |
596 | changes++; | 618 | changes++; |
597 | printk("cciss%d: device unexpectedly changed type\n", | 619 | printk(KERN_WARNING "cciss%d: device " |
598 | ctlr); | 620 | "unexpectedly changed\n", ctlr); |
599 | /* but if it does happen, we just ignore that device */ | 621 | /* but if it does happen, we just ignore that device */ |
600 | } | 622 | } |
601 | } | 623 | } |
@@ -1012,7 +1034,8 @@ cciss_scsi_interpret_error(CommandList_struct *cp) | |||
1012 | 1034 | ||
1013 | static int | 1035 | static int |
1014 | cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, | 1036 | cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, |
1015 | unsigned char *buf, unsigned char bufsize) | 1037 | unsigned char page, unsigned char *buf, |
1038 | unsigned char bufsize) | ||
1016 | { | 1039 | { |
1017 | int rc; | 1040 | int rc; |
1018 | CommandList_struct *cp; | 1041 | CommandList_struct *cp; |
@@ -1032,8 +1055,8 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, | |||
1032 | ei = cp->err_info; | 1055 | ei = cp->err_info; |
1033 | 1056 | ||
1034 | cdb[0] = CISS_INQUIRY; | 1057 | cdb[0] = CISS_INQUIRY; |
1035 | cdb[1] = 0; | 1058 | cdb[1] = (page != 0); |
1036 | cdb[2] = 0; | 1059 | cdb[2] = page; |
1037 | cdb[3] = 0; | 1060 | cdb[3] = 0; |
1038 | cdb[4] = bufsize; | 1061 | cdb[4] = bufsize; |
1039 | cdb[5] = 0; | 1062 | cdb[5] = 0; |
@@ -1053,6 +1076,25 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, | |||
1053 | return rc; | 1076 | return rc; |
1054 | } | 1077 | } |
1055 | 1078 | ||
1079 | /* Get the device id from inquiry page 0x83 */ | ||
1080 | static int cciss_scsi_get_device_id(ctlr_info_t *c, unsigned char *scsi3addr, | ||
1081 | unsigned char *device_id, int buflen) | ||
1082 | { | ||
1083 | int rc; | ||
1084 | unsigned char *buf; | ||
1085 | |||
1086 | if (buflen > 16) | ||
1087 | buflen = 16; | ||
1088 | buf = kzalloc(64, GFP_KERNEL); | ||
1089 | if (!buf) | ||
1090 | return -1; | ||
1091 | rc = cciss_scsi_do_inquiry(c, scsi3addr, 0x83, buf, 64); | ||
1092 | if (rc == 0) | ||
1093 | memcpy(device_id, &buf[8], buflen); | ||
1094 | kfree(buf); | ||
1095 | return rc != 0; | ||
1096 | } | ||
1097 | |||
1056 | static int | 1098 | static int |
1057 | cciss_scsi_do_report_phys_luns(ctlr_info_t *c, | 1099 | cciss_scsi_do_report_phys_luns(ctlr_info_t *c, |
1058 | ReportLunData_struct *buf, int bufsize) | 1100 | ReportLunData_struct *buf, int bufsize) |
@@ -1142,25 +1184,21 @@ cciss_update_non_disk_devices(int cntl_num, int hostno) | |||
1142 | ctlr_info_t *c; | 1184 | ctlr_info_t *c; |
1143 | __u32 num_luns=0; | 1185 | __u32 num_luns=0; |
1144 | unsigned char *ch; | 1186 | unsigned char *ch; |
1145 | /* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */ | 1187 | struct cciss_scsi_dev_t *currentsd, *this_device; |
1146 | struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA]; | ||
1147 | int ncurrent=0; | 1188 | int ncurrent=0; |
1148 | int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8; | 1189 | int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8; |
1149 | int i; | 1190 | int i; |
1150 | 1191 | ||
1151 | c = (ctlr_info_t *) hba[cntl_num]; | 1192 | c = (ctlr_info_t *) hba[cntl_num]; |
1152 | ld_buff = kzalloc(reportlunsize, GFP_KERNEL); | 1193 | ld_buff = kzalloc(reportlunsize, GFP_KERNEL); |
1153 | if (ld_buff == NULL) { | ||
1154 | printk(KERN_ERR "cciss: out of memory\n"); | ||
1155 | return; | ||
1156 | } | ||
1157 | inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); | 1194 | inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); |
1158 | if (inq_buff == NULL) { | 1195 | currentsd = kzalloc(sizeof(*currentsd) * |
1159 | printk(KERN_ERR "cciss: out of memory\n"); | 1196 | (CCISS_MAX_SCSI_DEVS_PER_HBA+1), GFP_KERNEL); |
1160 | kfree(ld_buff); | 1197 | if (ld_buff == NULL || inq_buff == NULL || currentsd == NULL) { |
1161 | return; | 1198 | printk(KERN_ERR "cciss: out of memory\n"); |
1199 | goto out; | ||
1162 | } | 1200 | } |
1163 | 1201 | this_device = ¤tsd[CCISS_MAX_SCSI_DEVS_PER_HBA]; | |
1164 | if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) { | 1202 | if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) { |
1165 | ch = &ld_buff->LUNListLength[0]; | 1203 | ch = &ld_buff->LUNListLength[0]; |
1166 | num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8; | 1204 | num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8; |
@@ -1179,23 +1217,34 @@ cciss_update_non_disk_devices(int cntl_num, int hostno) | |||
1179 | 1217 | ||
1180 | 1218 | ||
1181 | /* adjust our table of devices */ | 1219 | /* adjust our table of devices */ |
1182 | for(i=0; i<num_luns; i++) | 1220 | for (i = 0; i < num_luns; i++) { |
1183 | { | ||
1184 | int devtype; | ||
1185 | |||
1186 | /* for each physical lun, do an inquiry */ | 1221 | /* for each physical lun, do an inquiry */ |
1187 | if (ld_buff->LUN[i][3] & 0xC0) continue; | 1222 | if (ld_buff->LUN[i][3] & 0xC0) continue; |
1188 | memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE); | 1223 | memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE); |
1189 | memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8); | 1224 | memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8); |
1190 | 1225 | ||
1191 | if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff, | 1226 | if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, 0, inq_buff, |
1192 | (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) { | 1227 | (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) |
1193 | /* Inquiry failed (msg printed already) */ | 1228 | /* Inquiry failed (msg printed already) */ |
1194 | devtype = 0; /* so we will skip this device. */ | 1229 | continue; /* so we will skip this device. */ |
1195 | } else /* what kind of device is this? */ | 1230 | |
1196 | devtype = (inq_buff[0] & 0x1f); | 1231 | this_device->devtype = (inq_buff[0] & 0x1f); |
1197 | 1232 | this_device->bus = -1; | |
1198 | switch (devtype) | 1233 | this_device->target = -1; |
1234 | this_device->lun = -1; | ||
1235 | memcpy(this_device->scsi3addr, scsi3addr, 8); | ||
1236 | memcpy(this_device->vendor, &inq_buff[8], | ||
1237 | sizeof(this_device->vendor)); | ||
1238 | memcpy(this_device->model, &inq_buff[16], | ||
1239 | sizeof(this_device->model)); | ||
1240 | memcpy(this_device->revision, &inq_buff[32], | ||
1241 | sizeof(this_device->revision)); | ||
1242 | memset(this_device->device_id, 0, | ||
1243 | sizeof(this_device->device_id)); | ||
1244 | cciss_scsi_get_device_id(hba[cntl_num], scsi3addr, | ||
1245 | this_device->device_id, sizeof(this_device->device_id)); | ||
1246 | |||
1247 | switch (this_device->devtype) | ||
1199 | { | 1248 | { |
1200 | case 0x05: /* CD-ROM */ { | 1249 | case 0x05: /* CD-ROM */ { |
1201 | 1250 | ||
@@ -1220,15 +1269,10 @@ cciss_update_non_disk_devices(int cntl_num, int hostno) | |||
1220 | if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) { | 1269 | if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) { |
1221 | printk(KERN_INFO "cciss%d: %s ignored, " | 1270 | printk(KERN_INFO "cciss%d: %s ignored, " |
1222 | "too many devices.\n", cntl_num, | 1271 | "too many devices.\n", cntl_num, |
1223 | scsi_device_type(devtype)); | 1272 | scsi_device_type(this_device->devtype)); |
1224 | break; | 1273 | break; |
1225 | } | 1274 | } |
1226 | memcpy(¤tsd[ncurrent].scsi3addr[0], | 1275 | currentsd[ncurrent] = *this_device; |
1227 | &scsi3addr[0], 8); | ||
1228 | currentsd[ncurrent].devtype = devtype; | ||
1229 | currentsd[ncurrent].bus = -1; | ||
1230 | currentsd[ncurrent].target = -1; | ||
1231 | currentsd[ncurrent].lun = -1; | ||
1232 | ncurrent++; | 1276 | ncurrent++; |
1233 | break; | 1277 | break; |
1234 | default: | 1278 | default: |
@@ -1240,6 +1284,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno) | |||
1240 | out: | 1284 | out: |
1241 | kfree(inq_buff); | 1285 | kfree(inq_buff); |
1242 | kfree(ld_buff); | 1286 | kfree(ld_buff); |
1287 | kfree(currentsd); | ||
1243 | return; | 1288 | return; |
1244 | } | 1289 | } |
1245 | 1290 | ||
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h index d9c2c586502f..7b750245ae76 100644 --- a/drivers/block/cciss_scsi.h +++ b/drivers/block/cciss_scsi.h | |||
@@ -66,6 +66,10 @@ struct cciss_scsi_dev_t { | |||
66 | int devtype; | 66 | int devtype; |
67 | int bus, target, lun; /* as presented to the OS */ | 67 | int bus, target, lun; /* as presented to the OS */ |
68 | unsigned char scsi3addr[8]; /* as presented to the HW */ | 68 | unsigned char scsi3addr[8]; /* as presented to the HW */ |
69 | unsigned char device_id[16]; /* from inquiry pg. 0x83 */ | ||
70 | unsigned char vendor[8]; /* bytes 8-15 of inquiry data */ | ||
71 | unsigned char model[16]; /* bytes 16-31 of inquiry data */ | ||
72 | unsigned char revision[4]; /* bytes 32-35 of inquiry data */ | ||
69 | }; | 73 | }; |
70 | 74 | ||
71 | struct cciss_scsi_hba_t { | 75 | struct cciss_scsi_hba_t { |