public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* Scatter-gather segment merges by IOMMU?
@ 2008-08-08 19:44 Stefan Richter
  2008-08-08 20:25 ` Grant Grundler
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Richter @ 2008-08-08 19:44 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-kernel

Hi all,

the block layer usually tries to merge s/g segments if consecutive 
segments combined fit into the queue's max_segment_size.  When such a 
scatter gather list is DMA-mapped, can it happen that an IOMMU collapses 
the elements even further, so that sg_dma_len() of a DMA-mapped s/g 
segment exceeds max_segment_size?

As I understood some discussions in the past, this could indeed happen, 
which is a nuisance.  But I may have misunderstood something, or 
something may have changed in the meantime...
-- 
Stefan Richter
-=====-==--- =--- -=---
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Scatter-gather segment merges by IOMMU?
  2008-08-08 19:44 Scatter-gather segment merges by IOMMU? Stefan Richter
@ 2008-08-08 20:25 ` Grant Grundler
  2008-08-08 21:21   ` Stefan Richter
  0 siblings, 1 reply; 18+ messages in thread
From: Grant Grundler @ 2008-08-08 20:25 UTC (permalink / raw)
  To: Stefan Richter; +Cc: linux-scsi, linux-kernel

On Fri, Aug 8, 2008 at 12:44 PM, Stefan Richter
<stefanr@s5r6.in-berlin.de> wrote:
> Hi all,
>
> the block layer usually tries to merge s/g segments if consecutive segments
> combined fit into the queue's max_segment_size.  When such a scatter gather
> list is DMA-mapped, can it happen that an IOMMU collapses the elements even
> further, so that sg_dma_len() of a DMA-mapped s/g segment exceeds
> max_segment_size?

I don't see how. The IOMMU code only collapses the "physical" mappings and
does not add new elements to the SG list. ergo sg_dma_len() shouldn't change.

grant

>
> As I understood some discussions in the past, this could indeed happen,
> which is a nuisance.  But I may have misunderstood something, or something
> may have changed in the meantime...
> --
> Stefan Richter
> -=====-==--- =--- -=---
> http://arcgraph.de/sr/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Scatter-gather segment merges by IOMMU?
  2008-08-08 20:25 ` Grant Grundler
@ 2008-08-08 21:21   ` Stefan Richter
  2008-08-08 21:31     ` FUJITA Tomonori
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Richter @ 2008-08-08 21:21 UTC (permalink / raw)
  To: Grant Grundler; +Cc: linux-scsi, linux-kernel

Grant Grundler wrote:
> On Fri, Aug 8, 2008 at 12:44 PM, Stefan Richter
> <stefanr@s5r6.in-berlin.de> wrote:
>> Hi all,
>>
>> the block layer usually tries to merge s/g segments if consecutive segments
>> combined fit into the queue's max_segment_size.  When such a scatter gather
>> list is DMA-mapped, can it happen that an IOMMU collapses the elements even
>> further, so that sg_dma_len() of a DMA-mapped s/g segment exceeds
>> max_segment_size?
> 
> I don't see how. The IOMMU code only collapses the "physical" mappings and
> does not add new elements to the SG list. ergo sg_dma_len() shouldn't change.
> 
> grant
> 
>> As I understood some discussions in the past, this could indeed happen,
>> which is a nuisance.  But I may have misunderstood something, or something
>> may have changed in the meantime...

Well, I'm just doing my homework and am tracking down the various 
dma_map_sg implementations.

Here is what PPC does:
http://lxr.linux.no/linux+v2.6.26/arch/powerpc/kernel/iommu.c#L270

It looks at dma_get_max_seg_size(dev); and then merges according to it.

That's all nice and well, but in my case (FireWire storage protocol 
a.k.a. SBP-2, which is basically remote DMA), the max_segment_size of 
the PCI device is different from the size limit of the protocol.  We 
currently have to deconstruct such merges in the sbp2 drivers again:
http://lxr.linux.no/linux+v2.6.26/drivers/firewire/fw-sbp2.c#L1384

Either I keep it that way, or I let the protocol driver manipulate the 
FireWire controller's dev->dma_parms->max_segment_size (via 
dma_set_max_seg_size() of course), which is not entirely correct.

I first wanted to use blk_queue_max_segment_size(), but that falls short 
with dma_map_sg implementations like the above are at work.
-- 
Stefan Richter
-=====-==--- =--- -=---
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Scatter-gather segment merges by IOMMU?
  2008-08-08 21:21   ` Stefan Richter
@ 2008-08-08 21:31     ` FUJITA Tomonori
  2008-08-08 21:58       ` Stefan Richter
  0 siblings, 1 reply; 18+ messages in thread
From: FUJITA Tomonori @ 2008-08-08 21:31 UTC (permalink / raw)
  To: stefanr; +Cc: grundler, linux-scsi, linux-kernel

On Fri, 08 Aug 2008 23:21:28 +0200
Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:

> Grant Grundler wrote:
> > On Fri, Aug 8, 2008 at 12:44 PM, Stefan Richter
> > <stefanr@s5r6.in-berlin.de> wrote:
> >> Hi all,
> >>
> >> the block layer usually tries to merge s/g segments if consecutive segments
> >> combined fit into the queue's max_segment_size.  When such a scatter gather
> >> list is DMA-mapped, can it happen that an IOMMU collapses the elements even
> >> further, so that sg_dma_len() of a DMA-mapped s/g segment exceeds
> >> max_segment_size?
> > 
> > I don't see how. The IOMMU code only collapses the "physical" mappings and
> > does not add new elements to the SG list. ergo sg_dma_len() shouldn't change.
> > 
> > grant
> > 
> >> As I understood some discussions in the past, this could indeed happen,
> >> which is a nuisance.  But I may have misunderstood something, or something
> >> may have changed in the meantime...
> 
> Well, I'm just doing my homework and am tracking down the various 
> dma_map_sg implementations.
> 
> Here is what PPC does:
> http://lxr.linux.no/linux+v2.6.26/arch/powerpc/kernel/iommu.c#L270
> 
> It looks at dma_get_max_seg_size(dev); and then merges according to it.

Yes, IOMMUs were not able to handle this issue but they should now.


> That's all nice and well, but in my case (FireWire storage protocol 
> a.k.a. SBP-2, which is basically remote DMA), the max_segment_size of 
> the PCI device is different from the size limit of the protocol.  We 
> currently have to deconstruct such merges in the sbp2 drivers again:
> http://lxr.linux.no/linux+v2.6.26/drivers/firewire/fw-sbp2.c#L1384
> 
> Either I keep it that way, or I let the protocol driver manipulate the 
> FireWire controller's dev->dma_parms->max_segment_size (via 
> dma_set_max_seg_size() of course), which is not entirely correct.

Why is it not correct? Device drivers can set
dma_set_max_seg_size(). SCSI does that (see __scsi_alloc_queue).


> I first wanted to use blk_queue_max_segment_size(), but that falls short 
> with dma_map_sg implementations like the above are at work.

Yeah, we store the same value at two places (request_queue and device)
though it's not nice.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Scatter-gather segment merges by IOMMU?
  2008-08-08 21:31     ` FUJITA Tomonori
@ 2008-08-08 21:58       ` Stefan Richter
  2008-08-08 22:17         ` FUJITA Tomonori
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Richter @ 2008-08-08 21:58 UTC (permalink / raw)
  To: FUJITA Tomonori; +Cc: grundler, linux-scsi, linux-kernel

FUJITA Tomonori wrote:
> On Fri, 08 Aug 2008 23:21:28 +0200
> Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:
>> Here is what PPC does:
>> http://lxr.linux.no/linux+v2.6.26/arch/powerpc/kernel/iommu.c#L270
>>
>> It looks at dma_get_max_seg_size(dev); and then merges according to it.
> 
> Yes, IOMMUs were not able to handle this issue but they should now.
> 
> 
>> That's all nice and well, but in my case (FireWire storage protocol 
>> a.k.a. SBP-2, which is basically remote DMA), the max_segment_size of 
>> the PCI device is different from the size limit of the protocol.  We 
>> currently have to deconstruct such merges in the sbp2 drivers again:
>> http://lxr.linux.no/linux+v2.6.26/drivers/firewire/fw-sbp2.c#L1384
>>
>> Either I keep it that way, or I let the protocol driver manipulate the 
>> FireWire controller's dev->dma_parms->max_segment_size (via 
>> dma_set_max_seg_size() of course), which is not entirely correct.
> 
> Why is it not correct? Device drivers can set
> dma_set_max_seg_size(). SCSI does that (see __scsi_alloc_queue).

FireWire is a multi-protocol bus.  SBP-2 is just one of many quite 
different protocols.  SBP-2 targets read or write the initiators memory 
buffers via remote DMA.  These buffer may be exposed as s/g lists to the 
target.  The protocol limits these s/g lists to up to 65535 elements of 
up to 65535 bytes size each.

FireWire controllers on the other hand get their maximum segment size 
set to 65536 by the PCI subsystem.  (All FireWire controllers supported 
by mainline Linux are PCI or PCIe devices.)

In case of the drivers/firewire/ stack, the SBP-2 driver is currently 
the only one which uses dma_map_sg.  In case of the drivers/ieee1394/ 
stack, also the drivers for isochronous protocols, including userspace 
drivers via raw1394, use dma_map_sg.

