diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/block/cciss_scsi.c | 157 |
1 files changed, 118 insertions, 39 deletions
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 */ |
