diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-02-15 15:29:02 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-02-16 09:40:35 -0500 |
commit | e80de3704ac30ddb7f9a12447a2ecee32ccd7880 (patch) | |
tree | 87ffc83df0d904b48af17177266ba604c2a3fd86 /drivers | |
parent | 7bb6bf7c8ba0b4ccfecaa00d6faea51b0bd42c8c (diff) |
firewire: fw-sbp2: enforce a retry of __scsi_add_device if bus generation changed
fw-sbp2 is unable to reconnect while performing __scsi_add_device
because there is only a single workqueue thread context available for
both at the moment. This should be fixed eventually.
An actual failure of __scsi_add_device is easy to handle, but an
incomplete execution of __scsi_add_device with an sdev returned would
remain undetected and leave the SBP-2 target unusable.
Therefore we use a workaround: If there was a bus reset during
__scsi_add_device (i.e. during the SCSI probe), we remove the new sdev
immediately, log out, and attempt login and SCSI probe again.
Tested-by: Jarod Wilson <jwilson@redhat.com> (earlier version)
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 323b03bacd29..6d10934c58f1 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -762,22 +762,43 @@ static void sbp2_login(struct work_struct *work) | |||
762 | 762 | ||
763 | sdev = __scsi_add_device(shost, 0, 0, | 763 | sdev = __scsi_add_device(shost, 0, 0, |
764 | scsilun_to_int(&eight_bytes_lun), lu); | 764 | scsilun_to_int(&eight_bytes_lun), lu); |
765 | if (IS_ERR(sdev)) { | 765 | /* |
766 | smp_rmb(); /* generation may have changed */ | 766 | * FIXME: We are unable to perform reconnects while in sbp2_login(). |
767 | generation = device->generation; | 767 | * Therefore __scsi_add_device() will get into trouble if a bus reset |
768 | smp_rmb(); /* node_id must not be older than generation */ | 768 | * happens in parallel. It will either fail or leave us with an |
769 | * unusable sdev. As a workaround we check for this and retry the | ||
770 | * whole login and SCSI probing. | ||
771 | */ | ||
769 | 772 | ||
770 | sbp2_send_management_orb(lu, device->node_id, generation, | 773 | /* Reported error during __scsi_add_device() */ |
771 | SBP2_LOGOUT_REQUEST, lu->login_id, NULL); | 774 | if (IS_ERR(sdev)) |
772 | /* | 775 | goto out_logout_login; |
773 | * Set this back to sbp2_login so we fall back and | 776 | |
774 | * retry login on bus reset. | 777 | scsi_device_put(sdev); |
775 | */ | 778 | |
776 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | 779 | /* Unreported error during __scsi_add_device() */ |
777 | } else { | 780 | smp_rmb(); /* get current card generation */ |
778 | lu->sdev = sdev; | 781 | if (generation != device->card->generation) { |
779 | scsi_device_put(sdev); | 782 | scsi_remove_device(sdev); |
783 | goto out_logout_login; | ||
780 | } | 784 | } |
785 | |||
786 | /* No error during __scsi_add_device() */ | ||
787 | lu->sdev = sdev; | ||
788 | goto out; | ||
789 | |||
790 | out_logout_login: | ||
791 | smp_rmb(); /* generation may have changed */ | ||
792 | generation = device->generation; | ||
793 | smp_rmb(); /* node_id must not be older than generation */ | ||
794 | |||
795 | sbp2_send_management_orb(lu, device->node_id, generation, | ||
796 | SBP2_LOGOUT_REQUEST, lu->login_id, NULL); | ||
797 | /* | ||
798 | * If a bus reset happened, sbp2_update will have requeued | ||
799 | * lu->work already. Reset the work from reconnect to login. | ||
800 | */ | ||
801 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | ||
781 | out: | 802 | out: |
782 | sbp2_target_put(tgt); | 803 | sbp2_target_put(tgt); |
783 | } | 804 | } |