So if the SBP-2 driver manipulated the controller device's 
max_segment_size, it would influence the DMA mappings of the other 
protocols.  It wouldn't be a big deal; the isochronous mappings could 
only be collapsed to chunks of at most 15 pages instead of 16 pages. 
However, the mapping deconstructing code in the SBP-2 drivers is not a 
big deal either.
-- 
Stefan Richter
-=====-==--- =--- -=---
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Scatter-gather segment merges by IOMMU?
  2008-08-08 21:58       ` Stefan Richter
@ 2008-08-08 22:17         ` FUJITA Tomonori
  2008-08-09 18:20           ` [PATCH] ieee1394: sbp2: enforce s/g segment size limit Stefan Richter
  0 siblings, 1 reply; 18+ messages in thread
From: FUJITA Tomonori @ 2008-08-08 22:17 UTC (permalink / raw)
  To: stefanr; +Cc: fujita.tomonori, grundler, linux-scsi, linux-kernel

On Fri, 08 Aug 2008 23:58:23 +0200
Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:

> FUJITA Tomonori wrote:
> > On Fri, 08 Aug 2008 23:21:28 +0200
> > Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:
> >> Here is what PPC does:
> >> http://lxr.linux.no/linux+v2.6.26/arch/powerpc/kernel/iommu.c#L270
> >>
> >> It looks at dma_get_max_seg_size(dev); and then merges according to it.
> > 
> > Yes, IOMMUs were not able to handle this issue but they should now.
> > 
> > 
> >> That's all nice and well, but in my case (FireWire storage protocol 
> >> a.k.a. SBP-2, which is basically remote DMA), the max_segment_size of 
> >> the PCI device is different from the size limit of the protocol.  We 
> >> currently have to deconstruct such merges in the sbp2 drivers again:
> >> http://lxr.linux.no/linux+v2.6.26/drivers/firewire/fw-sbp2.c#L1384
> >>
> >> Either I keep it that way, or I let the protocol driver manipulate the 
> >> FireWire controller's dev->dma_parms->max_segment_size (via 
> >> dma_set_max_seg_size() of course), which is not entirely correct.
> > 
> > Why is it not correct? Device drivers can set
> > dma_set_max_seg_size(). SCSI does that (see __scsi_alloc_queue).
> 
> FireWire is a multi-protocol bus.  SBP-2 is just one of many quite 
> different protocols.  SBP-2 targets read or write the initiators memory 
> buffers via remote DMA.  These buffer may be exposed as s/g lists to the 
> target.  The protocol limits these s/g lists to up to 65535 elements of 
> up to 65535 bytes size each.
> 
> FireWire controllers on the other hand get their maximum segment size 
> set to 65536 by the PCI subsystem.  (All FireWire controllers supported 
> by mainline Linux are PCI or PCIe devices.)
> 
> In case of the drivers/firewire/ stack, the SBP-2 driver is currently 
> the only one which uses dma_map_sg.  In case of the drivers/ieee1394/ 
> stack, also the drivers for isochronous protocols, including userspace 
> drivers via raw1394, use dma_map_sg.

Thanks for the explanation.


> So if the SBP-2 driver manipulated the controller device's 
> max_segment_size, it would influence the DMA mappings of the other 
> protocols.  It wouldn't be a big deal; the isochronous mappings could 

IMHO, setting the safest value to max_segment_size is fine. After all,
the maximum is only 65536 bytes.


> only be collapsed to chunks of at most 15 pages instead of 16 pages. 
> However, the mapping deconstructing code in the SBP-2 drivers is not a 
> big deal either.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-08 22:17         ` FUJITA Tomonori
@ 2008-08-09 18:20           ` Stefan Richter
  2008-08-09 18:21             ` [PATCH] firewire: fw-sbp2: " Stefan Richter
  2008-08-12 17:04             ` [PATCH] ieee1394: sbp2: " Grant Grundler
  0 siblings, 2 replies; 18+ messages in thread
From: Stefan Richter @ 2008-08-09 18:20 UTC (permalink / raw)
  To: linux1394-devel; +Cc: FUJITA Tomonori, Grant Grundler, linux-kernel, linux-scsi

1. We don't need to round the SBP-2 segment size limit down to a
   multiple of 4 kB (0xffff -> 0xf000).  It is only necessary to
   ensure quadlet alignment (0xffff -> 0xfffc).

2. Use dma_set_max_seg_size() to tell the DMA mapping infrastructure
   and the block IO layer about the restriction.  This way we can
   remove the size checks and segment splitting in the queuecommand
   path.

   This assumes that no other code in the ieee1394 stack uses
   dma_map_sg() with conflicting requirements.  It furthermore assumes
   that the controller device's platform actually allows us to set the
   segment size to our liking.  Assert the latter with a BUG_ON().

3. Also use blk_queue_max_segment_size() to tell the block IO layer
   about it.  It cannot know it because our scsi_add_host() does not
   point to the FireWire controller's device.

We can also uniformly use dma_map_sg() for the single segment case just
like for the multi segment case, to further simplify the code.

Also clean up how the page table is converted to big endian.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
---

Applicable after
   [PATCH update] ieee1394: sbp2: stricter dma_sync
   [PATCH] ieee1394: sbp2: check for DMA mapping failures
from a few minutes ago.

 drivers/ieee1394/sbp2.c |  106 +++++++++++++---------------------------
 drivers/ieee1394/sbp2.h |   37 +++++--------
 2 files changed, 52 insertions(+), 91 deletions(-)

Index: linux-2.6.27-rc2/drivers/ieee1394/sbp2.h
===================================================================
--- linux-2.6.27-rc2.orig/drivers/ieee1394/sbp2.h
+++ linux-2.6.27-rc2/drivers/ieee1394/sbp2.h
@@ -139,13 +139,10 @@ struct sbp2_logout_orb {
 	u32 status_fifo_lo;
 } __attribute__((packed));
 
-#define PAGE_TABLE_SET_SEGMENT_BASE_HI(v)	((v) & 0xffff)
-#define PAGE_TABLE_SET_SEGMENT_LENGTH(v)	(((v) & 0xffff) << 16)
-
 struct sbp2_unrestricted_page_table {
-	u32 length_segment_base_hi;
-	u32 segment_base_lo;
-} __attribute__((packed));
+	__be32 high;
+	__be32 low;
+};
 
 #define RESP_STATUS_REQUEST_COMPLETE		0x0
 #define RESP_STATUS_TRANSPORT_FAILURE		0x1
@@ -216,15 +213,18 @@ struct sbp2_status_block {
 #define SBP2_UNIT_SPEC_ID_ENTRY			0x0000609e
 #define SBP2_SW_VERSION_ENTRY			0x00010483
 
-
 /*
- * SCSI specific definitions
+ * The default maximum s/g segment size of a FireWire controller is
+ * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
+ * be quadlet-aligned, we set the length limit to 0xffff & ~3.
  */
+#define SBP2_MAX_SEG_SIZE			0xfffc
 
-#define SBP2_MAX_SG_ELEMENT_LENGTH		0xf000
-/* There is no real limitation of the queue depth (i.e. length of the linked
+/*
+ * 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. */
+ * implementation detail of the sbp2 driver.
+ */
 #define SBP2_MAX_CMDS				8
 
 #define SBP2_SCSI_STATUS_GOOD			0x0
@@ -240,12 +240,6 @@ struct sbp2_status_block {
  * Representations of commands and devices
  */
 
-enum sbp2_dma_types {
-	CMD_DMA_NONE,
-	CMD_DMA_PAGE,
-	CMD_DMA_SINGLE
-};
-
 /* Per SCSI command */
 struct sbp2_command_info {
 	struct list_head list;
@@ -258,11 +252,10 @@ struct sbp2_command_info {
 	struct sbp2_unrestricted_page_table
 		scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
 	dma_addr_t sge_dma;
-	void *sge_buffer;
-	dma_addr_t cmd_dma;
-	enum sbp2_dma_types dma_type;
-	unsigned long dma_size;
-	enum dma_data_direction dma_dir;
+
+	struct scatterlist *sg_buffer;
+	int sg_count;
+	enum dma_data_direction sg_dir;
 };
 
 /* Per FireWire host */
Index: linux-2.6.27-rc2/drivers/ieee1394/sbp2.c
===================================================================
--- linux-2.6.27-rc2.orig/drivers/ieee1394/sbp2.c
+++ linux-2.6.27-rc2/drivers/ieee1394/sbp2.c
@@ -656,23 +656,10 @@ static struct sbp2_command_info *sbp2uti
 static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
 					    struct sbp2_command_info *cmd)
 {
-	struct hpsb_host *host = lu->ud->ne->host;
-
-	if (cmd->cmd_dma) {
-		if (cmd->dma_type == CMD_DMA_SINGLE)
-			dma_unmap_single(host->device.parent, cmd->cmd_dma,
-					 cmd->dma_size, cmd->dma_dir);
-		else if (cmd->dma_type == CMD_DMA_PAGE)
-			dma_unmap_page(host->device.parent, cmd->cmd_dma,
-				       cmd->dma_size, cmd->dma_dir);
-		/* XXX: Check for CMD_DMA_NONE bug */
-		cmd->dma_type = CMD_DMA_NONE;
-		cmd->cmd_dma = 0;
-	}
-	if (cmd->sge_buffer) {
-		dma_unmap_sg(host->device.parent, cmd->sge_buffer,
-			     cmd->dma_size, cmd->dma_dir);
-		cmd->sge_buffer = NULL;
+	if (cmd->sg_buffer) {
+		dma_unmap_sg(lu->ud->ne->host->device.parent, cmd->sg_buffer,
+			     cmd->sg_count, cmd->sg_dir);
+		cmd->sg_buffer = NULL;
 	}
 	list_move_tail(&cmd->list, &lu->cmd_orb_completed);
 }
@@ -827,6 +814,10 @@ static struct sbp2_lu *sbp2_alloc_device
 #endif
 	}
 
+	if (dma_get_max_seg_size(hi->host->device.parent) > SBP2_MAX_SEG_SIZE)
+		BUG_ON(dma_set_max_seg_size(hi->host->device.parent,
+					    SBP2_MAX_SEG_SIZE));
+
 	/* Prevent unloading of the 1394 host */
 	if (!try_module_get(hi->host->driver->owner)) {
 		SBP2_ERR("failed to get a reference on 1394 host driver");
@@ -1501,76 +1492,51 @@ static int sbp2_agent_reset(struct sbp2_
 static int 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,
+				    unsigned int sg_count,
 				    struct scatterlist *sg,
 				    u32 orb_direction,
 				    enum dma_data_direction dma_dir)
 {
 	struct device *dmadev = hi->host->device.parent;
+	struct sbp2_unrestricted_page_table *pt;
+	int i, j, len;
+
+	i = dma_map_sg(dmadev, sg, sg_count, dma_dir);
+	if (i == 0)
+		return -ENOMEM;
+
+	cmd->sg_buffer = sg;
+	cmd->sg_count = sg_count;
+	cmd->sg_dir = dma_dir;
 
-	cmd->dma_dir = dma_dir;
 	orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 	orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 	/* special case if only one element (and less than 64KB in size) */
-	if (scsi_use_sg == 1 && sg->length <= SBP2_MAX_SG_ELEMENT_LENGTH) {
-
-		cmd->dma_size = sg->length;
-		cmd->dma_type = CMD_DMA_PAGE;
-		cmd->cmd_dma = dma_map_page(dmadev, sg_page(sg), sg->offset,
-					    cmd->dma_size, cmd->dma_dir);
-		if (dma_mapping_error(dmadev, cmd->cmd_dma)) {
-			cmd->cmd_dma = 0;
-			return -ENOMEM;
-		}
-
-		orb->data_descriptor_lo = cmd->cmd_dma;
-		orb->misc |= ORB_SET_DATA_SIZE(cmd->dma_size);
-
+	if (i == 1) {
+		orb->data_descriptor_lo = sg_dma_address(sg);
+		orb->misc |= ORB_SET_DATA_SIZE(sg_dma_len(sg));
 	} else {
-		struct sbp2_unrestricted_page_table *sg_element =
-						&cmd->scatter_gather_element[0];
-		u32 sg_count, sg_len;
-		dma_addr_t sg_addr;
-		int i, count = dma_map_sg(dmadev, sg, scsi_use_sg, dma_dir);
-
-		cmd->dma_size = scsi_use_sg;
-		cmd->sge_buffer = sg;
-
-		/* use page tables (s/g) */
-		orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-		orb->data_descriptor_lo = cmd->sge_dma;
+		pt = &cmd->scatter_gather_element[0];
+		j = 0;
 
 		dma_sync_single_for_cpu(dmadev, cmd->sge_dma,
 					sizeof(cmd->scatter_gather_element),
 					DMA_TO_DEVICE);
 
-		/* 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++, 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) {
-					sg_element[sg_count].length_segment_base_hi =
-						PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
-					sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
-					sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
-				} else {
-					sg_element[sg_count].length_segment_base_hi =
-						PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
-					sg_len = 0;
-				}
-				sg_count++;
-			}
-		}
+		for_each_sg(sg, sg, sg_count, i) {
+			len = sg_dma_len(sg);
+			if (len == 0)
+				continue;
 
-		orb->misc |= ORB_SET_DATA_SIZE(sg_count);
+			pt[j].high = cpu_to_be32(len << 16);
+			pt[j].low = cpu_to_be32(sg_dma_address(sg));
+			j++;
+		}
 
-		sbp2util_cpu_to_be32_buffer(sg_element,
-				(sizeof(struct sbp2_unrestricted_page_table)) *
-				sg_count);
+		orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) |
+			     ORB_SET_DATA_SIZE(j);
+		orb->data_descriptor_lo = cmd->sge_dma;
 
 		dma_sync_single_for_device(dmadev, cmd->sge_dma,
 					   sizeof(cmd->scatter_gather_element),
@@ -2037,6 +2003,8 @@ static int sbp2scsi_slave_configure(stru
 		sdev->start_stop_pwr_cond = 1;
 	if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
 		blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
+
+	blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
 	return 0;
 }
 

-- 
Stefan Richter
-=====-==--- =--- -=--=
http://arcgraph.de/sr/


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] firewire: fw-sbp2: enforce s/g segment size limit
  2008-08-09 18:20           ` [PATCH] ieee1394: sbp2: enforce s/g segment size limit Stefan Richter
