Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 289971 Details for
Bug 370421
Upgrade firewire stack to latest upstream
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Proposed patch
c (text/plain), 80.28 KB, created by
Jay Fenlason
on 2007-12-19 03:49:15 UTC
(
hide
)
Description:
Proposed patch
Filename:
MIME Type:
Creator:
Jay Fenlason
Created:
2007-12-19 03:49:15 UTC
Size:
80.28 KB
patch
obsolete
>diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-card.c linux-2.6.18.i686/drivers/firewire/fw-card.c >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-card.c 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-card.c 2007-12-11 13:51:06.000000000 -0500 >@@ -569,9 +569,11 @@ fw_core_remove_card(struct fw_card *card > /* Set up the dummy driver. */ > card->driver = &dummy_driver; > >- fw_flush_transactions(card); >- > fw_destroy_nodes(card); >+ flush_scheduled_work(); >+ >+ fw_flush_transactions(card); >+ del_timer_sync(&card->flush_timer); > > fw_card_put(card); > } >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-cdev.c linux-2.6.18.i686/drivers/firewire/fw-cdev.c >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-cdev.c 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-cdev.c 2007-12-11 13:51:06.000000000 -0500 >@@ -23,20 +23,19 @@ > #include <linux/device.h> > #include <linux/vmalloc.h> > #include <linux/poll.h> >+#include <linux/preempt.h> >+#include <linux/time.h> > #include <linux/delay.h> > #include <linux/mm.h> > #include <linux/idr.h> > #include <linux/compat.h> > #include <linux/firewire-cdev.h> >+#include <asm/system.h> > #include <asm/uaccess.h> > #include "fw-transaction.h" > #include "fw-topology.h" > #include "fw-device.h" > >-/* >- * dequeue_event() just kfree()'s the event, so the event has to be >- * the first field in the struct. >- */ > > struct client; > struct client_resource { >@@ -45,6 +44,11 @@ struct client_resource { > u32 handle; > }; > >+/* >+ * dequeue_event() just kfree()'s the event, so the event has to be >+ * the first field in the struct. >+ */ >+ > struct event { > struct { void *data; size_t size; } v[2]; > struct list_head link; >@@ -138,11 +142,10 @@ static void queue_event(struct client *c > event->v[1].size = size1; > > spin_lock_irqsave(&client->lock, flags); >- > list_add_tail(&event->link, &client->event_list); >- wake_up_interruptible(&client->wait); >- > spin_unlock_irqrestore(&client->lock, flags); >+ >+ wake_up_interruptible(&client->wait); > } > > static int >@@ -363,7 +366,7 @@ complete_transaction(struct fw_card *car > response->response.data, response->response.length); > } > >-static ssize_t ioctl_send_request(struct client *client, void *buffer) >+static int ioctl_send_request(struct client *client, void *buffer) > { > struct fw_device *device = client->device; > struct fw_cdev_send_request *request = buffer; >@@ -395,7 +398,7 @@ static ssize_t ioctl_send_request(struct > request->tcode & 0x1f, > device->node->node_id, > request->generation, >- device->node->max_speed, >+ device->max_speed, > request->offset, > response->response.data, request->length, > complete_transaction, response); >@@ -619,25 +622,25 @@ iso_callback(struct fw_iso_context *cont > size_t header_length, void *header, void *data) > { > struct client *client = data; >- struct iso_interrupt *interrupt; >+ struct iso_interrupt *irq; > >- interrupt = kzalloc(sizeof(*interrupt) + header_length, GFP_ATOMIC); >- if (interrupt == NULL) >+ irq = kzalloc(sizeof(*irq) + header_length, GFP_ATOMIC); >+ if (irq == NULL) > return; > >- interrupt->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; >- interrupt->interrupt.closure = client->iso_closure; >- interrupt->interrupt.cycle = cycle; >- interrupt->interrupt.header_length = header_length; >- memcpy(interrupt->interrupt.header, header, header_length); >- queue_event(client, &interrupt->event, >- &interrupt->interrupt, >- sizeof(interrupt->interrupt) + header_length, NULL, 0); >+ irq->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT; >+ irq->interrupt.closure = client->iso_closure; >+ irq->interrupt.cycle = cycle; >+ irq->interrupt.header_length = header_length; >+ memcpy(irq->interrupt.header, header, header_length); >+ queue_event(client, &irq->event, &irq->interrupt, >+ sizeof(irq->interrupt) + header_length, NULL, 0); > } > > static int ioctl_create_iso_context(struct client *client, void *buffer) > { > struct fw_cdev_create_iso_context *request = buffer; >+ struct fw_iso_context *context; > > if (request->channel > 63) > return -EINVAL; >@@ -659,16 +662,17 @@ static int ioctl_create_iso_context(stru > return -EINVAL; > } > >- client->iso_closure = request->closure; >- client->iso_context = fw_iso_context_create(client->device->card, >+ context = fw_iso_context_create(client->device->card, > request->type, > request->channel, > request->speed, > request->header_size, > iso_callback, client); >- if (IS_ERR(client->iso_context)) >- return PTR_ERR(client->iso_context); >+ if (IS_ERR(context)) >+ return PTR_ERR(context); > >+ client->iso_closure = request->closure; >+ client->iso_context = context; > /* We only support one context at this time. */ > request->handle = 0; > >@@ -717,28 +721,29 @@ static int ioctl_queue_iso(struct client > buffer_end = 0; > } > >- if (!access_ok(VERIFY_READ, request->packets, request->size)) >+ p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); >+ >+ if (!access_ok(VERIFY_READ, p, request->size)) > return -EFAULT; > >- p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); > end = (void __user *)p + request->size; > count = 0; > while (p < end) { > if (get_user(control, &p->control)) > return -EFAULT; >- > u.packet.payload_length = GET_PAYLOAD_LENGTH(control); > u.packet.interrupt = GET_INTERRUPT(control); > u.packet.skip = GET_SKIP(control); > u.packet.tag = GET_TAG(control); > u.packet.sy = GET_SY(control); > u.packet.header_length = GET_HEADER_LENGTH(control); >+ > if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) { > header_length = u.packet.header_length; > } else { > /* > * We require that header_length is a multiple of >- * the fixed header size, ctx->header_size >+ * the fixed header size, ctx->header_size. > */ > if (ctx->header_size == 0) { > if (u.packet.header_length > 0) >@@ -806,6 +811,28 @@ static int ioctl_stop_iso(struct client > return fw_iso_context_stop(client->iso_context); > } > >+static int ioctl_get_cycle_timer(struct client *client, void *buffer) >+{ >+ struct fw_cdev_get_cycle_timer *request = buffer; >+ struct fw_card *card = client->device->card; >+ unsigned long long bus_time; >+ struct timeval tv; >+ unsigned long flags; >+ >+ preempt_disable(); >+ local_irq_save(flags); >+ >+ bus_time = card->driver->get_bus_time(card); >+ do_gettimeofday(&tv); >+ >+ local_irq_restore(flags); >+ preempt_enable(); >+ >+ request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec; >+ request->cycle_timer = bus_time & 0xffffffff; >+ return 0; >+} >+ > static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { > ioctl_get_info, > ioctl_send_request, >@@ -819,6 +846,7 @@ static int (* const ioctl_handlers[])(st > ioctl_queue_iso, > ioctl_start_iso, > ioctl_stop_iso, >+ ioctl_get_cycle_timer, > }; > > static int >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-device.c linux-2.6.18.i686/drivers/firewire/fw-device.c >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-device.c 2007-11-13 21:16:19.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-device.c 2007-12-11 13:51:06.000000000 -0500 >@@ -141,8 +141,8 @@ fw_unit_uevent(struct device *dev, char > get_modalias(unit, modalias, sizeof(modalias)); > > if (add_uevent_var(envp, num_envp, >- &i, buffer, buffer_size, &length, >- "MODALIAS=%s", modalias)) >+ &i, buffer, buffer_size, &length, >+ "MODALIAS=%s", modalias)) > return -ENOMEM; > } > >@@ -400,8 +400,7 @@ static int read_rom(struct fw_device *de > > offset = 0xfffff0000400ULL + index * 4; > fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, >- device->node_id, >- device->generation, SCODE_100, >+ device->node_id, device->generation, device->max_speed, > offset, NULL, 4, complete_transaction, &callback_data); > > wait_for_completion(&callback_data.done); >@@ -417,6 +416,8 @@ static int read_bus_info_block(struct fw > u32 stack[16], sp, key; > int i, end, length; > >+ device->max_speed = SCODE_100; >+ > /* First read the bus info block. */ > for (i = 0; i < 5; i++) { > if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) >@@ -433,6 +434,33 @@ static int read_bus_info_block(struct fw > return -1; > } > >+ device->max_speed = device->node->max_speed; >+ >+ /* >+ * Determine the speed of >+ * - devices with link speed less than PHY speed, >+ * - devices with 1394b PHY (unless only connected to 1394a PHYs), >+ * - all devices if there are 1394b repeaters. >+ * Note, we cannot use the bus info block's link_spd as starting point >+ * because some buggy firmwares set it lower than necessary and because >+ * 1394-1995 nodes do not have the field. >+ */ >+ if ((rom[2] & 0x7) < device->max_speed || >+ device->max_speed == SCODE_BETA || >+ device->card->beta_repeaters_present) { >+ u32 dummy; >+ >+ /* for S1600 and S3200 */ >+ if (device->max_speed == SCODE_BETA) >+ device->max_speed = device->card->link_speed; >+ >+ while (device->max_speed > SCODE_100) { >+ if (read_rom(device, 0, &dummy) == RCODE_COMPLETE) >+ break; >+ device->max_speed--; >+ } >+ } >+ > /* > * Now parse the config rom. The config rom is a recursive > * directory structure so we parse it using a stack of >@@ -672,8 +700,10 @@ static void fw_device_init(void *w) > FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) > fw_device_shutdown(&device->work); > else >- fw_notify("created new fw device %s (%d config rom retries)\n", >- device->device.bus_id, device->config_rom_retries); >+ fw_notify("created new fw device %s " >+ " (%d config rom retries, S%d00)\n", >+ device->device.bus_id, device->config_rom_retries, >+ 1 << device->max_speed); > > /* > * Reschedule the IRM work if we just finished reading the >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-device.h linux-2.6.18.i686/drivers/firewire/fw-device.h >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-device.h 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-device.h 2007-12-11 13:51:06.000000000 -0500 >@@ -40,6 +40,7 @@ struct fw_device { > struct fw_node *node; > int node_id; > int generation; >+ unsigned max_speed; > struct fw_card *card; > struct device device; > struct list_head link; >@@ -101,11 +102,6 @@ fw_unit(struct device *dev) > #define CSR_INSTANCE 0x18 > #define CSR_DIRECTORY_ID 0x20 > >-#define SBP2_COMMAND_SET_SPECIFIER 0x38 >-#define SBP2_COMMAND_SET 0x39 >-#define SBP2_COMMAND_SET_REVISION 0x3b >-#define SBP2_FIRMWARE_REVISION 0x3c >- > struct fw_csr_iterator { > u32 *p; > u32 *end; >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-ohci.c linux-2.6.18.i686/drivers/firewire/fw-ohci.c >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-ohci.c 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-ohci.c 2007-12-18 21:08:48.000000000 -0500 >@@ -17,21 +17,27 @@ > * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > */ > >-#include <linux/kernel.h> >-#include <linux/module.h> >-#include <linux/init.h> >-#include <linux/interrupt.h> >-#include <linux/pci.h> >+ >+ >+ >+ >+#include <linux/compiler.h> > #include <linux/delay.h> >-#include <linux/poll.h> > #include <linux/dma-mapping.h> >+#include <linux/gfp.h> >+#include <linux/init.h> >+#include <linux/interrupt.h> >+#include <linux/kernel.h> > #include <linux/mm.h> >+#include <linux/module.h> >+#include <linux/pci.h> >+#include <linux/spinlock.h> > >-#include <asm/uaccess.h> >-#include <asm/semaphore.h> >+#include <asm/page.h> >+#include <asm/system.h> > >-#include "fw-transaction.h" > #include "fw-ohci.h" >+#include "fw-transaction.h" > > #define DESCRIPTOR_OUTPUT_MORE 0 > #define DESCRIPTOR_OUTPUT_LAST (1 << 12) >@@ -223,6 +229,7 @@ ohci_update_phy_reg(struct fw_card *card > u32 val, old; > > reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); >+ flush_writes(ohci); > msleep(2); > val = reg_read(ohci, OHCI1394_PhyControl); > if ((val & OHCI1394_PhyControl_ReadDone) == 0) { >@@ -371,7 +378,7 @@ static void ar_context_tasklet(unsigned > > offset = offsetof(struct ar_buffer, data); > dma_unmap_single(ohci->card.device, >- ab->descriptor.data_address - offset, >+ le32_to_cpu(ab->descriptor.data_address) - offset, > PAGE_SIZE, DMA_BIDIRECTIONAL); > > buffer = ab; >@@ -425,13 +432,28 @@ static void ar_context_run(struct ar_con > size_t offset; > > offset = offsetof(struct ar_buffer, data); >- ab_bus = ab->descriptor.data_address - offset; >+ ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset; > > reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab_bus | 1); > reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN); > flush_writes(ctx->ohci); > } > >+static struct descriptor * >+find_branch_descriptor(struct descriptor *d, int z) >+{ >+ int b, key; >+ >+ b = (le16_to_cpu(d->control) & DESCRIPTOR_BRANCH_ALWAYS) >> 2; >+ key = (le16_to_cpu(d->control) & DESCRIPTOR_KEY_IMMEDIATE) >> 8; >+ >+ /* figure out which descriptor the branch address goes in */ >+ if (z == 2 && (b == 3 || key == 2)) >+ return d; >+ else >+ return d + z - 1; >+} >+ > static void context_tasklet(unsigned long data) > { > struct context *ctx = (struct context *) data; >@@ -450,7 +472,7 @@ static void context_tasklet(unsigned lon > address = le32_to_cpu(last->branch_address); > z = address & 0xf; > d = ctx->buffer + (address - ctx->buffer_bus) / sizeof(*d); >- last = (z == 2) ? d : d + z - 1; >+ last = find_branch_descriptor(d, z); > > if (!ctx->callback(ctx, d, last)) > break; >@@ -561,7 +583,7 @@ static void context_append(struct contex > > ctx->head_descriptor = d + z + extra; > ctx->prev_descriptor->branch_address = cpu_to_le32(d_bus | z); >- ctx->prev_descriptor = z == 2 ? d : d + z - 1; >+ ctx->prev_descriptor = find_branch_descriptor(d, z); > > dma_sync_single_for_device(ctx->ohci->card.device, ctx->buffer_bus, > ctx->buffer_size, DMA_TO_DEVICE); >@@ -584,7 +606,7 @@ static void context_stop(struct context > break; > > fw_notify("context_stop: still active (0x%08x)\n", reg); >- msleep(1); >+ mdelay(1); > } > } > >@@ -617,10 +639,12 @@ at_context_queue_packet(struct context * > d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE); > d[0].res_count = cpu_to_le16(packet->timestamp); > >- /* The DMA format for asyncronous link packets is different >+ /* >+ * The DMA format for asyncronous link packets is different > * from the IEEE1394 layout, so shift the fields around > * accordingly. If header_length is 8, it's a PHY packet, to >- * which we need to prepend an extra quadlet. */ >+ * which we need to prepend an extra quadlet. >+ */ > > header = (__le32 *) &d[1]; > if (packet->header_length > 8) { >@@ -648,7 +672,7 @@ at_context_queue_packet(struct context * > driver_data = (struct driver_data *) &d[3]; > driver_data->packet = packet; > packet->driver_data = driver_data; >- >+ > if (packet->payload_length > 0) { > payload_bus = > dma_map_single(ohci->card.device, packet->payload, >@@ -673,6 +697,9 @@ at_context_queue_packet(struct context * > > /* FIXME: Document how the locking works. */ > if (ohci->generation != packet->generation) { >+ if (packet->payload_length > 0) >+ dma_unmap_single(ohci->card.device, payload_bus, >+ packet->payload_length, DMA_TO_DEVICE); > packet->ack = RCODE_GENERATION; > return -1; > } >@@ -893,7 +920,7 @@ at_context_transmit(struct context *ctx, > > if (retval < 0) > packet->callback(packet, &ctx->ohci->card, packet->ack); >- >+ > } > > static void bus_reset_tasklet(unsigned long data) >@@ -902,13 +929,20 @@ static void bus_reset_tasklet(unsigned l > int self_id_count, i, j, reg; > int generation, new_generation; > unsigned long flags; >+ void *free_rom = NULL; >+ dma_addr_t free_rom_bus = 0; > > reg = reg_read(ohci, OHCI1394_NodeID); > if (!(reg & OHCI1394_NodeID_idValid)) { >- fw_error("node ID not valid, new bus reset in progress\n"); >+ fw_notify("node ID not valid, new bus reset in progress\n"); > return; > } >- ohci->node_id = reg & 0xffff; >+ if ((reg & OHCI1394_NodeID_nodeNumber) == 63) { >+ fw_notify("malconfigured bus\n"); >+ return; >+ } >+ ohci->node_id = reg & (OHCI1394_NodeID_busNumber | >+ OHCI1394_NodeID_nodeNumber); > > /* > * The count in the SelfIDCount register is the number of >@@ -919,12 +953,14 @@ static void bus_reset_tasklet(unsigned l > > self_id_count = (reg_read(ohci, OHCI1394_SelfIDCount) >> 3) & 0x3ff; > generation = (le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; >+ rmb(); > > for (i = 1, j = 0; j < self_id_count; i += 2, j++) { > if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) > fw_error("inconsistent self IDs\n"); > ohci->self_id_buffer[j] = le32_to_cpu(ohci->self_id_cpu[i]); > } >+ rmb(); > > /* > * Check the consistency of the self IDs we just read. The >@@ -965,10 +1001,10 @@ static void bus_reset_tasklet(unsigned l > */ > > if (ohci->next_config_rom != NULL) { >- if (ohci->next_config_rom != ohci->config_rom) >- dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, >- ohci->config_rom, >- ohci->config_rom_bus); >+ if (ohci->next_config_rom != ohci->config_rom) { >+ free_rom = ohci->config_rom; >+ free_rom_bus = ohci->config_rom_bus; >+ } > ohci->config_rom = ohci->next_config_rom; > ohci->config_rom_bus = ohci->next_config_rom_bus; > ohci->next_config_rom = NULL; >@@ -987,6 +1023,9 @@ static void bus_reset_tasklet(unsigned l > > spin_unlock_irqrestore(&ohci->lock, flags); > >+ if (free_rom) >+ dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, >+ free_rom, free_rom_bus); > fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation, > self_id_count, ohci->self_id_buffer); > } >@@ -1037,6 +1076,9 @@ static irqreturn_t irq_handler(int irq, > iso_event &= ~(1 << i); > } > >+ if (unlikely(event & OHCI1394_postedWriteErr)) >+ fw_error("PCI posted write error\n"); >+ > if (event & OHCI1394_cycle64Seconds) { > cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); > if ((cycle_time & 0x80000000) == 0) >@@ -1110,8 +1152,8 @@ static int ohci_enable(struct fw_card *c > OHCI1394_RQPkt | OHCI1394_RSPkt | > OHCI1394_reqTxComplete | OHCI1394_respTxComplete | > OHCI1394_isochRx | OHCI1394_isochTx | >- OHCI1394_masterIntEnable | >- OHCI1394_cycle64Seconds); >+ OHCI1394_postedWriteErr | OHCI1394_cycle64Seconds | >+ OHCI1394_masterIntEnable); > > /* Activate link_on bit and contender bit in our self ID packets.*/ > if (ohci_update_phy_reg(card, 4, 0, >@@ -1194,7 +1236,7 @@ ohci_set_config_rom(struct fw_card *card > { > struct fw_ohci *ohci; > unsigned long flags; >- int retval = 0; >+ int retval = -EBUSY; > __be32 *next_config_rom; > dma_addr_t next_config_rom_bus; > >@@ -1248,10 +1290,7 @@ ohci_set_config_rom(struct fw_card *card > > reg_write(ohci, OHCI1394_ConfigROMmap, > ohci->next_config_rom_bus); >- } else { >- dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, >- next_config_rom, next_config_rom_bus); >- retval = -EBUSY; >+ retval = 0; > } > > spin_unlock_irqrestore(&ohci->lock, flags); >@@ -1265,7 +1304,9 @@ ohci_set_config_rom(struct fw_card *card > */ > if (retval == 0) > fw_core_initiate_bus_reset(&ohci->card, 1); >- >+ else >+ dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, >+ next_config_rom, next_config_rom_bus); > return retval; > } > >@@ -1326,7 +1367,7 @@ ohci_enable_phys_dma(struct fw_card *car > } > > /* >- * NOTE, if the node ID contains a non-local bus ID, physical DMA is >+ * Note, if the node ID contains a non-local bus ID, physical DMA is > * enabled for _all_ nodes on remote buses. > */ > >@@ -1405,6 +1446,57 @@ static int handle_ir_dualbuffer_packet(s > return 1; > } > >+static int handle_ir_packet_per_buffer(struct context *context, >+ struct descriptor *d, >+ struct descriptor *last) >+{ >+ struct iso_context *ctx = >+ container_of(context, struct iso_context, context); >+ struct descriptor *pd = d + 1; >+ __le32 *ir_header; >+ size_t header_length; >+ void *p, *end; >+ int i, z; >+ >+ if (pd->res_count == pd->req_count) >+ /* Descriptor(s) not done yet, stop iteration */ >+ return 0; >+ >+ header_length = le16_to_cpu(d->req_count); >+ >+ i = ctx->header_length; >+ z = le32_to_cpu(pd->branch_address) & 0xf; >+ p = d + z; >+ end = p + header_length; >+ >+ while (p < end && i + ctx->base.header_size <= PAGE_SIZE) { >+ /* >+ * The iso header is byteswapped to little endian by >+ * the controller, but the remaining header quadlets >+ * are big endian. We want to present all the headers >+ * as big endian, so we have to swap the first quadlet. >+ */ >+ *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); >+ memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4); >+ i += ctx->base.header_size; >+ p += ctx->base.header_size + 4; >+ } >+ >+ ctx->header_length = i; >+ >+ if (le16_to_cpu(pd->control) & DESCRIPTOR_IRQ_ALWAYS) { >+ ir_header = (__le32 *) (d + z); >+ ctx->base.callback(&ctx->base, >+ le32_to_cpu(ir_header[0]) & 0xffff, >+ ctx->header_length, ctx->header, >+ ctx->base.callback_data); >+ ctx->header_length = 0; >+ } >+ >+ >+ return 1; >+} >+ > static int handle_it_packet(struct context *context, > struct descriptor *d, > struct descriptor *last) >@@ -1440,14 +1532,12 @@ ohci_allocate_iso_context(struct fw_card > } else { > mask = &ohci->ir_context_mask; > list = ohci->ir_context_list; >- callback = handle_ir_dualbuffer_packet; >+ if (ohci->version >= OHCI_VERSION_1_1) >+ callback = handle_ir_dualbuffer_packet; >+ else >+ callback = handle_ir_packet_per_buffer; > } > >- /* FIXME: We need a fallback for pre 1.1 OHCI. */ >- if (callback == handle_ir_dualbuffer_packet && >- ohci->version < OHCI_VERSION_1_1) >- return ERR_PTR(-EINVAL); >- > spin_lock_irqsave(&ohci->lock, flags); > index = ffs(*mask) - 1; > if (index >= 0) >@@ -1506,7 +1596,9 @@ static int ohci_start_iso(struct fw_iso_ > context_run(&ctx->context, match); > } else { > index = ctx - ohci->ir_context_list; >- control = IR_CONTEXT_DUAL_BUFFER_MODE | IR_CONTEXT_ISOCH_HEADER; >+ control = IR_CONTEXT_ISOCH_HEADER; >+ if (ohci->version >= OHCI_VERSION_1_1) >+ control |= IR_CONTEXT_DUAL_BUFFER_MODE; > match = (tags << 28) | (sync << 8) | ctx->base.channel; > if (cycle >= 0) { > match |= (cycle & 0x07fff) << 12; >@@ -1712,7 +1804,6 @@ ohci_queue_iso_receive_dualbuffer(struct > offset = payload & ~PAGE_MASK; > rest = p->payload_length; > >- /* FIXME: OHCI 1.0 doesn't support dual buffer receive */ > /* FIXME: make packet-per-buffer/dual-buffer a context option */ > while (rest > 0) { > d = context_get_descriptors(&ctx->context, >@@ -1751,6 +1842,81 @@ ohci_queue_iso_receive_dualbuffer(struct > } > > static int >+ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, >+ struct fw_iso_packet *packet, >+ struct fw_iso_buffer *buffer, >+ unsigned long payload) >+{ >+ struct iso_context *ctx = container_of(base, struct iso_context, base); >+ struct descriptor *d = NULL, *pd = NULL; >+ struct fw_iso_packet *p; >+ dma_addr_t d_bus, page_bus; >+ u32 z, header_z, rest; >+ int i, page, offset, packet_count, header_size; >+ >+ if (packet->skip) { >+ d = context_get_descriptors(&ctx->context, 1, &d_bus); >+ if (d == NULL) >+ return -ENOMEM; >+ >+ d->control = cpu_to_le16(DESCRIPTOR_STATUS | >+ DESCRIPTOR_INPUT_LAST | >+ DESCRIPTOR_BRANCH_ALWAYS | >+ DESCRIPTOR_WAIT); >+ context_append(&ctx->context, d, 1, 0); >+ } >+ >+ /* one descriptor for header, one for payload */ >+ /* FIXME: handle cases where we need multiple desc. for payload */ >+ z = 2; >+ p = packet; >+ >+ /* >+ * The OHCI controller puts the status word in the >+ * buffer too, so we need 4 extra bytes per packet. >+ */ >+ packet_count = p->header_length / ctx->base.header_size; >+ header_size = packet_count * (ctx->base.header_size + 4); >+ >+ /* Get header size in number of descriptors. */ >+ header_z = DIV_ROUND_UP(header_size, sizeof(*d)); >+ page = payload >> PAGE_SHIFT; >+ offset = payload & ~PAGE_MASK; >+ rest = p->payload_length; >+ >+ for (i = 0; i < packet_count; i++) { >+ /* d points to the header descriptor */ >+ d = context_get_descriptors(&ctx->context, >+ z + header_z, &d_bus); >+ if (d == NULL) >+ return -ENOMEM; >+ >+ d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE); >+ d->req_count = cpu_to_le16(header_size); >+ d->res_count = d->req_count; >+ d->data_address = cpu_to_le32(d_bus + (z * sizeof(*d))); >+ >+ /* pd points to the payload descriptor */ >+ pd = d + 1; >+ pd->control = cpu_to_le16(DESCRIPTOR_STATUS | >+ DESCRIPTOR_INPUT_LAST | >+ DESCRIPTOR_BRANCH_ALWAYS); >+ if (p->interrupt) >+ pd->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); >+ >+ pd->req_count = cpu_to_le16(rest); >+ pd->res_count = pd->req_count; >+ >+ page_bus = page_private(buffer->pages[page]); >+ pd->data_address = cpu_to_le32(page_bus + offset); >+ >+ context_append(&ctx->context, d, z, header_z); >+ } >+ >+ return 0; >+} >+ >+static int > ohci_queue_iso(struct fw_iso_context *base, > struct fw_iso_packet *packet, > struct fw_iso_buffer *buffer, >@@ -1764,8 +1930,9 @@ ohci_queue_iso(struct fw_iso_context *ba > return ohci_queue_iso_receive_dualbuffer(base, packet, > buffer, payload); > else >- /* FIXME: Implement fallback for OHCI 1.0 controllers. */ >- return -EINVAL; >+ return ohci_queue_iso_receive_packet_per_buffer(base, packet, >+ buffer, >+ payload); > } > > static const struct fw_card_driver ohci_driver = { >@@ -1805,7 +1972,7 @@ pci_probe(struct pci_dev *dev, const str > fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev); > > err = pci_enable_device(dev); >- if (err ) { >+ if (err) { > fw_error("Failed to enable OHCI hardware.\n"); > goto fail_put_card; > } >@@ -1886,7 +2053,6 @@ pci_probe(struct pci_dev *dev, const str > ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; > fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n", > dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff); >- > return 0; > > fail_self_id: >@@ -1944,14 +2110,12 @@ static int pci_suspend(struct pci_dev *p > free_irq(pdev->irq, ohci); > err = pci_save_state(pdev); > if (err) { >- fw_error("pci_save_state failed with %d\n", err); >+ fw_error("pci_save_state failed\n"); > return err; > } > err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); >- if (err) { >+ if (err) > fw_error("pci_set_power_state failed with %d\n", err); >- return err; >- } > > return 0; > } >@@ -1965,7 +2129,7 @@ static int pci_resume(struct pci_dev *pd > pci_restore_state(pdev); > err = pci_enable_device(pdev); > if (err) { >- fw_error("pci_enable_device failed with %d\n", err); >+ fw_error("pci_enable_device failed\n"); > return err; > } > >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-ohci.h linux-2.6.18.i686/drivers/firewire/fw-ohci.h >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-ohci.h 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-ohci.h 2007-12-11 13:51:06.000000000 -0500 >@@ -59,6 +59,8 @@ > #define OHCI1394_LinkControl_cycleSource (1 << 22) > #define OHCI1394_NodeID 0x0E8 > #define OHCI1394_NodeID_idValid 0x80000000 >+#define OHCI1394_NodeID_nodeNumber 0x0000003f >+#define OHCI1394_NodeID_busNumber 0x0000ffc0 > #define OHCI1394_PhyControl 0x0EC > #define OHCI1394_PhyControl_Read(addr) (((addr) << 8) | 0x00008000) > #define OHCI1394_PhyControl_ReadDone 0x80000000 >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-sbp2.c linux-2.6.18.i686/drivers/firewire/fw-sbp2.c >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-sbp2.c 2007-11-13 21:16:19.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-sbp2.c 2007-12-11 13:51:06.000000000 -0500 >@@ -18,7 +18,7 @@ > */ > > /* >- * The basic structure of this driver is based the old storage driver, >+ * The basic structure of this driver is based on the old storage driver, > * drivers/ieee1394/sbp2.c, originally written by > * James Goodwin <jamesg@filanet.com> > * with later contributions and ongoing maintenance from >@@ -27,7 +27,6 @@ > * and many others. > */ > >-#include <linux/err.h> > #include <linux/kernel.h> > #include <linux/module.h> > #include <linux/moduleparam.h> >@@ -36,12 +35,13 @@ > #include <linux/scatterlist.h> > #include <linux/dma-mapping.h> > #include <linux/blkdev.h> >+#include <linux/string.h> >+#include <linux/stringify.h> > #include <linux/timer.h> >-#include <linux/pci.h> >+#include <linux/workqueue.h> > > #include <scsi/scsi.h> > #include <scsi/scsi_cmnd.h> >-#include <scsi/scsi_dbg.h> > #include <scsi/scsi_device.h> > #include <scsi/scsi_host.h> > >@@ -61,41 +61,96 @@ module_param_named(exclusive_login, sbp2 > 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 *); > > static const char sbp2_driver_name[] = "sbp2"; > >-struct sbp2_device { >- struct kref kref; >+/* >+ * We create one struct sbp2_logical_unit per SBP-2 Logical Unit Number Entry >+ * and one struct scsi_device per sbp2_logical_unit. >+ */ >+struct sbp2_logical_unit { >+ struct sbp2_target *tgt; >+ struct list_head link; > struct scsi_device *sdev; >- struct fw_unit *unit; > struct fw_address_handler address_handler; > struct list_head orb_list; >- u64 management_agent_address; >+ > u64 command_block_agent_address; >- u32 workarounds; >+ u16 lun; > int login_id; > > /* >- * We cache these addresses and only update them once we've >- * logged in or reconnected to the sbp2 device. That way, any >- * IO to the device will automatically fail and get retried if >- * it happens in a window where the device is not ready to >- * handle it (e.g. after a bus reset but before we reconnect). >+ * The generation is updated once we've logged in or reconnected >+ * to the logical unit. Thus, I/O to the device will automatically >+ * fail and get retried if it happens in a window where the device >+ * is not ready, e.g. after a bus reset but before we reconnect. > */ >- int node_id; >- int address_high; > int generation; >- > int retries; > struct work_struct work; >- struct Scsi_Host *scsi_host; >+}; >+ >+/* >+ * We create one struct sbp2_target per IEEE 1212 Unit Directory >+ * and one struct Scsi_Host per sbp2_target. >+ */ >+struct sbp2_target { >+ struct kref kref; >+ struct fw_unit *unit; >+ >+ u64 management_agent_address; >+ int directory_id; >+ int node_id; >+ int address_high; >+ unsigned workarounds; >+ struct list_head lu_list; > }; > > #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 > #define SBP2_MAX_SECTORS 255 /* Max sectors supported */ >-#define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */ >+#define SBP2_ORB_TIMEOUT 200000 /* Timeout in ms */ > > #define SBP2_ORB_NULL 0x80000000 > >@@ -103,17 +158,9 @@ struct sbp2_device { > #define SBP2_DIRECTION_FROM_MEDIA 0x1 > > /* Unit directory keys */ >-#define SBP2_COMMAND_SET_SPECIFIER 0x38 >-#define SBP2_COMMAND_SET 0x39 >-#define SBP2_COMMAND_SET_REVISION 0x3b >-#define SBP2_FIRMWARE_REVISION 0x3c >- >-/* 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 >+#define SBP2_CSR_FIRMWARE_REVISION 0x3c >+#define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14 >+#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4 > > /* Management orb opcodes */ > #define SBP2_LOGIN_REQUEST 0x0 >@@ -161,10 +208,11 @@ struct sbp2_pointer { > > struct sbp2_orb { > struct fw_transaction t; >+ struct kref kref; > dma_addr_t request_bus; > int rcode; > struct sbp2_pointer pointer; >- void (*callback) (struct sbp2_orb * orb, struct sbp2_status * status); >+ void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status); > struct list_head link; > }; > >@@ -221,9 +269,9 @@ struct sbp2_command_orb { > } request; > struct scsi_cmnd *cmd; > scsi_done_fn_t done; >- struct fw_unit *unit; >+ struct sbp2_logical_unit *lu; > >- struct sbp2_pointer page_table[SG_ALL]; >+ struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8))); > dma_addr_t page_table_bus; > }; > >@@ -282,13 +330,21 @@ static const struct { > }; > > static void >+free_orb(struct kref *kref) >+{ >+ struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref); >+ >+ kfree(orb); >+} >+ >+static void > sbp2_status_write(struct fw_card *card, struct fw_request *request, > int tcode, int destination, int source, > int generation, int speed, > unsigned long long offset, > void *payload, size_t length, void *callback_data) > { >- struct sbp2_device *sd = callback_data; >+ struct sbp2_logical_unit *lu = callback_data; > struct sbp2_orb *orb; > struct sbp2_status status; > size_t header_size; >@@ -312,21 +368,23 @@ sbp2_status_write(struct fw_card *card, > > /* Lookup the orb corresponding to this status write. */ > spin_lock_irqsave(&card->lock, flags); >- list_for_each_entry(orb, &sd->orb_list, link) { >+ list_for_each_entry(orb, &lu->orb_list, link) { > if (STATUS_GET_ORB_HIGH(status) == 0 && >- STATUS_GET_ORB_LOW(status) == orb->request_bus && >- orb->rcode == RCODE_COMPLETE) { >+ STATUS_GET_ORB_LOW(status) == orb->request_bus) { >+ orb->rcode = RCODE_COMPLETE; > list_del(&orb->link); > break; > } > } > spin_unlock_irqrestore(&card->lock, flags); > >- if (&orb->link != &sd->orb_list) >+ if (&orb->link != &lu->orb_list) > orb->callback(orb, &status); > else > fw_error("status write for unknown orb\n"); > >+ kref_put(&orb->kref, free_orb); >+ > fw_send_response(card, request, RCODE_COMPLETE); > } > >@@ -337,21 +395,34 @@ complete_transaction(struct fw_card *car > struct sbp2_orb *orb = data; > unsigned long flags; > >- orb->rcode = rcode; >- if (rcode != RCODE_COMPLETE) { >+ /* >+ * This is a little tricky. We can get the status write for >+ * the orb before we get this callback. The status write >+ * handler above will assume the orb pointer transaction was >+ * successful and set the rcode to RCODE_COMPLETE for the orb. >+ * So this callback only sets the rcode if it hasn't already >+ * been set and only does the cleanup if the transaction >+ * failed and we didn't already get a status write. >+ */ > spin_lock_irqsave(&card->lock, flags); >+ if (orb->rcode == -1) >+ orb->rcode = rcode; >+ if (orb->rcode != RCODE_COMPLETE) { > list_del(&orb->link); > spin_unlock_irqrestore(&card->lock, flags); > orb->callback(orb, NULL); >+ } else { >+ spin_unlock_irqrestore(&card->lock, flags); > } >+ >+ kref_put(&orb->kref, free_orb); > } > > static void >-sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit, >+sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, > int node_id, int generation, u64 offset) > { >- struct fw_device *device = fw_device(unit->device.parent); >- struct sbp2_device *sd = unit->device.driver_data; >+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent); > unsigned long flags; > > orb->pointer.high = 0; >@@ -359,20 +430,22 @@ sbp2_send_orb(struct sbp2_orb *orb, stru > fw_memcpy_to_be32(&orb->pointer, &orb->pointer, sizeof(orb->pointer)); > > spin_lock_irqsave(&device->card->lock, flags); >- list_add_tail(&orb->link, &sd->orb_list); >+ list_add_tail(&orb->link, &lu->orb_list); > spin_unlock_irqrestore(&device->card->lock, flags); > >+ /* Take a ref for the orb list and for the transaction callback. */ >+ kref_get(&orb->kref); >+ kref_get(&orb->kref); >+ > fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, >- node_id, generation, >- device->node->max_speed, offset, >+ node_id, generation, device->max_speed, offset, > &orb->pointer, sizeof(orb->pointer), > complete_transaction, orb); > } > >-static int sbp2_cancel_orbs(struct fw_unit *unit) >+static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) > { >- struct fw_device *device = fw_device(unit->device.parent); >- struct sbp2_device *sd = unit->device.driver_data; >+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent); > struct sbp2_orb *orb, *next; > struct list_head list; > unsigned long flags; >@@ -380,7 +453,7 @@ static int sbp2_cancel_orbs(struct fw_un > > INIT_LIST_HEAD(&list); > spin_lock_irqsave(&device->card->lock, flags); >- list_splice_init(&sd->orb_list, &list); >+ list_splice_init(&lu->orb_list, &list); > spin_unlock_irqrestore(&device->card->lock, flags); > > list_for_each_entry_safe(orb, next, &list, link) { >@@ -399,7 +472,7 @@ static void > complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) > { > struct sbp2_management_orb *orb = >- (struct sbp2_management_orb *)base_orb; >+ container_of(base_orb, struct sbp2_management_orb, base); > > if (status) > memcpy(&orb->status, status, sizeof(*status)); >@@ -407,11 +480,11 @@ complete_management_orb(struct sbp2_orb > } > > static int >-sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation, >- int function, int lun, void *response) >+sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, >+ int generation, int function, int lun_or_login_id, >+ void *response) > { >- struct fw_device *device = fw_device(unit->device.parent); >- struct sbp2_device *sd = unit->device.driver_data; >+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent); > struct sbp2_management_orb *orb; > int retval = -ENOMEM; > >@@ -419,22 +492,12 @@ sbp2_send_management_orb(struct fw_unit > if (orb == NULL) > return -ENOMEM; > >- /* >- * The sbp2 device is going to send a block read request to >- * read out the request from host memory, so map it for >- * dma. >- */ >- 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)) >- goto out; >- >+ kref_init(&orb->base.kref); > orb->response_bus = > dma_map_single(device->card->device, &orb->response, > sizeof(orb->response), DMA_FROM_DEVICE); > if (dma_mapping_error(orb->response_bus)) >- goto out; >+ goto fail_mapping_response; > > orb->request.response.high = 0; > orb->request.response.low = orb->response_bus; >@@ -442,18 +505,13 @@ sbp2_send_management_orb(struct fw_unit > orb->request.misc = > MANAGEMENT_ORB_NOTIFY | > MANAGEMENT_ORB_FUNCTION(function) | >- MANAGEMENT_ORB_LUN(lun); >+ MANAGEMENT_ORB_LUN(lun_or_login_id); > orb->request.length = > MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response)); > >- orb->request.status_fifo.high = sd->address_handler.offset >> 32; >- orb->request.status_fifo.low = sd->address_handler.offset; >+ orb->request.status_fifo.high = lu->address_handler.offset >> 32; >+ orb->request.status_fifo.low = lu->address_handler.offset; > >- /* >- * FIXME: Yeah, ok this isn't elegant, we hardwire >- * 1 second reconnect time. The reconnect setting >- * is probably fine >- */ > if (function == SBP2_LOGIN_REQUEST) { > orb->request.misc |= > MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login) | >@@ -465,19 +523,25 @@ sbp2_send_management_orb(struct fw_unit > init_completion(&orb->done); > orb->base.callback = complete_management_orb; > >- sbp2_send_orb(&orb->base, unit, >- node_id, generation, sd->management_agent_address); >+ 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)) >+ goto fail_mapping_request; > >+ sbp2_send_orb(&orb->base, lu, node_id, generation, >+ lu->tgt->management_agent_address); >+ > wait_for_completion_timeout(&orb->done, > msecs_to_jiffies(SBP2_ORB_TIMEOUT)); > > retval = -EIO; >- if (sbp2_cancel_orbs(unit) == 0) { >+ if (sbp2_cancel_orbs(lu) == 0) { > /* >- * logout requests frequently get sent to devices that aren't >+ * Logout requests frequently get sent to devices that aren't > * there any more, resulting in extraneous error messages in > * the logs. Unfortunately, this means logout requests that >- * acutally fail don't get logged. >+ * actually fail don't get logged. > */ > if (function != SBP2_LOGOUT_REQUEST) > fw_error("orb reply timed out, rcode=0x%02x\n", >@@ -508,13 +572,14 @@ sbp2_send_management_orb(struct fw_unit > out: > dma_unmap_single(device->card->device, orb->base.request_bus, > sizeof(orb->request), DMA_TO_DEVICE); >+ fail_mapping_request: > dma_unmap_single(device->card->device, orb->response_bus, > sizeof(orb->response), DMA_FROM_DEVICE); >- >+ fail_mapping_response: > if (response) > fw_memcpy_from_be32(response, > orb->response, sizeof(orb->response)); >- kfree(orb); >+ kref_put(&orb->base.kref, free_orb); > > return retval; > } >@@ -528,10 +593,9 @@ complete_agent_reset_write(struct fw_car > kfree(t); > } > >-static int sbp2_agent_reset(struct fw_unit *unit) >+static int sbp2_agent_reset(struct sbp2_logical_unit *lu) > { >- struct fw_device *device = fw_device(unit->device.parent); >- struct sbp2_device *sd = unit->device.driver_data; >+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent); > struct fw_transaction *t; > static u32 zero; > >@@ -540,212 +604,330 @@ static int sbp2_agent_reset(struct fw_un > return -ENOMEM; > > fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST, >- sd->node_id, sd->generation, SCODE_400, >- sd->command_block_agent_address + SBP2_AGENT_RESET, >+ lu->tgt->node_id, lu->generation, device->max_speed, >+ lu->command_block_agent_address + SBP2_AGENT_RESET, > &zero, sizeof(zero), complete_agent_reset_write, t); > > return 0; > } > >+static void sbp2_release_target(struct kref *kref) >+{ >+ struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref); >+ struct sbp2_logical_unit *lu, *next; >+ struct Scsi_Host *shost = >+ container_of((void *)tgt, struct Scsi_Host, hostdata[0]); >+ >+ list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { >+ if (lu->sdev) >+ scsi_remove_device(lu->sdev); >+ >+ sbp2_send_management_orb(lu, tgt->node_id, lu->generation, >+ SBP2_LOGOUT_REQUEST, lu->login_id, NULL); >+ fw_core_remove_address_handler(&lu->address_handler); >+ list_del(&lu->link); >+ kfree(lu); >+ } >+ scsi_remove_host(shost); >+ fw_notify("released %s\n", tgt->unit->device.bus_id); >+ >+ put_device(&tgt->unit->device); >+ scsi_host_put(shost); >+} >+ >+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 sbp2_reconnect(void *w); >-static struct scsi_host_template scsi_driver_template; > >-static void release_sbp2_device(struct kref *kref) >+/* not exported in 2.6.18, so local copy */ >+static int scsilun_to_int(struct scsi_lun *scsilun) > { >- struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref); >- struct Scsi_Host *host = >- container_of((void *)sd, struct Scsi_Host, hostdata[0]); >- >- scsi_remove_host(host); >- sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation, >- SBP2_LOGOUT_REQUEST, sd->login_id, NULL); >- fw_core_remove_address_handler(&sd->address_handler); >- fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id); >- put_device(&sd->unit->device); >- scsi_host_put(host); >+ int i; >+ unsigned int lun; >+ >+ lun = 0; >+ for (i = 0; i < sizeof(lun); i += 2) >+ lun = lun | (((scsilun->scsi_lun[i] << 8) | >+ scsilun->scsi_lun[i + 1]) << (i * 8)); >+ return lun; > } > > static void sbp2_login(void *w) > { > struct work_struct *work = w; >- struct sbp2_device *sd = >- container_of(work, struct sbp2_device, work); >- struct Scsi_Host *host = >- container_of((void *)sd, struct Scsi_Host, hostdata[0]); >- struct fw_unit *unit = sd->unit; >+ struct sbp2_logical_unit *lu = >+ container_of(work, struct sbp2_logical_unit, work); >+ struct Scsi_Host *shost = >+ container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]); >+ struct scsi_device *sdev; >+ struct scsi_lun eight_bytes_lun; >+ struct fw_unit *unit = lu->tgt->unit; > struct fw_device *device = fw_device(unit->device.parent); > struct sbp2_login_response response; >- int generation, node_id, local_node_id, lun, retval; >- >- /* FIXME: Make this work for multi-lun devices. */ >- lun = 0; >+ int generation, node_id, local_node_id; > > generation = device->card->generation; > node_id = device->node->node_id; > local_node_id = device->card->local_node->node_id; > >- if (sbp2_send_management_orb(unit, node_id, generation, >- SBP2_LOGIN_REQUEST, lun, &response) < 0) { >- if (sd->retries++ < 5) { >- schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5)); >- } else { >- fw_error("failed to login to %s\n", >- unit->device.bus_id); >- kref_put(&sd->kref, release_sbp2_device); >- } >- return; >+ if (sbp2_send_management_orb(lu, node_id, generation, >+ SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { >+ if (lu->retries++ < 5) >+ sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); >+ else >+ fw_error("failed to login to %s LUN %04x\n", >+ unit->device.bus_id, lu->lun); >+ goto out; > } >- >- sd->generation = generation; >- sd->node_id = node_id; >- sd->address_high = local_node_id << 16; >+ lu->generation = generation; >+ lu->tgt->node_id = node_id; >+ lu->tgt->address_high = local_node_id << 16; > > /* Get command block agent offset and login id. */ >- sd->command_block_agent_address = >+ lu->command_block_agent_address = > ((u64) (response.command_block_agent.high & 0xffff) << 32) | > response.command_block_agent.low; >- sd->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response); >+ lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response); >+ >+ fw_notify("logged in to %s LUN %04x (%d retries)\n", >+ unit->device.bus_id, lu->lun, lu->retries); > >- fw_notify("logged in to sbp2 unit %s (%d retries)\n", >- unit->device.bus_id, sd->retries); > #if 0 > /* FIXME: The linux1394 sbp2 does this last step. */ > sbp2_set_busy_timeout(scsi_id); > #endif > >- PREPARE_WORK(&sd->work, sbp2_reconnect, &(sd->work)); >- sbp2_agent_reset(unit); >+ PREPARE_WORK(&lu->work, sbp2_reconnect, &(lu->work)); >+ sbp2_agent_reset(lu); > >- /* FIXME: Loop over luns here. */ >- retval = scsi_add_device(host, 0, 0, lun); >- if (retval < 0) { >- sbp2_send_management_orb(unit, sd->node_id, sd->generation, >- SBP2_LOGOUT_REQUEST, sd->login_id, >- NULL); >+ memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun)); >+ eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff; >+ eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff; >+ >+ sdev = __scsi_add_device(shost, 0, 0, >+ scsilun_to_int(&eight_bytes_lun), lu); >+ if (IS_ERR(sdev)) { >+ sbp2_send_management_orb(lu, node_id, generation, >+ SBP2_LOGOUT_REQUEST, lu->login_id, NULL); > /* > * Set this back to sbp2_login so we fall back and > * retry login on bus reset. > */ >- PREPARE_WORK(&sd->work, sbp2_login, &(sd->work)); >+ PREPARE_WORK(&lu->work, sbp2_login, &(lu->work)); >+ } else { >+ lu->sdev = sdev; >+ scsi_device_put(sdev); > } >- kref_put(&sd->kref, release_sbp2_device); >+ out: >+ sbp2_target_put(lu->tgt); > } > >-static int sbp2_probe(struct device *dev) >+static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) >+{ >+ struct sbp2_logical_unit *lu; >+ >+ lu = kmalloc(sizeof(*lu), GFP_KERNEL); >+ if (!lu) >+ return -ENOMEM; >+ >+ lu->address_handler.length = 0x100; >+ lu->address_handler.address_callback = sbp2_status_write; >+ lu->address_handler.callback_data = lu; >+ >+ if (fw_core_add_address_handler(&lu->address_handler, >+ &fw_high_memory_region) < 0) { >+ kfree(lu); >+ return -ENOMEM; >+ } >+ >+ lu->tgt = tgt; >+ lu->sdev = NULL; >+ lu->lun = lun_entry & 0xffff; >+ lu->retries = 0; >+ INIT_LIST_HEAD(&lu->orb_list); >+ INIT_WORK(&lu->work, sbp2_login, &(lu->work)); >+ >+ list_add_tail(&lu->link, &tgt->lu_list); >+ return 0; >+} >+ >+static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory) > { >- struct fw_unit *unit = fw_unit(dev); >- struct fw_device *device = fw_device(unit->device.parent); >- struct sbp2_device *sd; > struct fw_csr_iterator ci; >- struct Scsi_Host *host; >- int i, key, value, err; >- u32 model, firmware_revision; >+ int key, value; > >- err = -ENOMEM; >- host = scsi_host_alloc(&scsi_driver_template, sizeof(*sd)); >- if (host == NULL) >- goto fail; >+ fw_csr_iterator_init(&ci, directory); >+ while (fw_csr_iterator_next(&ci, &key, &value)) >+ if (key == SBP2_CSR_LOGICAL_UNIT_NUMBER && >+ sbp2_add_logical_unit(tgt, value) < 0) >+ return -ENOMEM; >+ return 0; >+} > >- sd = (struct sbp2_device *) host->hostdata; >- unit->device.driver_data = sd; >- sd->unit = unit; >- INIT_LIST_HEAD(&sd->orb_list); >- kref_init(&sd->kref); >- >- sd->address_handler.length = 0x100; >- sd->address_handler.address_callback = sbp2_status_write; >- sd->address_handler.callback_data = sd; >- >- err = fw_core_add_address_handler(&sd->address_handler, >- &fw_high_memory_region); >- if (err < 0) >- goto fail_host; >- >- err = fw_device_enable_phys_dma(device); >- if (err < 0) >- goto fail_address_handler; >- >- err = scsi_add_host(host, &unit->device); >- if (err < 0) >- goto fail_address_handler; >+static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory, >+ u32 *model, u32 *firmware_revision) >+{ >+ struct fw_csr_iterator ci; >+ int key, value; > >- /* >- * Scan unit directory to get management agent address, >- * firmware revison and model. Initialize firmware_revision >- * and model to values that wont match anything in our table. >- */ >- firmware_revision = 0xff000000; >- model = 0xff000000; >- fw_csr_iterator_init(&ci, unit->directory); >+ fw_csr_iterator_init(&ci, directory); > while (fw_csr_iterator_next(&ci, &key, &value)) { > switch (key) { >+ > case CSR_DEPENDENT_INFO | CSR_OFFSET: >- sd->management_agent_address = >+ tgt->management_agent_address = > 0xfffff0000000ULL + 4 * value; > break; >- case SBP2_FIRMWARE_REVISION: >- firmware_revision = value; >+ >+ case CSR_DIRECTORY_ID: >+ tgt->directory_id = value; > break; >+ > case CSR_MODEL: >- model = value; >+ *model = value; >+ break; >+ >+ case SBP2_CSR_FIRMWARE_REVISION: >+ *firmware_revision = value; >+ break; >+ >+ case SBP2_CSR_LOGICAL_UNIT_NUMBER: >+ if (sbp2_add_logical_unit(tgt, value) < 0) >+ return -ENOMEM; >+ break; >+ >+ case SBP2_CSR_LOGICAL_UNIT_DIRECTORY: >+ if (sbp2_scan_logical_unit_dir(tgt, ci.p + value) < 0) >+ return -ENOMEM; > break; > } > } >+ return 0; >+} >+ >+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); >+ >+ if (w & SBP2_WORKAROUND_OVERRIDE) >+ goto out; > > for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { >+ > if (sbp2_workarounds_table[i].firmware_revision != > (firmware_revision & 0xffffff00)) > continue; >+ > if (sbp2_workarounds_table[i].model != model && > sbp2_workarounds_table[i].model != ~0) > continue; >- sd->workarounds |= sbp2_workarounds_table[i].workarounds; >+ w |= sbp2_workarounds_table[i].workarounds; > break; > } > >- if (sd->workarounds) >- fw_notify("Workarounds for node %s: 0x%x " >+ out: >+ if (w) >+ fw_notify("Workarounds for %s: 0x%x " > "(firmware_revision 0x%06x, model_id 0x%06x)\n", >- unit->device.bus_id, >- sd->workarounds, firmware_revision, model); >+ tgt->unit->device.bus_id, >+ w, firmware_revision, model); >+ tgt->workarounds = w; >+} > >- get_device(&unit->device); >+static struct scsi_host_template scsi_driver_template; > >- /* >- * We schedule work to do the login so we can easily >- * reschedule retries. Always get the ref before scheduling >- * work. >- */ >- INIT_WORK(&sd->work, sbp2_login,&(sd->work)); >- if (schedule_delayed_work(&sd->work, 0)) >- kref_get(&sd->kref); >+static int sbp2_probe(struct device *dev) >+{ >+ struct fw_unit *unit = fw_unit(dev); >+ struct fw_device *device = fw_device(unit->device.parent); >+ struct sbp2_target *tgt; >+ struct sbp2_logical_unit *lu; >+ struct Scsi_Host *shost; >+ u32 model, firmware_revision; >+ >+ shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt)); >+ if (shost == NULL) >+ return -ENOMEM; >+ >+ tgt = (struct sbp2_target *)shost->hostdata; >+ unit->device.driver_data = tgt; >+ tgt->unit = unit; >+ kref_init(&tgt->kref); >+ INIT_LIST_HEAD(&tgt->lu_list); >+ >+ if (fw_device_enable_phys_dma(device) < 0) >+ goto fail_shost_put; >+ >+ if (scsi_add_host(shost, &unit->device) < 0) >+ goto fail_shost_put; >+ >+ /* Initialize to values that won't match anything in our table. */ >+ firmware_revision = 0xff000000; >+ model = 0xff000000; >+ >+ /* implicit directory ID */ >+ tgt->directory_id = ((unit->directory - device->config_rom) * 4 >+ + CSR_CONFIG_ROM) & 0xffffff; >+ >+ if (sbp2_scan_unit_dir(tgt, unit->directory, &model, >+ &firmware_revision) < 0) >+ goto fail_tgt_put; >+ >+ sbp2_init_workarounds(tgt, model, firmware_revision); >+ >+ get_device(&unit->device); > >+ /* 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); > return 0; > >- fail_address_handler: >- fw_core_remove_address_handler(&sd->address_handler); >- fail_host: >- scsi_host_put(host); >- fail: >- return err; >+ fail_tgt_put: >+ sbp2_target_put(tgt); >+ return -ENOMEM; >+ >+ fail_shost_put: >+ scsi_host_put(shost); >+ return -ENOMEM; > } > > static int sbp2_remove(struct device *dev) > { > struct fw_unit *unit = fw_unit(dev); >- struct sbp2_device *sd = unit->device.driver_data; >- >- kref_put(&sd->kref, release_sbp2_device); >+ struct sbp2_target *tgt = unit->device.driver_data; > >+ sbp2_target_put(tgt); > return 0; > } > > static void sbp2_reconnect(void *w) > { > struct work_struct *work = w; >- struct sbp2_device *sd = >- container_of(work, struct sbp2_device, work); >- struct fw_unit *unit = sd->unit; >+ struct sbp2_logical_unit *lu = >+ container_of(work, struct sbp2_logical_unit, work); >+ struct fw_unit *unit = lu->tgt->unit; > struct fw_device *device = fw_device(unit->device.parent); > int generation, node_id, local_node_id; > >@@ -753,40 +935,47 @@ static void sbp2_reconnect(void *w) > node_id = device->node->node_id; > local_node_id = device->card->local_node->node_id; > >- if (sbp2_send_management_orb(unit, node_id, generation, >+ if (sbp2_send_management_orb(lu, node_id, generation, > SBP2_RECONNECT_REQUEST, >- sd->login_id, NULL) < 0) { >- if (sd->retries++ >= 5) { >+ lu->login_id, NULL) < 0) { >+ if (lu->retries++ >= 5) { > fw_error("failed to reconnect to %s\n", > unit->device.bus_id); > /* Fall back and try to log in again. */ >- sd->retries = 0; >- PREPARE_WORK(&sd->work, sbp2_login, &(sd->work)); >+ lu->retries = 0; >+ PREPARE_WORK(&lu->work, sbp2_login, &(lu->work)); > } >- schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5)); >- return; >+ sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); >+ goto out; > } > >- sd->generation = generation; >- sd->node_id = node_id; >- sd->address_high = local_node_id << 16; >- >- fw_notify("reconnected to unit %s (%d retries)\n", >- unit->device.bus_id, sd->retries); >- sbp2_agent_reset(unit); >- sbp2_cancel_orbs(unit); >- kref_put(&sd->kref, release_sbp2_device); >+ lu->generation = generation; >+ lu->tgt->node_id = node_id; >+ lu->tgt->address_high = local_node_id << 16; >+ >+ fw_notify("reconnected to %s LUN %04x (%d retries)\n", >+ unit->device.bus_id, lu->lun, lu->retries); >+ sbp2_agent_reset(lu); >+ sbp2_cancel_orbs(lu); >+ out: >+ sbp2_target_put(lu->tgt); > } > > static void sbp2_update(struct fw_unit *unit) > { >- struct fw_device *device = fw_device(unit->device.parent); >- struct sbp2_device *sd = unit->device.driver_data; >+ struct sbp2_target *tgt = unit->device.driver_data; >+ struct sbp2_logical_unit *lu; > >- sd->retries = 0; >- fw_device_enable_phys_dma(device); >- if (schedule_delayed_work(&sd->work, 0)) >- kref_get(&sd->kref); >+ fw_device_enable_phys_dma(fw_device(unit->device.parent)); >+ >+ /* >+ * Fw-core serializes sbp2_update() against sbp2_remove(). >+ * Iteration over tgt->lu_list is therefore safe here. >+ */ >+ list_for_each_entry(lu, &tgt->lu_list, link) { >+ lu->retries = 0; >+ sbp2_queue_work(lu, 0); >+ } > } > > #define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e >@@ -854,15 +1043,14 @@ sbp2_status_to_sense_data(u8 *sbp2_statu > static void > complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) > { >- struct sbp2_command_orb *orb = (struct sbp2_command_orb *)base_orb; >- struct fw_unit *unit = orb->unit; >- struct fw_device *device = fw_device(unit->device.parent); >- struct scatterlist *sg; >+ struct sbp2_command_orb *orb = >+ container_of(base_orb, struct sbp2_command_orb, base); >+ struct fw_device *device = fw_device(orb->lu->tgt->unit->device.parent); > int result; > > if (status != NULL) { > if (STATUS_GET_DEAD(*status)) >- sbp2_agent_reset(unit); >+ sbp2_agent_reset(orb->lu); > > switch (STATUS_GET_RESPONSE(*status)) { > case SBP2_STATUS_REQUEST_COMPLETE: >@@ -893,30 +1081,26 @@ complete_command_orb(struct sbp2_orb *ba > dma_unmap_single(device->card->device, orb->base.request_bus, > sizeof(orb->request), DMA_TO_DEVICE); > >- if (orb->cmd->use_sg > 0) { >- sg = (struct scatterlist *)orb->cmd->request_buffer; >- dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg, >- orb->cmd->sc_data_direction); >- } >+ if (orb->cmd->use_sg > 0) >+ dma_unmap_sg(device->card->device, >+ (struct scatterlist *)orb->cmd->request_buffer, >+ orb->cmd->use_sg, orb->cmd->sc_data_direction); >+ > > if (orb->page_table_bus != 0) > dma_unmap_single(device->card->device, orb->page_table_bus, >- sizeof(orb->page_table_bus), DMA_TO_DEVICE); >+ sizeof(orb->page_table), DMA_TO_DEVICE); > > orb->cmd->result = result; > orb->done(orb->cmd); >- kfree(orb); > } > >-static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) >+static int >+sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, >+ struct sbp2_logical_unit *lu) > { >- struct sbp2_device *sd = >- (struct sbp2_device *)orb->cmd->device->host->hostdata; >- struct fw_unit *unit = sd->unit; >- struct fw_device *device = fw_device(unit->device.parent); > struct scatterlist *sg; > int sg_len, l, i, j, count; >- size_t size; > dma_addr_t sg_addr; > > sg = (struct scatterlist *)orb->cmd->request_buffer; >@@ -925,6 +1109,7 @@ static int sbp2_command_orb_map_scatterl > > if (count == 0) > goto fail; >+ > /* > * Handle the special case where there is only one element in > * the scatter list by converting it to an immediate block >@@ -933,21 +1118,28 @@ static int sbp2_command_orb_map_scatterl > * tables. > */ > if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) { >- orb->request.data_descriptor.high = sd->address_high; >+ orb->request.data_descriptor.high = lu->tgt->address_high; > orb->request.data_descriptor.low = sg_dma_address(sg); >- orb->request.misc |= >- COMMAND_ORB_DATA_SIZE(sg_dma_len(sg)); >+ orb->request.misc |= COMMAND_ORB_DATA_SIZE(sg_dma_len(sg)); > return 0; > } > > /* > * Convert the scatterlist to an sbp2 page table. If any >- * scatterlist entries are too big for sbp2 we split the as we go. >+ * 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_len = sg_dma_len(sg + i); >- sg_addr = sg_dma_address(sg + i); >+ sg_len = sg_dma_len(sg+i); >+ sg_addr = sg_dma_address(sg+i); > 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 = sg_addr; > orb->page_table[j].high = (l << 16); >@@ -957,8 +1149,13 @@ static int sbp2_command_orb_map_scatterl > } > } > >- size = sizeof(orb->page_table[0]) * j; >- >+ fw_memcpy_to_be32(orb->page_table, orb->page_table, >+ sizeof(orb->page_table[0]) * j); >+ 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)) >+ goto fail_page_table; > /* > * The data_descriptor pointer is the one case where we need > * to fill in the node ID part of the address. All other >@@ -967,18 +1164,12 @@ static int sbp2_command_orb_map_scatterl > * on other nodes so we need to put our ID in descriptor.high. > */ > >- orb->page_table_bus = >- dma_map_single(device->card->device, orb->page_table, >- size, DMA_TO_DEVICE); >- if (dma_mapping_error(orb->page_table_bus)) >- goto fail_page_table; >- orb->request.data_descriptor.high = sd->address_high; >+ orb->request.data_descriptor.high = lu->tgt->address_high; > orb->request.data_descriptor.low = orb->page_table_bus; > orb->request.misc |= > COMMAND_ORB_PAGE_TABLE_PRESENT | > COMMAND_ORB_DATA_SIZE(j); > >- fw_memcpy_to_be32(orb->page_table, orb->page_table, size); > return 0; > > fail_page_table: >@@ -992,18 +1183,18 @@ static int sbp2_command_orb_map_scatterl > > static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) > { >- struct sbp2_device *sd = >- (struct sbp2_device *)cmd->device->host->hostdata; >- struct fw_unit *unit = sd->unit; >- struct fw_device *device = fw_device(unit->device.parent); >+ struct sbp2_logical_unit *lu = cmd->device->hostdata; >+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent); > struct sbp2_command_orb *orb; >+ unsigned max_payload; >+ int retval = SCSI_MLQUEUE_HOST_BUSY; > > /* > * Bidirectional commands are not yet implemented, and unknown > * transfer direction not handled. > */ > if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) { >- fw_error("Cannot handle DMA_BIDIRECTIONAL, rejecting command\n"); >+ fw_error("Can't handle DMA_BIDIRECTIONAL, rejecting command\n"); > cmd->result = DID_ERROR << 16; > done(cmd); > return 0; >@@ -1011,18 +1202,15 @@ static int sbp2_scsi_queuecommand(struct > > orb = kzalloc(sizeof(*orb), GFP_ATOMIC); > if (orb == NULL) { >- goto fail_alloc; >+ fw_notify("failed to alloc orb\n"); >+ return SCSI_MLQUEUE_HOST_BUSY; > } > > /* Initialize rcode to something not RCODE_COMPLETE. */ > orb->base.rcode = -1; >- 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)) >- goto fail_mapping; > >- orb->unit = unit; >+ kref_init(&orb->base.kref); >+ orb->lu = lu; > orb->done = done; > orb->cmd = cmd; > >@@ -1034,9 +1222,11 @@ static int sbp2_scsi_queuecommand(struct > * specifies the max payload size as 2 ^ (max_payload + 2), so > * if we set this to max_speed + 7, we get the right value. > */ >+ max_payload = min(device->max_speed + 7, >+ device->card->max_receive - 1); > orb->request.misc = >- COMMAND_ORB_MAX_PAYLOAD(device->node->max_speed + 7) | >- COMMAND_ORB_SPEED(device->node->max_speed) | >+ COMMAND_ORB_MAX_PAYLOAD(max_payload) | >+ COMMAND_ORB_SPEED(device->max_speed) | > COMMAND_ORB_NOTIFY; > > if (cmd->sc_data_direction == DMA_FROM_DEVICE) >@@ -1046,8 +1236,9 @@ static int sbp2_scsi_queuecommand(struct > orb->request.misc |= > COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA); > >- if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0) >- goto fail_map_payload; >+ if (cmd->use_sg && sbp2_map_scatterlist(orb, device, lu) < 0) >+ goto out; >+ > fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); > > memset(orb->request.command_block, >@@ -1056,48 +1247,47 @@ static int sbp2_scsi_queuecommand(struct > > orb->base.callback = complete_command_orb; > >- sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation, >- sd->command_block_agent_address + SBP2_ORB_POINTER); >- >- return 0; >- >- fail_map_payload: >- dma_unmap_single(device->card->device, orb->base.request_bus, >+ orb->base.request_bus = >+ dma_map_single(device->card->device, &orb->request, > sizeof(orb->request), DMA_TO_DEVICE); >- fail_mapping: >- kfree(orb); >- fail_alloc: >- return SCSI_MLQUEUE_HOST_BUSY; >+ if (dma_mapping_error(orb->base.request_bus)) >+ goto out; >+ >+ sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, lu->generation, >+ lu->command_block_agent_address + SBP2_ORB_POINTER); >+ retval = 0; >+ out: >+ kref_put(&orb->base.kref, free_orb); >+ return retval; > } > > static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) > { >- struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata; >+ struct sbp2_logical_unit *lu = sdev->hostdata; > > sdev->allow_restart = 1; > >- if (sd->workarounds & SBP2_WORKAROUND_INQUIRY_36) >+ if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36) > sdev->inquiry_len = 36; >+ > return 0; > } > > static int sbp2_scsi_slave_configure(struct scsi_device *sdev) > { >- struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata; >- struct fw_unit *unit = sd->unit; >+ struct sbp2_logical_unit *lu = sdev->hostdata; > > sdev->use_10_for_rw = 1; > > if (sdev->type == TYPE_ROM) > sdev->use_10_for_ms = 1; >+ > if (sdev->type == TYPE_DISK && >- sd->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) >+ lu->tgt->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) > sdev->skip_ms_page_8 = 1; >- if (sd->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) { >- fw_notify("setting fix_capacity for %s\n", unit->device.bus_id); >+ if (lu->tgt->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) > sdev->fix_capacity = 1; >- } >- if (sd->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) >+ if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) > blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512); > > return 0; >@@ -1109,13 +1299,11 @@ static int sbp2_scsi_slave_configure(str > */ > static int sbp2_scsi_abort(struct scsi_cmnd *cmd) > { >- struct sbp2_device *sd = >- (struct sbp2_device *)cmd->device->host->hostdata; >- struct fw_unit *unit = sd->unit; >- >- sbp2_agent_reset(unit); >- sbp2_cancel_orbs(unit); >+ struct sbp2_logical_unit *lu = cmd->device->hostdata; > >+ fw_notify("sbp2_scsi_abort\n"); >+ sbp2_agent_reset(lu); >+ sbp2_cancel_orbs(lu); > return SUCCESS; > } > >@@ -1131,37 +1319,16 @@ sbp2_sysfs_ieee1394_id_show(struct devic > char *buf) > { > struct scsi_device *sdev = to_scsi_device(dev); >- struct sbp2_device *sd; >- struct fw_unit *unit; >+ struct sbp2_logical_unit *lu; > struct fw_device *device; >- u32 directory_id; >- struct fw_csr_iterator ci; >- int key, value, lun; > > if (!sdev) > return 0; >- sd = (struct sbp2_device *)sdev->host->hostdata; >- unit = sd->unit; >- device = fw_device(unit->device.parent); >- >- /* implicit directory ID */ >- directory_id = ((unit->directory - device->config_rom) * 4 >- + CSR_CONFIG_ROM) & 0xffffff; >- >- /* explicit directory ID, overrides implicit ID if present */ >- fw_csr_iterator_init(&ci, unit->directory); >- while (fw_csr_iterator_next(&ci, &key, &value)) >- if (key == CSR_DIRECTORY_ID) { >- directory_id = value; >- break; >- } >- >- /* FIXME: Make this work for multi-lun devices. */ >- lun = 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], >- directory_id, lun); >+ lu->tgt->directory_id, lu->lun); > } > > static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL); >@@ -1174,7 +1341,7 @@ static struct device_attribute *sbp2_scs > static struct scsi_host_template scsi_driver_template = { > .module = THIS_MODULE, > .name = "SBP-2 IEEE-1394", >- .proc_name = (char *)sbp2_driver_name, >+ .proc_name = sbp2_driver_name, > .queuecommand = sbp2_scsi_queuecommand, > .slave_alloc = sbp2_scsi_slave_alloc, > .slave_configure = sbp2_scsi_slave_configure, >@@ -1199,12 +1366,17 @@ MODULE_ALIAS("sbp2"); > > static int __init sbp2_init(void) > { >+ sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); >+ if (!sbp2_wq) >+ return -ENOMEM; >+ > return driver_register(&sbp2_driver.driver); > } > > static void __exit sbp2_cleanup(void) > { > driver_unregister(&sbp2_driver.driver); >+ destroy_workqueue(sbp2_wq); > } > > module_init(sbp2_init); >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-topology.c linux-2.6.18.i686/drivers/firewire/fw-topology.c >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-topology.c 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-topology.c 2007-12-11 13:51:06.000000000 -0500 >@@ -97,7 +97,7 @@ static struct fw_node *fw_node_create(u3 > { > struct fw_node *node; > >- node = kzalloc(sizeof *node + port_count * sizeof(node->ports[0]), >+ node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]), > GFP_ATOMIC); > if (node == NULL) > return NULL; >@@ -152,6 +152,10 @@ static void update_hop_count(struct fw_n > node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2); > } > >+static inline struct fw_node *fw_node(struct list_head *l) >+{ >+ return list_entry(l, struct fw_node, link); >+} > > /** > * build_tree - Build the tree representation of the topology >@@ -162,7 +166,7 @@ static void update_hop_count(struct fw_n > * This function builds the tree representation of the topology given > * by the self IDs from the latest bus reset. During the construction > * of the tree, the function checks that the self IDs are valid and >- * internally consistent. On succcess this funtions returns the >+ * internally consistent. On succcess this function returns the > * fw_node corresponding to the local card otherwise NULL. > */ > static struct fw_node *build_tree(struct fw_card *card, >@@ -172,7 +176,8 @@ static struct fw_node *build_tree(struct > struct list_head stack, *h; > u32 *next_sid, *end, q; > int i, port_count, child_port_count, phy_id, parent_count, stack_depth; >- unsigned gap_count; >+ int gap_count; >+ int beta_repeaters_present; > > local_node = NULL; > node = NULL; >@@ -182,7 +187,7 @@ static struct fw_node *build_tree(struct > phy_id = 0; > irm_node = NULL; > gap_count = SELF_ID_GAP_COUNT(*sid); >- card->beta_repeaters_present = 0; >+ beta_repeaters_present = 0; > > while (sid < end) { > next_sid = count_ports(sid, &port_count, &child_port_count); >@@ -210,6 +215,10 @@ static struct fw_node *build_tree(struct > */ > for (i = 0, h = &stack; i < child_port_count; i++) > h = h->prev; >+ /* >+ * When the stack is empty, this yields an invalid value, >+ * but that pointer will never be dereferenced. >+ */ > child = fw_node(h); > > node = fw_node_create(q, port_count, card->color); >@@ -275,16 +284,15 @@ static struct fw_node *build_tree(struct > > if (node->phy_speed == SCODE_BETA && > parent_count + child_port_count > 1) >- card->beta_repeaters_present = 1; >+ beta_repeaters_present = 1; > > /* > * If all PHYs does not report the same gap count > * setting, we fall back to 63 which will force a gap > * count reconfiguration and a reset. > */ >- if (SELF_ID_GAP_COUNT(q) != gap_count) { >+ if (SELF_ID_GAP_COUNT(q) != gap_count) > gap_count = 63; >- } > > update_hop_count(node); > >@@ -295,6 +303,7 @@ static struct fw_node *build_tree(struct > card->root_node = node; > card->irm_node = irm_node; > card->gap_count = gap_count; >+ card->beta_repeaters_present = beta_repeaters_present; > > return local_node; > } >@@ -427,7 +436,6 @@ update_tree(struct fw_card *card, struct > node0->link_on = node1->link_on; > node0->initiated_reset = node1->initiated_reset; > node0->max_hops = node1->max_hops; >- > node1->color = card->color; > fw_node_event(card, node0, event); > >@@ -445,10 +453,8 @@ update_tree(struct fw_card *card, struct > */ > if (node0->ports[i]->color == card->color) > continue; >- list_add_tail(&node0->ports[i]->link, >- &list0); >- list_add_tail(&node1->ports[i]->link, >- &list1); >+ list_add_tail(&node0->ports[i]->link, &list0); >+ list_add_tail(&node1->ports[i]->link, &list1); > } else if (node0->ports[i]) { > /* > * The nodes connected here were >@@ -486,7 +492,7 @@ update_topology_map(struct fw_card *card > card->topology_map[1]++; > node_count = (card->root_node->node_id & 0x3f) + 1; > card->topology_map[2] = (node_count << 16) | self_id_count; >- card->topology_map[0] = ((self_id_count + 2) << 16); >+ card->topology_map[0] = (self_id_count + 2) << 16; > memcpy(&card->topology_map[3], self_ids, self_id_count * 4); > fw_compute_block_crc(card->topology_map); > } >@@ -500,19 +506,19 @@ fw_core_handle_bus_reset(struct fw_card > unsigned long flags; > > fw_flush_transactions(card); >+ > spin_lock_irqsave(&card->lock, flags); >+ > /* > * If the new topology has a different self_id_count the topology > * changed, either nodes were added or removed. In that case we > * reset the IRM reset counter. > */ >- if (card->self_id_count && card->self_id_count != self_id_count) { >+ if (card->self_id_count != self_id_count) > card->bm_retries = 0; >- } > > card->node_id = node_id; > card->generation = generation; >- card->self_id_count = self_id_count; > card->reset_jiffies = jiffies; > schedule_delayed_work(&card->work, 0); > >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-topology.h linux-2.6.18.i686/drivers/firewire/fw-topology.h >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-topology.h 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-topology.h 2007-12-11 13:51:06.000000000 -0500 >@@ -31,11 +31,11 @@ struct fw_node { > u16 node_id; > u8 color; > u8 port_count; >- unsigned link_on : 1; >- unsigned initiated_reset : 1; >- unsigned b_path : 1; >- u8 phy_speed : 3; /* As in the self ID packet. */ >- u8 max_speed : 5; /* Minimum of all phy-speeds and port speeds on >+ u8 link_on : 1; >+ u8 initiated_reset : 1; >+ u8 b_path : 1; >+ u8 phy_speed : 2; /* As in the self ID packet. */ >+ u8 max_speed : 2; /* Minimum of all phy-speeds and port speeds on > * the path from the local node to this node. */ > u8 max_depth : 4; /* Maximum depth to any leaf node */ > u8 max_hops : 4; /* Max hops in this sub tree */ >@@ -51,12 +51,6 @@ struct fw_node { > }; > > static inline struct fw_node * >-fw_node(struct list_head *l) >-{ >- return list_entry(l, struct fw_node, link); >-} >- >-static inline struct fw_node * > fw_node_get(struct fw_node *node) > { > atomic_inc(&node->ref_count); >@@ -75,6 +69,6 @@ void > fw_destroy_nodes(struct fw_card *card); > > int >-fw_compute_block_crc(u32 *buffer); >+fw_compute_block_crc(u32 *block); > > #endif /* __fw_topology_h */ >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-transaction.c linux-2.6.18.i686/drivers/firewire/fw-transaction.c >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-transaction.c 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-transaction.c 2007-12-11 13:51:06.000000000 -0500 >@@ -76,7 +76,6 @@ close_transaction(struct fw_transaction > } > spin_unlock_irqrestore(&card->lock, flags); > >- BUG_ON(!t); > if (&t->link != &card->transaction_list) { > t->callback(card, rcode, payload, length, t->callback_data); > return 0; >@@ -229,7 +228,7 @@ fw_fill_request(struct fw_packet *packet > * > * @param card the card from which to send the request > * @param tcode the tcode for this transaction. Do not use >- * TCODE_LOCK_REQUEST directly, insted use TCODE_LOCK_MASK_SWAP >+ * TCODE_LOCK_REQUEST directly, instead use TCODE_LOCK_MASK_SWAP > * etc. to specify tcode and ext_tcode. > * @param node_id the destination node ID (bus ID and PHY ID concatenated) > * @param generation the generation for which node_id is valid >@@ -329,6 +328,7 @@ void fw_send_phy_config(struct fw_card * > q = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | > PHY_CONFIG_ROOT_ID(node_id) | > PHY_CONFIG_GAP_COUNT(gap_count); >+ > send_phy_packet(card, q, generation); > } > >@@ -410,7 +410,12 @@ EXPORT_SYMBOL(fw_unit_space_region); > * controller. When a request is received that falls within the > * specified address range, the specified callback is invoked. The > * parameters passed to the callback give the details of the >- * particular request >+ * particular request. >+ * >+ * Return value: 0 on success, non-zero otherwise. >+ * The start offset of the handler's address region is determined by >+ * fw_core_add_address_handler() and is returned in handler->offset. >+ * The offset is quadlet-aligned. > */ > int > fw_core_add_address_handler(struct fw_address_handler *handler, >@@ -422,14 +427,15 @@ fw_core_add_address_handler(struct fw_ad > > spin_lock_irqsave(&address_handler_lock, flags); > >- handler->offset = region->start; >+ handler->offset = roundup(region->start, 4); > while (handler->offset + handler->length <= region->end) { > other = > lookup_overlapping_address_handler(&address_handler_list, > handler->offset, > handler->length); > if (other != NULL) { >- handler->offset += other->length; >+ handler->offset += >+ roundup(other->offset + other->length, 4); > } else { > list_add_tail(&handler->link, &address_handler_list); > ret = 0; >@@ -605,8 +611,10 @@ fw_send_response(struct fw_card *card, s > * check is sufficient to ensure we don't send response to > * broadcast packets or posted writes. > */ >- if (request->ack != ACK_PENDING) >+ if (request->ack != ACK_PENDING) { >+ kfree ( request ); > return; >+ } > > if (rcode == RCODE_COMPLETE) > fw_fill_response(&request->response, request->request_header, >@@ -628,12 +636,6 @@ fw_core_handle_request(struct fw_card *c > unsigned long flags; > int tcode, destination, source; > >- if (p->payload_length > 2048) { >- /* FIXME: send error response. */ >- fw_error("fw_core_handle_request: too big\n"); >- return; >- } >- > if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) > return; > >@@ -738,7 +740,7 @@ fw_core_handle_response(struct fw_card * > } > EXPORT_SYMBOL(fw_core_handle_response); > >-const struct fw_address_region topology_map_region = >+static const struct fw_address_region topology_map_region = > { .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, }; > > static void >@@ -776,7 +778,7 @@ static struct fw_address_handler topolog > .address_callback = handle_topology_map, > }; > >-const struct fw_address_region registers_region = >+static const struct fw_address_region registers_region = > { .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, }; > > static void >diff -r -p -u linux-2.6.18.x86_64/drivers/firewire.orig/fw-transaction.h linux-2.6.18.i686/drivers/firewire/fw-transaction.h >--- linux-2.6.18.x86_64/drivers/firewire.orig/fw-transaction.h 2007-11-13 21:16:18.000000000 -0500 >+++ linux-2.6.18.i686/drivers/firewire/fw-transaction.h 2007-12-11 13:51:06.000000000 -0500 >@@ -81,7 +81,6 @@ > > #define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args) > #define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) >-#define fw_debug(s, args...) printk(KERN_DEBUG KBUILD_MODNAME ": " s, ## args) > > static inline void > fw_memcpy_from_be32(void *_dst, void *_src, size_t size) >@@ -124,6 +123,10 @@ typedef void (*fw_transaction_callback_t > size_t length, > void *callback_data); > >+/* >+ * Important note: The callback must guarantee that either fw_send_response() >+ * or kfree() is called on the @request. >+ */ > typedef void (*fw_address_callback_t)(struct fw_card *card, > struct fw_request *request, > int tcode, int destination, int source, >@@ -228,7 +231,7 @@ struct fw_card { > unsigned long reset_jiffies; > > unsigned long long guid; >- int max_receive; >+ unsigned max_receive; > int link_speed; > int config_rom_generation; > >@@ -245,20 +248,7 @@ struct fw_card { > struct fw_node *root_node; > struct fw_node *irm_node; > int color; >- /* >- * May range from 1(?) to 63 >- * This is the gap-count for the bus attached to this card. >- * All devices on a bus must use the same gap count. Too small a >- * gap count risks collision errors on the bus. Too large a >- * gap count wastes bus bandwidth. See the standards docs for >- * a discussion on gap count optimization. >- */ >- unsigned gap_count; >- /* >- * May be zero or nonzero: nonzero means that there are 1394b >- * repeaters on the bus, so the gap count cannot be easily(?) >- * optimized. >- */ >+ int gap_count; > int beta_repeaters_present; > > int index; >@@ -441,7 +431,7 @@ void fw_send_phy_config(struct fw_card * > > /* > * Called by the topology code to inform the device code of node >- * activity; found, lost, or updated nodes >+ * activity; found, lost, or updated nodes. > */ > void > fw_node_event(struct fw_card *card, struct fw_node *node, int event);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 370421
: 289971