summaryrefslogtreecommitdiff
path: root/sys/dev/ata/ata-all.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata/ata-all.c')
-rw-r--r--sys/dev/ata/ata-all.c267
1 files changed, 162 insertions, 105 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index 68782d57ba69..d82ad669ce05 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -81,11 +81,12 @@ static int ata_detach(device_t);
static int ata_resume(device_t);
static void ata_boot_attach(void);
static void ata_intr(void *);
-static int32_t ata_getparam(struct ata_softc *, int32_t, u_int8_t);
-static int8_t *active2str(int32_t);
-static void bswap(int8_t *, int32_t);
-static void btrim(int8_t *, int32_t);
-static void bpack(int8_t *, int8_t *, int32_t);
+static int ata_getparam(struct ata_softc *, int, u_int8_t);
+static int ata_service(struct ata_softc *);
+static char *active2str(int);
+static void bswap(int8_t *, int);
+static void btrim(int8_t *, int);
+static void bpack(int8_t *, int8_t *, int);
/* local vars */
static devclass_t ata_devclass;
@@ -204,11 +205,11 @@ struct ata_pci_softc {
struct resource bmio_1;
struct resource bmio_2;
struct resource *irq;
- int32_t irqcnt;
+ int irqcnt;
};
-int32_t
-ata_find_dev(device_t dev, int32_t type, int32_t revid)
+int
+ata_find_dev(device_t dev, u_int32_t type, u_int32_t revid)
{
device_t *children, child;
int nchildren, i;
@@ -284,6 +285,9 @@ ata_pci_match(device_t dev)
return "Cypress 82C693 ATA controller";
break;
+ case 0x01021078:
+ return "Cyrix 5530 ATA33 controller";
+
case 0x74091022:
return "AMD 756 ATA66 controller";
@@ -293,6 +297,7 @@ ata_pci_match(device_t dev)
case 0x4d38105a:
return "Promise ATA66 controller";
+ case 0x0d30105a:
case 0x4d30105a:
return "Promise ATA100 controller";
@@ -318,9 +323,6 @@ ata_pci_match(device_t dev)
case 0x06401095:
return "CMD 640 ATA controller !WARNING! buggy chip data loss possible";
- case 0x01021078:
- return "Cyrix 5530 ATA controller (generic mode)";
-
/* unknown chipsets, try generic DMA if it seems possible */
default:
if (pci_get_class(dev) == PCIC_STORAGE &&
@@ -393,7 +395,7 @@ ata_pci_attach(device_t dev)
}
else {
if (type == 0x4d33105a || type == 0x4d38105a ||
- type == 0x4d30105a || type == 0x00041103) {
+ type == 0x4d30105a || type == 0x0d30105a || type == 0x00041103) {
/* Promise and HighPoint controllers support busmastering DMA */
rid = 0x20;
sc->bmio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
@@ -411,21 +413,23 @@ ata_pci_attach(device_t dev)
(pci_read_config(dev, 0x53, 1) & ~0x01) | 0x02, 1);
break;
- case 0x4d38105a: /* Promise 66's need their clock changed */
- case 0x4d30105a: /* Promise 100's too */
+ case 0x4d38105a: /* Promise 66 & 100 need their clock changed */
+ case 0x4d30105a:
+ case 0x0d30105a:
outb(rman_get_start(sc->bmio) + 0x11,
inb(rman_get_start(sc->bmio) + 0x11) | 0x0a);
/* FALLTHROUGH */
- case 0x4d33105a: /* Promise's need burst mode to be turned on */
+ case 0x4d33105a: /* Promise (all) need burst mode to be turned on */
outb(rman_get_start(sc->bmio) + 0x1f,
inb(rman_get_start(sc->bmio) + 0x1f) | 0x01);
break;
- case 0x00041103: /* HighPoint's need to turn off interrupt prediction */
+ case 0x00041103: /* HighPoint */
switch (pci_get_revid(dev)) {
case 0x00:
case 0x01:
+ /* turn off interrupt prediction */
pci_write_config(dev, 0x51,
(pci_read_config(dev, 0x51, 1) & ~0x80), 1);
break;
@@ -433,10 +437,12 @@ ata_pci_attach(device_t dev)
case 0x02:
case 0x03:
case 0x04:
+ /* turn off interrupt prediction */
pci_write_config(dev, 0x51,
(pci_read_config(dev, 0x51, 1) & ~0x02), 1);
pci_write_config(dev, 0x55,
(pci_read_config(dev, 0x55, 1) & ~0x02), 1);
+ /* turn on interrupts */
pci_write_config(dev, 0x5a,
(pci_read_config(dev, 0x5a, 1) & ~0x10), 1);
@@ -761,8 +767,8 @@ ata_probe(device_t dev)
struct resource *altio = 0;
struct resource *bmio = 0;
int rid;
- int32_t ioaddr, altioaddr, bmaddr;
- int32_t mask = 0;
+ u_int32_t ioaddr, altioaddr, bmaddr;
+ int mask = 0;
u_int8_t status0, status1;
if (!scp || scp->flags & ATA_ATTACHED)
@@ -786,7 +792,7 @@ ata_probe(device_t dev)
if (altio)
altioaddr = rman_get_start(altio);
else
- altioaddr = ioaddr + ATA_IOSIZE;
+ altioaddr = ioaddr + ATA_IOSIZE - 2; /* pccard ?? XXX */
rid = ATA_BMADDR_RID;
bmio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
@@ -953,8 +959,8 @@ ata_resume(device_t dev)
return 0;
}
-static int32_t
-ata_getparam(struct ata_softc *scp, int32_t device, u_int8_t command)
+static int
+ata_getparam(struct ata_softc *scp, int device, u_int8_t command)
{
struct ata_params *ata_parm;
int8_t buffer[DEV_BSIZE];
@@ -965,7 +971,7 @@ ata_getparam(struct ata_softc *scp, int32_t device, u_int8_t command)
DELAY(1);
/* enable interrupt */
- outb(scp->altioaddr, ATA_A_4BIT);
+ outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
DELAY(1);
/* apparently some devices needs this repeated */
@@ -1006,7 +1012,7 @@ static void
ata_boot_attach(void)
{
struct ata_softc *scp;
- int32_t ctlr;
+ int ctlr;
/*
* run through all ata devices and look for real ATA & ATAPI devices
@@ -1063,7 +1069,7 @@ static void
ata_intr(void *data)
{
struct ata_softc *scp = (struct ata_softc *)data;
- u_int8_t dmastat;
+ u_int8_t dmastat = 0;
/*
* since we might share the IRQ with another device, and in some
@@ -1073,14 +1079,16 @@ ata_intr(void *data)
switch (scp->chiptype) {
#if NPCI > 0
case 0x00041103: /* HighPoint HPT366/368/370 */
- if (!((dmastat = ata_dmastatus(scp)) & ATA_BMSTAT_INTERRUPT))
+ if (((dmastat = ata_dmastatus(scp)) &
+ (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != ATA_BMSTAT_INTERRUPT)
return;
outb(scp->bmaddr + ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT);
break;
- case 0x4d33105a: /* Promise 33's */
- case 0x4d38105a: /* Promise 66's */
- case 0x4d30105a: /* Promise 100's */
+ case 0x4d33105a: /* Promise Ultra/Fasttrak 33 */
+ case 0x4d38105a: /* Promise Ultra/Fasttrak 66 */
+ case 0x4d30105a: /* Promise Ultra/Fasttrak 100 */
+ case 0x0d30105a: /* Promise OEM ATA100 */
{
struct ata_pci_softc *sc=device_get_softc(device_get_parent(scp->dev));
@@ -1088,37 +1096,39 @@ ata_intr(void *data)
((scp->unit) ? 0x00004000 : 0x00000400)))
return;
}
- /* FALLTHROUGH */
+
#endif
default:
if (scp->flags & ATA_DMA_ACTIVE) {
- if (!((dmastat = ata_dmastatus(scp)) & ATA_BMSTAT_INTERRUPT))
+ if (((dmastat = ata_dmastatus(scp)) &
+ (ATA_BMSTAT_ACTIVE|ATA_BMSTAT_INTERRUPT))!=ATA_BMSTAT_INTERRUPT)
return;
- else
- outb(scp->bmaddr+ATA_BMSTAT_PORT, dmastat|ATA_BMSTAT_INTERRUPT);
+ outb(scp->bmaddr + ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT);
}
}
DELAY(1);
- /* get status, if drive is busy it didn't interrupt so return */
- if ((scp->status = inb(scp->ioaddr + ATA_STATUS)) & ATA_S_BUSY)
+ /* if drive is busy it didn't interrupt */
+ if (inb(scp->altioaddr + ATA_ALTSTAT) & ATA_S_BUSY)
return;
+ /* clear interrupt and get status */
+ scp->status = inb(scp->ioaddr + ATA_STATUS);
+
+ if (scp->status & ATA_S_ERROR)
+ scp->error = inb(scp->ioaddr + ATA_ERROR);
+
/* find & call the responsible driver to process this interrupt */
switch (scp->active) {
#if NATADISK > 0
case ATA_ACTIVE_ATA:
- if (!scp->running)
- return;
- if (ad_interrupt(scp->running) == ATA_OP_CONTINUES)
+ if (!scp->running || ad_interrupt(scp->running) == ATA_OP_CONTINUES)
return;
break;
#endif
#if NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0
case ATA_ACTIVE_ATAPI:
- if (!scp->running)
- return;
- if (atapi_interrupt(scp->running) == ATA_OP_CONTINUES)
+ if (!scp->running || atapi_interrupt(scp->running) == ATA_OP_CONTINUES)
return;
break;
#endif
@@ -1132,20 +1142,29 @@ ata_intr(void *data)
case ATA_REINITING:
return;
- default:
case ATA_IDLE:
-#ifdef ATA_DEBUG
- {
- static int32_t intr_count = 0;
- if (intr_count++ < 10)
- ata_printf(scp, -1, "unwanted interrupt %d status = %02x\n",
- intr_count, scp->status);
+ if (scp->flags & ATA_QUEUED) {
+ scp->active = ATA_ACTIVE;
+ if (ata_service(scp) == ATA_OP_CONTINUES)
+ return;
}
+ /* FALLTHROUGH */
+
+ default:
+#ifdef ATA_DEBUG
+ {
+ static int intr_count = 0;
+
+ if (intr_count++ < 10)
+ ata_printf(scp, -1, "unwanted interrupt %d status = %02x\n",
+ intr_count, scp->status);
+ }
#endif
}
scp->active = ATA_IDLE;
scp->running = NULL;
ata_start(scp);
+ return;
}
void
@@ -1160,6 +1179,7 @@ ata_start(struct ata_softc *scp)
if (scp->active != ATA_IDLE)
return;
+
scp->active = ATA_ACTIVE;
#if NATADISK > 0
@@ -1174,9 +1194,10 @@ ata_start(struct ata_softc *scp)
TAILQ_REMOVE(&scp->ata_queue, ad_request, chain);
scp->active = ATA_ACTIVE_ATA;
scp->running = ad_request;
- ad_transfer(ad_request);
- return;
+ if (ad_transfer(ad_request) == ATA_OP_CONTINUES)
+ return;
}
+
#endif
#if NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0
/* find & call the responsible driver if anything on the ATAPI queue */
@@ -1198,18 +1219,18 @@ ata_start(struct ata_softc *scp)
}
void
-ata_reset(struct ata_softc *scp, int32_t *mask)
+ata_reset(struct ata_softc *scp, int *mask)
{
- int32_t timeout;
+ int timeout;
u_int8_t status0 = ATA_S_BUSY, status1 = ATA_S_BUSY;
/* reset channel */
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(1);
inb(scp->ioaddr + ATA_STATUS);
- outb(scp->altioaddr, ATA_A_IDS | ATA_A_RESET);
+ outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_IDS | ATA_A_RESET);
DELAY(10000);
- outb(scp->altioaddr, ATA_A_IDS);
+ outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_IDS);
DELAY(10000);
inb(scp->ioaddr + ATA_ERROR);
DELAY(3000);
@@ -1250,7 +1271,7 @@ ata_reset(struct ata_softc *scp, int32_t *mask)
DELAY(100);
}
DELAY(1);
- outb(scp->altioaddr, ATA_A_4BIT);
+ outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
if (status0 & ATA_S_BUSY)
*mask &= ~0x01;
if (status1 & ATA_S_BUSY)
@@ -1288,10 +1309,10 @@ ata_reset(struct ata_softc *scp, int32_t *mask)
}
}
-int32_t
+int
ata_reinit(struct ata_softc *scp)
{
- int32_t mask = 0, omask;
+ int mask = 0, omask;
scp->active = ATA_REINITING;
scp->running = NULL;
@@ -1325,21 +1346,41 @@ ata_reinit(struct ata_softc *scp)
return 0;
}
-int32_t
-ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask)
+static int
+ata_service(struct ata_softc *scp)
{
- u_int32_t timeout = 0;
+ /* do we have a SERVICE request from the drive ? */
+ if ((scp->status & (ATA_S_SERVICE|ATA_S_ERROR|ATA_S_DRQ)) == ATA_S_SERVICE){
+ outb(scp->bmaddr + ATA_BMSTAT_PORT, ata_dmastatus(scp) | ATA_BMSTAT_INTERRUPT);
+#if NATADISK > 0
+ if ((inb(scp->ioaddr + ATA_DRIVE) & ATA_SLAVE) == ATA_MASTER) {
+ if ((scp->devices & ATA_ATA_MASTER) && scp->dev_softc[0])
+ return ad_service((struct ad_softc *)scp->dev_softc[0], 0);
+ }
+ else {
+ if ((scp->devices & ATA_ATA_SLAVE) && scp->dev_softc[1])
+ return ad_service((struct ad_softc *)scp->dev_softc[1], 0);
+ }
+#endif
+ }
+ return ATA_OP_FINISHED;
+}
+
+int
+ata_wait(struct ata_softc *scp, int device, u_int8_t mask)
+{
+ int timeout = 0;
DELAY(1);
while (timeout < 5000000) { /* timeout 5 secs */
- scp->status = inb(scp->ioaddr + ATA_STATUS);
+ scp->status = inb(scp->altioaddr + ATA_ALTSTAT);
/* 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->ioaddr + ATA_STATUS);
+ scp->status = inb(scp->altioaddr + ATA_ALTSTAT);
}
/* are we done ? */
@@ -1365,7 +1406,7 @@ ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask)
/* Wait 50 msec for bits wanted. */
timeout = 5000;
while (timeout--) {
- scp->status = inb(scp->ioaddr + ATA_STATUS);
+ scp->status = inb(scp->altioaddr + ATA_ALTSTAT);
if ((scp->status & mask) == mask) {
if (scp->status & ATA_S_ERROR)
scp->error = inb(scp->ioaddr + ATA_ERROR);
@@ -1376,17 +1417,26 @@ ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask)
return -1;
}
-int32_t
-ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
- u_int32_t cylinder, u_int32_t head, u_int32_t sector,
- u_int32_t count, u_int32_t feature, int32_t flags)
+int
+ata_command(struct ata_softc *scp, int device, u_int8_t command,
+ u_int16_t cylinder, u_int8_t head, u_int8_t sector,
+ u_int8_t count, u_int8_t feature, int flags)
{
+ int error = 0;
#ifdef ATA_DEBUG
ata_printf(scp, device, "ata_command: addr=%04x, cmd=%02x, "
- "c=%d, h=%d, s=%d, count=%d, flags=%02x\n",
- scp->ioaddr, command, cylinder, head, sector, count, flags);
+ "c=%d, h=%d, s=%d, count=%d, feature=%d, flags=%02x\n",
+ scp->ioaddr, command, cylinder, head, sector,
+ count, feature, flags);
#endif
+ /* disable interrupt from device */
+ if (scp->flags & ATA_QUEUED)
+ outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_IDS | ATA_A_4BIT);
+
+ /* select device */
+ outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
+
/* ready to issue command ? */
if (ata_wait(scp, device, 0) < 0) {
ata_printf(scp, device,
@@ -1394,12 +1444,13 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
command, scp->status, scp->error);
return -1;
}
+
outb(scp->ioaddr + ATA_FEATURE, feature);
- outb(scp->ioaddr + ATA_CYL_LSB, cylinder);
+ outb(scp->ioaddr + ATA_COUNT, count);
+ outb(scp->ioaddr + ATA_SECTOR, sector);
outb(scp->ioaddr + ATA_CYL_MSB, cylinder >> 8);
+ outb(scp->ioaddr + ATA_CYL_LSB, cylinder);
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device | head);
- outb(scp->ioaddr + ATA_SECTOR, sector);
- outb(scp->ioaddr + ATA_COUNT, count);
switch (flags) {
case ATA_WAIT_INTR:
@@ -1409,10 +1460,15 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
scp->active = ATA_WAIT_INTR;
asleep((caddr_t)scp, PRIBIO, "atacmd", 10 * hz);
outb(scp->ioaddr + ATA_CMD, command);
+
+ /* enable interrupt */
+ if (scp->flags & ATA_QUEUED)
+ outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
+
if (await(PRIBIO, 10 * hz)) {
ata_printf(scp, device, "ata_command: timeout waiting for intr\n");
scp->active = ATA_IDLE;
- return -1;
+ error = -1;
}
break;
@@ -1427,9 +1483,7 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
ata_printf(scp, device,
"timeout waiting for command=%02x s=%02x e=%02x\n",
command, scp->status, scp->error);
- if (scp->active != ATA_REINITING)
- scp->active = ATA_IDLE;
- return -1;
+ error = -1;
}
if (scp->active != ATA_REINITING)
scp->active = ATA_IDLE;
@@ -1443,11 +1497,29 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
ata_printf(scp, device, "DANGER: illegal interrupt flag=%s\n",
active2str(flags));
}
- return 0;
+ /* enable interrupt */
+ if (scp->flags & ATA_QUEUED)
+ outb(scp->altioaddr + ATA_ALTCTRL, ATA_A_4BIT);
+ return error;
}
int
-ata_printf(struct ata_softc *scp, int32_t device, const char * fmt, ...)
+ata_get_lun(u_int32_t *map)
+{
+ int lun = ffs(~*map) - 1;
+
+ *map |= (1 << lun);
+ return lun;
+}
+
+void
+ata_free_lun(u_int32_t *map, int lun)
+{
+ *map &= ~(1 << lun);
+}
+
+int
+ata_printf(struct ata_softc *scp, int device, const char * fmt, ...)
{
va_list ap;
int ret;
@@ -1463,23 +1535,8 @@ ata_printf(struct ata_softc *scp, int32_t device, const char * fmt, ...)
return ret;
}
-int
-ata_get_lun(u_int32_t *map)
-{
- int lun = ffs(~*map) - 1;
-
- *map |= (1 << lun);
- return lun;
-}
-
-void
-ata_free_lun(u_int32_t *map, int lun)
-{
- *map &= ~(1 << lun);
-}
-
-int8_t *
-ata_mode2str(int32_t mode)
+char *
+ata_mode2str(int mode)
{
switch (mode) {
case ATA_PIO: return "BIOSPIO";
@@ -1497,8 +1554,8 @@ ata_mode2str(int32_t mode)
}
}
-int8_t
-ata_pio2mode(int32_t pio)
+int
+ata_pio2mode(int pio)
{
switch (pio) {
default:
@@ -1560,8 +1617,8 @@ ata_umode(struct ata_params *ap)
return -1;
}
-static int8_t *
-active2str(int32_t active)
+static char *
+active2str(int active)
{
static char buf[8];
@@ -1589,7 +1646,7 @@ active2str(int32_t active)
}
static void
-bswap(int8_t *buf, int32_t len)
+bswap(int8_t *buf, int len)
{
u_int16_t *ptr = (u_int16_t*)(buf + len);
@@ -1598,7 +1655,7 @@ bswap(int8_t *buf, int32_t len)
}
static void
-btrim(int8_t *buf, int32_t len)
+btrim(int8_t *buf, int len)
{
int8_t *ptr;
@@ -1610,9 +1667,9 @@ btrim(int8_t *buf, int32_t len)
}
static void
-bpack(int8_t *src, int8_t *dst, int32_t len)
+bpack(int8_t *src, int8_t *dst, int len)
{
- int32_t i, j, blank;
+ int i, j, blank;
for (i = j = blank = 0 ; i < len; i++) {
if (blank && src[i] == ' ') continue;
@@ -1633,14 +1690,14 @@ bpack(int8_t *src, int8_t *dst, int32_t len)
}
static void
-ata_change_mode(struct ata_softc *scp, int32_t device, int32_t mode)
+ata_change_mode(struct ata_softc *scp, int device, int mode)
{
- int32_t s = splbio();
+ int s = splbio();
while (scp->active != ATA_IDLE)
tsleep((caddr_t)&s, PRIBIO, "atachm", hz/4);
scp->active = ATA_REINITING;
- ata_dmainit(scp, device, ata_pmode(ATA_PARAM(scp, device)),
+ ata_dmainit(scp, device, ata_pmode(ATA_PARAM(scp, device)),
mode < ATA_DMA ? -1 : ata_wmode(ATA_PARAM(scp, device)),
mode < ATA_DMA ? -1 : ata_umode(ATA_PARAM(scp, device)));
scp->active = ATA_IDLE;