@ 2008-08-09 18:21             ` Stefan Richter
  2008-08-11 19:52               ` Grant Grundler
  2008-08-12 17:04             ` [PATCH] ieee1394: sbp2: " Grant Grundler
  1 sibling, 1 reply; 18+ messages in thread
From: Stefan Richter @ 2008-08-09 18:21 UTC (permalink / raw)
  To: linux1394-devel; +Cc: FUJITA Tomonori, Grant Grundler, linux-kernel, linux-scsi

1. We don't need to round the SBP-2 segment size limit down to a
   multiple of 4 kB (0xffff -> 0xf000).  It is only necessary to
   ensure quadlet alignment (0xffff -> 0xfffc).

2. Use dma_set_max_seg_size() to tell the DMA mapping infrastructure
   and the block IO layer about the restriction.  This way we can
   remove the size checks and segment splitting in the queuecommand
   path.

   This assumes that no other code in the firewire stack uses
   dma_map_sg() with conflicting requirements.  It furthermore assumes
   that the controller device's platform actually allows us to set the
   segment size to our liking.  Assert the latter with a BUG_ON().

3. Also use blk_queue_max_segment_size() to tell the block IO layer
   about it.  It cannot know it because our scsi_add_host() does not
   point to the FireWire controller's device.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/firewire/fw-sbp2.c |   68 +++++++++++++++++--------------------
 1 file changed, 33 insertions(+), 35 deletions(-)

Index: linux-2.6.27-rc2/drivers/firewire/fw-sbp2.c
===================================================================
--- linux-2.6.27-rc2.orig/drivers/firewire/fw-sbp2.c
+++ linux-2.6.27-rc2/drivers/firewire/fw-sbp2.c
@@ -29,6 +29,7 @@
  */
 
 #include <linux/blkdev.h>
+#include <linux/bug.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
@@ -181,10 +182,16 @@ struct sbp2_target {
 #define SBP2_MAX_LOGIN_ORB_TIMEOUT	40000U	/* Timeout in ms */
 #define SBP2_ORB_TIMEOUT		2000U	/* Timeout in ms */
 #define SBP2_ORB_NULL			0x80000000
-#define SBP2_MAX_SG_ELEMENT_LENGTH	0xf000
 #define SBP2_RETRY_LIMIT		0xf		/* 15 retries */
 #define SBP2_CYCLE_LIMIT		(0xc8 << 12)	/* 200 125us cycles */
 
+/*
+ * The default maximum s/g segment size of a FireWire controller is
+ * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
+ * be quadlet-aligned, we set the length limit to 0xffff & ~3.
+ */
+#define SBP2_MAX_SEG_SIZE		0xfffc
+
 /* Unit directory keys */
 #define SBP2_CSR_UNIT_CHARACTERISTICS	0x3a
 #define SBP2_CSR_FIRMWARE_REVISION	0x3c
@@ -1099,6 +1106,10 @@ static int sbp2_probe(struct device *dev
 	struct Scsi_Host *shost;
 	u32 model, firmware_revision;
 
+	if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE)
+		BUG_ON(dma_set_max_seg_size(device->card->device,
+					    SBP2_MAX_SEG_SIZE));
+
 	shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt));
 	if (shost == NULL)
 		return -ENOMEM;
@@ -1347,14 +1358,12 @@ static int
 sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device,
 		     struct sbp2_logical_unit *lu)
 {
-	struct scatterlist *sg;
-	int sg_len, l, i, j, count;
-	dma_addr_t sg_addr;
-
-	sg = scsi_sglist(orb->cmd);
-	count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
-			   orb->cmd->sc_data_direction);
-	if (count == 0)
+	struct scatterlist *sg = scsi_sglist(orb->cmd);
+	int i, j, len;
+
+	i = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
+		       orb->cmd->sc_data_direction);
+	if (i == 0)
 		goto fail;
 
 	/*
@@ -1364,7 +1373,7 @@ sbp2_map_scatterlist(struct sbp2_command
 	 * as the second generation iPod which doesn't support page
 	 * tables.
 	 */
-	if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) {
+	if (i == 1) {
 		orb->request.data_descriptor.high =
 			cpu_to_be32(lu->tgt->address_high);
 		orb->request.data_descriptor.low  =
@@ -1374,29 +1383,15 @@ sbp2_map_scatterlist(struct sbp2_command
 		return 0;
 	}
 
-	/*
-	 * Convert the scatterlist to an sbp2 page table.  If any
-	 * scatterlist entries are too big for sbp2, we split them as we
-	 * go.  Even if we ask the block I/O layer to not give us sg
-	 * elements larger than 65535 bytes, some IOMMUs may merge sg elements
-	 * during DMA mapping, and Linux currently doesn't prevent this.
-	 */
-	for (i = 0, j = 0; i < count; i++, sg = sg_next(sg)) {
-		sg_len = sg_dma_len(sg);
-		sg_addr = sg_dma_address(sg);
-		while (sg_len) {
-			/* FIXME: This won't get us out of the pinch. */
-			if (unlikely(j >= ARRAY_SIZE(orb->page_table))) {
-				fw_error("page table overflow\n");
-				goto fail_page_table;
-			}
-			l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH);
-			orb->page_table[j].low = cpu_to_be32(sg_addr);
-			orb->page_table[j].high = cpu_to_be32(l << 16);
-			sg_addr += l;
-			sg_len -= l;
-			j++;
-		}
+	j = 0;
+	for_each_sg(sg, sg, scsi_sg_count(orb->cmd), i) {
+		len = sg_dma_len(sg);
+		if (len == 0)
+			continue;
+
+		orb->page_table[j].high = cpu_to_be32(len << 16);
+		orb->page_table[j].low = cpu_to_be32(sg_dma_address(sg));
+		j++;
 	}
 
 	orb->page_table_bus =
@@ -1420,8 +1415,9 @@ sbp2_map_scatterlist(struct sbp2_command
 	return 0;
 
  fail_page_table:
-	dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
-		     orb->cmd->sc_data_direction);
+	orb->page_table_bus = 0;
+	dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
+		     scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction);
  fail:
 	return -ENOMEM;
 }
@@ -1542,6 +1538,8 @@ static int sbp2_scsi_slave_configure(str
 	if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
 		blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
 
+	blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
+
 	return 0;
 }
 

-- 
Stefan Richter
-=====-==--- =--- -=--=
http://arcgraph.de/sr/


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] firewire: fw-sbp2: enforce s/g segment size limit
  2008-08-09 18:21             ` [PATCH] firewire: fw-sbp2: " Stefan Richter
