diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 66 |
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); | |||
60 | MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " | 61 | MODULE_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 | |||
94 | static int sbp2_param_workarounds; | ||
95 | module_param_named(workarounds, sbp2_param_workarounds, int, 0644); | ||
96 | MODULE_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... */ |
64 | typedef void (*scsi_done_fn_t)(struct scsi_cmnd *); | 105 | typedef 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 | ||
778 | static struct scsi_host_template scsi_driver_template; | 820 | static struct scsi_host_template scsi_driver_template; |