diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-10-05 07:13:30 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-05 07:13:30 -0400 |
commit | cedc9a478d8c6265879dc3839ef3d4849a709184 (patch) | |
tree | 0c8e0fbffdb6081381c01b8cfd93c95b168acb44 /drivers/scsi/ahci.c | |
parent | ed39f731ab2e77e58122232f6e27333331d7793d (diff) |
libata: fix ATAPI DMA alignment issues
ATAPI needs to be padded to next 4 byte boundary, if misaligned.
Original work by me, many fixes from Tejun Heo.
Diffstat (limited to 'drivers/scsi/ahci.c')
-rw-r--r-- | drivers/scsi/ahci.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c2c8fa828e24..6e4bb36f8d7c 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -314,8 +314,15 @@ static int ahci_port_start(struct ata_port *ap) | |||
314 | return -ENOMEM; | 314 | return -ENOMEM; |
315 | memset(pp, 0, sizeof(*pp)); | 315 | memset(pp, 0, sizeof(*pp)); |
316 | 316 | ||
317 | ap->pad = dma_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ, &ap->pad_dma, GFP_KERNEL); | ||
318 | if (!ap->pad) { | ||
319 | kfree(pp); | ||
320 | return -ENOMEM; | ||
321 | } | ||
322 | |||
317 | mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); | 323 | mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); |
318 | if (!mem) { | 324 | if (!mem) { |
325 | dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma); | ||
319 | kfree(pp); | 326 | kfree(pp); |
320 | return -ENOMEM; | 327 | return -ENOMEM; |
321 | } | 328 | } |
@@ -391,6 +398,7 @@ static void ahci_port_stop(struct ata_port *ap) | |||
391 | ap->private_data = NULL; | 398 | ap->private_data = NULL; |
392 | dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, | 399 | dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, |
393 | pp->cmd_slot, pp->cmd_slot_dma); | 400 | pp->cmd_slot, pp->cmd_slot_dma); |
401 | dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma); | ||
394 | kfree(pp); | 402 | kfree(pp); |
395 | } | 403 | } |
396 | 404 | ||
@@ -476,23 +484,23 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) | |||
476 | static void ahci_fill_sg(struct ata_queued_cmd *qc) | 484 | static void ahci_fill_sg(struct ata_queued_cmd *qc) |
477 | { | 485 | { |
478 | struct ahci_port_priv *pp = qc->ap->private_data; | 486 | struct ahci_port_priv *pp = qc->ap->private_data; |
479 | unsigned int i; | 487 | struct scatterlist *sg; |
488 | struct ahci_sg *ahci_sg; | ||
480 | 489 | ||
481 | VPRINTK("ENTER\n"); | 490 | VPRINTK("ENTER\n"); |
482 | 491 | ||
483 | /* | 492 | /* |
484 | * Next, the S/G list. | 493 | * Next, the S/G list. |
485 | */ | 494 | */ |
486 | for (i = 0; i < qc->n_elem; i++) { | 495 | ahci_sg = pp->cmd_tbl_sg; |
487 | u32 sg_len; | 496 | ata_for_each_sg(sg, qc) { |
488 | dma_addr_t addr; | 497 | dma_addr_t addr = sg_dma_address(sg); |
489 | 498 | u32 sg_len = sg_dma_len(sg); | |
490 | addr = sg_dma_address(&qc->sg[i]); | 499 | |
491 | sg_len = sg_dma_len(&qc->sg[i]); | 500 | ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); |
492 | 501 | ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); | |
493 | pp->cmd_tbl_sg[i].addr = cpu_to_le32(addr & 0xffffffff); | 502 | ahci_sg->flags_size = cpu_to_le32(sg_len - 1); |
494 | pp->cmd_tbl_sg[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); | 503 | ahci_sg++; |
495 | pp->cmd_tbl_sg[i].flags_size = cpu_to_le32(sg_len - 1); | ||
496 | } | 504 | } |
497 | } | 505 | } |
498 | 506 | ||