GIT 6928b0009a64cc5eef5d6c43faba5241cfa5b60a git+ssh://master.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git commit Author: David Moore Date: Sun Jan 6 17:21:41 2008 -0500 firewire: fw-ohci: Dynamically allocate buffers for DMA descriptors Previously, the fw-ohci driver used fixed-length buffers for storing descriptors for isochronous receive DMA programs. If an application (such as libdc1394) generated a DMA program that was too large, fw-ohci would reach the limit of its fixed-sized buffer and return an error to userspace. This patch replaces the fixed-length ring-buffer with a linked-list of page-sized buffers. Additional buffers can be dynamically allocated and appended to the list when necessary. For a particular context, buffers are kept around after use and reused as necessary, so there is no allocation taking place after the DMA program is generated for the first time. In addition, the buffers it uses are coherent for DMA so there is no syncing required before and after writes. This syncing wasn't properly done in the previous version of the code. - This is the fourth version of my patch that replaces a fixed-length buffer for DMA descriptors with a dynamically allocated linked-list of buffers. As we discovered with the last attempt, new context programs are sometimes queued from interrupt context, making it unacceptable to call tasklet_disable() from context_get_descriptors(). This version of the patch uses ohci->lock for all locking needs instead of tasklet_disable/enable. There is a new requirement that context_get_descriptors() be called while holding ohci->lock. It was already held for the AT context, so adding the requirement for the iso context did not seem particularly onerous. In addition, this has the side benefit of allowing iso queue to be safely called from concurrent user-space threads, which previously was not safe. Signed-off-by: David Moore Signed-off-by: Kristian Høgsberg Signed-off-by: Jarod Wilson - Fixes the following issues: - Isochronous reception stopped prematurely if an application used a larger buffer. (Reproduced with coriander.) - Isochronous reception stopped after one or a few frames on VT630x in OHCI 1.0 mode. (Fixes reception in coriander, but dvgrab still doesn't work with these chips.) Patch update: struct member alignment, whitespace nits Signed-off-by: Stefan Richter commit 948b907d3fb2d02f77aea8d5b015cc533bff8d65 Author: Stefan Richter Date: Sat Dec 22 22:14:52 2007 +0100 firewire: fw-ohci: CycleTooLong interrupt management The firewire-ohci driver so far lacked the ability to resume cycle master duty after that condition happened, as added to ohci1394 in Linux 2.6.18 by commit 57fdb58fa5a140bdd52cf4c4ffc30df73676f0a5. This ports this patch to fw-ohci. The "cycle too long" condition has been seen in practice - with IIDC cameras if a mode with packets too large for a speed is chosen, - sporadically when capturing DV on a VIA VT6306 card with ohci1394/ ieee1394/ raw1394/ dvgrab 2. https://bugzilla.redhat.com/show_bug.cgi?id=415841#c7 (This does not fix Fedora bug 415841.) Signed-off-by: Stefan Richter commit f22532d403d2b91ec355c3dc008688bb87013600 Author: Rabin Vincent Date: Fri Dec 21 23:02:15 2007 +0530 firewire: Fix extraction of source node id Fix extraction of the source node id from the packet header. Signed-off-by: Rabin Vincent Signed-off-by: Stefan Richter commit 47349df008fd1ebcf6512200e9e2eccb313952c4 Author: David Moore Date: Wed Dec 19 15:26:38 2007 -0500 firewire: fw-ohci: Bug fixes for packet-per-buffer support This patch corrects a number of bugs in the current OHCI 1.0 packet-per-buffer support: 1. Correctly deal with payloads that cross a page boundary. The previous version would not split the descriptor at such a boundary, potentially corrupting unrelated memory. 2. Allow user-space to specify multiple packets per struct fw_cdev_iso_packet in the same way that dual-buffer allows. This is signaled by header_length being a multiple of header_size. This multiple determines the number of packets. The payload size allocated per packet is determined by dividing the total payload size by the number of packets. 3. Make sync support work properly for packet-per-buffer. I have tested this patch with libdc1394 by forcing my OHCI 1.1 controller to use the packet-per-buffer support instead of dual-buffer. I would greatly appreciate testing by those who have a DV devices and other types of iso streamers to make sure I didn't cause any regressions. Stefan, with this patch, I'm hoping that libdc1394 will work with all your OHCI 1.0 controllers now. The one bit of future work that remains for packet-per-buffer support is the automatic compaction of short payloads that I discussed with Kristian. Signed-off-by: David Moore Signed-off-by: Stefan Richter commit e9f5ca46377ac60a6b7d52c6c19a1661c87c6e20 Author: David Moore Date: Wed Dec 19 03:09:18 2007 -0500 firewire: fw-ohci: Fix for dualbuffer three-or-more buffers This patch fixes the problem where different OHCI 1.1 controllers behave differently when a received iso packet straddles three or more buffers when using the dual-buffer receive mode. Two changes are made in order to handle this situation: 1. The packet sync DMA descriptor is given a non-zero header length and non-zero payload length. This is because zero-payload descriptors are not discussed in the OHCI 1.1 specs and their behavior is thus undefined. Instead we use a header size just large enough for a single header and a payload length of 4 bytes for this first descriptor. 2. As we process received packets in the context's tasklet, read the packet length out of the headers. Keep track of the running total of the packet length as "excess_bytes", so we can ignore any descriptors where no packet starts or ends. These descriptors may not have had their first_res_count or second_res_count fields updated by the controller so we cannot rely on those values. The main drawback of this patch is that the excess_bytes value might get "out of sync" with the packet descriptors if something strange happens to the DMA program. I'm not if such a thing could ever happen, but I appreciate any suggestions in making it more robust. Also, the packet-per-buffer support may need a similar fix to deal with issue 1, but I haven't done any work on that yet. Stefan, I'm hoping that with this patch, all your OHCI 1.1 controllers will work properly with an unmodified version of libdc1394. Signed-off-by: David Moore Signed-off-by: Stefan Richter commit 070ca2f30c2bbaeeeb740dfad01cc9a27905e6a9 Author: Stefan Richter Date: Sun Dec 16 20:53:13 2007 +0100 ieee1394: ohci1394: don't schedule IT tasklets on IR events Bug noted by Pieter Palmers: Isochronous transmit tasklets were scheduled on isochronous receive events, in addition to the proper isochronous receive tasklets. http://marc.info/?l=linux1394-devel&m=119783196222802 Signed-off-by: Stefan Richter commit 27aa95c9e41622c0d4f5c8d30b62abae0cc9ada0 Author: Stefan Richter Date: Sun Dec 16 17:32:11 2007 +0100 firewire: fw-sbp2: remove unused misleading macro SBP2_MAX_SECTORS is nowhere used in fw-sbp2. It merely got copied over from sbp2 where it played a role in the past. Signed-off-by: Stefan Richter commit 332319e2852838221b2ece1389248414e060cc94 Author: Stefan Richter Date: Sun Dec 16 17:31:26 2007 +0100 ieee1394: sbp2: raise default transfer size limit This patch speeds up sbp2 a little bit --- but more importantly, it brings the behavior of sbp2 and fw-sbp2 closer to each other. Like fw-sbp2, sbp2 now does not limit the size of single transfers to 255 sectors anymore, unless told so by a blacklist flag or by module load parameters. Only very old bridge chips have been known to need the 255 sectors limit, and we have got one such chip in our hardwired blacklist. There certainly is a danger that more bridges need that limit; but I prefer to have this issue present in both fw-sbp2 and sbp2 rather than just one of them. An OXUF922 with 400GB 7200RPM disk on an S400 controller is sped up by this patch from 22.9 to 23.5 MB/s according to hdparm. The same effect could be achieved before by setting a higher max_sectors module parameter. On buses which use 1394b beta mode, sbp2 and fw-sbp2 will now achieve virtually the same bandwidth. Fw-sbp2 only remains faster on 1394a buses due to fw-core's gap count optimization. Signed-off-by: Stefan Richter commit bc2dfcc923803ab9a60e5316748e25d425a2bd08 Author: Stefan Richter Date: Sat Dec 15 14:11:41 2007 +0100 ieee1394: remove unused code The code has been in "#if 0 - #endif" since Linux 2.6.12. Signed-off-by: Stefan Richter commit aa541d501d5be17ba05e8e6374371c5b376ab994 Author: Stefan Richter Date: Sat Dec 15 14:04:42 2007 +0100 ieee1394: small cleanup after "nopage" Signed-off-by: Stefan Richter commit 598c25878bf4e7de677079022c42635ebd846e62 Author: Stefan Richter Date: Sat Dec 22 21:53:33 2007 +0100 Revert "firewire: fw-ohci: CycleTooLong interrupt management" This reverts commit 5bd0c4ef883f5e3c24ab91127de0292ebd0fa405. Needs to be updated to rate-limit the kernel log message. commit 0394d46dc8485840992f6dd57e39f2336e85a6fe Author: Nick Piggin Date: Wed Dec 5 18:15:53 2007 +1100 ieee1394: nopage Convert ieee1394 from nopage to fault. Remove redundant vma range checks (correct resource range check is retained). Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Stefan Richter commit 5bd0c4ef883f5e3c24ab91127de0292ebd0fa405 Author: Stefan Richter Date: Sun Dec 9 14:03:09 2007 +0100 firewire: fw-ohci: CycleTooLong interrupt management According to a report by Robin Theander, VIA VT6306 may sporadically trip the "isochronous cycle too long" condition when capturing DV in buffer-fill mode with ohci1394/ ieee1394/ raw1394/ dvgrab 2. https://bugzilla.redhat.com/show_bug.cgi?id=415841#c7 The firewire-ohci driver so far lacked the ability to resume cycle master duty after that condition happened, an ability added to ohci1394 in Linux 2.6.18 by a patch from Jean-Baptiste Mur (commit 57fdb58fa5a140bdd52cf4c4ffc30df73676f0a5). This ports this commit to fw-ohci just to be sure, since this condition can potentially also happen with fw-ohci. This does alas not fix above referenced Fedora bug 415841. Signed-off-by: Stefan Richter commit 1526cb4169cce7b87db54c47ce0fd0c1bd7fb16a Author: Joe Perches Date: Mon Nov 19 17:48:10 2007 -0800 ieee1394: Add missing "space" Signed-off-by: Joe Perches Signed-off-by: Stefan Richter commit b4be6170ef896e3a98a71e03f3514ccff264ffde Author: Jay Fenlason Date: Wed Nov 7 17:39:00 2007 -0500 firewire: fw-sbp2: quiet logout errors on device removal This suppresses both reply timed out and management write failed errors on LOGOUT requests. Signed-off-by: Jay Fenlason Signed-off-by: Stefan Richter commit 8f50ff61ed0282179371cbef173b8b0aad0d1313 Author: Stefan Richter Date: Sun Nov 4 14:59:24 2007 +0100 ieee1394: sbp2: s/g list access cosmetics Replace sg->length by sg_dma_len(sg). Rename a variable for shorter line lengths and eliminate some superfluous local variables. Signed-off-by: Stefan Richter commit fe702f621c6bdead79dd4172cd00b35ece4b88c3 Author: Stefan Richter Date: Sun Nov 4 14:58:43 2007 +0100 ieee1394: sbp2: enable s/g chaining Signed-off-by: Stefan Richter commit 53e11c39606617de4fea57077891abb3870ff383 Author: Stefan Richter Date: Sun Nov 4 14:58:11 2007 +0100 firewire: fw-sbp2: enable s/g chaining Signed-off-by: Stefan Richter commit c3e0d276f016e052dfd87b73041a5be6dd08454d Author: Stefan Richter Date: Wed Nov 7 01:12:51 2007 +0100 firewire: fw-sbp2: refactor workq and kref handling This somewhat reduces the size of firewire-sbp2.ko. Signed-off-by: Stefan Richter drivers/firewire/fw-ohci.c | 390 ++++++++++++++++++------------ drivers/firewire/fw-sbp2.c | 85 ++++--- drivers/firewire/fw-transaction.c | 2 +- drivers/ieee1394/dma.c | 39 +-- drivers/ieee1394/ieee1394_transactions.c | 68 ----- drivers/ieee1394/ohci1394.c | 12 +- drivers/ieee1394/raw1394.c | 4 +- drivers/ieee1394/sbp2.c | 53 +++-- drivers/ieee1394/sbp2.h | 1 - 9 files changed, 340 insertions(+), 314 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 436a855..7ebad3c 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -98,17 +98,48 @@ struct context; typedef int (*descriptor_callback_t)(struct context *ctx, struct descriptor *d, struct descriptor *last); + +/* + * A buffer that contains a block of DMA-able coherent memory used for + * storing a portion of a DMA descriptor program. + */ +struct descriptor_buffer { + struct list_head list; + dma_addr_t buffer_bus; + size_t buffer_size; + size_t used; + struct descriptor buffer[0]; +}; + struct context { struct fw_ohci *ohci; u32 regs; + int total_allocation; - struct descriptor *buffer; - dma_addr_t buffer_bus; - size_t buffer_size; - struct descriptor *head_descriptor; - struct descriptor *tail_descriptor; - struct descriptor *tail_descriptor_last; - struct descriptor *prev_descriptor; + /* + * List of page-sized buffers for storing DMA descriptors. + * Head of list contains buffers in use and tail of list contains + * free buffers. + */ + struct list_head buffer_list; + + /* + * Pointer to a buffer inside buffer_list that contains the tail + * end of the current DMA program. + */ + struct descriptor_buffer *buffer_tail; + + /* + * The descriptor containing the branch address of the first + * descriptor that has not yet been filled by the device. + */ + struct descriptor *last; + + /* + * The last descriptor in the DMA program. It contains the branch + * address that must be updated upon appending a new descriptor. + */ + struct descriptor *prev; descriptor_callback_t callback; @@ -125,6 +156,7 @@ struct context { struct iso_context { struct fw_iso_context base; struct context context; + int excess_bytes; void *header; size_t header_length; }; @@ -197,8 +229,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) #define SELF_ID_BUF_SIZE 0x800 #define OHCI_TCODE_PHY_PACKET 0x0e #define OHCI_VERSION_1_1 0x010010 -#define ISO_BUFFER_SIZE (64 * 1024) -#define AT_BUFFER_SIZE 4096 static char ohci_driver_name[] = KBUILD_MODNAME; @@ -455,71 +485,108 @@ find_branch_descriptor(struct descriptor *d, int z) static void context_tasklet(unsigned long data) { struct context *ctx = (struct context *) data; - struct fw_ohci *ohci = ctx->ohci; struct descriptor *d, *last; u32 address; int z; + struct descriptor_buffer *desc; - dma_sync_single_for_cpu(ohci->card.device, ctx->buffer_bus, - ctx->buffer_size, DMA_TO_DEVICE); - - d = ctx->tail_descriptor; - last = ctx->tail_descriptor_last; - + desc = list_entry(ctx->buffer_list.next, + struct descriptor_buffer, list); + last = ctx->last; while (last->branch_address != 0) { + struct descriptor_buffer *old_desc = desc; address = le32_to_cpu(last->branch_address); z = address & 0xf; - d = ctx->buffer + (address - ctx->buffer_bus) / sizeof(*d); + address &= ~0xf; + + /* If the branch address points to a buffer outside of the + * current buffer, advance to the next buffer. */ + if (address < desc->buffer_bus || + address >= desc->buffer_bus + desc->used) + desc = list_entry(desc->list.next, + struct descriptor_buffer, list); + d = desc->buffer + (address - desc->buffer_bus) / sizeof(*d); last = find_branch_descriptor(d, z); if (!ctx->callback(ctx, d, last)) break; - ctx->tail_descriptor = d; - ctx->tail_descriptor_last = last; + if (old_desc != desc) { + /* If we've advanced to the next buffer, move the + * previous buffer to the free list. */ + unsigned long flags; + old_desc->used = 0; + spin_lock_irqsave(&ctx->ohci->lock, flags); + list_move_tail(&old_desc->list, &ctx->buffer_list); + spin_unlock_irqrestore(&ctx->ohci->lock, flags); + } + ctx->last = last; } } +/* + * Allocate a new buffer and add it to the list of free buffers for this + * context. Must be called with ohci->lock held. + */ +static int +context_add_buffer(struct context *ctx) +{ + struct descriptor_buffer *desc; + dma_addr_t bus_addr; + int offset; + + /* + * 16MB of descriptors should be far more than enough for any DMA + * program. This will catch run-away userspace or DoS attacks. + */ + if (ctx->total_allocation >= 16*1024*1024) + return -ENOMEM; + + desc = dma_alloc_coherent(ctx->ohci->card.device, PAGE_SIZE, + &bus_addr, GFP_ATOMIC); + if (!desc) + return -ENOMEM; + + offset = (void *)&desc->buffer - (void *)desc; + desc->buffer_size = PAGE_SIZE - offset; + desc->buffer_bus = bus_addr + offset; + desc->used = 0; + + list_add_tail(&desc->list, &ctx->buffer_list); + ctx->total_allocation += PAGE_SIZE; + + return 0; +} + static int context_init(struct context *ctx, struct fw_ohci *ohci, - size_t buffer_size, u32 regs, - descriptor_callback_t callback) + u32 regs, descriptor_callback_t callback) { ctx->ohci = ohci; ctx->regs = regs; - ctx->buffer_size = buffer_size; - ctx->buffer = kmalloc(buffer_size, GFP_KERNEL); - if (ctx->buffer == NULL) + ctx->total_allocation = 0; + + INIT_LIST_HEAD(&ctx->buffer_list); + if (context_add_buffer(ctx) < 0) return -ENOMEM; + ctx->buffer_tail = list_entry(ctx->buffer_list.next, + struct descriptor_buffer, list); + tasklet_init(&ctx->tasklet, context_tasklet, (unsigned long)ctx); ctx->callback = callback; - ctx->buffer_bus = - dma_map_single(ohci->card.device, ctx->buffer, - buffer_size, DMA_TO_DEVICE); - if (dma_mapping_error(ctx->buffer_bus)) { - kfree(ctx->buffer); - return -ENOMEM; - } - - ctx->head_descriptor = ctx->buffer; - ctx->prev_descriptor = ctx->buffer; - ctx->tail_descriptor = ctx->buffer; - ctx->tail_descriptor_last = ctx->buffer; - /* * We put a dummy descriptor in the buffer that has a NULL * branch address and looks like it's been sent. That way we - * have a descriptor to append DMA programs to. Also, the - * ring buffer invariant is that it always has at least one - * element so that head == tail means buffer full. + * have a descriptor to append DMA programs to. */ - - memset(ctx->head_descriptor, 0, sizeof(*ctx->head_descriptor)); - ctx->head_descriptor->control = cpu_to_le16(DESCRIPTOR_OUTPUT_LAST); - ctx->head_descriptor->transfer_status = cpu_to_le16(0x8011); - ctx->head_descriptor++; + memset(ctx->buffer_tail->buffer, 0, sizeof(*ctx->buffer_tail->buffer)); + ctx->buffer_tail->buffer->control = cpu_to_le16(DESCRIPTOR_OUTPUT_LAST); + ctx->buffer_tail->buffer->transfer_status = cpu_to_le16(0x8011); + ctx->buffer_tail->used += sizeof(*ctx->buffer_tail->buffer); + ctx->last = ctx->buffer_tail->buffer; + ctx->prev = ctx->buffer_tail->buffer; return 0; } @@ -528,35 +595,42 @@ static void context_release(struct context *ctx) { struct fw_card *card = &ctx->ohci->card; + struct descriptor_buffer *desc, *tmp; - dma_unmap_single(card->device, ctx->buffer_bus, - ctx->buffer_size, DMA_TO_DEVICE); - kfree(ctx->buffer); + list_for_each_entry_safe(desc, tmp, &ctx->buffer_list, list) + dma_free_coherent(card->device, PAGE_SIZE, desc, + desc->buffer_bus - + ((void *)&desc->buffer - (void *)desc)); } +/* Must be called with ohci->lock held */ static struct descriptor * context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus) { - struct descriptor *d, *tail, *end; - - d = ctx->head_descriptor; - tail = ctx->tail_descriptor; - end = ctx->buffer + ctx->buffer_size / sizeof(*d); - - if (d + z <= tail) { - goto has_space; - } else if (d > tail && d + z <= end) { - goto has_space; - } else if (d > tail && ctx->buffer + z <= tail) { - d = ctx->buffer; - goto has_space; - } + struct descriptor *d = NULL; + struct descriptor_buffer *desc = ctx->buffer_tail; + + if (z * sizeof(*d) > desc->buffer_size) + return NULL; - return NULL; + if (z * sizeof(*d) > desc->buffer_size - desc->used) { + /* No room for the descriptor in this buffer, so advance to the + * next one. */ + + if (desc->list.next == &ctx->buffer_list) { + /* If there is no free buffer next in the list, + * allocate one. */ + if (context_add_buffer(ctx) < 0) + return NULL; + } + desc = list_entry(desc->list.next, + struct descriptor_buffer, list); + ctx->buffer_tail = desc; + } - has_space: + d = desc->buffer + desc->used / sizeof(*d); memset(d, 0, z * sizeof(*d)); - *d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d); + *d_bus = desc->buffer_bus + desc->used; return d; } @@ -566,7 +640,7 @@ static void context_run(struct context *ctx, u32 extra) struct fw_ohci *ohci = ctx->ohci; reg_write(ohci, COMMAND_PTR(ctx->regs), - le32_to_cpu(ctx->tail_descriptor_last->branch_address)); + le32_to_cpu(ctx->last->branch_address)); reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0); reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra); flush_writes(ohci); @@ -576,15 +650,13 @@ static void context_append(struct context *ctx, struct descriptor *d, int z, int extra) { dma_addr_t d_bus; + struct descriptor_buffer *desc = ctx->buffer_tail; - d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d); + d_bus = desc->buffer_bus + (d - desc->buffer) * sizeof(*d); - ctx->head_descriptor = d + z + extra; - ctx->prev_descriptor->branch_address = cpu_to_le32(d_bus | z); - 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); + desc->used += (z + extra) * sizeof(*d); + ctx->prev->branch_address = cpu_to_le32(d_bus | z); + ctx->prev = find_branch_descriptor(d, z); reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); flush_writes(ctx->ohci); @@ -1078,6 +1150,13 @@ static irqreturn_t irq_handler(int irq, void *data) if (unlikely(event & OHCI1394_postedWriteErr)) fw_error("PCI posted write error\n"); + if (unlikely(event & OHCI1394_cycleTooLong)) { + if (printk_ratelimit()) + fw_notify("isochronous cycle too long\n"); + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_cycleMaster); + } + if (event & OHCI1394_cycle64Seconds) { cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); if ((cycle_time & 0x80000000) == 0) @@ -1151,8 +1230,8 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length) OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_reqTxComplete | OHCI1394_respTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | - OHCI1394_postedWriteErr | OHCI1394_cycle64Seconds | - OHCI1394_masterIntEnable); + OHCI1394_postedWriteErr | OHCI1394_cycleTooLong | + OHCI1394_cycle64Seconds | OHCI1394_masterIntEnable); /* Activate link_on bit and contender bit in our self ID packets.*/ if (ohci_update_phy_reg(card, 4, 0, @@ -1408,9 +1487,13 @@ static int handle_ir_dualbuffer_packet(struct context *context, void *p, *end; int i; - if (db->first_res_count > 0 && db->second_res_count > 0) - /* This descriptor isn't done yet, stop iteration. */ - return 0; + if (db->first_res_count > 0 && db->second_res_count > 0) { + if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) { + /* This descriptor isn't done yet, stop iteration. */ + return 0; + } + ctx->excess_bytes -= le16_to_cpu(db->second_req_count); + } header_length = le16_to_cpu(db->first_req_count) - le16_to_cpu(db->first_res_count); @@ -1429,11 +1512,15 @@ static int handle_ir_dualbuffer_packet(struct context *context, *(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; + ctx->excess_bytes += + (le32_to_cpu(*(u32 *)(p + 4)) >> 16) & 0xffff; p += ctx->base.header_size + 4; } - ctx->header_length = i; + ctx->excess_bytes -= le16_to_cpu(db->second_req_count) - + le16_to_cpu(db->second_res_count); + if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) { ir_header = (__le32 *) (db + 1); ctx->base.callback(&ctx->base, @@ -1452,24 +1539,24 @@ static int handle_ir_packet_per_buffer(struct context *context, { struct iso_context *ctx = container_of(context, struct iso_context, context); - struct descriptor *pd = d + 1; + struct descriptor *pd; __le32 *ir_header; - size_t header_length; - void *p, *end; - int i, z; + void *p; + int i; - if (pd->res_count == pd->req_count) + for (pd = d; pd <= last; pd++) { + if (pd->transfer_status) + break; + } + if (pd > last) /* 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; + p = last + 1; - while (p < end && i + ctx->base.header_size <= PAGE_SIZE) { + if (ctx->base.header_size > 0 && + i + ctx->base.header_size <= PAGE_SIZE) { /* * The iso header is byteswapped to little endian by * the controller, but the remaining header quadlets @@ -1478,14 +1565,11 @@ static int handle_ir_packet_per_buffer(struct context *context, */ *(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 += ctx->base.header_size; } - ctx->header_length = i; - - if (le16_to_cpu(pd->control) & DESCRIPTOR_IRQ_ALWAYS) { - ir_header = (__le32 *) (d + z); + if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { + ir_header = (__le32 *) p; ctx->base.callback(&ctx->base, le32_to_cpu(ir_header[0]) & 0xffff, ctx->header_length, ctx->header, @@ -1493,7 +1577,6 @@ static int handle_ir_packet_per_buffer(struct context *context, ctx->header_length = 0; } - return 1; } @@ -1559,8 +1642,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size) if (ctx->header == NULL) goto out; - retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE, - regs, callback); + retval = context_init(&ctx->context, ohci, regs, callback); if (retval < 0) goto out_with_header; @@ -1775,19 +1857,6 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, * packet, retransmit or terminate.. */ - if (packet->skip) { - d = context_get_descriptors(&ctx->context, 2, &d_bus); - if (d == NULL) - return -ENOMEM; - - db = (struct db_descriptor *) d; - db->control = cpu_to_le16(DESCRIPTOR_STATUS | - DESCRIPTOR_BRANCH_ALWAYS | - DESCRIPTOR_WAIT); - db->first_size = cpu_to_le16(ctx->base.header_size + 4); - context_append(&ctx->context, d, 2, 0); - } - p = packet; z = 2; @@ -1815,11 +1884,18 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, db->control = cpu_to_le16(DESCRIPTOR_STATUS | DESCRIPTOR_BRANCH_ALWAYS); db->first_size = cpu_to_le16(ctx->base.header_size + 4); - db->first_req_count = cpu_to_le16(header_size); + if (p->skip && rest == p->payload_length) { + db->control |= cpu_to_le16(DESCRIPTOR_WAIT); + db->first_req_count = db->first_size; + } else { + db->first_req_count = cpu_to_le16(header_size); + } db->first_res_count = db->first_req_count; db->first_buffer = cpu_to_le32(d_bus + sizeof(*db)); - if (offset + rest < PAGE_SIZE) + if (p->skip && rest == p->payload_length) + length = 4; + else if (offset + rest < PAGE_SIZE) length = rest; else length = PAGE_SIZE - offset; @@ -1835,7 +1911,8 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, context_append(&ctx->context, d, z, header_z); offset = (offset + length) & ~PAGE_MASK; rest -= length; - page++; + if (offset == 0) + page++; } return 0; @@ -1849,67 +1926,70 @@ ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, { struct iso_context *ctx = container_of(base, struct iso_context, base); struct descriptor *d = NULL, *pd = NULL; - struct fw_iso_packet *p; + struct fw_iso_packet *p = packet; 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; + int i, j, length; + int page, offset, packet_count, header_size, payload_per_buffer; /* * 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); + header_size = 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; + payload_per_buffer = p->payload_length / packet_count; for (i = 0; i < packet_count; i++) { /* d points to the header descriptor */ + z = DIV_ROUND_UP(payload_per_buffer + offset, PAGE_SIZE) + 1; d = context_get_descriptors(&ctx->context, - z + header_z, &d_bus); + z + header_z, &d_bus); if (d == NULL) return -ENOMEM; - d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE); + d->control = cpu_to_le16(DESCRIPTOR_STATUS | + DESCRIPTOR_INPUT_MORE); + if (p->skip && i == 0) + d->control |= cpu_to_le16(DESCRIPTOR_WAIT); d->req_count = cpu_to_le16(header_size); d->res_count = d->req_count; + d->transfer_status = 0; d->data_address = cpu_to_le32(d_bus + (z * sizeof(*d))); - /* pd points to the payload descriptor */ - pd = d + 1; + rest = payload_per_buffer; + for (j = 1; j < z; j++) { + pd = d + j; + pd->control = cpu_to_le16(DESCRIPTOR_STATUS | + DESCRIPTOR_INPUT_MORE); + + if (offset + rest < PAGE_SIZE) + length = rest; + else + length = PAGE_SIZE - offset; + pd->req_count = cpu_to_le16(length); + pd->res_count = pd->req_count; + pd->transfer_status = 0; + + page_bus = page_private(buffer->pages[page]); + pd->data_address = cpu_to_le32(page_bus + offset); + + offset = (offset + length) & ~PAGE_MASK; + rest -= length; + if (offset == 0) + page++; + } pd->control = cpu_to_le16(DESCRIPTOR_STATUS | DESCRIPTOR_INPUT_LAST | DESCRIPTOR_BRANCH_ALWAYS); - if (p->interrupt) + if (p->interrupt && i == packet_count - 1) 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); } @@ -1923,16 +2003,22 @@ ohci_queue_iso(struct fw_iso_context *base, unsigned long payload) { struct iso_context *ctx = container_of(base, struct iso_context, base); + unsigned long flags; + int retval; + spin_lock_irqsave(&ctx->context.ohci->lock, flags); if (base->type == FW_ISO_CONTEXT_TRANSMIT) - return ohci_queue_iso_transmit(base, packet, buffer, payload); + retval = ohci_queue_iso_transmit(base, packet, buffer, payload); else if (ctx->context.ohci->version >= OHCI_VERSION_1_1) - return ohci_queue_iso_receive_dualbuffer(base, packet, + retval = ohci_queue_iso_receive_dualbuffer(base, packet, buffer, payload); else - return ohci_queue_iso_receive_packet_per_buffer(base, packet, + retval = ohci_queue_iso_receive_packet_per_buffer(base, packet, buffer, payload); + spin_unlock_irqrestore(&ctx->context.ohci->lock, flags); + + return retval; } static const struct fw_card_driver ohci_driver = { @@ -2004,10 +2090,10 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) ar_context_init(&ohci->ar_response_ctx, ohci, OHCI1394_AsRspRcvContextControlSet); - context_init(&ohci->at_request_ctx, ohci, AT_BUFFER_SIZE, + context_init(&ohci->at_request_ctx, ohci, OHCI1394_AsReqTrContextControlSet, handle_at_packet); - context_init(&ohci->at_response_ctx, ohci, AT_BUFFER_SIZE, + context_init(&ohci->at_response_ctx, ohci, OHCI1394_AsRspTrContextControlSet, handle_at_packet); reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 624ff3e..9040417 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -151,9 +151,7 @@ struct sbp2_target { }; #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_NULL 0x80000000 #define SBP2_DIRECTION_TO_MEDIA 0x0 @@ -540,14 +538,26 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, retval = -EIO; if (sbp2_cancel_orbs(lu) == 0) { - fw_error("orb reply timed out, rcode=0x%02x\n", - orb->base.rcode); + /* + * 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 + * actually fail don't get logged. + */ + if (function != SBP2_LOGOUT_REQUEST) + fw_error("orb reply timed out, rcode=0x%02x\n", + orb->base.rcode); goto out; } if (orb->base.rcode != RCODE_COMPLETE) { - fw_error("management write failed, rcode 0x%02x\n", - orb->base.rcode); + /* + * On device removal from the bus, sometimes the logout + * request times out, sometimes it just fails. + */ + if (function != SBP2_LOGOUT_REQUEST) + fw_error("management write failed, rcode 0x%02x\n", + orb->base.rcode); goto out; } @@ -628,6 +638,21 @@ 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 sbp2_reconnect(struct work_struct *work); static void sbp2_login(struct work_struct *work) @@ -649,16 +674,12 @@ static void sbp2_login(struct work_struct *work) if (sbp2_send_management_orb(lu, node_id, generation, SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { - if (lu->retries++ < 5) { - if (queue_delayed_work(sbp2_wq, &lu->work, - DIV_ROUND_UP(HZ, 5))) - kref_get(&lu->tgt->kref); - } else { + 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); - } - kref_put(&lu->tgt->kref, sbp2_release_target); - return; + goto out; } lu->generation = generation; @@ -700,7 +721,8 @@ static void sbp2_login(struct work_struct *work) lu->sdev = sdev; scsi_device_put(sdev); } - kref_put(&lu->tgt->kref, sbp2_release_target); + out: + sbp2_target_put(lu->tgt); } static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) @@ -865,18 +887,13 @@ static int sbp2_probe(struct device *dev) get_device(&unit->device); - /* - * We schedule work to do the login so we can easily - * reschedule retries. Always get the ref before scheduling - * work. - */ + /* Do the login in a workqueue so we can easily reschedule retries. */ list_for_each_entry(lu, &tgt->lu_list, link) - if (queue_delayed_work(sbp2_wq, &lu->work, 0)) - kref_get(&tgt->kref); + sbp2_queue_work(lu, 0); return 0; fail_tgt_put: - kref_put(&tgt->kref, sbp2_release_target); + sbp2_target_put(tgt); return -ENOMEM; fail_shost_put: @@ -889,7 +906,7 @@ static int sbp2_remove(struct device *dev) struct fw_unit *unit = fw_unit(dev); struct sbp2_target *tgt = unit->device.driver_data; - kref_put(&tgt->kref, sbp2_release_target); + sbp2_target_put(tgt); return 0; } @@ -915,10 +932,8 @@ static void sbp2_reconnect(struct work_struct *work) lu->retries = 0; PREPARE_DELAYED_WORK(&lu->work, sbp2_login); } - if (queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5))) - kref_get(&lu->tgt->kref); - kref_put(&lu->tgt->kref, sbp2_release_target); - return; + sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); + goto out; } lu->generation = generation; @@ -930,8 +945,8 @@ static void sbp2_reconnect(struct work_struct *work) sbp2_agent_reset(lu); sbp2_cancel_orbs(lu); - - kref_put(&lu->tgt->kref, sbp2_release_target); + out: + sbp2_target_put(lu->tgt); } static void sbp2_update(struct fw_unit *unit) @@ -947,8 +962,7 @@ static void sbp2_update(struct fw_unit *unit) */ list_for_each_entry(lu, &tgt->lu_list, link) { lu->retries = 0; - if (queue_delayed_work(sbp2_wq, &lu->work, 0)) - kref_get(&tgt->kref); + sbp2_queue_work(lu, 0); } } @@ -1103,9 +1117,9 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, * 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); + 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))) { @@ -1325,6 +1339,7 @@ static struct scsi_host_template scsi_driver_template = { .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .cmd_per_lun = 1, .can_queue = 1, .sdev_attrs = sbp2_scsi_sysfs_attrs, diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index c00d4a9..8018c3b 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -650,7 +650,7 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p) HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | p->header[2]; tcode = HEADER_GET_TCODE(p->header[0]); destination = HEADER_GET_DESTINATION(p->header[0]); - source = HEADER_GET_SOURCE(p->header[0]); + source = HEADER_GET_SOURCE(p->header[1]); spin_lock_irqsave(&address_handler_lock, flags); handler = lookup_enclosing_address_handler(&address_handler_list, diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c index 7c4eb39..73685e7 100644 --- a/drivers/ieee1394/dma.c +++ b/drivers/ieee1394/dma.c @@ -231,37 +231,24 @@ void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, #ifdef CONFIG_MMU -/* nopage() handler for mmap access */ - -static struct page *dma_region_pagefault(struct vm_area_struct *area, - unsigned long address, int *type) +static int dma_region_pagefault(struct vm_area_struct *vma, + struct vm_fault *vmf) { - unsigned long offset; - unsigned long kernel_virt_addr; - struct page *ret = NOPAGE_SIGBUS; - - struct dma_region *dma = (struct dma_region *)area->vm_private_data; + struct dma_region *dma = (struct dma_region *)vma->vm_private_data; if (!dma->kvirt) - goto out; - - if ((address < (unsigned long)area->vm_start) || - (address > - (unsigned long)area->vm_start + (dma->n_pages << PAGE_SHIFT))) - goto out; - - if (type) - *type = VM_FAULT_MINOR; - offset = address - area->vm_start; - kernel_virt_addr = (unsigned long)dma->kvirt + offset; - ret = vmalloc_to_page((void *)kernel_virt_addr); - get_page(ret); - out: - return ret; + return VM_FAULT_SIGBUS; + + if (vmf->pgoff >= dma->n_pages) + return VM_FAULT_SIGBUS; + + vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT)); + get_page(vmf->page); + return 0; } static struct vm_operations_struct dma_region_vm_ops = { - .nopage = dma_region_pagefault, + .fault = dma_region_pagefault, }; /** @@ -275,7 +262,7 @@ int dma_region_mmap(struct dma_region *dma, struct file *file, if (!dma->kvirt) return -EINVAL; - /* must be page-aligned */ + /* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */ if (vma->vm_pgoff != 0) return -EINVAL; diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 6779893..10c3d9f 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c @@ -570,71 +570,3 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, return retval; } - -#if 0 - -int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, - u64 addr, int extcode, quadlet_t * data, quadlet_t arg) -{ - struct hpsb_packet *packet; - int retval = 0; - - BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet - - packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg); - if (!packet) - return -ENOMEM; - - packet->generation = generation; - retval = hpsb_send_packet_and_wait(packet); - if (retval < 0) - goto hpsb_lock_fail; - - retval = hpsb_packet_success(packet); - - if (retval == 0) { - *data = packet->data[0]; - } - - hpsb_lock_fail: - hpsb_free_tlabel(packet); - hpsb_free_packet(packet); - - return retval; -} - -int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, - quadlet_t * buffer, size_t length, u32 specifier_id, - unsigned int version) -{ - struct hpsb_packet *packet; - int retval = 0; - u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8; - u8 specifier_id_lo = specifier_id & 0xff; - - HPSB_VERBOSE("Send GASP: channel = %d, length = %Zd", channel, length); - - length += 8; - - packet = hpsb_make_streampacket(host, NULL, length, channel, 3, 0); - if (!packet) - return -ENOMEM; - - packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi); - packet->data[1] = - cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff)); - - memcpy(&(packet->data[2]), buffer, length - 8); - - packet->generation = generation; - - packet->no_waiter = 1; - - retval = hpsb_send_packet(packet); - if (retval < 0) - hpsb_free_packet(packet); - - return retval; -} - -#endif /* 0 */ diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 372c5c1..969de2a 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2126,10 +2126,14 @@ static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, list_for_each_entry(t, &ohci->iso_tasklet_list, link) { mask = 1 << t->context; - if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask) - tasklet_schedule(&t->tasklet); - else if (rx_event & mask) - tasklet_schedule(&t->tasklet); + if (t->type == OHCI_ISO_TRANSMIT) { + if (tx_event & mask) + tasklet_schedule(&t->tasklet); + } else { + /* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */ + if (rx_event & mask) + tasklet_schedule(&t->tasklet); + } } spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index cadf047..37e7e10 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -858,7 +858,7 @@ static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, int found = 0, size = 0, rcode = -1; struct arm_request_response *arm_req_resp = NULL; - DBGMSG("arm_read called by node: %X" + DBGMSG("arm_read called by node: %X " "addr: %4.4x %8.8x length: %Zu", nodeid, (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), length); @@ -1012,7 +1012,7 @@ static int arm_write(struct hpsb_host *host, int nodeid, int destid, int found = 0, size = 0, rcode = -1, length_conflict = 0; struct arm_request_response *arm_req_resp = NULL; - DBGMSG("arm_write called by node: %X" + DBGMSG("arm_write called by node: %X " "addr: %4.4x %8.8x length: %Zu", nodeid, (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), length); diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index b83d254..d2747f0 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -51,6 +51,7 @@ * Grep for inline FIXME comments below. */ +#include #include #include #include @@ -127,17 +128,21 @@ MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers " "(default = Y, faster but buggy = N)"); /* - * Bump up max_sectors if you'd like to support very large sized - * transfers. Please note that some older sbp2 bridge chips are broken for - * transfers greater or equal to 128KB. Default is a value of 255 - * sectors, or just under 128KB (at 512 byte sector size). I can note that - * the Oxsemi sbp2 chipsets have no problems supporting very large - * transfer sizes. + * Adjust max_sectors if you'd like to influence how many sectors each SCSI + * command can transfer at most. Please note that some older SBP-2 bridge + * chips are broken for transfers greater or equal to 128KB, therefore + * max_sectors used to be a safe 255 sectors for many years. We now have a + * default of 0 here which means that we let the SCSI stack choose a limit. + * + * The SBP2_WORKAROUND_128K_MAX_TRANS flag, if set either in the workarounds + * module parameter or in the sbp2_workarounds_table[], will override the + * value of max_sectors. We should use sbp2_workarounds_table[] to cover any + * bridge chip which becomes known to need the 255 sectors limit. */ -static int sbp2_max_sectors = SBP2_MAX_SECTORS; +static int sbp2_max_sectors; module_param_named(max_sectors, sbp2_max_sectors, int, 0444); MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported " - "(default = " __stringify(SBP2_MAX_SECTORS) ")"); + "(default = 0 = use SCSI stack's default)"); /* * Exclusive login to sbp2 device? In most cases, the sbp2 driver should @@ -326,6 +331,7 @@ static struct scsi_host_template sbp2_shost_template = { .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, + .use_sg_chaining = ENABLE_SG_CHAINING, .cmd_per_lun = SBP2_MAX_CMDS, .can_queue = SBP2_MAX_CMDS, .sdev_attrs = sbp2_sysfs_sdev_attrs, @@ -1451,7 +1457,7 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, struct sbp2_fwhost_info *hi, struct sbp2_command_info *cmd, unsigned int scsi_use_sg, - struct scatterlist *sgpnt, + struct scatterlist *sg, u32 orb_direction, enum dma_data_direction dma_dir) { @@ -1461,12 +1467,12 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, /* special case if only one element (and less than 64KB in size) */ if ((scsi_use_sg == 1) && - (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) { + (sg_dma_len(sg) <= SBP2_MAX_SG_ELEMENT_LENGTH)) { - cmd->dma_size = sgpnt[0].length; + cmd->dma_size = sg_dma_len(sg); cmd->dma_type = CMD_DMA_PAGE; cmd->cmd_dma = dma_map_page(hi->host->device.parent, - sg_page(&sgpnt[0]), sgpnt[0].offset, + sg_page(sg), sg->offset, cmd->dma_size, cmd->dma_dir); orb->data_descriptor_lo = cmd->cmd_dma; @@ -1477,11 +1483,11 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, &cmd->scatter_gather_element[0]; u32 sg_count, sg_len; dma_addr_t sg_addr; - int i, count = dma_map_sg(hi->host->device.parent, sgpnt, + int i, count = dma_map_sg(hi->host->device.parent, sg, scsi_use_sg, dma_dir); cmd->dma_size = scsi_use_sg; - cmd->sge_buffer = sgpnt; + cmd->sge_buffer = sg; /* use page tables (s/g) */ orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); @@ -1489,9 +1495,9 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, /* loop through and fill out our SBP-2 page tables * (and split up anything too large) */ - for (i = 0, sg_count = 0 ; i < count; i++, sgpnt++) { - sg_len = sg_dma_len(sgpnt); - sg_addr = sg_dma_address(sgpnt); + for (i = 0, sg_count = 0; i < count; i++, sg = sg_next(sg)) { + sg_len = sg_dma_len(sg); + sg_addr = sg_dma_address(sg); while (sg_len) { sg_element[sg_count].segment_base_lo = sg_addr; if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) { @@ -1521,11 +1527,10 @@ static void sbp2_create_command_orb(struct sbp2_lu *lu, unchar *scsi_cmd, unsigned int scsi_use_sg, unsigned int scsi_request_bufflen, - void *scsi_request_buffer, + struct scatterlist *sg, enum dma_data_direction dma_dir) { struct sbp2_fwhost_info *hi = lu->hi; - struct scatterlist *sgpnt = (struct scatterlist *)scsi_request_buffer; struct sbp2_command_orb *orb = &cmd->command_orb; u32 orb_direction; @@ -1560,7 +1565,7 @@ static void sbp2_create_command_orb(struct sbp2_lu *lu, orb->data_descriptor_lo = 0x0; orb->misc |= ORB_SET_DIRECTION(1); } else - sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sgpnt, + sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sg, orb_direction, dma_dir); sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb)); @@ -1650,7 +1655,6 @@ static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { unchar *scsi_cmd = (unchar *)SCpnt->cmnd; - unsigned int request_bufflen = scsi_bufflen(SCpnt); struct sbp2_command_info *cmd; cmd = sbp2util_allocate_command_orb(lu, SCpnt, done); @@ -1658,7 +1662,7 @@ static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt, return -EIO; sbp2_create_command_orb(lu, cmd, scsi_cmd, scsi_sg_count(SCpnt), - request_bufflen, scsi_sglist(SCpnt), + scsi_bufflen(SCpnt), scsi_sglist(SCpnt), SCpnt->sc_data_direction); sbp2_link_orb_command(lu, cmd); @@ -1981,6 +1985,8 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev) sdev->skip_ms_page_8 = 1; if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) sdev->fix_capacity = 1; + if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) + blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512); return 0; } @@ -2087,9 +2093,6 @@ static int sbp2_module_init(void) sbp2_shost_template.cmd_per_lun = 1; } - if (sbp2_default_workarounds & SBP2_WORKAROUND_128K_MAX_TRANS && - (sbp2_max_sectors * 512) > (128 * 1024)) - sbp2_max_sectors = 128 * 1024 / 512; sbp2_shost_template.max_sectors = sbp2_max_sectors; hpsb_register_highlevel(&sbp2_highlevel); diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index 333a4bb..d2ecb0d 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -222,7 +222,6 @@ struct sbp2_status_block { */ #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 -#define SBP2_MAX_SECTORS 255 /* There is no real limitation of the queue depth (i.e. length of the linked * list of command ORBs) at the target. The chosen depth is merely an * implementation detail of the sbp2 driver. */