The Silicon Image 311x controllers support an alternate scatter/gather
table format that eliminates the 64k DMA boundary issue that plagues
normal PCI IDE DMA.

Turning on this feature simply involves using alternate BMDMA Command 
and Status registers, and then using an alternate scatter/gather table
format.

Here is a COMPLETELY UNTESTED patch to turn this feature on.

This feature is described in the chapter "Second PCI Bus Master Registers
Usage" of the public 3112 docs at
http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2


diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -67,6 +67,8 @@ enum {
        SIL_INTR_STEERING       = (1 << 1),
        SIL_QUIRK_MOD15WRITE    = (1 << 0),
        SIL_QUIRK_UDMA5MAX      = (1 << 1),
+
+       SIL_DMA_BOUNDARY        = 0xffffffffU,
 };
 
 static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id 
*ent);
@@ -74,6 +76,8 @@ static void sil_dev_config(struct ata_po
 static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void sil_post_set_mode (struct ata_port *ap);
+static void sil_qc_prep(struct ata_queued_cmd *qc);
+
 
 static struct pci_device_id sil_pci_tbl[] = {
        { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
@@ -126,13 +130,13 @@ static Scsi_Host_Template sil_sht = {
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
-       .sg_tablesize           = LIBATA_MAX_PRD,
+       .sg_tablesize           = ATA_MAX_PRD,
        .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
        .proc_name              = DRV_NAME,
-       .dma_boundary           = ATA_DMA_BOUNDARY,
+       .dma_boundary           = SIL_DMA_BOUNDARY,
        .slave_configure        = ata_scsi_slave_config,
        .bios_param             = ata_std_bios_param,
        .ordered_flush          = 1,
@@ -152,7 +156,7 @@ static struct ata_port_operations sil_op
        .bmdma_start            = ata_bmdma_start,
        .bmdma_stop             = ata_bmdma_stop,
        .bmdma_status           = ata_bmdma_status,
-       .qc_prep                = ata_qc_prep,
+       .qc_prep                = sil_qc_prep,
        .qc_issue               = ata_qc_issue_prot,
        .eng_timeout            = ata_eng_timeout,
        .irq_handler            = ata_interrupt,
@@ -197,10 +201,10 @@ static const struct {
        unsigned long xfer_mode;/* data transfer mode register */
 } sil_port[] = {
        /* port 0 ... */
-       { 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4 },
-       { 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4 },
-       { 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4 },
-       { 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4 },
+       { 0x80, 0x8A, 0x10, 0x100, 0x148, 0xb4 },
+       { 0xC0, 0xCA, 0x18, 0x180, 0x1c8, 0xf4 },
+       { 0x280, 0x28A, 0x210, 0x300, 0x348, 0x2b4 },
+       { 0x2C0, 0x2CA, 0x218, 0x380, 0x3c8, 0x2f4 },
        /* ... port 3 */
 };
 
@@ -210,6 +214,37 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
+
+static inline void sil_fill_sg(struct ata_queued_cmd *qc)
+{
+       struct scatterlist *sg = qc->sg;
+       struct ata_port *ap = qc->ap;
+       unsigned int idx, nelem;
+
+       assert(sg != NULL);
+       assert(qc->n_elem > 0);
+
+       idx = 0;
+       for (nelem = qc->n_elem; nelem; nelem--,sg++) {
+               u32 addr = sg_dma_address(sg);
+               u32 sg_len = sg_dma_len(sg);
+
+               ap->prd[idx].addr = cpu_to_le32(addr);
+               ap->prd[idx].flags_len = cpu_to_le32(sg_len);
+       }
+
+       if (idx)
+               ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+static void sil_qc_prep(struct ata_queued_cmd *qc)
+{
+       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+               return;
+
+       sil_fill_sg(qc);
+}
+
 static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
 {
        u8 cache_line = 0;
-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to