@ 2008-08-11 19:52               ` Grant Grundler
  2008-08-13  9:38                 ` Stefan Richter
  0 siblings, 1 reply; 18+ messages in thread
From: Grant Grundler @ 2008-08-11 19:52 UTC (permalink / raw)
  To: Stefan Richter; +Cc: linux1394-devel, FUJITA Tomonori, linux-scsi, linux-kernel

On Sat, Aug 9, 2008 at 11:21 AM, Stefan Richter
<stefanr@s5r6.in-berlin.de> wrote:
> 1. We don't need to round the SBP-2 segment size limit down to a
>   multiple of 4 kB (0xffff -> 0xf000).  It is only necessary to
>   ensure quadlet alignment (0xffff -> 0xfffc).
>
> 2. Use dma_set_max_seg_size() to tell the DMA mapping infrastructure
>   and the block IO layer about the restriction.  This way we can
>   remove the size checks and segment splitting in the queuecommand
>   path.
>
>   This assumes that no other code in the firewire stack uses
>   dma_map_sg() with conflicting requirements.  It furthermore assumes
>   that the controller device's platform actually allows us to set the
>   segment size to our liking.  Assert the latter with a BUG_ON().
>
> 3. Also use blk_queue_max_segment_size() to tell the block IO layer
>   about it.  It cannot know it because our scsi_add_host() does not
>   point to the FireWire controller's device.
>
> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
> ---
>  drivers/firewire/fw-sbp2.c |   68 +++++++++++++++++--------------------
>  1 file changed, 33 insertions(+), 35 deletions(-)
>
> Index: linux-2.6.27-rc2/drivers/firewire/fw-sbp2.c
> ===================================================================
> --- linux-2.6.27-rc2.orig/drivers/firewire/fw-sbp2.c
> +++ linux-2.6.27-rc2/drivers/firewire/fw-sbp2.c
> @@ -29,6 +29,7 @@
>  */
>
>  #include <linux/blkdev.h>
> +#include <linux/bug.h>
>  #include <linux/delay.h>
>  #include <linux/device.h>
>  #include <linux/dma-mapping.h>
> @@ -181,10 +182,16 @@ struct sbp2_target {
>  #define SBP2_MAX_LOGIN_ORB_TIMEOUT     40000U  /* Timeout in ms */
>  #define SBP2_ORB_TIMEOUT               2000U   /* Timeout in ms */
>  #define SBP2_ORB_NULL                  0x80000000
> -#define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
>  #define SBP2_RETRY_LIMIT               0xf             /* 15 retries */
>  #define SBP2_CYCLE_LIMIT               (0xc8 << 12)    /* 200 125us cycles */
>
> +/*
> + * The default maximum s/g segment size of a FireWire controller is
> + * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
> + * be quadlet-aligned, we set the length limit to 0xffff & ~3.
> + */
> +#define SBP2_MAX_SEG_SIZE              0xfffc
> +
>  /* Unit directory keys */
>  #define SBP2_CSR_UNIT_CHARACTERISTICS  0x3a
>  #define SBP2_CSR_FIRMWARE_REVISION     0x3c
> @@ -1099,6 +1106,10 @@ static int sbp2_probe(struct device *dev
>        struct Scsi_Host *shost;
>        u32 model, firmware_revision;
>
> +       if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE)
> +               BUG_ON(dma_set_max_seg_size(device->card->device,
> +                                           SBP2_MAX_SEG_SIZE));
> +
>        shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt));
>        if (shost == NULL)
>                return -ENOMEM;
> @@ -1347,14 +1358,12 @@ static int
>  sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device,
>                     struct sbp2_logical_unit *lu)
>  {
> -       struct scatterlist *sg;
> -       int sg_len, l, i, j, count;
> -       dma_addr_t sg_addr;
> -
> -       sg = scsi_sglist(orb->cmd);
> -       count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
> -                          orb->cmd->sc_data_direction);
> -       if (count == 0)
> +       struct scatterlist *sg = scsi_sglist(orb->cmd);
> +       int i, j, len;
> +
> +       i = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
> +                      orb->cmd->sc_data_direction);
> +       if (i == 0)
>                goto fail;
>
>        /*
> @@ -1364,7 +1373,7 @@ sbp2_map_scatterlist(struct sbp2_command
>         * as the second generation iPod which doesn't support page
>         * tables.
>         */
> -       if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) {
> +       if (i == 1) {
>                orb->request.data_descriptor.high =
>                        cpu_to_be32(lu->tgt->address_high);
>                orb->request.data_descriptor.low  =
> @@ -1374,29 +1383,15 @@ sbp2_map_scatterlist(struct sbp2_command
>                return 0;
>        }
>
> -       /*
> -        * Convert the scatterlist to an sbp2 page table.  If any
> -        * scatterlist entries are too big for sbp2, we split them as we
> -        * go.  Even if we ask the block I/O layer to not give us sg
> -        * elements larger than 65535 bytes, some IOMMUs may merge sg elements
> -        * during DMA mapping, and Linux currently doesn't prevent this.
> -        */
> -       for (i = 0, j = 0; i < count; i++, sg = sg_next(sg)) {
> -               sg_len = sg_dma_len(sg);
> -               sg_addr = sg_dma_address(sg);
> -               while (sg_len) {
> -                       /* FIXME: This won't get us out of the pinch. */
> -                       if (unlikely(j >= ARRAY_SIZE(orb->page_table))) {
> -                               fw_error("page table overflow\n");
> -                               goto fail_page_table;
> -                       }
> -                       l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH);
> -                       orb->page_table[j].low = cpu_to_be32(sg_addr);
> -                       orb->page_table[j].high = cpu_to_be32(l << 16);

I didn't check the rest of the driver - but it would be good if it
explicitly called dma_set_mask() or  pci_dma_set_mask() with a 32-bit
mask value. Most drivers assume 32-bit and that's why I point this
out.

The rest looks ok at first glance.

thanks,
grant

> -                       sg_addr += l;
> -                       sg_len -= l;
> -                       j++;
> -               }
> +       j = 0;
> +       for_each_sg(sg, sg, scsi_sg_count(orb->cmd), i) {
> +               len = sg_dma_len(sg);
> +               if (len == 0)
> +                       continue;
> +
> +               orb->page_table[j].high = cpu_to_be32(len << 16);
> +               orb->page_table[j].low = cpu_to_be32(sg_dma_address(sg));
> +               j++;
>        }
>
>        orb->page_table_bus =
> @@ -1420,8 +1415,9 @@ sbp2_map_scatterlist(struct sbp2_command
>        return 0;
>
>  fail_page_table:
> -       dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
> -                    orb->cmd->sc_data_direction);
> +       orb->page_table_bus = 0;
> +       dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
> +                    scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction);
>  fail:
>        return -ENOMEM;
>  }
> @@ -1542,6 +1538,8 @@ static int sbp2_scsi_slave_configure(str
>        if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
>                blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
>
> +       blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
> +
>        return 0;
>  }
>
>
> --
> Stefan Richter
> -=====-==--- =--- -=--=
> http://arcgraph.de/sr/
>
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-09 18:20           ` [PATCH] ieee1394: sbp2: enforce s/g segment size limit Stefan Richter
  2008-08-09 18:21             ` [PATCH] firewire: fw-sbp2: " Stefan Richter
@ 2008-08-12 17:04             ` Grant Grundler
  2008-08-12 23:44               ` FUJITA Tomonori
  1 sibling, 1 reply; 18+ messages in thread
From: Grant Grundler @ 2008-08-12 17:04 UTC (permalink / raw)
  To: Stefan Richter; +Cc: FUJITA Tomonori, linux1394-devel, linux-kernel, linux-scsi

On Sat, Aug 9, 2008 at 11:20 AM, Stefan Richter
<stefanr@s5r6.in-berlin.de> wrote:
> 1. We don't need to round the SBP-2 segment size limit down to a
>   multiple of 4 kB (0xffff -> 0xf000).  It is only necessary to
>   ensure quadlet alignment (0xffff -> 0xfffc).
>
> 2. Use dma_set_max_seg_size() to tell the DMA mapping infrastructure
>   and the block IO layer about the restriction.  This way we can
>   remove the size checks and segment splitting in the queuecommand
>   path.
>
>   This assumes that no other code in the ieee1394 stack uses
>   dma_map_sg() with conflicting requirements.  It furthermore assumes
>   that the controller device's platform actually allows us to set the
>   segment size to our liking.  Assert the latter with a BUG_ON().
>
> 3. Also use blk_queue_max_segment_size() to tell the block IO layer
>   about it.  It cannot know it because our scsi_add_host() does not
>   point to the FireWire controller's device.
>
> We can also uniformly use dma_map_sg() for the single segment case just
> like for the multi segment case, to further simplify the code.
>
> Also clean up how the page table is converted to big endian.
>
> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
> ---
>
> Applicable after
>   [PATCH update] ieee1394: sbp2: stricter dma_sync
>   [PATCH] ieee1394: sbp2: check for DMA mapping failures
> from a few minutes ago.
>
>  drivers/ieee1394/sbp2.c |  106 +++++++++++++---------------------------
>  drivers/ieee1394/sbp2.h |   37 +++++--------
>  2 files changed, 52 insertions(+), 91 deletions(-)
...
> +               for_each_sg(sg, sg, sg_count, i) {
> +                       len = sg_dma_len(sg);
> +                       if (len == 0)
> +                               continue;
>
> -               orb->misc |= ORB_SET_DATA_SIZE(sg_count);
> +                       pt[j].high = cpu_to_be32(len << 16);
> +                       pt[j].low = cpu_to_be32(sg_dma_address(sg));
> +                       j++;
> +               }

