firewire: fw-sbp2: expose module parameter for workarounds
authorStefan Richter <stefanr@s5r6.in-berlin.de>
Mon, 13 Aug 2007 15:48:25 +0000 (17:48 +0200)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Tue, 16 Oct 2007 22:00:03 +0000 (00:00 +0200)
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: Stefan Richter <stefanr@s5r6.in-berlin.de>
drivers/firewire/fw-sbp2.c

index 1efc67b1d26e3a6c9d2a03352af4f002c5a649e2..f96f19293dd1f882bf426e8756f15f55111b13df 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/blkdev.h>
 #include <linux/string.h>
+#include <linux/stringify.h>
 #include <linux/timer.h>
 
 #include <scsi/scsi.h>
@@ -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 "
                 "(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... */
 typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
 
@@ -122,13 +163,6 @@ struct sbp2_target {
 #define SBP2_CSR_LOGICAL_UNIT_NUMBER   0x14
 #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 */
 #define SBP2_LOGIN_REQUEST             0x0
 #define SBP2_QUERY_LOGINS_REQUEST      0x1
@@ -751,8 +785,15 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
                                  u32 firmware_revision)
 {
        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++) {
 
@@ -764,15 +805,16 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
                    sbp2_workarounds_table[i].model != ~0)
                        continue;
 
-               tgt->workarounds |= sbp2_workarounds_table[i].workarounds;
+               w |= sbp2_workarounds_table[i].workarounds;
                break;
        }
-
-       if (tgt->workarounds)
+ out:
+       if (w)
                fw_notify("Workarounds for %s: 0x%x "
                          "(firmware_revision 0x%06x, model_id 0x%06x)\n",
                          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;