diff options
author | Stephen M. Cameron <scameron@beardog.cce.hp.com> | 2010-05-27 15:14:39 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 12:01:17 -0500 |
commit | def342bd745d88ed73541b9c07cefb13d8c576fd (patch) | |
tree | 2ed39e2ac30fc7af9529906a2450e96830282844 /drivers/scsi/hpsa.c | |
parent | d28ce020fb0ef9254fc9e0bd07f5898c69af9f7d (diff) | |
download | lwn-def342bd745d88ed73541b9c07cefb13d8c576fd.tar.gz lwn-def342bd745d88ed73541b9c07cefb13d8c576fd.zip |
[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>
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r-- | drivers/scsi/hpsa.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 410910762fc5..1133b5fda0e7 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 |