diff options
author | Jody McIntyre <scjody@steamballoon.com> | 2005-09-30 14:59:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-30 15:41:18 -0400 |
commit | abd559b1052e28d8b9c28aabde241f18fa89090b (patch) | |
tree | 8720378a6a4e57b4e80969348fe9aa67ae899461 /drivers/ieee1394/sbp2.c | |
parent | 105d7b38b08f85c9abc3fd31e5cfa7ee4cf0a402 (diff) |
[PATCH] sbp2: fix deadlocks and delays on device removal/rmmod
Fixes for deadlocks of the ieee1394 and scsi subsystems and long delays in
futile error recovery attempts when SBP-2 devices are removed or drivers are
unloaded.
- Complete commands quickly with DID_NO_CONNECT if the 1394 node is gone or if
the 1394 low-level driver was unloaded.
- Skip unnecessary work in the eh_abort_handler and eh_device_reset_handler if
the node or 1394 low-level driver is gone.
- Let scsi's high-level shut down gracefully when sbp2 is being unloaded or
detached from the 1394 unit. A call to scsi_remove_device is added for this
purpose, which requires us to store a scsi_device pointer.
- scsi_device pointer is obtained from slave_alloc hook and cleared by
slave_destroy. This avoids usage of the pointer after the scsi device was
deleted e.g. by the user via scsi_mod's sysfs interface.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: Jody McIntyre <scjody@steamballoon.com>
Cc: Ben Collins <bcollins@debian.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/ieee1394/sbp2.c')
-rw-r--r-- | drivers/ieee1394/sbp2.c | 96 |
1 files changed, 58 insertions, 38 deletions
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index de88218ef7cc..5d86b03979ec 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c | |||
@@ -596,6 +596,14 @@ static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_i | |||
596 | spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); | 596 | spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); |
597 | } | 597 | } |
598 | 598 | ||
599 | /* | ||
600 | * Is scsi_id valid? Is the 1394 node still present? | ||
601 | */ | ||
602 | static inline int sbp2util_node_is_available(struct scsi_id_instance_data *scsi_id) | ||
603 | { | ||
604 | return scsi_id && scsi_id->ne && !scsi_id->ne->in_limbo; | ||
605 | } | ||
606 | |||
599 | 607 | ||
600 | 608 | ||
601 | /********************************************* | 609 | /********************************************* |
@@ -631,11 +639,23 @@ static int sbp2_remove(struct device *dev) | |||
631 | { | 639 | { |
632 | struct unit_directory *ud; | 640 | struct unit_directory *ud; |
633 | struct scsi_id_instance_data *scsi_id; | 641 | struct scsi_id_instance_data *scsi_id; |
642 | struct scsi_device *sdev; | ||
634 | 643 | ||
635 | SBP2_DEBUG("sbp2_remove"); | 644 | SBP2_DEBUG("sbp2_remove"); |
636 | 645 | ||
637 | ud = container_of(dev, struct unit_directory, device); | 646 | ud = container_of(dev, struct unit_directory, device); |
638 | scsi_id = ud->device.driver_data; | 647 | scsi_id = ud->device.driver_data; |
648 | if (!scsi_id) | ||
649 | return 0; | ||
650 | |||
651 | /* Trigger shutdown functions in scsi's highlevel. */ | ||
652 | if (scsi_id->scsi_host) | ||
653 | scsi_unblock_requests(scsi_id->scsi_host); | ||
654 | sdev = scsi_id->sdev; | ||
655 | if (sdev) { | ||
656 | scsi_id->sdev = NULL; | ||
657 | scsi_remove_device(sdev); | ||
658 | } | ||
639 | 659 | ||
640 | sbp2_logout_device(scsi_id); | 660 | sbp2_logout_device(scsi_id); |
641 | sbp2_remove_device(scsi_id); | 661 | sbp2_remove_device(scsi_id); |
@@ -2473,37 +2493,26 @@ static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt, | |||
2473 | struct scsi_id_instance_data *scsi_id = | 2493 | struct scsi_id_instance_data *scsi_id = |
2474 | (struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0]; | 2494 | (struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0]; |
2475 | struct sbp2scsi_host_info *hi; | 2495 | struct sbp2scsi_host_info *hi; |
2496 | int result = DID_NO_CONNECT << 16; | ||
2476 | 2497 | ||
2477 | SBP2_DEBUG("sbp2scsi_queuecommand"); | 2498 | SBP2_DEBUG("sbp2scsi_queuecommand"); |
2478 | 2499 | ||
2479 | /* | 2500 | if (!sbp2util_node_is_available(scsi_id)) |
2480 | * If scsi_id is null, it means there is no device in this slot, | 2501 | goto done; |
2481 | * so we should return selection timeout. | ||
2482 | */ | ||
2483 | if (!scsi_id) { | ||
2484 | SCpnt->result = DID_NO_CONNECT << 16; | ||
2485 | done (SCpnt); | ||
2486 | return 0; | ||
2487 | } | ||
2488 | 2502 | ||
2489 | hi = scsi_id->hi; | 2503 | hi = scsi_id->hi; |
2490 | 2504 | ||
2491 | if (!hi) { | 2505 | if (!hi) { |
2492 | SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!"); | 2506 | SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!"); |
2493 | SCpnt->result = DID_NO_CONNECT << 16; | 2507 | goto done; |
2494 | done (SCpnt); | ||
2495 | return(0); | ||
2496 | } | 2508 | } |
2497 | 2509 | ||
2498 | /* | 2510 | /* |
2499 | * Until we handle multiple luns, just return selection time-out | 2511 | * Until we handle multiple luns, just return selection time-out |
2500 | * to any IO directed at non-zero LUNs | 2512 | * to any IO directed at non-zero LUNs |
2501 | */ | 2513 | */ |
2502 | if (SCpnt->device->lun) { | 2514 | if (SCpnt->device->lun) |
2503 | SCpnt->result = DID_NO_CONNECT << 16; | 2515 | goto done; |
2504 | done (SCpnt); | ||
2505 | return(0); | ||
2506 | } | ||
2507 | 2516 | ||
2508 | /* | 2517 | /* |
2509 | * Check for request sense command, and handle it here | 2518 | * Check for request sense command, and handle it here |
@@ -2514,7 +2523,7 @@ static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt, | |||
2514 | memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen); | 2523 | memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen); |
2515 | memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); | 2524 | memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); |
2516 | sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done); | 2525 | sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done); |
2517 | return(0); | 2526 | return 0; |
2518 | } | 2527 | } |
2519 | 2528 | ||
2520 | /* | 2529 | /* |
@@ -2522,9 +2531,8 @@ static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt, | |||
2522 | */ | 2531 | */ |
2523 | if (!hpsb_node_entry_valid(scsi_id->ne)) { | 2532 | if (!hpsb_node_entry_valid(scsi_id->ne)) { |
2524 | SBP2_ERR("Bus reset in progress - rejecting command"); | 2533 | SBP2_ERR("Bus reset in progress - rejecting command"); |
2525 | SCpnt->result = DID_BUS_BUSY << 16; | 2534 | result = DID_BUS_BUSY << 16; |
2526 | done (SCpnt); | 2535 | goto done; |
2527 | return(0); | ||
2528 | } | 2536 | } |
2529 | 2537 | ||
2530 | /* | 2538 | /* |
@@ -2535,8 +2543,12 @@ static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt, | |||
2535 | sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, | 2543 | sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, |
2536 | SCpnt, done); | 2544 | SCpnt, done); |
2537 | } | 2545 | } |
2546 | return 0; | ||
2538 | 2547 | ||
2539 | return(0); | 2548 | done: |
2549 | SCpnt->result = result; | ||
2550 | done(SCpnt); | ||
2551 | return 0; | ||
2540 | } | 2552 | } |
2541 | 2553 | ||
2542 | /* | 2554 | /* |
@@ -2683,14 +2695,27 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id, | |||
2683 | } | 2695 | } |
2684 | 2696 | ||
2685 | 2697 | ||
2686 | static int sbp2scsi_slave_configure (struct scsi_device *sdev) | 2698 | static int sbp2scsi_slave_alloc(struct scsi_device *sdev) |
2687 | { | 2699 | { |
2688 | blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); | 2700 | ((struct scsi_id_instance_data *)sdev->host->hostdata[0])->sdev = sdev; |
2701 | return 0; | ||
2702 | } | ||
2703 | |||
2689 | 2704 | ||
2705 | static int sbp2scsi_slave_configure(struct scsi_device *sdev) | ||
2706 | { | ||
2707 | blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); | ||
2690 | return 0; | 2708 | return 0; |
2691 | } | 2709 | } |
2692 | 2710 | ||
2693 | 2711 | ||
2712 | static void sbp2scsi_slave_destroy(struct scsi_device *sdev) | ||
2713 | { | ||
2714 | ((struct scsi_id_instance_data *)sdev->host->hostdata[0])->sdev = NULL; | ||
2715 | return; | ||
2716 | } | ||
2717 | |||
2718 | |||
2694 | /* | 2719 | /* |
2695 | * Called by scsi stack when something has really gone wrong. Usually | 2720 | * Called by scsi stack when something has really gone wrong. Usually |
2696 | * called when a command has timed-out for some reason. | 2721 | * called when a command has timed-out for some reason. |
@@ -2705,7 +2730,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) | |||
2705 | SBP2_ERR("aborting sbp2 command"); | 2730 | SBP2_ERR("aborting sbp2 command"); |
2706 | scsi_print_command(SCpnt); | 2731 | scsi_print_command(SCpnt); |
2707 | 2732 | ||
2708 | if (scsi_id) { | 2733 | if (sbp2util_node_is_available(scsi_id)) { |
2709 | 2734 | ||
2710 | /* | 2735 | /* |
2711 | * Right now, just return any matching command structures | 2736 | * Right now, just return any matching command structures |
@@ -2742,31 +2767,24 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) | |||
2742 | /* | 2767 | /* |
2743 | * Called by scsi stack when something has really gone wrong. | 2768 | * Called by scsi stack when something has really gone wrong. |
2744 | */ | 2769 | */ |
2745 | static int __sbp2scsi_reset(struct scsi_cmnd *SCpnt) | 2770 | static int sbp2scsi_reset(struct scsi_cmnd *SCpnt) |
2746 | { | 2771 | { |
2747 | struct scsi_id_instance_data *scsi_id = | 2772 | struct scsi_id_instance_data *scsi_id = |
2748 | (struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0]; | 2773 | (struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0]; |
2774 | unsigned long flags; | ||
2749 | 2775 | ||
2750 | SBP2_ERR("reset requested"); | 2776 | SBP2_ERR("reset requested"); |
2751 | 2777 | ||
2752 | if (scsi_id) { | 2778 | spin_lock_irqsave(SCpnt->device->host->host_lock, flags); |
2779 | |||
2780 | if (sbp2util_node_is_available(scsi_id)) { | ||
2753 | SBP2_ERR("Generating sbp2 fetch agent reset"); | 2781 | SBP2_ERR("Generating sbp2 fetch agent reset"); |
2754 | sbp2_agent_reset(scsi_id, 0); | 2782 | sbp2_agent_reset(scsi_id, 0); |
2755 | } | 2783 | } |
2756 | 2784 | ||
2757 | return(SUCCESS); | ||
2758 | } | ||
2759 | |||
2760 | static int sbp2scsi_reset(struct scsi_cmnd *SCpnt) | ||
2761 | { | ||
2762 | unsigned long flags; | ||
2763 | int rc; | ||
2764 | |||
2765 | spin_lock_irqsave(SCpnt->device->host->host_lock, flags); | ||
2766 | rc = __sbp2scsi_reset(SCpnt); | ||
2767 | spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); | 2785 | spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); |
2768 | 2786 | ||
2769 | return rc; | 2787 | return SUCCESS; |
2770 | } | 2788 | } |
2771 | 2789 | ||
2772 | static const char *sbp2scsi_info (struct Scsi_Host *host) | 2790 | static const char *sbp2scsi_info (struct Scsi_Host *host) |
@@ -2817,7 +2835,9 @@ static struct scsi_host_template scsi_driver_template = { | |||
2817 | .eh_device_reset_handler = sbp2scsi_reset, | 2835 | .eh_device_reset_handler = sbp2scsi_reset, |
2818 | .eh_bus_reset_handler = sbp2scsi_reset, | 2836 | .eh_bus_reset_handler = sbp2scsi_reset, |
2819 | .eh_host_reset_handler = sbp2scsi_reset, | 2837 | .eh_host_reset_handler = sbp2scsi_reset, |
2838 | .slave_alloc = sbp2scsi_slave_alloc, | ||
2820 | .slave_configure = sbp2scsi_slave_configure, | 2839 | .slave_configure = sbp2scsi_slave_configure, |
2840 | .slave_destroy = sbp2scsi_slave_destroy, | ||
2821 | .this_id = -1, | 2841 | .this_id = -1, |
2822 | .sg_tablesize = SG_ALL, | 2842 | .sg_tablesize = SG_ALL, |
2823 | .use_clustering = ENABLE_CLUSTERING, | 2843 | .use_clustering = ENABLE_CLUSTERING, |