diff options
author | Jarod Wilson <jwilson@redhat.com> | 2008-03-07 01:43:01 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-03-13 19:56:59 -0400 |
commit | 51f9dbef5be41f3ff6000c874741a3a357f9bad7 (patch) | |
tree | 9ee2f70c6ce881624fc35aabc0129cafeb8fee0c /drivers/firewire/fw-sbp2.c | |
parent | 11bf20ad028880a56689f086bfbabfd88b2af38b (diff) |
firewire: fw-sbp2: set single-phase retry_limit
Per the SBP-2 specification, all SBP-2 target devices must have a BUSY_TIMEOUT
register. Per the 1394-1995 specification, the retry_limt portion of the
register should be set to 0x0 initially, and set on the target by a logged in
initiator (i.e., a Linux host w/firewire controller(s)).
Well, as it turns out, lots of devices these days have actually moved on to
starting to implement SBP-3 compliance, which says that retry_limit should
default to 0xf instead (yes, SBP-3 stomps directly on 1394-1995, oops).
Prior to this change, the firewire driver stack didn't touch retry_limit, and
any SBP-3 compliant device worked fine, while SBP-2 compliant ones were unable
to retransmit when the host returned an ack_busy_X, which resulted in stalled
out I/O, eventually causing the SCSI layer to give up and offline the device.
The simple fix is for us to set retry_limit to 0xf in the register for all
devices (which actually matches what the old ieee1394 stack did).
Prior to this change, a hard disk behind an SBP-2 Prolific PL-3507 bridge chip
would routinely encounter buffer I/O errors and wind up offlined by the SCSI
layer. With this change, I've encountered zero I/O failures moving tens of GB
of data around.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-sbp2.c')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 03069a454c07..8bce569a7c5a 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -173,6 +173,7 @@ struct sbp2_target { | |||
173 | #define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */ | 173 | #define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */ |
174 | #define SBP2_ORB_NULL 0x80000000 | 174 | #define SBP2_ORB_NULL 0x80000000 |
175 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 | 175 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 |
176 | #define SBP2_RETRY_LIMIT 0xf /* 15 retries */ | ||
176 | 177 | ||
177 | #define SBP2_DIRECTION_TO_MEDIA 0x0 | 178 | #define SBP2_DIRECTION_TO_MEDIA 0x0 |
178 | #define SBP2_DIRECTION_FROM_MEDIA 0x1 | 179 | #define SBP2_DIRECTION_FROM_MEDIA 0x1 |
@@ -812,6 +813,30 @@ static void sbp2_target_put(struct sbp2_target *tgt) | |||
812 | kref_put(&tgt->kref, sbp2_release_target); | 813 | kref_put(&tgt->kref, sbp2_release_target); |
813 | } | 814 | } |
814 | 815 | ||
816 | static void | ||
817 | complete_set_busy_timeout(struct fw_card *card, int rcode, | ||
818 | void *payload, size_t length, void *done) | ||
819 | { | ||
820 | complete(done); | ||
821 | } | ||
822 | |||
823 | static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) | ||
824 | { | ||
825 | struct fw_device *device = fw_device(lu->tgt->unit->device.parent); | ||
826 | DECLARE_COMPLETION_ONSTACK(done); | ||
827 | struct fw_transaction t; | ||
828 | static __be32 busy_timeout; | ||
829 | |||
830 | /* FIXME: we should try to set dual-phase cycle_limit too */ | ||
831 | busy_timeout = cpu_to_be32(SBP2_RETRY_LIMIT); | ||
832 | |||
833 | fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST, | ||
834 | lu->tgt->node_id, lu->generation, device->max_speed, | ||
835 | CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, &busy_timeout, | ||
836 | sizeof(busy_timeout), complete_set_busy_timeout, &done); | ||
837 | wait_for_completion(&done); | ||
838 | } | ||
839 | |||
815 | static void sbp2_reconnect(struct work_struct *work); | 840 | static void sbp2_reconnect(struct work_struct *work); |
816 | 841 | ||
817 | static void sbp2_login(struct work_struct *work) | 842 | static void sbp2_login(struct work_struct *work) |
@@ -864,10 +889,8 @@ static void sbp2_login(struct work_struct *work) | |||
864 | fw_notify("%s: logged in to LUN %04x (%d retries)\n", | 889 | fw_notify("%s: logged in to LUN %04x (%d retries)\n", |
865 | tgt->bus_id, lu->lun, lu->retries); | 890 | tgt->bus_id, lu->lun, lu->retries); |
866 | 891 | ||
867 | #if 0 | 892 | /* set appropriate retry limit(s) in BUSY_TIMEOUT register */ |
868 | /* FIXME: The linux1394 sbp2 does this last step. */ | 893 | sbp2_set_busy_timeout(lu); |
869 | sbp2_set_busy_timeout(scsi_id); | ||
870 | #endif | ||
871 | 894 | ||
872 | PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect); | 895 | PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect); |
873 | sbp2_agent_reset(lu); | 896 | sbp2_agent_reset(lu); |