diff options
author | sos <sos@FreeBSD.org> | 2005-08-17 15:00:33 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2005-08-17 15:00:33 +0000 |
commit | 1a7d21ba0c1724e113d2ec0ab81e9402b2c52a05 (patch) | |
tree | 38b1d32592a63f6ff4d2ba100c795d72d75927d4 /sys/dev | |
parent | 705a1ddfe6ef68db01049c1c375c4fe446d65ce0 (diff) | |
download | FreeBSD-src-1a7d21ba0c1724e113d2ec0ab81e9402b2c52a05.zip FreeBSD-src-1a7d21ba0c1724e113d2ec0ab81e9402b2c52a05.tar.gz |
Add support for working around controllers that cannot do DMA in 48bit mode.
The workaround use PIO mode above ~137GB to allow using the disk.
Add the Acer chips with rev < 0xc4 as first candidate.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ata/ata-all.c | 69 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.h | 3 | ||||
-rw-r--r-- | sys/dev/ata/ata-chipset.c | 48 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 4 | ||||
-rw-r--r-- | sys/dev/ata/ata-lowlevel.c | 8 |
5 files changed, 97 insertions, 35 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 03ec49a..3db5df7 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -699,11 +699,11 @@ ata_default_registers(device_t dev) ch->r_io[ATA_ALTSTAT].offset = ch->r_io[ATA_CONTROL].offset; } -u_int8_t +void ata_modify_if_48bit(struct ata_request *request) { + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); struct ata_device *atadev = device_get_softc(request->dev); - u_int8_t command = request->u.ata.command; atadev->flags &= ~ATA_D_48BIT_ACTIVE; @@ -712,31 +712,72 @@ ata_modify_if_48bit(struct ata_request *request) atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { /* translate command into 48bit version */ - switch (command) { + switch (request->u.ata.command) { case ATA_READ: - command = ATA_READ48; break; + request->u.ata.command = ATA_READ48; + break; case ATA_READ_MUL: - command = ATA_READ_MUL48; break; + request->u.ata.command = ATA_READ_MUL48; + break; case ATA_READ_DMA: - command = ATA_READ_DMA48; break; + if (ch->flags & ATA_NO_48BIT_DMA) { + if (request->transfersize > DEV_BSIZE) + request->u.ata.command = ATA_READ_MUL48; + else + request->u.ata.command = ATA_READ48; + request->flags &= ~ATA_R_DMA; + } + else + request->u.ata.command = ATA_READ_DMA48; + break; case ATA_READ_DMA_QUEUED: - command = ATA_READ_DMA_QUEUED48; break; + if (ch->flags & ATA_NO_48BIT_DMA) { + if (request->transfersize > DEV_BSIZE) + request->u.ata.command = ATA_READ_MUL48; + else + request->u.ata.command = ATA_READ48; + request->flags &= ~ATA_R_DMA; + } + else + request->u.ata.command = ATA_READ_DMA_QUEUED48; + break; case ATA_WRITE: - command = ATA_WRITE48; break; + request->u.ata.command = ATA_WRITE48; + break; case ATA_WRITE_MUL: - command = ATA_WRITE_MUL48; break; + request->u.ata.command = ATA_WRITE_MUL48; + break; case ATA_WRITE_DMA: - command = ATA_WRITE_DMA48; break; + if (ch->flags & ATA_NO_48BIT_DMA) { + if (request->transfersize > DEV_BSIZE) + request->u.ata.command = ATA_WRITE_MUL48; + else + request->u.ata.command = ATA_WRITE48; + request->flags &= ~ATA_R_DMA; + } + else + request->u.ata.command = ATA_WRITE_DMA48; + break; case ATA_WRITE_DMA_QUEUED: - command = ATA_WRITE_DMA_QUEUED48; break; + if (ch->flags & ATA_NO_48BIT_DMA) { + if (request->transfersize > DEV_BSIZE) + request->u.ata.command = ATA_WRITE_MUL48; + else + request->u.ata.command = ATA_WRITE48; + request->u.ata.command = ATA_WRITE48; + request->flags &= ~ATA_R_DMA; + } + else + request->u.ata.command = ATA_WRITE_DMA_QUEUED48; + break; case ATA_FLUSHCACHE: - command = ATA_FLUSHCACHE48; break; + request->u.ata.command = ATA_FLUSHCACHE48; + break; default: - return command; + return; } atadev->flags |= ATA_D_48BIT_ACTIVE; } - return command; } void diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index aaa3c14..bce3497 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -493,6 +493,7 @@ struct ata_channel { #define ATA_NO_SLAVE 0x01 #define ATA_USE_16BIT 0x02 #define ATA_ATAPI_DMA_RO 0x04 +#define ATA_NO_48BIT_DMA 0x08 int devices; /* what is present */ #define ATA_ATA_MASTER 0x01 @@ -535,7 +536,7 @@ int ata_resume(device_t dev); int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data); int ata_identify(device_t dev); void ata_default_registers(device_t dev); -u_int8_t ata_modify_if_48bit(struct ata_request *request); +void ata_modify_if_48bit(struct ata_request *request); void ata_udelay(int interval); char *ata_mode2str(int mode); int ata_pmode(struct ata_params *ap); diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index 8156ce6..0749f98 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -74,6 +74,7 @@ static void ata_acard_850_setmode(device_t dev, int mode); static void ata_acard_86X_setmode(device_t dev, int mode); static int ata_ali_chipinit(device_t dev); static int ata_ali_allocate(device_t dev); +static int ata_ali_sata_allocate(device_t dev); static void ata_ali_setmode(device_t dev, int mode); static int ata_amd_chipinit(device_t dev); static int ata_cyrix_chipinit(device_t dev); @@ -372,7 +373,7 @@ ata_ahci_allocate(device_t dev) /* XXX SOS this is a hack to satisfy various legacy cruft */ ch->r_io[ATA_CYL_LSB].res = ctlr->r_res2; ch->r_io[ATA_CYL_LSB].offset = ATA_AHCI_P_SIG + 1 + offset; - ch->r_io[ATA_CYL_LSB].res = ctlr->r_res2; + ch->r_io[ATA_CYL_MSB].res = ctlr->r_res2; ch->r_io[ATA_CYL_MSB].offset = ATA_AHCI_P_SIG + 3 + offset; ch->r_io[ATA_STATUS].res = ctlr->r_res2; ch->r_io[ATA_STATUS].offset = ATA_AHCI_P_TFD + offset; @@ -424,9 +425,11 @@ ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request) int idx = 0; /* XXX SOS add ATAPI commands support later */ + ata_modify_if_48bit(request); + fis[idx++] = 0x27; /* host to device */ fis[idx++] = 0x80; /* command FIS (note PM goes here) */ - fis[idx++] = ata_modify_if_48bit(request); + fis[idx++] = request->u.ata.command; fis[idx++] = request->u.ata.feature; fis[idx++] = request->u.ata.lba; @@ -870,7 +873,7 @@ ata_ali_chipinit(device_t dev) pci_write_config(dev, PCIR_COMMAND, pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2); ctlr->channels = ctlr->chip->cfg1; - ctlr->allocate = ata_ali_allocate; + ctlr->allocate = ata_ali_sata_allocate; ctlr->setmode = ata_sata_setmode; break; @@ -881,6 +884,13 @@ ata_ali_chipinit(device_t dev) /* enable cable detection and UDMA support on newer chips */ pci_write_config(dev, 0x4b, pci_read_config(dev, 0x4b, 1) | 0x09, 1); + + /* only chips with revision > 0xc4 can do 48bit DMA */ + if (ctlr->chip->chiprev <= 0xc4) + device_printf(dev, + "using PIO transfers above 137GB as workaround for " + "48bit DMA access bug, expect reduced performance\n"); + ctlr->allocate = ata_ali_allocate; ctlr->setmode = ata_ali_setmode; break; @@ -897,6 +907,21 @@ ata_ali_chipinit(device_t dev) static int ata_ali_allocate(device_t dev) { + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + + /* setup the usual register normal pci style */ + ata_pci_allocate(dev); + + if (ctlr->chip->chiprev <= 0xc4) + ch->flags |= ATA_NO_48BIT_DMA; + + return 0; +} + +static int +ata_ali_sata_allocate(device_t dev) +{ device_t parent = device_get_parent(dev); struct ata_pci_controller *ctlr = device_get_softc(parent); struct ata_channel *ch = device_get_softc(dev); @@ -1616,10 +1641,8 @@ ata_intel_31244_command(struct ata_request *request) { struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); struct ata_device *atadev = device_get_softc(request->dev); - u_int8_t command; u_int64_t lba; - command = ata_modify_if_48bit(request); if (!(atadev->flags & ATA_D_48BIT_ACTIVE)) return (ata_generic_command(request)); @@ -1630,13 +1653,13 @@ ata_intel_31244_command(struct ata_request *request) ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count); ATA_IDX_OUTW(ch, ATA_SECTOR, ((lba >> 16) & 0xff00) | (lba & 0x00ff)); - ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((lba >> 24) & 0xff00) | ((lba >> 8) & - 0x00ff)); - ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((lba >> 32) & 0xff00) | ((lba >> 16) & - 0x00ff)); + ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((lba >> 24) & 0xff00) | + ((lba >> 8) & 0x00ff)); + ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((lba >> 32) & 0xff00) | + ((lba >> 16) & 0x00ff)); /* issue command to controller */ - ATA_IDX_OUTB(ch, ATA_COMMAND, command); + ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command); return 0; } @@ -2803,7 +2826,6 @@ static int ata_promise_apkt(u_int8_t *bytep, struct ata_request *request) { struct ata_device *atadev = device_get_softc(request->dev); - u_int8_t command; int i = 12; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_PDC_WAIT_NBUSY|ATA_DRIVE; @@ -2811,8 +2833,6 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request) bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_CTL; bytep[i++] = ATA_A_4BIT; - command = ata_modify_if_48bit(request); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_FEATURE; bytep[i++] = request->u.ata.feature >> 8; @@ -2848,7 +2868,7 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request) ATA_D_IBM | atadev->unit | ((request->u.ata.lba >> 24)&0xf); } bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_END | ATA_COMMAND; - bytep[i++] = command; + bytep[i++] = request->u.ata.command; return i; } diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 9aed614..1a79dc1 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -244,7 +244,7 @@ ad_strategy(struct bio *bp) request->u.ata.command = ATA_READ_DMA; request->flags |= ATA_R_DMA; } - else if (atadev->max_iosize > DEV_BSIZE) + else if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_READ_MUL; else request->u.ata.command = ATA_READ; @@ -255,7 +255,7 @@ ad_strategy(struct bio *bp) request->u.ata.command = ATA_WRITE_DMA; request->flags |= ATA_R_DMA; } - else if (atadev->max_iosize > DEV_BSIZE) + else if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_WRITE_MUL; else request->u.ata.command = ATA_WRITE; diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index 2a40e00..2751e87 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -83,6 +83,9 @@ ata_begin_transaction(struct ata_request *request) (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE))) request->flags &= ~ATA_R_DMA; + /* check for 48 bit access and convert if needed */ + ata_modify_if_48bit(request); + switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) { /* ATA PIO data transfer and control commands */ @@ -710,8 +713,6 @@ ata_generic_command(struct ata_request *request) ATA_PROTO_ATAPI_12 ? 6 : 8); } else { - u_int8_t command = ata_modify_if_48bit(request); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature >> 8); ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); @@ -726,7 +727,6 @@ ata_generic_command(struct ata_request *request) ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit); } else { - command = request->u.ata.command; ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count); if (atadev->flags & ATA_D_USE_CHS) { @@ -760,7 +760,7 @@ ata_generic_command(struct ata_request *request) } /* issue command to controller */ - ATA_IDX_OUTB(ch, ATA_COMMAND, command); + ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command); } return 0; |