summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen M. Cameron <scameron@beardog.cce.hp.com>2010-05-27 20:14:39 (GMT)
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 17:01:17 (GMT)
commitdef342bd745d88ed73541b9c07cefb13d8c576fd (patch)
tree2ed39e2ac30fc7af9529906a2450e96830282844
parentd28ce020fb0ef9254fc9e0bd07f5898c69af9f7d (diff)
downloadlinux-def342bd745d88ed73541b9c07cefb13d8c576fd.tar.xz
[SCSI] hpsa: fix block fetch table problem.
We have 32 (MAXSGENTRIES) scatter gather elements embedded in the command. With all these, the total command size is about 576 bytes. However, the last entry in the block fetch table is 35. (the block fetch table contains the number of 16-byte chunks the firmware needs to fetch for a given number of scatter gather elements.) 35 * 16 = 560 bytes, which isn't enough. It needs to be 36. (36 * 16 == 576) or, MAXSGENTRIES + 4. (plus 4 because there's a bunch of stuff at the front of the command before the first scatter gather element that takes up 4 * 16 bytes.) Without this fix, the controller may have to perform two DMA operations to fetch the command since the first one may not get the whole thing. Signed-off-by: Don Brace <brace@beardog.cce.hp.com> Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/hpsa.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 4109107..1133b5f 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3826,7 +3826,26 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
{
int i;
unsigned long register_value;
- int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */
+
+ /* This is a bit complicated. There are 8 registers on
+ * the controller which we write to to tell it 8 different
+ * sizes of commands which there may be. It's a way of
+ * reducing the DMA done to fetch each command. Encoded into
+ * each command's tag are 3 bits which communicate to the controller
+ * which of the eight sizes that command fits within. The size of
+ * each command depends on how many scatter gather entries there are.
+ * Each SG entry requires 16 bytes. The eight registers are programmed
+ * with the number of 16-byte blocks a command of that size requires.
+ * The smallest command possible requires 5 such 16 byte blocks.
+ * the largest command possible requires MAXSGENTRIES + 4 16-byte
+ * blocks. Note, this only extends to the SG entries contained
+ * within the command block, and does not extend to chained blocks
+ * of SG elements. bft[] contains the eight values we write to
+ * the registers. They are not evenly distributed, but have more
+ * sizes for small commands, and fewer sizes for larger commands.
+ */
+ int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
+ BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
/* 5 = 1 s/g entry or 4k
* 6 = 2 s/g entry or 8k
* 8 = 4 s/g entry or 16k