While this code will probably work correctly, I believe if the
sg_dma_len() returns 0, one has walked off the end of the
"bus address" list.

pci_map_sg() returns how many DMA addr/len pairs are used
and that count could (should?) be used when pulling the
dma_len/addr pairs out of the sg list.

Effectively, the SG list is really two lists with seperate counts:
the original list with virtual addresses/len/count and the "DMA mapped"
list with it's own count of addresses/len pairs. When no IOMMU
is used those lists are 1:1.

hth,
grant

> -               sbp2util_cpu_to_be32_buffer(sg_element,
> -                               (sizeof(struct sbp2_unrestricted_page_table)) *
> -                               sg_count);
> +               orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) |
> +                            ORB_SET_DATA_SIZE(j);
> +               orb->data_descriptor_lo = cmd->sge_dma;
>
>                dma_sync_single_for_device(dmadev, cmd->sge_dma,
>                                           sizeof(cmd->scatter_gather_element),
> @@ -2037,6 +2003,8 @@ static int sbp2scsi_slave_configure(stru
>                sdev->start_stop_pwr_cond = 1;
>        if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
>                blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
> +
> +       blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
>        return 0;
>  }
>
>
> --
> Stefan Richter
> -=====-==--- =--- -=--=
> http://arcgraph.de/sr/
>
>

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-12 17:04             ` [PATCH] ieee1394: sbp2: " Grant Grundler
@ 2008-08-12 23:44               ` FUJITA Tomonori
  2008-08-13 10:19                 ` [PATCH update] " Stefan Richter
  0 siblings, 1 reply; 18+ messages in thread
From: FUJITA Tomonori @ 2008-08-12 23:44 UTC (permalink / raw)
  To: grundler
  Cc: fujita.tomonori, stefanr, linux1394-devel, linux-kernel,
	linux-scsi

On Tue, 12 Aug 2008 10:04:14 -0700
"Grant Grundler" <grundler@google.com> wrote:

> On Sat, Aug 9, 2008 at 11:20 AM, Stefan Richter
> <stefanr@s5r6.in-berlin.de> wrote:
> > 1. We don't need to round the SBP-2 segment size limit down to a
> >   multiple of 4 kB (0xffff -> 0xf000).  It is only necessary to
> >   ensure quadlet alignment (0xffff -> 0xfffc).
> >
> > 2. Use dma_set_max_seg_size() to tell the DMA mapping infrastructure
> >   and the block IO layer about the restriction.  This way we can
> >   remove the size checks and segment splitting in the queuecommand
> >   path.
> >
> >   This assumes that no other code in the ieee1394 stack uses
> >   dma_map_sg() with conflicting requirements.  It furthermore assumes
> >   that the controller device's platform actually allows us to set the
> >   segment size to our liking.  Assert the latter with a BUG_ON().
> >
> > 3. Also use blk_queue_max_segment_size() to tell the block IO layer
> >   about it.  It cannot know it because our scsi_add_host() does not
> >   point to the FireWire controller's device.
> >
> > We can also uniformly use dma_map_sg() for the single segment case just
> > like for the multi segment case, to further simplify the code.
> >
> > Also clean up how the page table is converted to big endian.
> >
> > Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
> > ---
> >
> > Applicable after
> >   [PATCH update] ieee1394: sbp2: stricter dma_sync
> >   [PATCH] ieee1394: sbp2: check for DMA mapping failures
> > from a few minutes ago.
> >
> >  drivers/ieee1394/sbp2.c |  106 +++++++++++++---------------------------
> >  drivers/ieee1394/sbp2.h |   37 +++++--------
> >  2 files changed, 52 insertions(+), 91 deletions(-)
> ...
> > +               for_each_sg(sg, sg, sg_count, i) {
> > +                       len = sg_dma_len(sg);
> > +                       if (len == 0)
> > +                               continue;
> >
> > -               orb->misc |= ORB_SET_DATA_SIZE(sg_count);
> > +                       pt[j].high = cpu_to_be32(len << 16);
> > +                       pt[j].low = cpu_to_be32(sg_dma_address(sg));
> > +                       j++;
> > +               }
> 
> While this code will probably work correctly, I believe if the
> sg_dma_len() returns 0, one has walked off the end of the
> "bus address" list.
>
> pci_map_sg() returns how many DMA addr/len pairs are used
> and that count could (should?) be used when pulling the
> dma_len/addr pairs out of the sg list.

Yeah, from a quick look, seems that this patch wrongly handles
sg_count.

This patch sets scsi_sg_count(sc) to sg_count, right? for_each_sg is
expected to be used with a return value of pci_map_sg.

Then this patch can simply do something like:

for_each_sg(sg, sg, sg_count, i) {
        pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
        pt[i].low = cpu_to_be32(sg_dma_address(sg));
}

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] firewire: fw-sbp2: enforce s/g segment size limit
  2008-08-11 19:52               ` Grant Grundler
@ 2008-08-13  9:38                 ` Stefan Richter
  0 siblings, 0 replies; 18+ messages in thread
From: Stefan Richter @ 2008-08-13  9:38 UTC (permalink / raw)
  To: Grant Grundler; +Cc: FUJITA Tomonori, linux1394-devel, linux-kernel, linux-scsi

Grant Grundler wrote:
> On Sat, Aug 9, 2008 at 11:21 AM, Stefan Richter
>> -                       orb->page_table[j].low = cpu_to_be32(sg_addr);
>> -                       orb->page_table[j].high = cpu_to_be32(l << 16);
> 
> I didn't check the rest of the driver - but it would be good if it
> explicitly called dma_set_mask() or  pci_dma_set_mask() with a 32-bit
> mask value. Most drivers assume 32-bit and that's why I point this
> out.

I thought about this and currently think that I should not do this. 
There is the API to set the mask, but there is no API to _decrease_ the 
mask only.  The SBP-2 protocol driver should not set DMA_32BIT_MASK if 
any other driver already set for example DMA_31BIT_MASK for whatever reason.

For now, this is no issue.  FireWire low-level drivers exist only for 
controllers with 32 bit local bus addressing capability.  I am sure that 
somebody will remember to modify the SBP-2 driver(s) if there will ever 
be a controller type and a driver for it which can address more than 4 GB.

On the other hand, we also currently have no reason to set a smaller 
mask.  We recently discovered a chip bug which requires DMA_31BIT_MASK 
for a special mode of data reception (only for cache-coherent DMA 
though), but we now work around this chip bug by simply falling back to 
an alternative mode.
-- 
Stefan Richter
-=====-==--- =--- -==-=
http://arcgraph.de/sr/

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH update] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-12 23:44               ` FUJITA Tomonori
@ 2008-08-13 10:19                 ` Stefan Richter
  2008-08-13 10:20                   ` [PATCH update] firewire: fw-sbp2: " Stefan Richter
                                     ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Stefan Richter @ 2008-08-13 10:19 UTC (permalink / raw)
  To: FUJITA Tomonori; +Cc: grundler, linux1394-devel, linux-kernel, linux-scsi

On 13 Aug, FUJITA Tomonori wrote:
> On Tue, 12 Aug 2008 10:04:14 -0700
> "Grant Grundler" <grundler@google.com> wrote:
> 
>> On Sat, Aug 9, 2008 at 11:20 AM, Stefan Richter
>> <stefanr@s5r6.in-berlin.de> wrote:
>> >  drivers/ieee1394/sbp2.c |  106 +++++++++++++---------------------------
>> >  drivers/ieee1394/sbp2.h |   37 +++++--------
>> >  2 files changed, 52 insertions(+), 91 deletions(-)
>> ...
>> > +               for_each_sg(sg, sg, sg_count, i) {
>> > +                       len = sg_dma_len(sg);
>> > +                       if (len == 0)
>> > +                               continue;
>> >
>> > -               orb->misc |= ORB_SET_DATA_SIZE(sg_count);
>> > +                       pt[j].high = cpu_to_be32(len << 16);
>> > +                       pt[j].low = cpu_to_be32(sg_dma_address(sg));
>> > +                       j++;
>> > +               }
>> 
>> While this code will probably work correctly, I believe if the
>> sg_dma_len() returns 0, one has walked off the end of the
>> "bus address" list.
>>
>> pci_map_sg() returns how many DMA addr/len pairs are used
>> and that count could (should?) be used when pulling the
>> dma_len/addr pairs out of the sg list.
> 
> Yeah, from a quick look, seems that this patch wrongly handles
> sg_count.
> 
> This patch sets scsi_sg_count(sc) to sg_count, right?

Well, I keep the original scsi_sg_count to call dma_unmap_sg with it
later.  According to Corbet/ Rubini/ Kroah-Hartman: LDD3, dma_unmap_sg
is to be called with the number of s/g elements before DMA-mapping.
>From a quick look at some dma_unmap_sg implementations, this seems still
to be the case; or it doesn't actually matter.

> for_each_sg is expected to be used with a return value of pci_map_sg.
> 
> Then this patch can simply do something like:
> 
> for_each_sg(sg, sg, sg_count, i) {
>         pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
>         pt[i].low = cpu_to_be32(sg_dma_address(sg));
> }

Thanks a lot for looking at this; here is my patch fixed.

 
From: Stefan Richter <stefanr@s5r6.in-berlin.de>
Subject: ieee1394: sbp2: enforce s/g segment size limit

1. We don't need to round the SBP-2 segment size limit down to a
   multiple of 4 kB (0xffff -> 0xf000).  It is only necessary to
   ensure quadlet alignment (0xffff -> 0xfffc).

2. Use dma_set_max_seg_size() to tell the DMA mapping infrastructure
   and the block IO layer about the restriction.  This way we can
   remove the size checks and segment splitting in the queuecommand
   path.

   This assumes that no other code in the ieee1394 stack uses
   dma_map_sg() with conflicting requirements.  It furthermore assumes
   that the controller device's platform actually allows us to set the
   segment size to our liking.  Assert the latter with a BUG_ON().

3. Also use blk_queue_max_segment_size() to tell the block IO layer
   about it.  It cannot know it because our scsi_add_host() does not
   point to the FireWire controller's device.

We can also uniformly use dma_map_sg() for the single segment case just
like for the multi segment case, to further simplify the code.

Also clean up how the page table is converted to big endian.

Thanks to Grant Grundler and FUJITA Tomonori for advice.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/ieee1394/sbp2.c |  100 ++++++++++++----------------------------
 drivers/ieee1394/sbp2.h |   37 ++++++--------
 2 files changed, 46 insertions(+), 91 deletions(-)

Index: linux/drivers/ieee1394/sbp2.h
===================================================================
--- linux.orig/drivers/ieee1394/sbp2.h
+++ linux/drivers/ieee1394/sbp2.h
@@ -139,13 +139,10 @@ struct sbp2_logout_orb {
 	u32 status_fifo_lo;
 } __attribute__((packed));
 
-#define PAGE_TABLE_SET_SEGMENT_BASE_HI(v)	((v) & 0xffff)
-#define PAGE_TABLE_SET_SEGMENT_LENGTH(v)	(((v) & 0xffff) << 16)
-
 struct sbp2_unrestricted_page_table {
-	u32 length_segment_base_hi;
-	u32 segment_base_lo;
-} __attribute__((packed));
+	__be32 high;
+	__be32 low;
+};
 
 #define RESP_STATUS_REQUEST_COMPLETE		0x0
 #define RESP_STATUS_TRANSPORT_FAILURE		0x1
