aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-sbp2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/fw-sbp2.c')
-rw-r--r--drivers/firewire/fw-sbp2.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 1efc67b1d26e..f96f19293dd1 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -37,6 +37,7 @@
37#include <linux/dma-mapping.h> 37#include <linux/dma-mapping.h>
38#include <linux/blkdev.h> 38#include <linux/blkdev.h>
39#include <linux/string.h> 39#include <linux/string.h>
40#include <linux/stringify.h>
40#include <linux/timer.h> 41#include <linux/timer.h>
41 42
42#include <scsi/scsi.h> 43#include <scsi/scsi.h>
@@ -60,6 +61,46 @@ module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644);
60MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " 61MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
61 "(default = Y, use N for concurrent initiators)"); 62 "(default = Y, use N for concurrent initiators)");
62 63
64/*
65 * Flags for firmware oddities
66 *
67 * - 128kB max transfer
68 * Limit transfer size. Necessary for some old bridges.
69 *
70 * - 36 byte inquiry
71 * When scsi_mod probes the device, let the inquiry command look like that
72 * from MS Windows.
73 *
74 * - skip mode page 8
75 * Suppress sending of mode_sense for mode page 8 if the device pretends to
76 * support the SCSI Primary Block commands instead of Reduced Block Commands.
77 *
78 * - fix capacity
79 * Tell sd_mod to correct the last sector number reported by read_capacity.
80 * Avoids access beyond actual disk limits on devices with an off-by-one bug.
81 * Don't use this with devices which don't have this bug.
82 *
83 * - override internal blacklist
84 * Instead of adding to the built-in blacklist, use only the workarounds
85 * specified in the module load parameter.
86 * Useful if a blacklist entry interfered with a non-broken device.
87 */
88#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
89#define SBP2_WORKAROUND_INQUIRY_36 0x2
90#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
91#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
92#define SBP2_WORKAROUND_OVERRIDE 0x100
93
94static int sbp2_param_workarounds;
95module_param_named(workarounds, sbp2_param_workarounds, int, 0644);
96MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
97 ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
98 ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
99 ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
100 ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
101 ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
102 ", or a combination)");
103
63/* I don't know why the SCSI stack doesn't define something like this... */ 104/* I don't know why the SCSI stack doesn't define something like this... */
64typedef void (*scsi_done_fn_t)(struct scsi_cmnd *); 105typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
65 106
@@ -122,13 +163,6 @@ struct sbp2_target {
122#define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14 163#define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14
123#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4 164#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4
124 165
125/* Flags for detected oddities and brokeness */
126#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
127#define SBP2_WORKAROUND_INQUIRY_36 0x2
128#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
129#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
130#define SBP2_WORKAROUND_OVERRIDE 0x100
131
132/* Management orb opcodes */ 166/* Management orb opcodes */
133#define SBP2_LOGIN_REQUEST 0x0 167#define SBP2_LOGIN_REQUEST 0x0
134#define SBP2_QUERY_LOGINS_REQUEST 0x1 168#define SBP2_QUERY_LOGINS_REQUEST 0x1
@@ -751,8 +785,15 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
751 u32 firmware_revision) 785 u32 firmware_revision)
752{ 786{
753 int i; 787 int i;
788 unsigned w = sbp2_param_workarounds;
789
790 if (w)
791 fw_notify("Please notify linux1394-devel@lists.sourceforge.net "
792 "if you need the workarounds parameter for %s\n",
793 tgt->unit->device.bus_id);
754 794
755 tgt->workarounds = 0; 795 if (w & SBP2_WORKAROUND_OVERRIDE)
796 goto out;
756 797
757 for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { 798 for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
758 799
@@ -764,15 +805,16 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
764 sbp2_workarounds_table[i].model != ~0) 805 sbp2_workarounds_table[i].model != ~0)
765 continue; 806 continue;
766 807
767 tgt->workarounds |= sbp2_workarounds_table[i].workarounds; 808 w |= sbp2_workarounds_table[i].workarounds;
768 break; 809 break;
769 } 810 }
770 811 out:
771 if (tgt->workarounds) 812 if (w)
772 fw_notify("Workarounds for %s: 0x%x " 813 fw_notify("Workarounds for %s: 0x%x "
773 "(firmware_revision 0x%06x, model_id 0x%06x)\n", 814 "(firmware_revision 0x%06x, model_id 0x%06x)\n",
774 tgt->unit->device.bus_id, 815 tgt->unit->device.bus_id,
775 tgt->workarounds, firmware_revision, model); 816 w, firmware_revision, model);
817 tgt->workarounds = w;
776} 818}
777 819
778static struct scsi_host_template scsi_driver_template; 820static struct scsi_host_template scsi_driver_template;