summaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-12-05 08:43:12 +0100
committerJeff Garzik <jeff@garzik.org>2008-01-23 11:24:15 +0100
commit0bcc65ad78ae517de16b2ca07a2891f49d44d156 (patch)
tree87eecc4aec56500f3e29a1e82b631093f950ac85 /drivers/ata
parentlibata: convert to chained sg (diff)
downloadlinux-0bcc65ad78ae517de16b2ca07a2891f49d44d156.tar.xz
linux-0bcc65ad78ae517de16b2ca07a2891f49d44d156.zip
libata: make qc->nbytes include extra buffers
qc->nbytes didn't use to include extra buffers setup by libata core layer and my be odd. This patch makes qc->nbytes include any extra buffers setup by libata core layer and guaranteed to be aligned on 4 byte boundary. This value is to be used to program the host controller. As this represents the actual length of buffer available to the controller and the controller must be able to deal with short transfers for ATAPI commands which can transfer variable length, this shouldn't break any controllers while making problems like rounding-down and controllers choking up on odd transfer bytes much less likely. The unmodified value is stored in new field qc->raw_nbytes. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-core.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index e998028302da..ee72994500a3 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4763,13 +4763,15 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
}
static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc,
- unsigned int *n_elem_extra)
+ unsigned int *n_elem_extra,
+ unsigned int *nbytes_extra)
{
struct ata_port *ap = qc->ap;
unsigned int n_elem = qc->n_elem;
struct scatterlist *lsg, *copy_lsg = NULL, *tsg = NULL, *esg = NULL;
*n_elem_extra = 0;
+ *nbytes_extra = 0;
/* needs padding? */
qc->pad_len = qc->nbytes & 3;
@@ -4833,6 +4835,7 @@ static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc,
esg = &qc->extra_sg[1];
(*n_elem_extra)++;
+ (*nbytes_extra) += 4 - qc->pad_len;
}
if (copy_lsg)
@@ -4866,11 +4869,11 @@ static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc,
static int ata_sg_setup(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- unsigned int n_elem, n_elem_extra;
+ unsigned int n_elem, n_elem_extra, nbytes_extra;
VPRINTK("ENTER, ata%u\n", ap->print_id);
- n_elem = ata_sg_setup_extra(qc, &n_elem_extra);
+ n_elem = ata_sg_setup_extra(qc, &n_elem_extra, &nbytes_extra);
if (n_elem) {
n_elem = dma_map_sg(ap->dev, qc->sg, n_elem, qc->dma_dir);
@@ -4885,7 +4888,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
qc->n_elem = qc->mapped_n_elem = n_elem;
qc->n_elem += n_elem_extra;
-
+ qc->nbytes += nbytes_extra;
qc->flags |= ATA_QCFLAG_DMAMAP;
return 0;
@@ -5949,6 +5952,9 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
*/
BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes));
+ /* ata_sg_setup() may update nbytes */
+ qc->raw_nbytes = qc->nbytes;
+
if (ata_is_dma(prot) || (ata_is_pio(prot) &&
(ap->flags & ATA_FLAG_PIO_DMA)))
if (ata_sg_setup(qc))