@@ -216,15 +213,18 @@ struct sbp2_status_block {
 #define SBP2_UNIT_SPEC_ID_ENTRY			0x0000609e
 #define SBP2_SW_VERSION_ENTRY			0x00010483
 
-
 /*
- * SCSI specific definitions
+ * The default maximum s/g segment size of a FireWire controller is
+ * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
+ * be quadlet-aligned, we set the length limit to 0xffff & ~3.
  */
+#define SBP2_MAX_SEG_SIZE			0xfffc
 
-#define SBP2_MAX_SG_ELEMENT_LENGTH		0xf000
-/* There is no real limitation of the queue depth (i.e. length of the linked
+/*
+ * 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. */
+ * implementation detail of the sbp2 driver.
+ */
 #define SBP2_MAX_CMDS				8
 
 #define SBP2_SCSI_STATUS_GOOD			0x0
@@ -240,12 +240,6 @@ struct sbp2_status_block {
  * Representations of commands and devices
  */
 
-enum sbp2_dma_types {
-	CMD_DMA_NONE,
-	CMD_DMA_PAGE,
-	CMD_DMA_SINGLE
-};
-
 /* Per SCSI command */
 struct sbp2_command_info {
 	struct list_head list;
@@ -258,11 +252,10 @@ struct sbp2_command_info {
 	struct sbp2_unrestricted_page_table
 		scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
 	dma_addr_t sge_dma;
-	void *sge_buffer;
-	dma_addr_t cmd_dma;
-	enum sbp2_dma_types dma_type;
-	unsigned long dma_size;
-	enum dma_data_direction dma_dir;
+
+	struct scatterlist *sg_buffer;
+	int sg_count;
+	enum dma_data_direction sg_dir;
 };
 
 /* Per FireWire host */
Index: linux/drivers/ieee1394/sbp2.c
===================================================================
--- linux.orig/drivers/ieee1394/sbp2.c
+++ linux/drivers/ieee1394/sbp2.c
@@ -656,23 +656,10 @@ static struct sbp2_command_info *sbp2uti
 static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
 					    struct sbp2_command_info *cmd)
 {
-	struct hpsb_host *host = lu->ud->ne->host;
-
-	if (cmd->cmd_dma) {
-		if (cmd->dma_type == CMD_DMA_SINGLE)
-			dma_unmap_single(host->device.parent, cmd->cmd_dma,
-					 cmd->dma_size, cmd->dma_dir);
-		else if (cmd->dma_type == CMD_DMA_PAGE)
-			dma_unmap_page(host->device.parent, cmd->cmd_dma,
-				       cmd->dma_size, cmd->dma_dir);
-		/* XXX: Check for CMD_DMA_NONE bug */
-		cmd->dma_type = CMD_DMA_NONE;
-		cmd->cmd_dma = 0;
-	}
-	if (cmd->sge_buffer) {
-		dma_unmap_sg(host->device.parent, cmd->sge_buffer,
-			     cmd->dma_size, cmd->dma_dir);
-		cmd->sge_buffer = NULL;
+	if (cmd->sg_buffer) {
+		dma_unmap_sg(lu->ud->ne->host->device.parent, cmd->sg_buffer,
+			     cmd->sg_count, cmd->sg_dir);
+		cmd->sg_buffer = NULL;
 	}
 	list_move_tail(&cmd->list, &lu->cmd_orb_completed);
 }
@@ -827,6 +814,10 @@ static struct sbp2_lu *sbp2_alloc_device
 #endif
 	}
 
+	if (dma_get_max_seg_size(hi->host->device.parent) > SBP2_MAX_SEG_SIZE)
+		BUG_ON(dma_set_max_seg_size(hi->host->device.parent,
+					    SBP2_MAX_SEG_SIZE));
+
 	/* Prevent unloading of the 1394 host */
 	if (!try_module_get(hi->host->driver->owner)) {
 		SBP2_ERR("failed to get a reference on 1394 host driver");
@@ -1501,76 +1492,45 @@ static int sbp2_agent_reset(struct sbp2_
 static int 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,
+				    unsigned int sg_count,
 				    struct scatterlist *sg,
 				    u32 orb_direction,
 				    enum dma_data_direction dma_dir)
 {
 	struct device *dmadev = hi->host->device.parent;
+	struct sbp2_unrestricted_page_table *pt;
+	int i, n;
+
+	n = dma_map_sg(dmadev, sg, sg_count, dma_dir);
+	if (n == 0)
+		return -ENOMEM;
+
+	cmd->sg_buffer = sg;
+	cmd->sg_count = sg_count;
+	cmd->sg_dir = dma_dir;
 
-	cmd->dma_dir = dma_dir;
 	orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 	orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
 	/* special case if only one element (and less than 64KB in size) */
-	if (scsi_use_sg == 1 && sg->length <= SBP2_MAX_SG_ELEMENT_LENGTH) {
-
-		cmd->dma_size = sg->length;
-		cmd->dma_type = CMD_DMA_PAGE;
-		cmd->cmd_dma = dma_map_page(dmadev, sg_page(sg), sg->offset,
-					    cmd->dma_size, cmd->dma_dir);
-		if (dma_mapping_error(cmd->cmd_dma)) {
-			cmd->cmd_dma = 0;
-			return -ENOMEM;
-		}
-
-		orb->data_descriptor_lo = cmd->cmd_dma;
-		orb->misc |= ORB_SET_DATA_SIZE(cmd->dma_size);
-
+	if (n == 1) {
+		orb->misc |= ORB_SET_DATA_SIZE(sg_dma_len(sg));
+		orb->data_descriptor_lo = sg_dma_address(sg);
 	} else {
-		struct sbp2_unrestricted_page_table *sg_element =
-						&cmd->scatter_gather_element[0];
-		u32 sg_count, sg_len;
-		dma_addr_t sg_addr;
-		int i, count = dma_map_sg(dmadev, sg, scsi_use_sg, dma_dir);
-
-		cmd->dma_size = scsi_use_sg;
-		cmd->sge_buffer = sg;
-
-		/* use page tables (s/g) */
-		orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-		orb->data_descriptor_lo = cmd->sge_dma;
+		pt = &cmd->scatter_gather_element[0];
 
 		dma_sync_single_for_cpu(dmadev, cmd->sge_dma,
 					sizeof(cmd->scatter_gather_element),
 					DMA_TO_DEVICE);
 
-		/* 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++, 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) {
-					sg_element[sg_count].length_segment_base_hi =
-						PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
-					sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
-					sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
-				} else {
-					sg_element[sg_count].length_segment_base_hi =
-						PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
-					sg_len = 0;
-				}
-				sg_count++;
-			}
+		for_each_sg(sg, sg, n, i) {
+			pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
+			pt[i].low = cpu_to_be32(sg_dma_address(sg));
 		}
 
-		orb->misc |= ORB_SET_DATA_SIZE(sg_count);
-
-		sbp2util_cpu_to_be32_buffer(sg_element,
-				(sizeof(struct sbp2_unrestricted_page_table)) *
-				sg_count);
+		orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) |
+			     ORB_SET_DATA_SIZE(n);
+		orb->data_descriptor_lo = cmd->sge_dma;
 
 		dma_sync_single_for_device(dmadev, cmd->sge_dma,
 					   sizeof(cmd->scatter_gather_element),
@@ -2037,6 +1997,8 @@ static int sbp2scsi_slave_configure(stru
 		sdev->start_stop_pwr_cond = 1;
 	if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
 		blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
+
+	blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
 	return 0;
 }
 

-- 
Stefan Richter
-=====-==--- =--- -==-=
http://arcgraph.de/sr/


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH update] firewire: fw-sbp2: enforce s/g segment size limit
  2008-08-13 10:19                 ` [PATCH update] " Stefan Richter
@ 2008-08-13 10:20                   ` Stefan Richter
  2008-08-13 10:27                   ` [PATCH update] ieee1394: sbp2: " Stefan Richter
  2008-08-14  0:55                   ` FUJITA Tomonori
  2 siblings, 0 replies; 18+ messages in thread
From: Stefan Richter @ 2008-08-13 10:20 UTC (permalink / raw)
  To: FUJITA Tomonori; +Cc: grundler, linux1394-devel, linux-kernel, linux-scsi

1. We don't need to round the SBP-2 segment size limit down to a
   multiple of 4 kB (0xffff -> 0xf000).  It is only necessary to
   ensure quadlet alignment (0xffff -> 0xfffc).

2. Use dma_set_max_seg_size() to tell the DMA mapping infrastructure
   and the block IO layer about the restriction.  This way we can
   remove the size checks and segment splitting in the queuecommand
   path.

   This assumes that no other code in the firewire stack uses
   dma_map_sg() with conflicting requirements.  It furthermore assumes
   that the controller device's platform actually allows us to set the
   segment size to our liking.  Assert the latter with a BUG_ON().

3. Also use blk_queue_max_segment_size() to tell the block IO layer
   about it.  It cannot know it because our scsi_add_host() does not
   point to the FireWire controller's device.

Thanks to Grant Grundler and FUJITA Tomonori for advice.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/firewire/fw-sbp2.c |   64 ++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 36 deletions(-)

Index: linux/drivers/firewire/fw-sbp2.c
===================================================================
--- linux.orig/drivers/firewire/fw-sbp2.c
+++ linux/drivers/firewire/fw-sbp2.c
@@ -29,6 +29,7 @@
  */
 
 #include <linux/blkdev.h>
+#include <linux/bug.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
@@ -181,10 +182,16 @@ struct sbp2_target {
 #define SBP2_MAX_LOGIN_ORB_TIMEOUT	40000U	/* Timeout in ms */
 #define SBP2_ORB_TIMEOUT		2000U	/* Timeout in ms */
 #define SBP2_ORB_NULL			0x80000000
-#define SBP2_MAX_SG_ELEMENT_LENGTH	0xf000
 #define SBP2_RETRY_LIMIT		0xf		/* 15 retries */
 #define SBP2_CYCLE_LIMIT		(0xc8 << 12)	/* 200 125us cycles */
 
+/*
+ * The default maximum s/g segment size of a FireWire controller is
+ * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
+ * be quadlet-aligned, we set the length limit to 0xffff & ~3.
+ */
+#define SBP2_MAX_SEG_SIZE		0xfffc
+
 /* Unit directory keys */
 #define SBP2_CSR_UNIT_CHARACTERISTICS	0x3a
 #define SBP2_CSR_FIRMWARE_REVISION	0x3c
@@ -1099,6 +1106,10 @@ static int sbp2_probe(struct device *dev
 	struct Scsi_Host *shost;
 	u32 model, firmware_revision;
 
+	if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE)
+		BUG_ON(dma_set_max_seg_size(device->card->device,
+					    SBP2_MAX_SEG_SIZE));
+
 	shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt));
 	if (shost == NULL)
 		return -ENOMEM;
@@ -1347,14 +1358,12 @@ static int
 sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device,
 		     struct sbp2_logical_unit *lu)
 {
-	struct scatterlist *sg;
-	int sg_len, l, i, j, count;
-	dma_addr_t sg_addr;
-
-	sg = scsi_sglist(orb->cmd);
-	count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
-			   orb->cmd->sc_data_direction);
-	if (count == 0)
+	struct scatterlist *sg = scsi_sglist(orb->cmd);
+	int i, n;
+
+	n = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
+		       orb->cmd->sc_data_direction);
+	if (n == 0)
 		goto fail;
 
 	/*
@@ -1364,7 +1373,7 @@ sbp2_map_scatterlist(struct sbp2_command
 	 * as the second generation iPod which doesn't support page
 	 * tables.
 	 */
-	if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) {
+	if (n == 1) {
 		orb->request.data_descriptor.high =
 			cpu_to_be32(lu->tgt->address_high);
 		orb->request.data_descriptor.low  =
@@ -1374,29 +1383,9 @@ sbp2_map_scatterlist(struct sbp2_command
 		return 0;
 	}
 
-	/*
-	 * Convert the scatterlist to an sbp2 page table.  If any
-	 * scatterlist entries are too big for sbp2, we split them as we
-	 * go.  Even if we ask the block I/O layer to not give us sg
-	 * elements larger than 65535 bytes, some IOMMUs may merge sg elements
-	 * during DMA mapping, and Linux currently doesn't prevent this.
-	 */
-	for (i = 0, j = 0; i < count; i++, sg = sg_next(sg)) {
-		sg_len = sg_dma_len(sg);
-		sg_addr = sg_dma_address(sg);
-		while (sg_len) {
-			/* FIXME: This won't get us out of the pinch. */
-			if (unlikely(j >= ARRAY_SIZE(orb->page_table))) {
-				fw_error("page table overflow\n");
-				goto fail_page_table;
-			}
-			l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH);
-			orb->page_table[j].low = cpu_to_be32(sg_addr);
-			orb->page_table[j].high = cpu_to_be32(l << 16);
-			sg_addr += l;
-			sg_len -= l;
-			j++;
-		}
+	for_each_sg(sg, sg, n, i) {
+		orb->page_table[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
+		orb->page_table[i].low = cpu_to_be32(sg_dma_address(sg));
 	}
 
 	orb->page_table_bus =
@@ -1415,13 +1404,14 @@ sbp2_map_scatterlist(struct sbp2_command
 	orb->request.data_descriptor.high = cpu_to_be32(lu->tgt->address_high);
 	orb->request.data_descriptor.low  = cpu_to_be32(orb->page_table_bus);
 	orb->request.misc |= cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT |
-					 COMMAND_ORB_DATA_SIZE(j));
+					 COMMAND_ORB_DATA_SIZE(n));
 
 	return 0;
 
  fail_page_table:
-	dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
-		     orb->cmd->sc_data_direction);
+	orb->page_table_bus = 0;
+	dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
+		     scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction);
  fail:
 	return -ENOMEM;
 }
@@ -1542,6 +1532,8 @@ static int sbp2_scsi_slave_configure(str
 	if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
 		blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
 
+	blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
+
 	return 0;
 }
 

-- 
Stefan Richter
-=====-==--- =--- -==-=
http://arcgraph.de/sr/


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH update] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-13 10:19                 ` [PATCH update] " Stefan Richter
  2008-08-13 10:20                   ` [PATCH update] firewire: fw-sbp2: " Stefan Richter
@ 2008-08-13 10:27                   ` Stefan Richter
  2008-08-14  0:55                   ` FUJITA Tomonori
  2 siblings, 0 replies; 18+ messages in thread
From: Stefan Richter @ 2008-08-13 10:27 UTC (permalink / raw)
  To: FUJITA Tomonori; +Cc: grundler, linux1394-devel, linux-kernel, linux-scsi

I wrote:
> -		if (dma_mapping_error(cmd->cmd_dma)) {

PS:  That's the 2.6.26 version; the 2.6.27 patch has an additional 
argument here, if anybody cares...
-- 
Stefan Richter
-=====-==--- =--- -==-=
http://arcgraph.de/sr/

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH update] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-13 10:19                 ` [PATCH update] " Stefan Richter
  2008-08-13 10:20                   ` [PATCH update] firewire: fw-sbp2: " Stefan Richter
  2008-08-13 10:27                   ` [PATCH update] ieee1394: sbp2: " Stefan Richter
@ 2008-08-14  0:55                   ` FUJITA Tomonori
  2008-08-14  7:12                     ` Stefan Richter
  2 siblings, 1 reply; 18+ messages in thread
From: FUJITA Tomonori @ 2008-08-14  0:55 UTC (permalink / raw)
  To: stefanr
  Cc: fujita.tomonori, grundler, linux1394-devel, linux-kernel,
	linux-scsi

On Wed, 13 Aug 2008 12:19:59 +0200 (CEST)
Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:

> On 13 Aug, FUJITA Tomonori wrote:
> > On Tue, 12 Aug 2008 10:04:14 -0700
> > "Grant Grundler" <grundler@google.com> wrote:
> > 
> >> On Sat, Aug 9, 2008 at 11:20 AM, Stefan Richter
> >> <stefanr@s5r6.in-berlin.de> wrote:
> >> >  drivers/ieee1394/sbp2.c |  106 +++++++++++++---------------------------
> >> >  drivers/ieee1394/sbp2.h |   37 +++++--------
> >> >  2 files changed, 52 insertions(+), 91 deletions(-)
> >> ...
> >> > +               for_each_sg(sg, sg, sg_count, i) {
> >> > +                       len = sg_dma_len(sg);
> >> > +                       if (len == 0)
> >> > +                               continue;
> >> >
> >> > -               orb->misc |= ORB_SET_DATA_SIZE(sg_count);
> >> > +                       pt[j].high = cpu_to_be32(len << 16);
> >> > +                       pt[j].low = cpu_to_be32(sg_dma_address(sg));
> >> > +                       j++;
> >> > +               }
> >> 
> >> While this code will probably work correctly, I believe if the
> >> sg_dma_len() returns 0, one has walked off the end of the
> >> "bus address" list.
> >>
> >> pci_map_sg() returns how many DMA addr/len pairs are used
> >> and that count could (should?) be used when pulling the
> >> dma_len/addr pairs out of the sg list.
> > 
> > Yeah, from a quick look, seems that this patch wrongly handles
> > sg_count.
> > 
> > This patch sets scsi_sg_count(sc) to sg_count, right?
> 
> Well, I keep the original scsi_sg_count to call dma_unmap_sg with it
> later.

You need to keep it? You can access to it via scsi_sg_count when
calling dma_unmap_sg? Seems that firewire code does.


> According to Corbet/ Rubini/ Kroah-Hartman: LDD3, dma_unmap_sg
> is to be called with the number of s/g elements before DMA-mapping.

Are you talking about?

=
To unmap a scatterlist, just call:

	pci_unmap_sg(pdev, sglist, nents, direction);

Again, make sure DMA activity has already finished.

PLEASE NOTE:  The 'nents' argument to the pci_unmap_sg call must be
              the _same_ one you passed into the pci_map_sg call,
	      it should _NOT_ be the 'count' value _returned_ from the
              pci_map_sg call.


This is from Documentation/DMA-mapping.txt


> From a quick look at some dma_unmap_sg implementations, this seems still
> to be the case; or it doesn't actually matter.

I think that all the IOMMUs are fine even if you call dma_unmap_sg
with a 'nents' value that dma_map_sg returned. But, well, it's against
the rule.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH update] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-14  0:55                   ` FUJITA Tomonori
@ 2008-08-14  7:12                     ` Stefan Richter
  2008-08-14  7:21                       ` FUJITA Tomonori
  0 siblings, 1 reply; 18+ messages in thread
