Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+54 −12
Original line number Diff line number Diff line
@@ -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;