Commit 2df222b8 authored by Stefan Richter's avatar Stefan Richter

firewire: fw-sbp2: expose module parameter for workarounds

On rare occasions, the ability to set one of the workaround flags at
runtime may save the day.

People who experience I/O errors with firewire-sbp2 while the old sbp2
driver worked for them should try workarounds=1 and report to the devel
mailinglist whether that improves things.  Firewire-sbp2 defaults to the
SCSI stack's maximum transfer size per command, while sbp2 limits them
to 128 kBytes.  Flag 1 accomplishes just that.
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent 5a3c2be6
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/stringify.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
...@@ -60,6 +61,46 @@ module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644); ...@@ -60,6 +61,46 @@ module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644);
MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
"(default = Y, use N for concurrent initiators)"); "(default = Y, use N for concurrent initiators)");
/*
* Flags for firmware oddities
*
* - 128kB max transfer
* Limit transfer size. Necessary for some old bridges.
*
* - 36 byte inquiry
* When scsi_mod probes the device, let the inquiry command look like that
* from MS Windows.
*
* - skip mode page 8
* Suppress sending of mode_sense for mode page 8 if the device pretends to
* support the SCSI Primary Block commands instead of Reduced Block Commands.
*
* - fix capacity
* Tell sd_mod to correct the last sector number reported by read_capacity.
* Avoids access beyond actual disk limits on devices with an off-by-one bug.
* Don't use this with devices which don't have this bug.
*
* - override internal blacklist
* Instead of adding to the built-in blacklist, use only the workarounds
* specified in the module load parameter.
* Useful if a blacklist entry interfered with a non-broken device.
*/
#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
#define SBP2_WORKAROUND_INQUIRY_36 0x2
#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
#define SBP2_WORKAROUND_OVERRIDE 0x100
static int sbp2_param_workarounds;
module_param_named(workarounds, sbp2_param_workarounds, int, 0644);
MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
", or a combination)");
/* I don't know why the SCSI stack doesn't define something like this... */ /* I don't know why the SCSI stack doesn't define something like this... */
typedef void (*scsi_done_fn_t)(struct scsi_cmnd *); typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
...@@ -122,13 +163,6 @@ struct sbp2_target { ...@@ -122,13 +163,6 @@ struct sbp2_target {
#define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14 #define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14
#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4 #define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4
/* Flags for detected oddities and brokeness */
#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
#define SBP2_WORKAROUND_INQUIRY_36 0x2
#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
#define SBP2_WORKAROUND_OVERRIDE 0x100
/* Management orb opcodes */ /* Management orb opcodes */
#define SBP2_LOGIN_REQUEST 0x0 #define SBP2_LOGIN_REQUEST 0x0
#define SBP2_QUERY_LOGINS_REQUEST 0x1 #define SBP2_QUERY_LOGINS_REQUEST 0x1
...@@ -751,8 +785,15 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, ...@@ -751,8 +785,15 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
u32 firmware_revision) u32 firmware_revision)
{ {
int i; int i;
unsigned w = sbp2_param_workarounds;
if (w)
fw_notify("Please notify linux1394-devel@lists.sourceforge.net "
"if you need the workarounds parameter for %s\n",
tgt->unit->device.bus_id);
tgt->workarounds = 0; if (w & SBP2_WORKAROUND_OVERRIDE)
goto out;
for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
...@@ -764,15 +805,16 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, ...@@ -764,15 +805,16 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
sbp2_workarounds_table[i].model != ~0) sbp2_workarounds_table[i].model != ~0)
continue; continue;
tgt->workarounds |= sbp2_workarounds_table[i].workarounds; w |= sbp2_workarounds_table[i].workarounds;
break; break;
} }
out:
if (tgt->workarounds) if (w)
fw_notify("Workarounds for %s: 0x%x " fw_notify("Workarounds for %s: 0x%x "
"(firmware_revision 0x%06x, model_id 0x%06x)\n", "(firmware_revision 0x%06x, model_id 0x%06x)\n",
tgt->unit->device.bus_id, tgt->unit->device.bus_id,
tgt->workarounds, firmware_revision, model); w, firmware_revision, model);
tgt->workarounds = w;
} }
static struct scsi_host_template scsi_driver_template; static struct scsi_host_template scsi_driver_template;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment