summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ata/ata-all.c39
-rw-r--r--sys/dev/ata/ata-all.h13
-rw-r--r--sys/dev/ata/ata-disk.c42
-rw-r--r--sys/dev/ata/ata-disk.h1
-rw-r--r--sys/dev/ata/ata-dma.c4
5 files changed, 65 insertions, 34 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index 6f93312..e8b66aa 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -124,7 +124,7 @@ ata_isa_probe(device_t dev)
/* alloctate the altport range */
if (bus_get_resource(dev, SYS_RES_IOPORT, 1, &tmp, &tmp)) {
bus_set_resource(dev, SYS_RES_IOPORT, 1,
- rman_get_start(port) + ATA_ALTPORT,
+ rman_get_start(port) + ATA_ALTOFFSET,
ATA_ALTIOSIZE);
}
bus_release_resource(dev, SYS_RES_IOPORT, 0, port);
@@ -172,7 +172,7 @@ ata_pccard_probe(device_t dev)
*/
if (len <= ATA_IOSIZE) {
bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
- rman_get_start(port) + ATA_ALTPORT, ATA_ALTIOSIZE);
+ rman_get_start(port) + ATA_ALTOFFSET, ATA_ALTIOSIZE);
}
bus_release_resource(dev, SYS_RES_IOPORT, 0, port);
scp->unit = device_get_unit(dev);
@@ -538,7 +538,7 @@ ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
case ATA_ALTADDR_RID:
if (masterdev) {
myrid = 0;
- start = (unit == 0 ? IO_WD1 : IO_WD2) + ATA_ALTPORT;
+ start = (unit == 0 ? IO_WD1 : IO_WD2) + ATA_ALTOFFSET;
end = start + ATA_ALTIOSIZE - 1;
count = ATA_ALTIOSIZE;
}
@@ -787,10 +787,14 @@ ata_probe(device_t dev)
rid = ATA_ALTADDR_RID;
altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
ATA_ALTIOSIZE, RF_ACTIVE);
- if (altio)
- altioaddr = rman_get_start(altio);
+ if (altio) {
+ if (pci_get_progif(device_get_parent(dev)) & PCIP_STORAGE_IDE_MASTERDEV)
+ altioaddr = rman_get_start(altio);
+ else
+ altioaddr = rman_get_start(altio) + 0x02;
+ }
else
- altioaddr = ioaddr + ATA_IOSIZE - 2; /* pccard ?? XXX */
+ altioaddr = ioaddr + ATA_IOSIZE;
rid = ATA_BMADDR_RID;
bmio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
@@ -969,7 +973,7 @@ ata_getparam(struct ata_softc *scp, int device, u_int8_t command)
DELAY(1);
/* enable interrupt */
- outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
+ outb(scp->altioaddr, ATA_A_4BIT);
DELAY(1);
/* apparently some devices needs this repeated */
@@ -1107,7 +1111,7 @@ ata_intr(void *data)
DELAY(1);
/* if drive is busy it didn't interrupt */
- if (inb(scp->altioaddr + ATA_ALTSTAT) & ATA_S_BUSY)
+ if (inb(scp->altioaddr) & ATA_S_BUSY)
return;
/* clear interrupt and get status */
@@ -1226,9 +1230,9 @@ ata_reset(struct ata_softc *scp, int *mask)
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(1);
inb(scp->ioaddr + ATA_STATUS);
- outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_IDS | ATA_A_RESET);
+ outb(scp->altioaddr, ATA_A_IDS | ATA_A_RESET);
DELAY(10000);
- outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_IDS);
+ outb(scp->altioaddr, ATA_A_IDS);
DELAY(10000);
inb(scp->ioaddr + ATA_ERROR);
DELAY(3000);
@@ -1269,7 +1273,7 @@ ata_reset(struct ata_softc *scp, int *mask)
DELAY(100);
}
DELAY(1);
- outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
+ outb(scp->altioaddr, ATA_A_4BIT);
if (status0 & ATA_S_BUSY)
*mask &= ~0x01;
if (status1 & ATA_S_BUSY)
@@ -1368,17 +1372,18 @@ int
ata_wait(struct ata_softc *scp, int device, u_int8_t mask)
{
int timeout = 0;
+ int statio = scp->ioaddr + ATA_STATUS;
DELAY(1);
while (timeout < 5000000) { /* timeout 5 secs */
- scp->status = inb(scp->altioaddr + ATA_ALTSTAT);
+ scp->status = inb(statio);
/* if drive fails status, reselect the drive just to be sure */
if (scp->status == 0xff) {
ata_printf(scp, device, "no status, reselecting device\n");
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
DELAY(1);
- scp->status = inb(scp->altioaddr + ATA_ALTSTAT);
+ scp->status = inb(statio);
}
/* are we done ? */
@@ -1404,7 +1409,7 @@ ata_wait(struct ata_softc *scp, int device, u_int8_t mask)
/* Wait 50 msec for bits wanted. */
timeout = 5000;
while (timeout--) {
- scp->status = inb(scp->altioaddr + ATA_ALTSTAT);
+ scp->status = inb(statio);
if ((scp->status & mask) == mask) {
if (scp->status & ATA_S_ERROR)
scp->error = inb(scp->ioaddr + ATA_ERROR);
@@ -1430,7 +1435,7 @@ ata_command(struct ata_softc *scp, int device, u_int8_t command,
/* disable interrupt from device */
if (scp->flags & ATA_QUEUED)
- outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_IDS | ATA_A_4BIT);
+ outb(scp->altioaddr, ATA_A_IDS | ATA_A_4BIT);
/* select device */
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
@@ -1461,7 +1466,7 @@ ata_command(struct ata_softc *scp, int device, u_int8_t command,
/* enable interrupt */
if (scp->flags & ATA_QUEUED)
- outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
+ outb(scp->altioaddr, ATA_A_4BIT);
if (await(PRIBIO, 10 * hz)) {
ata_printf(scp, device, "ata_command: timeout waiting for intr\n");
@@ -1497,7 +1502,7 @@ ata_command(struct ata_softc *scp, int device, u_int8_t command,
}
/* enable interrupt */
if (scp->flags & ATA_QUEUED)
- outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
+ outb(scp->altioaddr, ATA_A_4BIT);
return error;
}
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index 3ab34ce..8b5bdc4 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -74,13 +74,17 @@
#define ATA_C_READ_DMA 0xc8 /* read w/DMA command */
#define ATA_C_WRITE_DMA 0xca /* write w/DMA command */
#define ATA_C_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */
+#define ATA_C_FLUSHCACHE 0xe7 /* flush cache to disk */
#define ATA_C_ATA_IDENTIFY 0xec /* get ATA params */
#define ATA_C_SETFEATURES 0xef /* features command */
#define ATA_C_F_SETXFER 0x03 /* set transfer mode */
#define ATA_C_F_ENAB_WCACHE 0x02 /* enable write cache */
-#define ATA_C_F_ENAB_SRVIRQ 0x5e /* enable service interrupt */
+#define ATA_C_F_DIS_WCACHE 0x82 /* disable write cache */
#define ATA_C_F_ENAB_RCACHE 0xaa /* enable readahead cache */
+#define ATA_C_F_DIS_RCACHE 0x55 /* disable readahead cache */
+#define ATA_C_F_ENAB_RELIRQ 0x5d /* enable release interrupt */
#define ATA_C_F_DIS_RELIRQ 0xdd /* disable release interrupt */
+#define ATA_C_F_ENAB_SRVIRQ 0x5e /* enable service interrupt */
#define ATA_C_F_DIS_SRVIRQ 0xde /* disable service interrupt */
#define ATA_STATUS 0x07 /* status register */
@@ -95,15 +99,12 @@
#define ATA_S_READY 0x40 /* drive ready */
#define ATA_S_BUSY 0x80 /* busy */
-#define ATA_ALTSTAT 0x02 /* alternate status register */
-#define ATA_ALTCTRL 0X02 /* alternate device control */
+#define ATA_ALTOFFSET 0x206 /* alternate registers offset */
+#define ATA_ALTIOSIZE 0x01 /* alternate registers size */
#define ATA_A_IDS 0x02 /* disable interrupts */
#define ATA_A_RESET 0x04 /* RESET controller */
#define ATA_A_4BIT 0x08 /* 4 head bits */
-#define ATA_ALTPORT 0x204 /* alternate registers offset */
-#define ATA_ALTIOSIZE 0x01 /* alternate registers size */
-
/* misc defines */
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x10
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c
index aa97a6d..6391982 100644
--- a/sys/dev/ata/ata-disk.c
+++ b/sys/dev/ata/ata-disk.c
@@ -1,3 +1,4 @@
+#define ATA_FLUSHCACHE_ON
/*-
* Copyright (c) 1998,1999,2000 Søren Schmidt
* All rights reserved.
@@ -316,7 +317,17 @@ ad_start(struct ad_softc *adp)
if (!bp)
return;
- /* if tagged queueing enabled get free tag */
+#ifdef ATA_FLUSHCACHE_ON
+ /*
+ * if BIO_ORDERED is set cache should be flushed, if there are
+ * any outstanding requests, hold off and wait for them to finish
+ */
+ if (adp->flags & AD_F_TAG_ENABLED &&
+ bp->bio_flags & BIO_ORDERED && adp->outstanding > 0)
+ return;
+#endif
+
+ /* if tagged queueing enabled get next free tag */
if (adp->flags & AD_F_TAG_ENABLED) {
while (tag <= adp->num_tags && adp->tags[tag])
tag++;
@@ -337,7 +348,8 @@ ad_start(struct ad_softc *adp)
request->bytecount = bp->bio_bcount;
request->data = bp->bio_data;
request->tag = tag;
- request->flags = (bp->bio_cmd == BIO_READ) ? ADR_F_READ : 0;
+ if (bp->bio_cmd == BIO_READ)
+ request->flags |= ADR_F_READ;
if (adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA) {
if (!(request->dmatab = ata_dmaalloc(adp->controller, adp->unit)))
adp->controller->mode[ATA_DEV(adp->unit)] = ATA_PIO;
@@ -442,6 +454,8 @@ ad_transfer(struct ad_request *request)
}
#if 0
/*
+ * wait for data transfer phase
+ *
* well this should be here acording to specs, but
* promise controllers doesn't like it, they lockup!
* thats probably why tags doesn't work on the promise
@@ -455,12 +469,6 @@ ad_transfer(struct ad_request *request)
#endif
}
- /* check for possible error from controller */
- if (adp->controller->status & ATA_S_ERROR) {
- printf("ad%d: error executing transfer cmd\n", adp->lun);
- goto transfer_failed;
- }
-
/* start transfer, return and wait for interrupt */
ata_dmastart(adp->controller, adp->unit,
request->dmatab, request->flags & ADR_F_READ);
@@ -534,6 +542,9 @@ ad_interrupt(struct ad_request *request)
struct ad_softc *adp = request->device;
int dma_stat = 0;
+ if (request->flags & ADR_F_FLUSHCACHE)
+ goto finish;
+
/* finish DMA transfer */
if (request->flags & ADR_F_DMA_USED)
dma_stat = ata_dmadone(adp->controller);
@@ -632,6 +643,18 @@ ad_interrupt(struct ad_request *request)
untimeout((timeout_t *)ad_timeout, request, request->timeout_handle);
request->bp->bio_resid = request->bytecount;
+
+#ifdef ATA_FLUSHCACHE_ON
+ if (request->bp->bio_flags & BIO_ORDERED) {
+ request->flags |= ADR_F_FLUSHCACHE;
+ if (ata_command(adp->controller, adp->unit, ATA_C_FLUSHCACHE,
+ 0, 0, 0, 0, 0, ATA_IMMEDIATE))
+ printf("ad%d: flushing cache failed\n", adp->lun);
+ else
+ return ATA_OP_CONTINUES;
+ }
+#endif
+finish:
devstat_end_transaction_bio(&adp->stats, request->bp);
biodone(request->bp);
ad_free(request);
@@ -670,10 +693,11 @@ ad_service(struct ad_softc *adp, int change)
DELAY(1);
}
}
- adp->controller->status = inb(adp->controller->altioaddr + ATA_ALTSTAT);
+ adp->controller->status = inb(adp->controller->altioaddr);
/* do we have a SERVICE request from the drive ? */
if (adp->flags & AD_F_TAG_ENABLED &&
+ adp->outstanding > 0 &&
adp->controller->status & ATA_S_SERVICE) {
struct ad_request *request;
int tag;
diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h
index 13ea2f9..37b0ced 100644
--- a/sys/dev/ata/ata-disk.h
+++ b/sys/dev/ata/ata-disk.h
@@ -43,6 +43,7 @@ struct ad_request {
#define ADR_F_DMA_USED 0x0004
#define ADR_F_QUEUED 0x0008
#define ADR_F_FORCE_PIO 0x0010
+#define ADR_F_FLUSHCACHE 0x0020
caddr_t data; /* pointer to data buf */
struct bio *bp; /* associated bio ptr */
diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c
index 3385b67..46ebbd1 100644
--- a/sys/dev/ata/ata-dma.c
+++ b/sys/dev/ata/ata-dma.c
@@ -524,7 +524,7 @@ via_82c586:
(device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE))
break;
- if (udmamode >=5 &&
+ if (udmamode >= 5 &&
(scp->chiptype == 0x4d30105a || scp->chiptype == 0x0d30105a) &&
!(pci_read_config(parent, 0x50, 2)&(scp->unit ? 1<<11 : 1<<10))) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
@@ -539,7 +539,7 @@ via_82c586:
return;
}
}
- if (udmamode >=4 && (scp->chiptype == 0x4d38105a ||
+ if (udmamode >= 4 && (scp->chiptype == 0x4d38105a ||
scp->chiptype == 0x4d30105a || scp->chiptype == 0x0d30105a) &&
!(pci_read_config(parent, 0x50, 2)&(scp->unit ? 1<<11 : 1<<10))) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
OpenPOWER on IntegriCloud