diff options
| author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-08-13 11:48:25 -0400 |
|---|---|---|
| committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-10-16 18:00:03 -0400 |
| commit | 2df222b8f8fe9e18c9c9fdfd46f60dad55f5ac14 (patch) | |
| tree | d01c8f5a5840c8e975d50ca84d20bb581876030e /drivers/firewire | |
| parent | 5a3c2be6c9a5641a06c71c906645d676fa4d3fdc (diff) | |
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: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
| -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; |
