diff options
Diffstat (limited to 'drivers/block/cciss_scsi.c')
-rw-r--r-- | drivers/block/cciss_scsi.c | 195 |
1 files changed, 154 insertions, 41 deletions
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e4bf9a11ca0d..e1233aabda77 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -358,23 +358,68 @@ 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; |
368 | struct cciss_scsi_dev_t *sd; | 373 | struct cciss_scsi_dev_t *sd; |
374 | int i, bus, target, lun; | ||
375 | unsigned char addr1[8], addr2[8]; | ||
369 | 376 | ||
370 | if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) { | 377 | if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) { |
371 | printk("cciss%d: Too many devices, " | 378 | printk("cciss%d: Too many devices, " |
372 | "some will be inaccessible.\n", ctlr); | 379 | "some will be inaccessible.\n", ctlr); |
373 | return -1; | 380 | return -1; |
374 | } | 381 | } |
382 | |||
383 | bus = target = -1; | ||
384 | lun = 0; | ||
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. */ | ||
387 | if (scsi3addr[4] != 0) { | ||
388 | /* Search through our list and find the device which */ | ||
389 | /* has the same 8 byte LUN address, excepting byte 4. */ | ||
390 | /* Assign the same bus and target for this new LUN. */ | ||
391 | /* Use the logical unit number from the firmware. */ | ||
392 | memcpy(addr1, scsi3addr, 8); | ||
393 | addr1[4] = 0; | ||
394 | for (i = 0; i < n; i++) { | ||
395 | sd = &ccissscsi[ctlr].dev[i]; | ||
396 | memcpy(addr2, sd->scsi3addr, 8); | ||
397 | addr2[4] = 0; | ||
398 | /* differ only in byte 4? */ | ||
399 | if (memcmp(addr1, addr2, 8) == 0) { | ||
400 | bus = sd->bus; | ||
401 | target = sd->target; | ||
402 | lun = scsi3addr[4]; | ||
403 | break; | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | |||
375 | sd = &ccissscsi[ctlr].dev[n]; | 408 | sd = &ccissscsi[ctlr].dev[n]; |
376 | if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0) | 409 | if (lun == 0) { |
377 | return -1; | 410 | if (find_bus_target_lun(ctlr, |
411 | &sd->bus, &sd->target, &sd->lun) != 0) | ||
412 | return -1; | ||
413 | } else { | ||
414 | sd->bus = bus; | ||
415 | sd->target = target; | ||
416 | sd->lun = lun; | ||
417 | } | ||
418 | added[*nadded].bus = sd->bus; | ||
419 | added[*nadded].target = sd->target; | ||
420 | added[*nadded].lun = sd->lun; | ||
421 | (*nadded)++; | ||
422 | |||
378 | memcpy(&sd->scsi3addr[0], scsi3addr, 8); | 423 | memcpy(&sd->scsi3addr[0], scsi3addr, 8); |
379 | sd->devtype = devtype; | 424 | sd->devtype = devtype; |
380 | ccissscsi[ctlr].ndevices++; | 425 | ccissscsi[ctlr].ndevices++; |
@@ -390,7 +435,8 @@ cciss_scsi_add_entry(int ctlr, int hostno, | |||
390 | } | 435 | } |
391 | 436 | ||
392 | static void | 437 | static void |
393 | cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | 438 | cciss_scsi_remove_entry(int ctlr, int hostno, int entry, |
439 | struct scsi2map *removed, int *nremoved) | ||
394 | { | 440 | { |
395 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ | 441 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ |
396 | int i; | 442 | int i; |
@@ -398,6 +444,10 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | |||
398 | 444 | ||
399 | if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; | 445 | if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; |
400 | sd = ccissscsi[ctlr].dev[entry]; | 446 | sd = ccissscsi[ctlr].dev[entry]; |
447 | removed[*nremoved].bus = sd.bus; | ||
448 | removed[*nremoved].target = sd.target; | ||
449 | removed[*nremoved].lun = sd.lun; | ||
450 | (*nremoved)++; | ||
401 | for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++) | 451 | for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++) |
402 | ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1]; | 452 | ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1]; |
403 | ccissscsi[ctlr].ndevices--; | 453 | ccissscsi[ctlr].ndevices--; |
@@ -417,6 +467,26 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | |||
417 | (a)[1] == (b)[1] && \ | 467 | (a)[1] == (b)[1] && \ |
418 | (a)[0] == (b)[0]) | 468 | (a)[0] == (b)[0]) |
419 | 469 | ||
470 | static void fixup_botched_add(int ctlr, char *scsi3addr) | ||
471 | { | ||
472 | /* called when scsi_add_device fails in order to re-adjust */ | ||
473 | /* ccissscsi[] to match the mid layer's view. */ | ||
474 | unsigned long flags; | ||
475 | int i, j; | ||
476 | CPQ_TAPE_LOCK(ctlr, flags); | ||
477 | for (i = 0; i < ccissscsi[ctlr].ndevices; i++) { | ||
478 | if (memcmp(scsi3addr, | ||
479 | ccissscsi[ctlr].dev[i].scsi3addr, 8) == 0) { | ||
480 | for (j = i; j < ccissscsi[ctlr].ndevices-1; j++) | ||
481 | ccissscsi[ctlr].dev[j] = | ||
482 | ccissscsi[ctlr].dev[j+1]; | ||
483 | ccissscsi[ctlr].ndevices--; | ||
484 | break; | ||
485 | } | ||
486 | } | ||
487 | CPQ_TAPE_UNLOCK(ctlr, flags); | ||
488 | } | ||
489 | |||
420 | static int | 490 | static int |
421 | adjust_cciss_scsi_table(int ctlr, int hostno, | 491 | adjust_cciss_scsi_table(int ctlr, int hostno, |
422 | struct cciss_scsi_dev_t sd[], int nsds) | 492 | struct cciss_scsi_dev_t sd[], int nsds) |
@@ -429,13 +499,33 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
429 | int i,j, found, changes=0; | 499 | int i,j, found, changes=0; |
430 | struct cciss_scsi_dev_t *csd; | 500 | struct cciss_scsi_dev_t *csd; |
431 | unsigned long flags; | 501 | unsigned long flags; |
502 | struct scsi2map *added, *removed; | ||
503 | int nadded, nremoved; | ||
504 | struct Scsi_Host *sh = NULL; | ||
505 | |||
506 | added = kzalloc(sizeof(*added) * CCISS_MAX_SCSI_DEVS_PER_HBA, | ||
507 | GFP_KERNEL); | ||
508 | removed = kzalloc(sizeof(*removed) * CCISS_MAX_SCSI_DEVS_PER_HBA, | ||
509 | GFP_KERNEL); | ||
510 | |||
511 | if (!added || !removed) { | ||
512 | printk(KERN_WARNING "cciss%d: Out of memory in " | ||
513 | "adjust_cciss_scsi_table\n", ctlr); | ||
514 | goto free_and_out; | ||
515 | } | ||
432 | 516 | ||
433 | CPQ_TAPE_LOCK(ctlr, flags); | 517 | CPQ_TAPE_LOCK(ctlr, flags); |
434 | 518 | ||
519 | if (hostno != -1) /* if it's not the first time... */ | ||
520 | sh = ((struct cciss_scsi_adapter_data_t *) | ||
521 | hba[ctlr]->scsi_ctlr)->scsi_host; | ||
522 | |||
435 | /* find any devices in ccissscsi[] that are not in | 523 | /* find any devices in ccissscsi[] that are not in |
436 | sd[] and remove them from ccissscsi[] */ | 524 | sd[] and remove them from ccissscsi[] */ |
437 | 525 | ||
438 | i = 0; | 526 | i = 0; |
527 | nremoved = 0; | ||
528 | nadded = 0; | ||
439 | while(i<ccissscsi[ctlr].ndevices) { | 529 | while(i<ccissscsi[ctlr].ndevices) { |
440 | csd = &ccissscsi[ctlr].dev[i]; | 530 | csd = &ccissscsi[ctlr].dev[i]; |
441 | found=0; | 531 | found=0; |
@@ -455,8 +545,9 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
455 | /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n", | 545 | /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n", |
456 | ctlr, scsi_device_type(csd->devtype), hostno, | 546 | ctlr, scsi_device_type(csd->devtype), hostno, |
457 | csd->bus, csd->target, csd->lun); */ | 547 | csd->bus, csd->target, csd->lun); */ |
458 | cciss_scsi_remove_entry(ctlr, hostno, i); | 548 | cciss_scsi_remove_entry(ctlr, hostno, i, |
459 | /* note, i not incremented */ | 549 | removed, &nremoved); |
550 | /* remove ^^^, hence i not incremented */ | ||
460 | } | 551 | } |
461 | else if (found == 1) { /* device is different kind */ | 552 | else if (found == 1) { /* device is different kind */ |
462 | changes++; | 553 | changes++; |
@@ -464,8 +555,15 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
464 | "(device type now %s).\n", | 555 | "(device type now %s).\n", |
465 | ctlr, hostno, csd->bus, csd->target, csd->lun, | 556 | ctlr, hostno, csd->bus, csd->target, csd->lun, |
466 | scsi_device_type(csd->devtype)); | 557 | scsi_device_type(csd->devtype)); |
558 | cciss_scsi_remove_entry(ctlr, hostno, i, | ||
559 | removed, &nremoved); | ||
560 | /* remove ^^^, hence i not incremented */ | ||
561 | if (cciss_scsi_add_entry(ctlr, hostno, | ||
562 | &sd[j].scsi3addr[0], sd[j].devtype, | ||
563 | added, &nadded) != 0) | ||
564 | /* we just removed one, so add can't fail. */ | ||
565 | BUG(); | ||
467 | csd->devtype = sd[j].devtype; | 566 | csd->devtype = sd[j].devtype; |
468 | i++; /* so just move along. */ | ||
469 | } else /* device is same as it ever was, */ | 567 | } else /* device is same as it ever was, */ |
470 | i++; /* so just move along. */ | 568 | i++; /* so just move along. */ |
471 | } | 569 | } |
@@ -489,7 +587,9 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
489 | if (!found) { | 587 | if (!found) { |
490 | changes++; | 588 | changes++; |
491 | if (cciss_scsi_add_entry(ctlr, hostno, | 589 | if (cciss_scsi_add_entry(ctlr, hostno, |
492 | &sd[i].scsi3addr[0], sd[i].devtype) != 0) | 590 | |
591 | &sd[i].scsi3addr[0], sd[i].devtype, | ||
592 | added, &nadded) != 0) | ||
493 | break; | 593 | break; |
494 | } else if (found == 1) { | 594 | } else if (found == 1) { |
495 | /* should never happen... */ | 595 | /* should never happen... */ |
@@ -501,9 +601,50 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
501 | } | 601 | } |
502 | CPQ_TAPE_UNLOCK(ctlr, flags); | 602 | CPQ_TAPE_UNLOCK(ctlr, flags); |
503 | 603 | ||
504 | if (!changes) | 604 | /* Don't notify scsi mid layer of any changes the first time through */ |
505 | printk("cciss%d: No device changes detected.\n", ctlr); | 605 | /* (or if there are no changes) scsi_scan_host will do it later the */ |
606 | /* first time through. */ | ||
607 | if (hostno == -1 || !changes) | ||
608 | goto free_and_out; | ||
609 | |||
610 | /* Notify scsi mid layer of any removed devices */ | ||
611 | for (i = 0; i < nremoved; i++) { | ||
612 | struct scsi_device *sdev = | ||
613 | scsi_device_lookup(sh, removed[i].bus, | ||
614 | removed[i].target, removed[i].lun); | ||
615 | if (sdev != NULL) { | ||
616 | scsi_remove_device(sdev); | ||
617 | scsi_device_put(sdev); | ||
618 | } else { | ||
619 | /* We don't expect to get here. */ | ||
620 | /* future cmds to this device will get selection */ | ||
621 | /* timeout as if the device was gone. */ | ||
622 | printk(KERN_WARNING "cciss%d: didn't find " | ||
623 | "c%db%dt%dl%d\n for removal.", | ||
624 | ctlr, hostno, removed[i].bus, | ||
625 | removed[i].target, removed[i].lun); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | /* Notify scsi mid layer of any added devices */ | ||
630 | for (i = 0; i < nadded; i++) { | ||
631 | int rc; | ||
632 | rc = scsi_add_device(sh, added[i].bus, | ||
633 | added[i].target, added[i].lun); | ||
634 | if (rc == 0) | ||
635 | continue; | ||
636 | printk(KERN_WARNING "cciss%d: scsi_add_device " | ||
637 | "c%db%dt%dl%d failed, device not added.\n", | ||
638 | ctlr, hostno, | ||
639 | added[i].bus, added[i].target, added[i].lun); | ||
640 | /* now we have to remove it from ccissscsi, */ | ||
641 | /* since it didn't get added to scsi mid layer */ | ||
642 | fixup_botched_add(ctlr, added[i].scsi3addr); | ||
643 | } | ||
506 | 644 | ||
645 | free_and_out: | ||
646 | kfree(added); | ||
647 | kfree(removed); | ||
507 | return 0; | 648 | return 0; |
508 | } | 649 | } |
509 | 650 | ||
@@ -1355,32 +1496,6 @@ cciss_unregister_scsi(int ctlr) | |||
1355 | } | 1496 | } |
1356 | 1497 | ||
1357 | static int | 1498 | 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) | 1499 | cciss_engage_scsi(int ctlr) |
1385 | { | 1500 | { |
1386 | struct cciss_scsi_adapter_data_t *sa; | 1501 | struct cciss_scsi_adapter_data_t *sa; |
@@ -1391,15 +1506,15 @@ cciss_engage_scsi(int ctlr) | |||
1391 | sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; | 1506 | sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; |
1392 | stk = &sa->cmd_stack; | 1507 | stk = &sa->cmd_stack; |
1393 | 1508 | ||
1394 | if (((struct cciss_scsi_adapter_data_t *) | 1509 | if (sa->registered) { |
1395 | hba[ctlr]->scsi_ctlr)->registered) { | ||
1396 | printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); | 1510 | printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); |
1397 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1511 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
1398 | return ENXIO; | 1512 | return ENXIO; |
1399 | } | 1513 | } |
1514 | sa->registered = 1; | ||
1400 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1515 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
1401 | cciss_update_non_disk_devices(ctlr, -1); | 1516 | cciss_update_non_disk_devices(ctlr, -1); |
1402 | cciss_register_scsi(ctlr); | 1517 | cciss_scsi_detect(ctlr); |
1403 | return 0; | 1518 | return 0; |
1404 | } | 1519 | } |
1405 | 1520 | ||
@@ -1493,7 +1608,5 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) | |||
1493 | /* If no tape support, then these become defined out of existence */ | 1608 | /* If no tape support, then these become defined out of existence */ |
1494 | 1609 | ||
1495 | #define cciss_scsi_setup(cntl_num) | 1610 | #define cciss_scsi_setup(cntl_num) |
1496 | #define cciss_unregister_scsi(ctlr) | ||
1497 | #define cciss_register_scsi(ctlr) | ||
1498 | 1611 | ||
1499 | #endif /* CONFIG_CISS_SCSI_TAPE */ | 1612 | #endif /* CONFIG_CISS_SCSI_TAPE */ |