diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-12-20 23:39:47 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-12-20 23:39:47 +0100 |
commit | 55fa518867978e1f5fd8353098f80d125ac734d7 (patch) | |
tree | 3502b331c1f9ec4cac25dc8ba30b6a0a324e350c /drivers/firewire | |
parent | bb1f24bf00a85f666b56a09b7cdbfd221af16c2c (diff) | |
parent | eea0579fc85e64e9f05361d5aacf496fe7a151aa (diff) |
Merge branch 'topic/pcsp-fix' into topic/misc
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/fw-card.c | 56 | ||||
-rw-r--r-- | drivers/firewire/fw-cdev.c | 6 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 51 | ||||
-rw-r--r-- | drivers/firewire/fw-ohci.c | 52 | ||||
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 156 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.c | 6 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.c | 48 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 11 |
8 files changed, 198 insertions, 188 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index bbd73a406e53..418c18f07e9d 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -189,39 +189,16 @@ static const char gap_count_table[] = { 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 }; -struct bm_data { - struct fw_transaction t; - struct { - __be32 arg; - __be32 data; - } lock; - u32 old; - int rcode; - struct completion done; -}; - -static void -complete_bm_lock(struct fw_card *card, int rcode, - void *payload, size_t length, void *data) -{ - struct bm_data *bmd = data; - - if (rcode == RCODE_COMPLETE) - bmd->old = be32_to_cpu(*(__be32 *) payload); - bmd->rcode = rcode; - complete(&bmd->done); -} - static void fw_card_bm_work(struct work_struct *work) { struct fw_card *card = container_of(work, struct fw_card, work.work); struct fw_device *root_device; struct fw_node *root_node, *local_node; - struct bm_data bmd; unsigned long flags; - int root_id, new_root_id, irm_id, gap_count, generation, grace; + int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode; bool do_reset = false; + __be32 lock_data[2]; spin_lock_irqsave(&card->lock, flags); local_node = card->local_node; @@ -263,33 +240,28 @@ fw_card_bm_work(struct work_struct *work) goto pick_me; } - bmd.lock.arg = cpu_to_be32(0x3f); - bmd.lock.data = cpu_to_be32(local_node->node_id); + lock_data[0] = cpu_to_be32(0x3f); + lock_data[1] = cpu_to_be32(local_node->node_id); spin_unlock_irqrestore(&card->lock, flags); - init_completion(&bmd.done); - fw_send_request(card, &bmd.t, TCODE_LOCK_COMPARE_SWAP, - irm_id, generation, - SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, - &bmd.lock, sizeof(bmd.lock), - complete_bm_lock, &bmd); - wait_for_completion(&bmd.done); + rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, + irm_id, generation, SCODE_100, + CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, + lock_data, sizeof(lock_data)); - if (bmd.rcode == RCODE_GENERATION) { - /* - * Another bus reset happened. Just return, - * the BM work has been rescheduled. - */ + if (rcode == RCODE_GENERATION) + /* Another bus reset, BM work has been rescheduled. */ goto out; - } - if (bmd.rcode == RCODE_COMPLETE && bmd.old != 0x3f) + if (rcode == RCODE_COMPLETE && + lock_data[0] != cpu_to_be32(0x3f)) /* Somebody else is BM, let them do the work. */ goto out; spin_lock_irqsave(&card->lock, flags); - if (bmd.rcode != RCODE_COMPLETE) { + + if (rcode != RCODE_COMPLETE) { /* * The lock request failed, maybe the IRM * isn't really IRM capable after all. Let's diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 2e6d5848d217..ed03234cbea8 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -720,8 +720,8 @@ static int ioctl_create_iso_context(struct client *client, void *buffer) #define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff) #define GET_INTERRUPT(v) (((v) >> 16) & 0x01) #define GET_SKIP(v) (((v) >> 17) & 0x01) -#define GET_TAG(v) (((v) >> 18) & 0x02) -#define GET_SY(v) (((v) >> 20) & 0x04) +#define GET_TAG(v) (((v) >> 18) & 0x03) +#define GET_SY(v) (((v) >> 20) & 0x0f) #define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff) static int ioctl_queue_iso(struct client *client, void *buffer) @@ -913,7 +913,7 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg) return -EFAULT; } - return 0; + return retval; } static long diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 0855fb5568e8..6b9be42c7b98 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -381,46 +381,21 @@ static struct device_attribute fw_device_attributes[] = { __ATTR_NULL, }; -struct read_quadlet_callback_data { - struct completion done; - int rcode; - u32 data; -}; - -static void -complete_transaction(struct fw_card *card, int rcode, - void *payload, size_t length, void *data) -{ - struct read_quadlet_callback_data *callback_data = data; - - if (rcode == RCODE_COMPLETE) - callback_data->data = be32_to_cpu(*(__be32 *)payload); - callback_data->rcode = rcode; - complete(&callback_data->done); -} - static int read_rom(struct fw_device *device, int generation, int index, u32 *data) { - struct read_quadlet_callback_data callback_data; - struct fw_transaction t; - u64 offset; + int rcode; /* device->node_id, accessed below, must not be older than generation */ smp_rmb(); - init_completion(&callback_data.done); - - offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4; - fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, + rcode = fw_run_transaction(device->card, TCODE_READ_QUADLET_REQUEST, device->node_id, generation, device->max_speed, - offset, NULL, 4, complete_transaction, &callback_data); - - wait_for_completion(&callback_data.done); - - *data = callback_data.data; + (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4, + data, 4); + be32_to_cpus(data); - return callback_data.rcode; + return rcode; } #define READ_BIB_ROM_SIZE 256 @@ -612,8 +587,7 @@ static void create_units(struct fw_device *device) unit->device.bus = &fw_bus_type; unit->device.type = &fw_unit_type; unit->device.parent = &device->device; - snprintf(unit->device.bus_id, sizeof(unit->device.bus_id), - "%s.%d", device->device.bus_id, i++); + dev_set_name(&unit->device, "%s.%d", dev_name(&device->device), i++); init_fw_attribute_group(&unit->device, fw_unit_attributes, @@ -736,8 +710,7 @@ static void fw_device_init(struct work_struct *work) device->device.type = &fw_device_type; device->device.parent = device->card->device; device->device.devt = MKDEV(fw_cdev_major, minor); - snprintf(device->device.bus_id, sizeof(device->device.bus_id), - "fw%d", minor); + dev_set_name(&device->device, "fw%d", minor); init_fw_attribute_group(&device->device, fw_device_attributes, @@ -766,13 +739,13 @@ static void fw_device_init(struct work_struct *work) if (device->config_rom_retries) fw_notify("created device %s: GUID %08x%08x, S%d00, " "%d config ROM retries\n", - device->device.bus_id, + dev_name(&device->device), device->config_rom[3], device->config_rom[4], 1 << device->max_speed, device->config_rom_retries); else fw_notify("created device %s: GUID %08x%08x, S%d00\n", - device->device.bus_id, + dev_name(&device->device), device->config_rom[3], device->config_rom[4], 1 << device->max_speed); device->config_rom_retries = 0; @@ -908,12 +881,12 @@ static void fw_device_refresh(struct work_struct *work) FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) goto gone; - fw_notify("refreshed device %s\n", device->device.bus_id); + fw_notify("refreshed device %s\n", dev_name(&device->device)); device->config_rom_retries = 0; goto out; give_up: - fw_notify("giving up on refresh of device %s\n", device->device.bus_id); + fw_notify("giving up on refresh of device %s\n", dev_name(&device->device)); gone: atomic_set(&device->state, FW_DEVICE_SHUTDOWN); fw_device_shutdown(work); diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 251416f2148f..46610b090415 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -476,6 +476,7 @@ static int ar_context_add_page(struct ar_context *ctx) if (ab == NULL) return -ENOMEM; + ab->next = NULL; memset(&ab->descriptor, 0, sizeof(ab->descriptor)); ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | DESCRIPTOR_STATUS | @@ -496,6 +497,21 @@ static int ar_context_add_page(struct ar_context *ctx) return 0; } +static void ar_context_release(struct ar_context *ctx) +{ + struct ar_buffer *ab, *ab_next; + size_t offset; + dma_addr_t ab_bus; + + for (ab = ctx->current_buffer; ab; ab = ab_next) { + ab_next = ab->next; + offset = offsetof(struct ar_buffer, data); + ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset; + dma_free_coherent(ctx->ohci->card.device, PAGE_SIZE, + ab, ab_bus); + } +} + #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) #define cond_le32_to_cpu(v) \ (ohci->old_uninorth ? (__force __u32)(v) : le32_to_cpu(v)) @@ -2349,8 +2365,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); if (ohci == NULL) { - fw_error("Could not malloc fw_ohci data.\n"); - return -ENOMEM; + err = -ENOMEM; + goto fail; } fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev); @@ -2359,7 +2375,7 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) err = pci_enable_device(dev); if (err) { - fw_error("Failed to enable OHCI hardware.\n"); + fw_error("Failed to enable OHCI hardware\n"); goto fail_free; } @@ -2427,9 +2443,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ohci->ir_context_list = kzalloc(size, GFP_KERNEL); if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) { - fw_error("Out of memory for it/ir contexts.\n"); err = -ENOMEM; - goto fail_registers; + goto fail_contexts; } /* self-id dma buffer allocation */ @@ -2438,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) &ohci->self_id_bus, GFP_KERNEL); if (ohci->self_id_cpu == NULL) { - fw_error("Out of memory for self ID buffer.\n"); err = -ENOMEM; - goto fail_registers; + goto fail_contexts; } bus_options = reg_read(ohci, OHCI1394_BusOptions); @@ -2454,15 +2468,19 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) goto fail_self_id; fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n", - dev->dev.bus_id, version >> 16, version & 0xff); + dev_name(&dev->dev), version >> 16, version & 0xff); return 0; fail_self_id: dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, ohci->self_id_cpu, ohci->self_id_bus); - fail_registers: - kfree(ohci->it_context_list); + fail_contexts: kfree(ohci->ir_context_list); + kfree(ohci->it_context_list); + context_release(&ohci->at_response_ctx); + context_release(&ohci->at_request_ctx); + ar_context_release(&ohci->ar_response_ctx); + ar_context_release(&ohci->ar_request_ctx); pci_iounmap(dev, ohci->registers); fail_iomem: pci_release_region(dev, 0); @@ -2471,6 +2489,9 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) fail_free: kfree(&ohci->card); ohci_pmac_off(dev); + fail: + if (err == -ENOMEM) + fw_error("Out of memory\n"); return err; } @@ -2491,8 +2512,19 @@ static void pci_remove(struct pci_dev *dev) software_reset(ohci); free_irq(dev->irq, ohci); + + if (ohci->next_config_rom && ohci->next_config_rom != ohci->config_rom) + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + ohci->next_config_rom, ohci->next_config_rom_bus); + if (ohci->config_rom) + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + ohci->config_rom, ohci->config_rom_bus); dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, ohci->self_id_cpu, ohci->self_id_bus); + ar_context_release(&ohci->ar_request_ctx); + ar_context_release(&ohci->ar_response_ctx); + context_release(&ohci->at_request_ctx); + context_release(&ohci->at_response_ctx); kfree(ohci->it_context_list); kfree(ohci->ir_context_list); pci_iounmap(dev, ohci->registers); diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index aaff50ebba1d..97df6dac3a82 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -29,6 +29,7 @@ */ #include <linux/blkdev.h> +#include <linux/bug.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/dma-mapping.h> @@ -172,6 +173,9 @@ struct sbp2_target { int blocked; /* ditto */ }; +/* Impossible login_id, to detect logout attempt before successful login */ +#define INVALID_LOGIN_ID 0x10000 + /* * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be * provided in the config rom. Most devices do provide a value, which @@ -181,10 +185,16 @@ struct sbp2_target { #define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */ #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_CYCLE_LIMIT (0xc8 << 12) /* 200 125us cycles */ +/* + * The default maximum s/g segment size of a FireWire controller is + * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to + * be quadlet-aligned, we set the length limit to 0xffff & ~3. + */ +#define SBP2_MAX_SEG_SIZE 0xfffc + /* Unit directory keys */ #define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a #define SBP2_CSR_FIRMWARE_REVISION 0x3c @@ -621,25 +631,15 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, return retval; } -static void -complete_agent_reset_write(struct fw_card *card, int rcode, - void *payload, size_t length, void *done) -{ - complete(done); -} - static void sbp2_agent_reset(struct sbp2_logical_unit *lu) { struct fw_device *device = fw_device(lu->tgt->unit->device.parent); - DECLARE_COMPLETION_ONSTACK(done); - struct fw_transaction t; - static u32 z; + __be32 d = 0; - fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST, - lu->tgt->node_id, lu->generation, device->max_speed, - lu->command_block_agent_address + SBP2_AGENT_RESET, - &z, sizeof(z), complete_agent_reset_write, &done); - wait_for_completion(&done); + fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, + lu->tgt->node_id, lu->generation, device->max_speed, + lu->command_block_agent_address + SBP2_AGENT_RESET, + &d, sizeof(d)); } static void @@ -653,7 +653,7 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) { struct fw_device *device = fw_device(lu->tgt->unit->device.parent); struct fw_transaction *t; - static u32 z; + static __be32 d; t = kmalloc(sizeof(*t), GFP_ATOMIC); if (t == NULL) @@ -662,7 +662,7 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST, lu->tgt->node_id, lu->generation, device->max_speed, lu->command_block_agent_address + SBP2_AGENT_RESET, - &z, sizeof(z), complete_agent_reset_write_no_wait, t); + &d, sizeof(d), complete_agent_reset_write_no_wait, t); } static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation) @@ -791,9 +791,20 @@ static void sbp2_release_target(struct kref *kref) scsi_remove_device(sdev); scsi_device_put(sdev); } - sbp2_send_management_orb(lu, tgt->node_id, lu->generation, - SBP2_LOGOUT_REQUEST, lu->login_id, NULL); - + if (lu->login_id != INVALID_LOGIN_ID) { + int generation, node_id; + /* + * tgt->node_id may be obsolete here if we failed + * during initial login or after a bus reset where + * the topology changed. + */ + generation = device->generation; + smp_rmb(); /* node_id vs. generation */ + node_id = device->node_id; + sbp2_send_management_orb(lu, node_id, generation, + SBP2_LOGOUT_REQUEST, + lu->login_id, NULL); + } fw_core_remove_address_handler(&lu->address_handler); list_del(&lu->link); kfree(lu); @@ -808,26 +819,20 @@ static void sbp2_release_target(struct kref *kref) static struct workqueue_struct *sbp2_wq; -/* - * Always get the target's kref when scheduling work on one its units. - * Each workqueue job is responsible to call sbp2_target_put() upon return. - */ -static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) -{ - if (queue_delayed_work(sbp2_wq, &lu->work, delay)) - kref_get(&lu->tgt->kref); -} - static void sbp2_target_put(struct sbp2_target *tgt) { kref_put(&tgt->kref, sbp2_release_target); } -static void -complete_set_busy_timeout(struct fw_card *card, int rcode, - void *payload, size_t length, void *done) +/* + * Always get the target's kref when scheduling work on one its units. + * Each workqueue job is responsible to call sbp2_target_put() upon return. + */ +static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) { - complete(done); + kref_get(&lu->tgt->kref); + if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) + sbp2_target_put(lu->tgt); } /* @@ -849,17 +854,12 @@ complete_set_busy_timeout(struct fw_card *card, int rcode, static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) { struct fw_device *device = fw_device(lu->tgt->unit->device.parent); - DECLARE_COMPLETION_ONSTACK(done); - struct fw_transaction t; - static __be32 busy_timeout; + __be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | 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, - CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, &busy_timeout, - sizeof(busy_timeout), complete_set_busy_timeout, &done); - wait_for_completion(&done); + fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, + lu->tgt->node_id, lu->generation, device->max_speed, + CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, + &d, sizeof(d)); } static void sbp2_reconnect(struct work_struct *work); @@ -993,6 +993,7 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) lu->tgt = tgt; lu->lun = lun_entry & 0xffff; + lu->login_id = INVALID_LOGIN_ID; lu->retries = 0; lu->has_sdev = false; lu->blocked = false; @@ -1121,6 +1122,10 @@ static int sbp2_probe(struct device *dev) struct Scsi_Host *shost; u32 model, firmware_revision; + if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE) + BUG_ON(dma_set_max_seg_size(device->card->device, + SBP2_MAX_SEG_SIZE)); + shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt)); if (shost == NULL) return -ENOMEM; @@ -1130,7 +1135,7 @@ static int sbp2_probe(struct device *dev) tgt->unit = unit; kref_init(&tgt->kref); INIT_LIST_HEAD(&tgt->lu_list); - tgt->bus_id = unit->device.bus_id; + tgt->bus_id = dev_name(&unit->device); tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; if (fw_device_enable_phys_dma(device) < 0) @@ -1158,7 +1163,7 @@ static int sbp2_probe(struct device *dev) /* Do the login in a workqueue so we can easily reschedule retries. */ list_for_each_entry(lu, &tgt->lu_list, link) - sbp2_queue_work(lu, 0); + sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); return 0; fail_tgt_put: @@ -1369,14 +1374,12 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, struct sbp2_logical_unit *lu) { - struct scatterlist *sg; - int sg_len, l, i, j, count; - dma_addr_t sg_addr; - - sg = scsi_sglist(orb->cmd); - count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd), - orb->cmd->sc_data_direction); - if (count == 0) + struct scatterlist *sg = scsi_sglist(orb->cmd); + int i, n; + + n = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd), + orb->cmd->sc_data_direction); + if (n == 0) goto fail; /* @@ -1386,7 +1389,7 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, * as the second generation iPod which doesn't support page * tables. */ - if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) { + if (n == 1) { orb->request.data_descriptor.high = cpu_to_be32(lu->tgt->address_high); orb->request.data_descriptor.low = @@ -1396,29 +1399,9 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, return 0; } - /* - * Convert the scatterlist to an sbp2 page table. If any - * scatterlist entries are too big for sbp2, we split them as we - * go. Even if we ask the block I/O layer to not give us sg - * elements larger than 65535 bytes, some IOMMUs may merge sg elements - * during DMA mapping, and Linux currently doesn't prevent this. - */ - for (i = 0, j = 0; i < count; i++, sg = sg_next(sg)) { - sg_len = sg_dma_len(sg); - sg_addr = sg_dma_address(sg); - while (sg_len) { - /* FIXME: This won't get us out of the pinch. */ - if (unlikely(j >= ARRAY_SIZE(orb->page_table))) { - fw_error("page table overflow\n"); - goto fail_page_table; - } - l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH); - orb->page_table[j].low = cpu_to_be32(sg_addr); - orb->page_table[j].high = cpu_to_be32(l << 16); - sg_addr += l; - sg_len -= l; - j++; - } + for_each_sg(sg, sg, n, i) { + orb->page_table[i].high = cpu_to_be32(sg_dma_len(sg) << 16); + orb->page_table[i].low = cpu_to_be32(sg_dma_address(sg)); } orb->page_table_bus = @@ -1437,13 +1420,13 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, orb->request.data_descriptor.high = cpu_to_be32(lu->tgt->address_high); orb->request.data_descriptor.low = cpu_to_be32(orb->page_table_bus); orb->request.misc |= cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT | - COMMAND_ORB_DATA_SIZE(j)); + COMMAND_ORB_DATA_SIZE(n)); return 0; fail_page_table: - dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd), - orb->cmd->sc_data_direction); + dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd), + scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction); fail: return -ENOMEM; } @@ -1456,7 +1439,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) struct fw_device *device = fw_device(lu->tgt->unit->device.parent); struct sbp2_command_orb *orb; unsigned int max_payload; - int retval = SCSI_MLQUEUE_HOST_BUSY; + int generation, retval = SCSI_MLQUEUE_HOST_BUSY; /* * Bidirectional commands are not yet implemented, and unknown @@ -1500,6 +1483,9 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) if (cmd->sc_data_direction == DMA_FROM_DEVICE) orb->request.misc |= cpu_to_be32(COMMAND_ORB_DIRECTION); + generation = device->generation; + smp_rmb(); /* sbp2_map_scatterlist looks at tgt->address_high */ + if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0) goto out; @@ -1512,7 +1498,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) 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, + sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, generation, lu->command_block_agent_address + SBP2_ORB_POINTER); retval = 0; out: @@ -1564,6 +1550,8 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512); + blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE); + return 0; } diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index c1b81077c4a8..5e204713002d 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c @@ -413,7 +413,7 @@ static void update_tree(struct fw_card *card, struct fw_node *root) { struct list_head list0, list1; - struct fw_node *node0, *node1; + struct fw_node *node0, *node1, *next1; int i, event; INIT_LIST_HEAD(&list0); @@ -485,7 +485,9 @@ update_tree(struct fw_card *card, struct fw_node *root) } node0 = fw_node(node0->link.next); - node1 = fw_node(node1->link.next); + next1 = fw_node(node1->link.next); + fw_node_put(node1); + node1 = next1; } } diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index e5d1a0b64fcf..022ac4fabb67 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -247,7 +247,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, */ void fw_send_request(struct fw_card *card, struct fw_transaction *t, - int tcode, int node_id, int generation, int speed, + int tcode, int destination_id, int generation, int speed, unsigned long long offset, void *payload, size_t length, fw_transaction_callback_t callback, void *callback_data) @@ -279,13 +279,14 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, card->current_tlabel = (card->current_tlabel + 1) & 0x1f; card->tlabel_mask |= (1 << tlabel); - t->node_id = node_id; + t->node_id = destination_id; t->tlabel = tlabel; t->callback = callback; t->callback_data = callback_data; - fw_fill_request(&t->packet, tcode, t->tlabel, node_id, card->node_id, - generation, speed, offset, payload, length); + fw_fill_request(&t->packet, tcode, t->tlabel, + destination_id, card->node_id, generation, + speed, offset, payload, length); t->packet.callback = transmit_complete_callback; list_add_tail(&t->link, &card->transaction_list); @@ -296,6 +297,45 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, } EXPORT_SYMBOL(fw_send_request); +struct transaction_callback_data { + struct completion done; + void *payload; + int rcode; +}; + +static void transaction_callback(struct fw_card *card, int rcode, + void *payload, size_t length, void *data) +{ + struct transaction_callback_data *d = data; + + if (rcode == RCODE_COMPLETE) + memcpy(d->payload, payload, length); + d->rcode = rcode; + complete(&d->done); +} + +/** + * fw_run_transaction - send request and sleep until transaction is completed + * + * Returns the RCODE. + */ +int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, + int generation, int speed, unsigned long long offset, + void *data, size_t length) +{ + struct transaction_callback_data d; + struct fw_transaction t; + + init_completion(&d.done); + d.payload = data; + fw_send_request(card, &t, tcode, destination_id, generation, speed, + offset, data, length, transaction_callback, &d); + wait_for_completion(&d.done); + + return d.rcode; +} +EXPORT_SYMBOL(fw_run_transaction); + static DEFINE_MUTEX(phy_config_mutex); static DECLARE_COMPLETION(phy_config_done); diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 2ae1b0d6cb7b..aed7dbb17cda 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -248,7 +248,7 @@ struct fw_card { struct fw_node *local_node; struct fw_node *root_node; struct fw_node *irm_node; - int color; + u8 color; /* must be u8 to match the definition in struct fw_node */ int gap_count; bool beta_repeaters_present; @@ -426,11 +426,14 @@ fw_core_initiate_bus_reset(struct fw_card *card, int short_reset); void fw_send_request(struct fw_card *card, struct fw_transaction *t, - int tcode, int node_id, int generation, int speed, - unsigned long long offset, - void *data, size_t length, + int tcode, int destination_id, int generation, int speed, + unsigned long long offset, void *data, size_t length, fw_transaction_callback_t callback, void *callback_data); +int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, + int generation, int speed, unsigned long long offset, + void *data, size_t length); + int fw_cancel_transaction(struct fw_card *card, struct fw_transaction *transaction); |