diff options
Diffstat (limited to 'drivers/ieee1394/sbp2.c')
-rw-r--r-- | drivers/ieee1394/sbp2.c | 243 |
1 files changed, 162 insertions, 81 deletions
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 2c765ca5aa5..5413dc43b9f 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -42,6 +42,7 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/string.h> +#include <linux/stringify.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/fs.h> @@ -117,7 +118,8 @@ MODULE_PARM_DESC(serialize_io, "Serialize I/O coming from scsi drivers (default */ static int max_sectors = SBP2_MAX_SECTORS; module_param(max_sectors, int, 0444); -MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = 255)"); +MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = " + __stringify(SBP2_MAX_SECTORS) ")"); /* * Exclusive login to sbp2 device? In most cases, the sbp2 driver should @@ -135,18 +137,45 @@ module_param(exclusive_login, int, 0644); MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)"); /* - * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on - * if your sbp2 device is not properly handling the SCSI inquiry command. - * This hack makes the inquiry look more like a typical MS Windows inquiry - * by enforcing 36 byte inquiry and avoiding access to mode_sense page 8. + * If any of the following workarounds is required for your device to work, + * please submit the kernel messages logged by sbp2 to the linux1394-devel + * mailing list. * - * If force_inquiry_hack=1 is required for your device to work, - * please submit the logged sbp2_firmware_revision value of this device to - * the linux1394-devel mailing list. + * - 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. */ +static int sbp2_default_workarounds; +module_param_named(workarounds, sbp2_default_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)"); + +/* legacy parameter */ static int force_inquiry_hack; module_param(force_inquiry_hack, int, 0644); -MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)"); +MODULE_PARM_DESC(force_inquiry_hack, "Deprecated, use 'workarounds'"); /* * Export information about protocols/devices supported by this driver. @@ -266,14 +295,55 @@ static struct hpsb_protocol_driver sbp2_driver = { }; /* - * List of device firmwares that require the inquiry hack. - * Yields a few false positives but did not break other devices so far. + * List of devices with known bugs. + * + * The firmware_revision field, masked with 0xffff00, is the best indicator + * for the type of bridge chip of a device. It yields a few false positives + * but this did not break correctly behaving devices so far. */ -static u32 sbp2_broken_inquiry_list[] = { - 0x00002800, /* Stefan Richter <stefanr@s5r6.in-berlin.de> */ - /* DViCO Momobay CX-1 */ - 0x00000200 /* Andreas Plesch <plesch@fas.harvard.edu> */ - /* QPS Fire DVDBurner */ +static const struct { + u32 firmware_revision; + u32 model_id; + unsigned workarounds; +} sbp2_workarounds_table[] = { + /* TSB42AA9 */ { + .firmware_revision = 0x002800, + .workarounds = SBP2_WORKAROUND_INQUIRY_36 | + SBP2_WORKAROUND_MODE_SENSE_8, + }, + /* Initio bridges, actually only needed for some older ones */ { + .firmware_revision = 0x000200, + .workarounds = SBP2_WORKAROUND_INQUIRY_36, + }, + /* Symbios bridge */ { + .firmware_revision = 0xa0b800, + .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, + }, + /* + * Note about the following Apple iPod blacklist entries: + * + * There are iPods (2nd gen, 3rd gen) with model_id==0. Since our + * matching logic treats 0 as a wildcard, we cannot match this ID + * without rewriting the matching routine. Fortunately these iPods + * do not feature the read_capacity bug according to one report. + * Read_capacity behaviour as well as model_id could change due to + * Apple-supplied firmware updates though. + */ + /* iPod 4th generation */ { + .firmware_revision = 0x0a2700, + .model_id = 0x000021, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + }, + /* iPod mini */ { + .firmware_revision = 0x0a2700, + .model_id = 0x000023, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + }, + /* iPod Photo */ { + .firmware_revision = 0x0a2700, + .model_id = 0x00007e, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + } }; /************************************** @@ -496,22 +566,17 @@ static struct sbp2_command_info *sbp2util_find_command_for_orb( /* * This function finds the sbp2_command for a given outstanding SCpnt. * Only looks at the inuse list. + * Must be called with scsi_id->sbp2_command_orb_lock held. */ -static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt) +static struct sbp2_command_info *sbp2util_find_command_for_SCpnt( + struct scsi_id_instance_data *scsi_id, void *SCpnt) { struct sbp2_command_info *command; - unsigned long flags; - spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); - if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { - list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) { - if (command->Current_SCpnt == SCpnt) { - spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); + if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) + list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) + if (command->Current_SCpnt == SCpnt) return command; - } - } - } - spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return NULL; } @@ -580,17 +645,15 @@ static void sbp2util_free_command_dma(struct sbp2_command_info *command) /* * This function moves a command to the completed orb list. + * Must be called with scsi_id->sbp2_command_orb_lock held. */ -static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, - struct sbp2_command_info *command) +static void sbp2util_mark_command_completed( + struct scsi_id_instance_data *scsi_id, + struct sbp2_command_info *command) { - unsigned long flags; - - spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); list_del(&command->list); sbp2util_free_command_dma(command); list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed); - spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); } /* @@ -772,12 +835,17 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud /* Register the status FIFO address range. We could use the same FIFO * for targets at different nodes. However we need different FIFOs per - * target in order to support multi-unit devices. */ + * target in order to support multi-unit devices. + * The FIFO is located out of the local host controller's physical range + * but, if possible, within the posted write area. Status writes will + * then be performed as unified transactions. This slightly reduces + * bandwidth usage, and some Prolific based devices seem to require it. + */ scsi_id->status_fifo_addr = hpsb_allocate_and_register_addrspace( &sbp2_highlevel, ud->ne->host, &sbp2_ops, sizeof(struct sbp2_status_block), sizeof(quadlet_t), - ~0ULL, ~0ULL); - if (!scsi_id->status_fifo_addr) { + 0x010000000000ULL, CSR1212_ALL_SPACE_END); + if (scsi_id->status_fifo_addr == ~0ULL) { SBP2_ERR("failed to allocate status FIFO address range"); goto failed_alloc; } @@ -1457,7 +1525,8 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id, struct csr1212_dentry *dentry; u64 management_agent_addr; u32 command_set_spec_id, command_set, unit_characteristics, - firmware_revision, workarounds; + firmware_revision; + unsigned workarounds; int i; SBP2_DEBUG_ENTER(); @@ -1513,12 +1582,8 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id, case SBP2_FIRMWARE_REVISION_KEY: /* Firmware revision */ firmware_revision = kv->value.immediate; - if (force_inquiry_hack) - SBP2_INFO("sbp2_firmware_revision = %x", - (unsigned int)firmware_revision); - else - SBP2_DEBUG("sbp2_firmware_revision = %x", - (unsigned int)firmware_revision); + SBP2_DEBUG("sbp2_firmware_revision = %x", + (unsigned int)firmware_revision); break; default: @@ -1526,41 +1591,44 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id, } } - /* This is the start of our broken device checking. We try to hack - * around oddities and known defects. */ - workarounds = 0x0; + workarounds = sbp2_default_workarounds; + if (force_inquiry_hack) { + SBP2_WARN("force_inquiry_hack is deprecated. " + "Use parameter 'workarounds' instead."); + workarounds |= SBP2_WORKAROUND_INQUIRY_36; + } - /* If the vendor id is 0xa0b8 (Symbios vendor id), then we have a - * bridge with 128KB max transfer size limitation. For sanity, we - * only voice this when the current max_sectors setting - * exceeds the 128k limit. By default, that is not the case. - * - * It would be really nice if we could detect this before the scsi - * host gets initialized. That way we can down-force the - * max_sectors to account for it. That is not currently - * possible. */ - if ((firmware_revision & 0xffff00) == - SBP2_128KB_BROKEN_FIRMWARE && - (max_sectors * 512) > (128*1024)) { - SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.", - NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid)); - SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!", - max_sectors); - workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER; - } - - /* Check for a blacklisted set of devices that require us to force - * a 36 byte host inquiry. This can be overriden as a module param - * (to force all hosts). */ - for (i = 0; i < ARRAY_SIZE(sbp2_broken_inquiry_list); i++) { - if ((firmware_revision & 0xffff00) == - sbp2_broken_inquiry_list[i]) { - SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround", - NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid)); - workarounds |= SBP2_BREAKAGE_INQUIRY_HACK; - break; /* No need to continue. */ + if (!(workarounds & SBP2_WORKAROUND_OVERRIDE)) + for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { + if (sbp2_workarounds_table[i].firmware_revision && + sbp2_workarounds_table[i].firmware_revision != + (firmware_revision & 0xffff00)) + continue; + if (sbp2_workarounds_table[i].model_id && + sbp2_workarounds_table[i].model_id != ud->model_id) + continue; + workarounds |= sbp2_workarounds_table[i].workarounds; + break; } - } + + if (workarounds) + SBP2_INFO("Workarounds for node " NODE_BUS_FMT ": 0x%x " + "(firmware_revision 0x%06x, vendor_id 0x%06x," + " model_id 0x%06x)", + NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid), + workarounds, firmware_revision, + ud->vendor_id ? ud->vendor_id : ud->ne->vendor_id, + ud->model_id); + + /* We would need one SCSI host template for each target to adjust + * max_sectors on the fly, therefore warn only. */ + if (workarounds & SBP2_WORKAROUND_128K_MAX_TRANS && + (max_sectors * 512) > (128 * 1024)) + SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB " + "max transfer size. WARNING: Current max_sectors " + "setting is larger than 128KB (%d sectors)", + NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid), + max_sectors); /* If this is a logical unit directory entry, process the parent * to get the values. */ @@ -2148,7 +2216,9 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest * Matched status with command, now grab scsi command pointers and check status */ SCpnt = command->Current_SCpnt; + spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); sbp2util_mark_command_completed(scsi_id, command); + spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); if (SCpnt) { @@ -2452,19 +2522,25 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev) scsi_id->sdev = sdev; - if (force_inquiry_hack || - scsi_id->workarounds & SBP2_BREAKAGE_INQUIRY_HACK) { + if (scsi_id->workarounds & SBP2_WORKAROUND_INQUIRY_36) sdev->inquiry_len = 36; - sdev->skip_ms_page_8 = 1; - } return 0; } static int sbp2scsi_slave_configure(struct scsi_device *sdev) { + struct scsi_id_instance_data *scsi_id = + (struct scsi_id_instance_data *)sdev->host->hostdata[0]; + blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + + if (sdev->type == TYPE_DISK && + scsi_id->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) + sdev->skip_ms_page_8 = 1; + if (scsi_id->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) + sdev->fix_capacity = 1; return 0; } @@ -2484,6 +2560,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) (struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0]; struct sbp2scsi_host_info *hi = scsi_id->hi; struct sbp2_command_info *command; + unsigned long flags; SBP2_ERR("aborting sbp2 command"); scsi_print_command(SCpnt); @@ -2494,6 +2571,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) * Right now, just return any matching command structures * to the free pool. */ + spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt); if (command) { SBP2_DEBUG("Found command to abort"); @@ -2511,6 +2589,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) command->Current_done(command->Current_SCpnt); } } + spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); /* * Initiate a fetch agent reset. @@ -2605,7 +2684,9 @@ static int sbp2_module_init(void) scsi_driver_template.cmd_per_lun = 1; } - /* Set max sectors (module load option). Default is 255 sectors. */ + if (sbp2_default_workarounds & SBP2_WORKAROUND_128K_MAX_TRANS && + (max_sectors * 512) > (128 * 1024)) + max_sectors = 128 * 1024 / 512; scsi_driver_template.max_sectors = max_sectors; /* Register our high level driver with 1394 stack */ |