summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2005-08-17 15:00:33 +0000
committersos <sos@FreeBSD.org>2005-08-17 15:00:33 +0000
commit1a7d21ba0c1724e113d2ec0ab81e9402b2c52a05 (patch)
tree38b1d32592a63f6ff4d2ba100c795d72d75927d4 /sys/dev
parent705a1ddfe6ef68db01049c1c375c4fe446d65ce0 (diff)
downloadFreeBSD-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.c69
-rw-r--r--sys/dev/ata/ata-all.h3
-rw-r--r--sys/dev/ata/ata-chipset.c48
-rw-r--r--sys/dev/ata/ata-disk.c4
-rw-r--r--sys/dev/ata/ata-lowlevel.c8
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;
OpenPOWER on IntegriCloud