diff options
-rw-r--r-- | Documentation/cciss.txt | 21 | ||||
-rw-r--r-- | drivers/block/cciss_scsi.c | 157 |
2 files changed, 124 insertions, 54 deletions
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt index 63e59b8847c5..8244c6442faa 100644 --- a/Documentation/cciss.txt +++ b/Documentation/cciss.txt | |||
@@ -112,27 +112,18 @@ Hot plug support for SCSI tape drives | |||
112 | 112 | ||
113 | Hot plugging of SCSI tape drives is supported, with some caveats. | 113 | Hot plugging of SCSI tape drives is supported, with some caveats. |
114 | The cciss driver must be informed that changes to the SCSI bus | 114 | The cciss driver must be informed that changes to the SCSI bus |
115 | have been made, in addition to and prior to informing the SCSI | 115 | have been made. This may be done via the /proc filesystem. |
116 | mid layer. This may be done via the /proc filesystem. For example: | 116 | For example: |
117 | 117 | ||
118 | echo "rescan" > /proc/scsi/cciss0/1 | 118 | echo "rescan" > /proc/scsi/cciss0/1 |
119 | 119 | ||
120 | This causes the adapter to query the adapter about changes to the | 120 | This causes the driver to query the adapter about changes to the |
121 | physical SCSI buses and/or fibre channel arbitrated loop and the | 121 | physical SCSI buses and/or fibre channel arbitrated loop and the |
122 | driver to make note of any new or removed sequential access devices | 122 | driver to make note of any new or removed sequential access devices |
123 | or medium changers. The driver will output messages indicating what | 123 | or medium changers. The driver will output messages indicating what |
124 | devices have been added or removed and the controller, bus, target and | 124 | devices have been added or removed and the controller, bus, target and |
125 | lun used to address the device. Once this is done, the SCSI mid layer | 125 | lun used to address the device. It then notifies the SCSI mid layer |
126 | can be informed of changes to the virtual SCSI bus which the driver | 126 | of these changes. |
127 | presents to it in the usual way. For example: | ||
128 | |||
129 | echo scsi add-single-device 3 2 1 0 > /proc/scsi/scsi | ||
130 | |||
131 | to add a device on controller 3, bus 2, target 1, lun 0. Note that | ||
132 | the driver makes an effort to preserve the devices positions | ||
133 | in the virtual SCSI bus, so if you are only moving tape drives | ||
134 | around on the same adapter and not adding or removing tape drives | ||
135 | from the adapter, informing the SCSI mid layer may not be necessary. | ||
136 | 127 | ||
137 | Note that the naming convention of the /proc filesystem entries | 128 | Note that the naming convention of the /proc filesystem entries |
138 | contains a number in addition to the driver name. (E.g. "cciss0" | 129 | contains a number in addition to the driver name. (E.g. "cciss0" |
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e4bf9a11ca0d..c673ff14126a 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -358,10 +358,15 @@ find_bus_target_lun(int ctlr, int *bus, int *target, int *lun) | |||
358 | } | 358 | } |
359 | return (!found); | 359 | return (!found); |
360 | } | 360 | } |
361 | struct scsi2map { | ||
362 | char scsi3addr[8]; | ||
363 | int bus, target, lun; | ||
364 | }; | ||
361 | 365 | ||
362 | static int | 366 | static int |
363 | cciss_scsi_add_entry(int ctlr, int hostno, | 367 | cciss_scsi_add_entry(int ctlr, int hostno, |
364 | unsigned char *scsi3addr, int devtype) | 368 | unsigned char *scsi3addr, int devtype, |
369 | struct scsi2map *added, int *nadded) | ||
365 | { | 370 | { |
366 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ | 371 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ |
367 | int n = ccissscsi[ctlr].ndevices; | 372 | int n = ccissscsi[ctlr].ndevices; |
@@ -375,6 +380,12 @@ cciss_scsi_add_entry(int ctlr, int hostno, | |||
375 | sd = &ccissscsi[ctlr].dev[n]; | 380 | sd = &ccissscsi[ctlr].dev[n]; |
376 | if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0) | 381 | if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0) |
377 | return -1; | 382 | return -1; |
383 | |||
384 | added[*nadded].bus = sd->bus; | ||
385 | added[*nadded].target = sd->target; | ||
386 | added[*nadded].lun = sd->lun; | ||
387 | (*nadded)++; | ||
388 | |||
378 | memcpy(&sd->scsi3addr[0], scsi3addr, 8); | 389 | memcpy(&sd->scsi3addr[0], scsi3addr, 8); |
379 | sd->devtype = devtype; | 390 | sd->devtype = devtype; |
380 | ccissscsi[ctlr].ndevices++; | 391 | ccissscsi[ctlr].ndevices++; |
@@ -390,7 +401,8 @@ cciss_scsi_add_entry(int ctlr, int hostno, | |||
390 | } | 401 | } |
391 | 402 | ||
392 | static void | 403 | static void |
393 | cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | 404 | cciss_scsi_remove_entry(int ctlr, int hostno, int entry, |
405 | struct scsi2map *removed, int *nremoved) | ||
394 | { | 406 | { |
395 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ | 407 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ |
396 | int i; | 408 | int i; |
@@ -398,6 +410,10 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | |||
398 | 410 | ||
399 | if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; | 411 | if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; |
400 | sd = ccissscsi[ctlr].dev[entry]; | 412 | sd = ccissscsi[ctlr].dev[entry]; |
413 | removed[*nremoved].bus = sd.bus; | ||
414 | removed[*nremoved].target = sd.target; | ||
415 | removed[*nremoved].lun = sd.lun; | ||
416 | (*nremoved)++; | ||
401 | for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++) | 417 | for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++) |
402 | ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1]; | 418 | ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1]; |
403 | ccissscsi[ctlr].ndevices--; | 419 | ccissscsi[ctlr].ndevices--; |
@@ -417,6 +433,26 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | |||
417 | (a)[1] == (b)[1] && \ | 433 | (a)[1] == (b)[1] && \ |
418 | (a)[0] == (b)[0]) | 434 | (a)[0] == (b)[0]) |
419 | 435 | ||
436 | static void fixup_botched_add(int ctlr, char *scsi3addr) | ||
437 | { | ||
438 | /* called when scsi_add_device fails in order to re-adjust */ | ||
439 | /* ccissscsi[] to match the mid layer's view. */ | ||
440 | unsigned long flags; | ||
441 | int i, j; | ||
442 | CPQ_TAPE_LOCK(ctlr, flags); | ||
443 | for (i = 0; i < ccissscsi[ctlr].ndevices; i++) { | ||
444 | if (memcmp(scsi3addr, | ||
445 | ccissscsi[ctlr].dev[i].scsi3addr, 8) == 0) { | ||
446 | for (j = i; j < ccissscsi[ctlr].ndevices-1; j++) | ||
447 | ccissscsi[ctlr].dev[j] = | ||
448 | ccissscsi[ctlr].dev[j+1]; | ||
449 | ccissscsi[ctlr].ndevices--; | ||
450 | break; | ||
451 | } | ||
452 | } | ||
453 | CPQ_TAPE_UNLOCK(ctlr, flags); | ||
454 | } | ||
455 | |||
420 | static int | 456 | static int |
421 | adjust_cciss_scsi_table(int ctlr, int hostno, | 457 | adjust_cciss_scsi_table(int ctlr, int hostno, |
422 | struct cciss_scsi_dev_t sd[], int nsds) | 458 | struct cciss_scsi_dev_t sd[], int nsds) |
@@ -429,13 +465,33 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
429 | int i,j, found, changes=0; | 465 | int i,j, found, changes=0; |
430 | struct cciss_scsi_dev_t *csd; | 466 | struct cciss_scsi_dev_t *csd; |
431 | unsigned long flags; | 467 | unsigned long flags; |
468 | struct scsi2map *added, *removed; | ||
469 | int nadded, nremoved; | ||
470 | struct Scsi_Host *sh = NULL; | ||
471 | |||
472 | added = kzalloc(sizeof(*added) * CCISS_MAX_SCSI_DEVS_PER_HBA, | ||
473 | GFP_KERNEL); | ||
474 | removed = kzalloc(sizeof(*removed) * CCISS_MAX_SCSI_DEVS_PER_HBA, | ||
475 | GFP_KERNEL); | ||
476 | |||
477 | if (!added || !removed) { | ||
478 | printk(KERN_WARNING "cciss%d: Out of memory in " | ||
479 | "adjust_cciss_scsi_table\n", ctlr); | ||
480 | goto free_and_out; | ||
481 | } | ||
432 | 482 | ||
433 | CPQ_TAPE_LOCK(ctlr, flags); | 483 | CPQ_TAPE_LOCK(ctlr, flags); |
434 | 484 | ||
485 | if (hostno != -1) /* if it's not the first time... */ | ||
486 | sh = ((struct cciss_scsi_adapter_data_t *) | ||
487 | hba[ctlr]->scsi_ctlr)->scsi_host; | ||
488 | |||
435 | /* find any devices in ccissscsi[] that are not in | 489 | /* find any devices in ccissscsi[] that are not in |
436 | sd[] and remove them from ccissscsi[] */ | 490 | sd[] and remove them from ccissscsi[] */ |
437 | 491 | ||
438 | i = 0; | 492 | i = 0; |
493 | nremoved = 0; | ||
494 | nadded = 0; | ||
439 | while(i<ccissscsi[ctlr].ndevices) { | 495 | while(i<ccissscsi[ctlr].ndevices) { |
440 | csd = &ccissscsi[ctlr].dev[i]; | 496 | csd = &ccissscsi[ctlr].dev[i]; |
441 | found=0; | 497 | found=0; |
@@ -455,8 +511,9 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
455 | /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n", | 511 | /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n", |
456 | ctlr, scsi_device_type(csd->devtype), hostno, | 512 | ctlr, scsi_device_type(csd->devtype), hostno, |
457 | csd->bus, csd->target, csd->lun); */ | 513 | csd->bus, csd->target, csd->lun); */ |
458 | cciss_scsi_remove_entry(ctlr, hostno, i); | 514 | cciss_scsi_remove_entry(ctlr, hostno, i, |
459 | /* note, i not incremented */ | 515 | removed, &nremoved); |
516 | /* remove ^^^, hence i not incremented */ | ||
460 | } | 517 | } |
461 | else if (found == 1) { /* device is different kind */ | 518 | else if (found == 1) { /* device is different kind */ |
462 | changes++; | 519 | changes++; |
@@ -464,8 +521,15 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
464 | "(device type now %s).\n", | 521 | "(device type now %s).\n", |
465 | ctlr, hostno, csd->bus, csd->target, csd->lun, | 522 | ctlr, hostno, csd->bus, csd->target, csd->lun, |
466 | scsi_device_type(csd->devtype)); | 523 | scsi_device_type(csd->devtype)); |
524 | cciss_scsi_remove_entry(ctlr, hostno, i, | ||
525 | removed, &nremoved); | ||
526 | /* remove ^^^, hence i not incremented */ | ||
527 | if (cciss_scsi_add_entry(ctlr, hostno, | ||
528 | &sd[j].scsi3addr[0], sd[j].devtype, | ||
529 | added, &nadded) != 0) | ||
530 | /* we just removed one, so add can't fail. */ | ||
531 | BUG(); | ||
467 | csd->devtype = sd[j].devtype; | 532 | csd->devtype = sd[j].devtype; |
468 | i++; /* so just move along. */ | ||
469 | } else /* device is same as it ever was, */ | 533 | } else /* device is same as it ever was, */ |
470 | i++; /* so just move along. */ | 534 | i++; /* so just move along. */ |
471 | } | 535 | } |
@@ -489,7 +553,9 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
489 | if (!found) { | 553 | if (!found) { |
490 | changes++; | 554 | changes++; |
491 | if (cciss_scsi_add_entry(ctlr, hostno, | 555 | if (cciss_scsi_add_entry(ctlr, hostno, |
492 | &sd[i].scsi3addr[0], sd[i].devtype) != 0) | 556 | |
557 | &sd[i].scsi3addr[0], sd[i].devtype, | ||
558 | added, &nadded) != 0) | ||
493 | break; | 559 | break; |
494 | } else if (found == 1) { | 560 | } else if (found == 1) { |
495 | /* should never happen... */ | 561 | /* should never happen... */ |
@@ -501,9 +567,50 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
501 | } | 567 | } |
502 | CPQ_TAPE_UNLOCK(ctlr, flags); | 568 | CPQ_TAPE_UNLOCK(ctlr, flags); |
503 | 569 | ||
504 | if (!changes) | 570 | /* Don't notify scsi mid layer of any changes the first time through */ |
505 | printk("cciss%d: No device changes detected.\n", ctlr); | 571 | /* (or if there are no changes) scsi_scan_host will do it later the */ |
572 | /* first time through. */ | ||
573 | if (hostno == -1 || !changes) | ||
574 | goto free_and_out; | ||
575 | |||
576 | /* Notify scsi mid layer of any removed devices */ | ||
577 | for (i = 0; i < nremoved; i++) { | ||
578 | struct scsi_device *sdev = | ||
579 | scsi_device_lookup(sh, removed[i].bus, | ||
580 | removed[i].target, removed[i].lun); | ||
581 | if (sdev != NULL) { | ||
582 | scsi_remove_device(sdev); | ||
583 | scsi_device_put(sdev); | ||
584 | } else { | ||
585 | /* We don't expect to get here. */ | ||
586 | /* future cmds to this device will get selection */ | ||
587 | /* timeout as if the device was gone. */ | ||
588 | printk(KERN_WARNING "cciss%d: didn't find " | ||
589 | "c%db%dt%dl%d\n for removal.", | ||
590 | ctlr, hostno, removed[i].bus, | ||
591 | removed[i].target, removed[i].lun); | ||
592 | } | ||
593 | } | ||
594 | |||
595 | /* Notify scsi mid layer of any added devices */ | ||
596 | for (i = 0; i < nadded; i++) { | ||
597 | int rc; | ||
598 | rc = scsi_add_device(sh, added[i].bus, | ||
599 | added[i].target, added[i].lun); | ||
600 | if (rc == 0) | ||
601 | continue; | ||
602 | printk(KERN_WARNING "cciss%d: scsi_add_device " | ||
603 | "c%db%dt%dl%d failed, device not added.\n", | ||
604 | ctlr, hostno, | ||
605 | added[i].bus, added[i].target, added[i].lun); | ||
606 | /* now we have to remove it from ccissscsi, */ | ||
607 | /* since it didn't get added to scsi mid layer */ | ||
608 | fixup_botched_add(ctlr, added[i].scsi3addr); | ||
609 | } | ||
506 | 610 | ||
611 | free_and_out: | ||
612 | kfree(added); | ||
613 | kfree(removed); | ||
507 | return 0; | 614 | return 0; |
508 | } | 615 | } |
509 | 616 | ||
@@ -1355,32 +1462,6 @@ cciss_unregister_scsi(int ctlr) | |||
1355 | } | 1462 | } |
1356 | 1463 | ||
1357 | static int | 1464 | static int |
1358 | cciss_register_scsi(int ctlr) | ||
1359 | { | ||
1360 | unsigned long flags; | ||
1361 | |||
1362 | CPQ_TAPE_LOCK(ctlr, flags); | ||
1363 | |||
1364 | /* Since this is really a block driver, the SCSI core may not be | ||
1365 | initialized at init time, in which case, calling scsi_register_host | ||
1366 | would hang. Instead, we do it later, via /proc filesystem | ||
1367 | and rc scripts, when we know SCSI core is good to go. */ | ||
1368 | |||
1369 | /* Only register if SCSI devices are detected. */ | ||
1370 | if (ccissscsi[ctlr].ndevices != 0) { | ||
1371 | ((struct cciss_scsi_adapter_data_t *) | ||
1372 | hba[ctlr]->scsi_ctlr)->registered = 1; | ||
1373 | CPQ_TAPE_UNLOCK(ctlr, flags); | ||
1374 | return cciss_scsi_detect(ctlr); | ||
1375 | } | ||
1376 | CPQ_TAPE_UNLOCK(ctlr, flags); | ||
1377 | printk(KERN_INFO | ||
1378 | "cciss%d: No appropriate SCSI device detected, " | ||
1379 | "SCSI subsystem not engaged.\n", ctlr); | ||
1380 | return 0; | ||
1381 | } | ||
1382 | |||
1383 | static int | ||
1384 | cciss_engage_scsi(int ctlr) | 1465 | cciss_engage_scsi(int ctlr) |
1385 | { | 1466 | { |
1386 | struct cciss_scsi_adapter_data_t *sa; | 1467 | struct cciss_scsi_adapter_data_t *sa; |
@@ -1391,15 +1472,15 @@ cciss_engage_scsi(int ctlr) | |||
1391 | sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; | 1472 | sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; |
1392 | stk = &sa->cmd_stack; | 1473 | stk = &sa->cmd_stack; |
1393 | 1474 | ||
1394 | if (((struct cciss_scsi_adapter_data_t *) | 1475 | if (sa->registered) { |
1395 | hba[ctlr]->scsi_ctlr)->registered) { | ||
1396 | printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); | 1476 | printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); |
1397 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1477 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
1398 | return ENXIO; | 1478 | return ENXIO; |
1399 | } | 1479 | } |
1480 | sa->registered = 1; | ||
1400 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1481 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
1401 | cciss_update_non_disk_devices(ctlr, -1); | 1482 | cciss_update_non_disk_devices(ctlr, -1); |
1402 | cciss_register_scsi(ctlr); | 1483 | cciss_scsi_detect(ctlr); |
1403 | return 0; | 1484 | return 0; |
1404 | } | 1485 | } |
1405 | 1486 | ||
@@ -1493,7 +1574,5 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) | |||
1493 | /* If no tape support, then these become defined out of existence */ | 1574 | /* If no tape support, then these become defined out of existence */ |
1494 | 1575 | ||
1495 | #define cciss_scsi_setup(cntl_num) | 1576 | #define cciss_scsi_setup(cntl_num) |
1496 | #define cciss_unregister_scsi(ctlr) | ||
1497 | #define cciss_register_scsi(ctlr) | ||
1498 | 1577 | ||
1499 | #endif /* CONFIG_CISS_SCSI_TAPE */ | 1578 | #endif /* CONFIG_CISS_SCSI_TAPE */ |