From: Stefan Richter @ 2008-08-14  7:12 UTC (permalink / raw)
  To: FUJITA Tomonori; +Cc: grundler, linux1394-devel, linux-kernel, linux-scsi

On 14 Aug, FUJITA Tomonori wrote:
> On Wed, 13 Aug 2008 12:19:59 +0200 (CEST)
> Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:
>> I keep the original scsi_sg_count to call dma_unmap_sg with it
>> later.
> 
> You need to keep it? You can access to it via scsi_sg_count when
> calling dma_unmap_sg? Seems that firewire code does.

Yes, I can easily do it this way; fixed below.

[...nents in dma_unmap_sg...]
> This is from Documentation/DMA-mapping.txt

Right.  How did I forget about that?



From: Stefan Richter <stefanr@s5r6.in-berlin.de>
Subject: ieee1394: sbp2: remove redundant struct members

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/ieee1394/sbp2.c |   14 +++++---------
 drivers/ieee1394/sbp2.h |    4 ----
 2 files changed, 5 insertions(+), 13 deletions(-)

Index: linux/drivers/ieee1394/sbp2.c
===================================================================
--- linux.orig/drivers/ieee1394/sbp2.c
+++ linux/drivers/ieee1394/sbp2.c
@@ -656,11 +656,11 @@ static struct sbp2_command_info *sbp2uti
 static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
 					    struct sbp2_command_info *cmd)
 {
-	if (cmd->sg_buffer) {
-		dma_unmap_sg(lu->ud->ne->host->device.parent, cmd->sg_buffer,
-			     cmd->sg_count, cmd->sg_dir);
-		cmd->sg_buffer = NULL;
-	}
+	if (scsi_sg_count(cmd->Current_SCpnt) > 0)
+		dma_unmap_sg(lu->ud->ne->host->device.parent,
+			     scsi_sglist(cmd->Current_SCpnt),
+			     scsi_sg_count(cmd->Current_SCpnt),
+			     cmd->Current_SCpnt->sc_data_direction);
 	list_move_tail(&cmd->list, &lu->cmd_orb_completed);
 }
 
@@ -1505,10 +1505,6 @@ static int sbp2_prep_command_orb_sg(stru
 	if (n == 0)
 		return -ENOMEM;
 
-	cmd->sg_buffer = sg;
-	cmd->sg_count = sg_count;
-	cmd->sg_dir = dma_dir;
-
 	orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 	orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
Index: linux/drivers/ieee1394/sbp2.h
===================================================================
--- linux.orig/drivers/ieee1394/sbp2.h
+++ linux/drivers/ieee1394/sbp2.h
@@ -252,10 +252,6 @@ struct sbp2_command_info {
 	struct sbp2_unrestricted_page_table
 		scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
 	dma_addr_t sge_dma;
-
-	struct scatterlist *sg_buffer;
-	int sg_count;
-	enum dma_data_direction sg_dir;
 };
 
 /* Per FireWire host */


-- 
Stefan Richter
-=====-==--- =--- -===-
http://arcgraph.de/sr/


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH update] ieee1394: sbp2: enforce s/g segment size limit
  2008-08-14  7:12                     ` Stefan Richter
@ 2008-08-14  7:21                       ` FUJITA Tomonori
  0 siblings, 0 replies; 18+ messages in thread
From: FUJITA Tomonori @ 2008-08-14  7:21 UTC (permalink / raw)
  To: stefanr
  Cc: fujita.tomonori, grundler, linux1394-devel, linux-kernel,
	linux-scsi

On Thu, 14 Aug 2008 09:12:01 +0200 (CEST)
Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:

> On 14 Aug, FUJITA Tomonori wrote:
> > On Wed, 13 Aug 2008 12:19:59 +0200 (CEST)
> > Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:
> >> I keep the original scsi_sg_count to call dma_unmap_sg with it
> >> later.
> > 
> > You need to keep it? You can access to it via scsi_sg_count when
> > calling dma_unmap_sg? Seems that firewire code does.
> 
> Yes, I can easily do it this way; fixed below.
> 
> [...nents in dma_unmap_sg...]
> > This is from Documentation/DMA-mapping.txt
> 
> Right.  How did I forget about that?
> 
> 
> 
> From: Stefan Richter <stefanr@s5r6.in-berlin.de>
> Subject: ieee1394: sbp2: remove redundant struct members
> 
> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
> ---
>  drivers/ieee1394/sbp2.c |   14 +++++---------
>  drivers/ieee1394/sbp2.h |    4 ----
>  2 files changed, 5 insertions(+), 13 deletions(-)
> 
> Index: linux/drivers/ieee1394/sbp2.c
> ===================================================================
> --- linux.orig/drivers/ieee1394/sbp2.c
> +++ linux/drivers/ieee1394/sbp2.c
> @@ -656,11 +656,11 @@ static struct sbp2_command_info *sbp2uti
>  static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
>  					    struct sbp2_command_info *cmd)
>  {
> -	if (cmd->sg_buffer) {
> -		dma_unmap_sg(lu->ud->ne->host->device.parent, cmd->sg_buffer,
> -			     cmd->sg_count, cmd->sg_dir);
> -		cmd->sg_buffer = NULL;
> -	}
> +	if (scsi_sg_count(cmd->Current_SCpnt) > 0)

static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd)

so 

> +	if (scsi_sg_count(cmd->Current_SCpnt))

make more sense, I think. It looks a nice cleanup except for it.


> +		dma_unmap_sg(lu->ud->ne->host->device.parent,
> +			     scsi_sglist(cmd->Current_SCpnt),
> +			     scsi_sg_count(cmd->Current_SCpnt),
> +			     cmd->Current_SCpnt->sc_data_direction);
>  	list_move_tail(&cmd->list, &lu->cmd_orb_completed);
>  }
>  
> @@ -1505,10 +1505,6 @@ static int sbp2_prep_command_orb_sg(stru
>  	if (n == 0)
>  		return -ENOMEM;
>  
> -	cmd->sg_buffer = sg;
> -	cmd->sg_count = sg_count;
> -	cmd->sg_dir = dma_dir;
> -
>  	orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
>  	orb->misc |= ORB_SET_DIRECTION(orb_direction);
>  
> Index: linux/drivers/ieee1394/sbp2.h
> ===================================================================
> --- linux.orig/drivers/ieee1394/sbp2.h
> +++ linux/drivers/ieee1394/sbp2.h
> @@ -252,10 +252,6 @@ struct sbp2_command_info {
>  	struct sbp2_unrestricted_page_table
>  		scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
>  	dma_addr_t sge_dma;
> -
> -	struct scatterlist *sg_buffer;
> -	int sg_count;
> -	enum dma_data_direction sg_dir;
>  };
>  
>  /* Per FireWire host */
> 
> 
> -- 
> Stefan Richter
> -=====-==--- =--- -===-
> http://arcgraph.de/sr/
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2008-08-14  7:21 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-08 19:44 Scatter-gather segment merges by IOMMU? Stefan Richter
2008-08-08 20:25 ` Grant Grundler
2008-08-08 21:21   ` Stefan Richter
2008-08-08 21:31     ` FUJITA Tomonori
2008-08-08 21:58       ` Stefan Richter
2008-08-08 22:17         ` FUJITA Tomonori
2008-08-09 18:20           ` [PATCH] ieee1394: sbp2: enforce s/g segment size limit Stefan Richter
2008-08-09 18:21             ` [PATCH] firewire: fw-sbp2: " Stefan Richter
2008-08-11 19:52               ` Grant Grundler
2008-08-13  9:38                 ` Stefan Richter
2008-08-12 17:04             ` [PATCH] ieee1394: sbp2: " Grant Grundler
2008-08-12 23:44               ` FUJITA Tomonori
2008-08-13 10:19                 ` [PATCH update] " Stefan Richter
2008-08-13 10:20                   ` [PATCH update] firewire: fw-sbp2: " Stefan Richter
2008-08-13 10:27                   ` [PATCH update] ieee1394: sbp2: " Stefan Richter
2008-08-14  0:55                   ` FUJITA Tomonori
2008-08-14  7:12                     ` Stefan Richter
2008-08-14  7:21                       ` FUJITA Tomonori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox