Date: Fri, 25 Jan 2008 23:31:12 -0500 From: Jarod Wilson Subject: firewire: fw-sbp2: Use sbp2 device-provided mgt orb timeout for logins To be more compliant with section 7.4.8 of the SBP-2 specification, use the mgt_ORB_timeout specified in the SBP-2 device's config rom for login ORB attempts (though with some sanity checks). A happy side-effect is that certain device and controller combinations that sometimes take more than 20 seconds to get synced up (like my laptop with just about any SBP-2 device) now function more reliably. Signed-off-by: Jarod Wilson Signed-off-by: Stefan Richter (silenced sparse) --- drivers/firewire/fw-sbp2.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) Index: linux/drivers/firewire/fw-sbp2.c =================================================================== --- linux.orig/drivers/firewire/fw-sbp2.c +++ linux/drivers/firewire/fw-sbp2.c @@ -149,15 +149,17 @@ struct sbp2_target { unsigned workarounds; struct list_head lu_list; + + unsigned int mgt_orb_timeout; }; /* * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be - * provided in the config rom. A high timeout value really only matters - * on initial login, where we'll just use 20s rather than hassling with - * reading the config rom, since it really wouldn't buy us much. + * provided in the config rom. Most devices do provide a value, which + * we'll use for login management orbs, but with some sane limits. */ -#define SBP2_LOGIN_ORB_TIMEOUT 20000 /* Timeout in ms */ +#define SBP2_MIN_LOGIN_ORB_TIMEOUT 5000U /* Timeout in ms */ +#define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */ #define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */ #define SBP2_ORB_NULL 0x80000000 #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 @@ -166,6 +168,7 @@ struct sbp2_target { #define SBP2_DIRECTION_FROM_MEDIA 0x1 /* Unit directory keys */ +#define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a #define SBP2_CSR_FIRMWARE_REVISION 0x3c #define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14 #define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4 @@ -527,7 +530,7 @@ sbp2_send_management_orb(struct sbp2_log orb->request.misc |= MANAGEMENT_ORB_RECONNECT(2) | MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login); - timeout = SBP2_LOGIN_ORB_TIMEOUT; + timeout = lu->tgt->mgt_orb_timeout; } else { timeout = SBP2_ORB_TIMEOUT; } @@ -777,6 +780,7 @@ static int sbp2_scan_unit_dir(struct sbp { struct fw_csr_iterator ci; int key, value; + unsigned int timeout; fw_csr_iterator_init(&ci, directory); while (fw_csr_iterator_next(&ci, &key, &value)) { @@ -799,6 +803,21 @@ static int sbp2_scan_unit_dir(struct sbp *firmware_revision = value; break; + case SBP2_CSR_UNIT_CHARACTERISTICS: + /* the timeout value is stored in 500ms units */ + timeout = ((unsigned int) value >> 8 & 0xff) * 500; + timeout = max(timeout, SBP2_MIN_LOGIN_ORB_TIMEOUT); + tgt->mgt_orb_timeout = + min(timeout, SBP2_MAX_LOGIN_ORB_TIMEOUT); + + if (timeout > tgt->mgt_orb_timeout) + fw_notify("%s: config rom contains %ds " + "management ORB timeout, limiting " + "to %ds\n", tgt->unit->device.bus_id, + timeout / 1000, + tgt->mgt_orb_timeout / 1000); + break; + case SBP2_CSR_LOGICAL_UNIT_NUMBER: if (sbp2_add_logical_unit(tgt, value) < 0) return -ENOMEM;