mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
11bf20ad02
commit
51f9dbef5b
|
@ -173,6 +173,7 @@ struct sbp2_target {
|
|||
#define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */
|
||||
#define SBP2_ORB_NULL 0x80000000
|
||||
#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
|
||||
#define SBP2_RETRY_LIMIT 0xf /* 15 retries */
|
||||
|
||||
#define SBP2_DIRECTION_TO_MEDIA 0x0
|
||||
#define SBP2_DIRECTION_FROM_MEDIA 0x1
|
||||
|
@ -812,6 +813,30 @@ static void sbp2_target_put(struct sbp2_target *tgt)
|
|||
kref_put(&tgt->kref, sbp2_release_target);
|
||||
}
|
||||
|
||||
static void
|
||||
complete_set_busy_timeout(struct fw_card *card, int rcode,
|
||||
void *payload, size_t length, void *done)
|
||||
{
|
||||
complete(done);
|
||||
}
|
||||
|
||||
static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu)
|
||||
{
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
struct fw_transaction t;
|
||||
static __be32 busy_timeout;
|
||||
|
||||
/* FIXME: we should try to set dual-phase cycle_limit too */
|
||||
busy_timeout = cpu_to_be32(SBP2_RETRY_LIMIT);
|
||||
|
||||
fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST,
|
||||
lu->tgt->node_id, lu->generation, device->max_speed,
|
||||
CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, &busy_timeout,
|
||||
sizeof(busy_timeout), complete_set_busy_timeout, &done);
|
||||
wait_for_completion(&done);
|
||||
}
|
||||
|
||||
static void sbp2_reconnect(struct work_struct *work);
|
||||
|
||||
static void sbp2_login(struct work_struct *work)
|
||||
|
@ -864,10 +889,8 @@ static void sbp2_login(struct work_struct *work)
|
|||
fw_notify("%s: logged in to LUN %04x (%d retries)\n",
|
||||
tgt->bus_id, lu->lun, lu->retries);
|
||||
|
||||
#if 0
|
||||
/* FIXME: The linux1394 sbp2 does this last step. */
|
||||
sbp2_set_busy_timeout(scsi_id);
|
||||
#endif
|
||||
/* set appropriate retry limit(s) in BUSY_TIMEOUT register */
|
||||
sbp2_set_busy_timeout(lu);
|
||||
|
||||
PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
|
||||
sbp2_agent_reset(lu);
|
||||
|
|
Loading…
Reference in New Issue