X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Ffirewire%2Ffw-sbp2.c;h=aaff50ebba1def2892a8945be8b9289d39921c4f;hb=a95a5ed856e902e513119d4cc5b745faa202f761;hp=6255187928416231d9647e3901b7e184ddf33c3d;hpb=a5fd9ec7a29202f388fc011a11cfb0101d9f9a34;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 6255187..aaff50e 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -86,6 +86,11 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " * - delay inquiry * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry. * + * - power condition + * Set the power condition field in the START STOP UNIT commands sent by + * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on). + * Some disks need this to spin down or to resume properly. + * * - override internal blacklist * Instead of adding to the built-in blacklist, use only the workarounds * specified in the module load parameter. @@ -97,6 +102,7 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " #define SBP2_WORKAROUND_FIX_CAPACITY 0x8 #define SBP2_WORKAROUND_DELAY_INQUIRY 0x10 #define SBP2_INQUIRY_DELAY 12 +#define SBP2_WORKAROUND_POWER_CONDITION 0x20 #define SBP2_WORKAROUND_OVERRIDE 0x100 static int sbp2_param_workarounds; @@ -107,6 +113,8 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY) + ", set power condition in start stop unit = " + __stringify(SBP2_WORKAROUND_POWER_CONDITION) ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) ", or a combination)"); @@ -153,6 +161,7 @@ struct sbp2_target { struct list_head lu_list; u64 management_agent_address; + u64 guid; int directory_id; int node_id; int address_high; @@ -173,7 +182,8 @@ struct sbp2_target { #define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */ #define SBP2_ORB_NULL 0x80000000 #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 -#define SBP2_RETRY_LIMIT 0xf /* 15 retries */ +#define SBP2_RETRY_LIMIT 0xf /* 15 retries */ +#define SBP2_CYCLE_LIMIT (0xc8 << 12) /* 200 125us cycles */ /* Unit directory keys */ #define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a @@ -308,18 +318,25 @@ static const struct { .firmware_revision = 0x002800, .model = 0x001010, .workarounds = SBP2_WORKAROUND_INQUIRY_36 | - SBP2_WORKAROUND_MODE_SENSE_8, + SBP2_WORKAROUND_MODE_SENSE_8 | + SBP2_WORKAROUND_POWER_CONDITION, }, /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { .firmware_revision = 0x002800, .model = 0x000000, - .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY, + .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY | + SBP2_WORKAROUND_POWER_CONDITION, }, /* Initio bridges, actually only needed for some older ones */ { .firmware_revision = 0x000200, .model = ~0, .workarounds = SBP2_WORKAROUND_INQUIRY_36, }, + /* PL-3507 bridge with Prolific firmware */ { + .firmware_revision = 0x012800, + .model = ~0, + .workarounds = SBP2_WORKAROUND_POWER_CONDITION, + }, /* Symbios bridge */ { .firmware_revision = 0xa0b800, .model = ~0, @@ -526,7 +543,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, orb->response_bus = dma_map_single(device->card->device, &orb->response, sizeof(orb->response), DMA_FROM_DEVICE); - if (dma_mapping_error(orb->response_bus)) + if (dma_mapping_error(device->card->device, orb->response_bus)) goto fail_mapping_response; orb->request.response.high = 0; @@ -560,7 +577,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, orb->base.request_bus = dma_map_single(device->card->device, &orb->request, sizeof(orb->request), DMA_TO_DEVICE); - if (dma_mapping_error(orb->base.request_bus)) + if (dma_mapping_error(device->card->device, orb->base.request_bus)) goto fail_mapping_request; sbp2_send_orb(&orb->base, lu, node_id, generation, @@ -782,7 +799,7 @@ static void sbp2_release_target(struct kref *kref) kfree(lu); } scsi_remove_host(shost); - fw_notify("released %s\n", tgt->bus_id); + fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no); fw_unit_put(tgt->unit); scsi_host_put(shost); @@ -813,6 +830,22 @@ complete_set_busy_timeout(struct fw_card *card, int rcode, complete(done); } +/* + * Write retransmit retry values into the BUSY_TIMEOUT register. + * - The single-phase retry protocol is supported by all SBP-2 devices, but the + * default retry_limit value is 0 (i.e. never retry transmission). We write a + * saner value after logging into the device. + * - The dual-phase retry protocol is optional to implement, and if not + * supported, writes to the dual-phase portion of the register will be + * ignored. We try to write the original 1394-1995 default here. + * - In the case of devices that are also SBP-3-compliant, all writes are + * ignored, as the register is read-only, but contains single-phase retry of + * 15, which is what we're trying to set for all SBP-2 device anyway, so this + * write attempt is safe and yields more consistent behavior for all devices. + * + * See section 8.3.2.3.5 of the 1394-1995 spec, section 6.2 of the SBP-2 spec, + * and section 6.4 of the SBP-3 spec for further details. + */ static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) { struct fw_device *device = fw_device(lu->tgt->unit->device.parent); @@ -820,8 +853,7 @@ static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) struct fw_transaction t; static __be32 busy_timeout; - /* FIXME: we should try to set dual-phase cycle_limit too */ - busy_timeout = cpu_to_be32(SBP2_RETRY_LIMIT); + busy_timeout = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT); fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST, lu->tgt->node_id, lu->generation, device->max_speed, @@ -1034,7 +1066,8 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory, break; case SBP2_CSR_LOGICAL_UNIT_DIRECTORY: - if (sbp2_scan_logical_unit_dir(tgt, ci.p + value) < 0) + /* Adjust for the increment in the iterator */ + if (sbp2_scan_logical_unit_dir(tgt, ci.p - 1 + value) < 0) return -ENOMEM; break; } @@ -1098,6 +1131,7 @@ static int sbp2_probe(struct device *dev) kref_init(&tgt->kref); INIT_LIST_HEAD(&tgt->lu_list); tgt->bus_id = unit->device.bus_id; + tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; if (fw_device_enable_phys_dma(device) < 0) goto fail_shost_put; @@ -1390,7 +1424,7 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, orb->page_table_bus = dma_map_single(device->card->device, orb->page_table, sizeof(orb->page_table), DMA_TO_DEVICE); - if (dma_mapping_error(orb->page_table_bus)) + if (dma_mapping_error(device->card->device, orb->page_table_bus)) goto fail_page_table; /* @@ -1469,13 +1503,13 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0) goto out; - memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd)); + memcpy(orb->request.command_block, cmd->cmnd, cmd->cmd_len); orb->base.callback = complete_command_orb; orb->base.request_bus = dma_map_single(device->card->device, &orb->request, sizeof(orb->request), DMA_TO_DEVICE); - if (dma_mapping_error(orb->base.request_bus)) + if (dma_mapping_error(device->card->device, orb->base.request_bus)) goto out; sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, lu->generation, @@ -1511,6 +1545,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) sdev->use_10_for_rw = 1; + if (sbp2_param_exclusive_login) + sdev->manage_start_stop = 1; + if (sdev->type == TYPE_ROM) sdev->use_10_for_ms = 1; @@ -1521,6 +1558,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) if (lu->tgt->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) sdev->fix_capacity = 1; + if (lu->tgt->workarounds & SBP2_WORKAROUND_POWER_CONDITION) + sdev->start_stop_pwr_cond = 1; + if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512); @@ -1555,16 +1595,14 @@ sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr, { struct scsi_device *sdev = to_scsi_device(dev); struct sbp2_logical_unit *lu; - struct fw_device *device; if (!sdev) return 0; lu = sdev->hostdata; - device = fw_device(lu->tgt->unit->device.parent); - return sprintf(buf, "%08x%08x:%06x:%04x\n", - device->config_rom[3], device->config_rom[4], + return sprintf(buf, "%016llx:%06x:%04x\n", + (unsigned long long)lu->tgt->guid, lu->tgt->directory_id, lu->lun); }