diff options
author | sos <sos@FreeBSD.org> | 2000-01-17 02:04:19 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2000-01-17 02:04:19 +0000 |
commit | 73d5bc432ffa855032af2d3a79d07f7dd49515ac (patch) | |
tree | 27aeff474453ba4d32a590e4b72176b77bbfc87a | |
parent | 668e3ec014a72ca0849b346ab9f82e12e8c5776d (diff) | |
download | FreeBSD-src-73d5bc432ffa855032af2d3a79d07f7dd49515ac.zip FreeBSD-src-73d5bc432ffa855032af2d3a79d07f7dd49515ac.tar.gz |
Add support for the Intel 810 chipset (ICH type of chips)
Prober support for the VIA 82C686, I finally got the right datasheet.
Get rid of atapi_wait, merge it into ata_wait.
Avoid a couple of races by using asleep instead of tsleep.
Always use 16bit transfers on ISA systems.
Clear up the atapi_read/write functions.
-rw-r--r-- | sys/dev/ata/ata-all.c | 72 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.h | 1 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 36 | ||||
-rw-r--r-- | sys/dev/ata/ata-dma.c | 62 | ||||
-rw-r--r-- | sys/dev/ata/atapi-all.c | 105 | ||||
-rw-r--r-- | sys/dev/ata/atapi-cd.c | 5 |
6 files changed, 157 insertions, 124 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 253effa..327ee04 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -133,6 +133,7 @@ ata_isaprobe(device_t dev) if (res) { isa_set_portsize(dev, res); *(int *)device_get_softc(dev) = lun; + atadevices[lun]->flags |= ATA_USE_16BIT; return 0; } return ENXIO; @@ -197,6 +198,12 @@ ata_pcimatch(device_t dev) case 0x71998086: return "Intel PIIX4 ATA-33 controller"; + case 0x24118086: + return "Intel ICH ATA-66 controller"; + + case 0x24218086: + return "Intel ICH0 ATA-33 controller"; + case 0x522910b9: return "AcerLabs Aladdin ATA-33 controller"; @@ -363,7 +370,18 @@ ata_pciattach(device_t dev) /* set sector size */ pci_write_config(dev, 0x60, DEV_BSIZE, 2); pci_write_config(dev, 0x68, DEV_BSIZE, 2); + + /* prepare for ATA-66 on the 82C686 */ + if (ata_find_dev(dev, 0x06861106)) + pci_write_config(dev, 0x50, + pci_read_config(dev, 0x50, 4) | 0x070f070f, 4); break; + + case 0x00041103: /* HighPoint HPT366 controller */ + printf("hpt366: cache_line_size=0x%02x latency_timer=0x%02x min_grant=0x%02x max_latency=0x%02x\n", + pci_read_config(dev, 0x0c, 1), pci_read_config(dev, 0x0d, 1), + pci_read_config(dev, 0x3e, 1), pci_read_config(dev, 0x3f, 1)); + } /* now probe the addresse found for "real" ATA/ATAPI hardware */ @@ -809,30 +827,25 @@ ata_reinit(struct ata_softc *scp) int32_t ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask) { - u_int8_t status; u_int32_t timeout = 0; - + DELAY(1); - while (timeout <= 5000000) { /* timeout 5 secs */ - status = inb(scp->ioaddr + ATA_STATUS); + while (timeout < 5000000) { /* timeout 5 secs */ + scp->status = inb(scp->ioaddr + ATA_STATUS); /* if drive fails status, reselect the drive just to be sure */ - if (status == 0xff) { - printf("ata%d: %s: no status, reselecting device\n", + if (scp->status == 0xff) { + printf("ata%d-%s: no status, reselecting device\n", scp->lun, device?"slave":"master"); outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device); DELAY(1); - status = inb(scp->ioaddr + ATA_STATUS); - } - if (status == 0xff) - return -1; - scp->status = status; - if (!(status & ATA_S_BUSY)) { - if (status & ATA_S_ERROR) - scp->error = inb(scp->ioaddr + ATA_ERROR); - if ((status & mask) == mask) - return (status & ATA_S_ERROR); + scp->status = inb(scp->ioaddr + ATA_STATUS); } + + /* are we done ? */ + if (!(scp->status & ATA_S_BUSY)) + break; + if (timeout > 1000) { timeout += 1000; DELAY(1000); @@ -841,9 +854,27 @@ ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask) timeout += 10; DELAY(10); } - } - return -1; -} + } + if (scp->status & ATA_S_ERROR) + scp->error = inb(scp->ioaddr + ATA_ERROR); + if (timeout >= 5000000) + return -1; + if (!mask) + return (scp->status & ATA_S_ERROR); + + /* Wait 50 msec for bits wanted. */ + timeout = 5000; + while (timeout--) { + scp->status = inb(scp->ioaddr + ATA_STATUS); + if ((scp->status & mask) == mask) { + if (scp->status & ATA_S_ERROR) + scp->error = inb(scp->ioaddr + ATA_ERROR); + return (scp->status & ATA_S_ERROR); + } + DELAY (10); + } + return -1; +} int32_t ata_command(struct ata_softc *scp, int32_t device, u_int32_t command, @@ -876,8 +907,9 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command, if (scp->active != ATA_IDLE) printf("WARNING: WAIT_INTR active=%s\n", active2str(scp->active)); scp->active = ATA_WAIT_INTR; + asleep((caddr_t)scp, PRIBIO, "atacmd", 500); outb(scp->ioaddr + ATA_CMD, command); - if (tsleep((caddr_t)scp, PRIBIO, "atacmd", 500)) { + if (await(PRIBIO, 500)) { printf("ata_command: timeout waiting for interrupt\n"); scp->active = ATA_IDLE; return -1; diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index e6d7c5e..b9f739b 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -148,6 +148,7 @@ struct ata_softc { int32_t flags; /* controller flags */ #define ATA_DMA_ACTIVE 0x01 #define ATA_ATAPI_DMA_RO 0x02 +#define ATA_USE_16BIT 0x04 int32_t devices; /* what is present */ #define ATA_ATA_MASTER 0x01 diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 619f1fe..c288987 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -498,15 +498,15 @@ ad_transfer(struct ad_request *request) printf("ad_transfer: timeout waiting for DRQ"); /* output the data */ -#ifdef ATA_16BIT_ONLY - outsw(adp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)request->data + request->donecount), - request->currentsize / sizeof(int16_t)); -#else - outsl(adp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)request->data + request->donecount), - request->currentsize / sizeof(int32_t)); -#endif + if (adp->controller->flags & ATA_USE_16BIT) + outsw(adp->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)request->data + request->donecount), + request->currentsize / sizeof(int16_t)); + else + outsl(adp->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)request->data + request->donecount), + request->currentsize / sizeof(int32_t)); + request->bytecount -= request->currentsize; } @@ -589,15 +589,15 @@ oops: } /* data ready, read in */ -#ifdef ATA_16BIT_ONLY - insw(adp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)request->data + request->donecount), - request->currentsize / sizeof(int16_t)); -#else - insl(adp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)request->data + request->donecount), - request->currentsize / sizeof(int32_t)); -#endif + if (adp->controller->flags & ATA_USE_16BIT) + insw(adp->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)request->data + request->donecount), + request->currentsize / sizeof(int16_t)); + else + insl(adp->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)request->data + request->donecount), + request->currentsize / sizeof(int32_t)); + request->bytecount -= request->currentsize; } diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index d87a81e..fe5288b 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -98,16 +98,20 @@ ata_dmainit(struct ata_softc *scp, int32_t device, switch (scp->chiptype) { case 0x71118086: /* Intel PIIX4 */ - case 0x71998086: /* Intel PIIX4 */ + case 0x71998086: /* Intel PIIX4e */ + case 0x24118086: /* Intel ICH */ + case 0x24218086: /* Intel ICH0 */ if (udmamode >= 2) { int32_t mask48, new48; error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) - printf("ata%d-%s: %s setting up UDMA2 mode on PIIX4 chip\n", + printf("ata%d-%s: %s setting up UDMA2 mode on %s chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", - (error) ? "failed" : "success"); + (error) ? "failed" : "success", + (scp->chiptype == 0x24118086) ? "ICH" : + (scp->chiptype == 0x24218086) ? "ICH0" :"PIIX4"); if (!error) { mask48 = (1 << devno) + (3 << (16 + (devno << 2))); new48 = (1 << devno) + (2 << (16 + (devno << 2))); @@ -143,10 +147,12 @@ ata_dmainit(struct ata_softc *scp, int32_t device, error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) - printf("ata%d-%s: %s setting up WDMA2 mode on PIIX%s chip\n", + printf("ata%d-%s: %s setting up WDMA2 mode on %s chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", (error) ? "failed" : "success", - (scp->chiptype == 0x70108086) ? "3" : "4"); + (scp->chiptype == 0x70108086) ? "PIIX3" : + (scp->chiptype == 0x24118086) ? "ICH" : + (scp->chiptype == 0x24218086) ? "ICH0" :"PIIX4"); if (!error) { if (device == ATA_MASTER) { mask40 = 0x0000330f; @@ -251,16 +257,44 @@ ata_dmainit(struct ata_softc *scp, int32_t device, case 0x05711106: /* VIA 82C571, 82C586, 82C596 & 82C686 */ case 0x74091022: /* AMD 756 */ - /* UDMA4 mode only on 82C686 and AMD 756 */ - if ((udmamode >= 4 && ata_find_dev(scp->dev, 0x06861106)) || - (udmamode >= 4 && scp->chiptype == 0x74091022)) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + /* UDMA modes on 82C686 */ + if (ata_find_dev(scp->dev, 0x06861106)) { + if (udmamode >= 4) { + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + printf("ata%d-%s: %s setting up UDMA4 mode on VIA chip\n", + scp->lun, (device == ATA_MASTER) ? "master":"slave", + (error) ? "failed" : "success"); + if (!error) { + pci_write_config(scp->dev, 0x53 - devno, 0xe8, 1); + scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_UDMA4; + return 0; + } + } + if (udmamode >= 2) { + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + printf("ata%d-%s: %s setting up UDMA2 mode on VIA chip\n", + scp->lun, (device == ATA_MASTER) ? "master":"slave", + (error) ? "failed" : "success"); + if (!error) { + pci_write_config(scp->dev, 0x53 - devno, 0xea, 1); + scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_UDMA2; + return 0; + } + } + } + + /* UDMA4 mode on AMD 756 */ + if (udmamode >= 4 && scp->chiptype == 0x74091022) { + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) - printf("ata%d-%s: %s setting up UDMA4 mode on %s chip\n", + printf("ata%d-%s: %s setting up UDMA4 mode on AMD chip\n", scp->lun, (device == ATA_MASTER) ? "master":"slave", - (error) ? "failed" : "success", - (scp->chiptype == 0x74091022) ? "AMD" : "VIA"); + (error) ? "failed" : "success"); if (!error) { pci_write_config(scp->dev, 0x53 - devno, 0xc3, 1); scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_UDMA4; @@ -268,11 +302,10 @@ ata_dmainit(struct ata_softc *scp, int32_t device, } } - /* UDMA2 mode only on 82C586 > rev1, 82C596, 82C686, AMD 756 */ + /* UDMA2 mode only on 82C586 > rev1, 82C596, AMD 756 */ if ((udmamode >= 2 && ata_find_dev(scp->dev, 0x05861106) && pci_read_config(scp->dev, 0x08, 1) >= 0x01) || (udmamode >= 2 && ata_find_dev(scp->dev, 0x05961106)) || - (udmamode >= 2 && ata_find_dev(scp->dev, 0x06861106)) || (udmamode >= 2 && scp->chiptype == 0x74091022)) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); @@ -288,7 +321,6 @@ ata_dmainit(struct ata_softc *scp, int32_t device, } } if (wdmamode >= 2 && apiomode >= 4) { - /* set WDMA2 mode timing */ error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c index 7654fb3..07984bca 100644 --- a/sys/dev/ata/atapi-all.c +++ b/sys/dev/ata/atapi-all.c @@ -56,7 +56,6 @@ static void atapi_timeout(struct atapi_request *request); static int8_t *atapi_type(int32_t); static int8_t *atapi_cmd2str(u_int8_t); static int8_t *atapi_skey2str(u_int8_t); -static int32_t atapi_wait(struct atapi_softc *, u_int8_t); static void atapi_init(void); /* extern references */ @@ -208,11 +207,11 @@ atapi_getparam(struct atapi_softc *atp) if (ata_command(atp->controller, atp->unit, ATA_C_ATAPI_IDENTIFY, 0, 0, 0, 0, 0, ATA_WAIT_INTR)) return -1; - if (atapi_wait(atp, ATA_S_DRQ)) + if (ata_wait(atp->controller, atp->unit, ATA_S_DRQ)) return -1; insw(atp->controller->ioaddr + ATA_DATA, buffer, sizeof(buffer)/sizeof(int16_t)); - if (atapi_wait(atp, 0)) + if (ata_wait(atp->controller, atp->unit, 0)) return -1; if (!(atapi_parm = malloc(sizeof(struct atapi_params), M_ATAPI, M_NOWAIT))) return -1; @@ -254,6 +253,10 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data, /* append onto controller queue and try to start controller */ s = splbio(); + + /* if not using callbacks, prepare to sleep for this request */ + if (!callback) + asleep((caddr_t)request, PRIBIO, "atprq", 0); TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain); if (atp->controller->active == ATA_IDLE) ata_start(atp->controller); @@ -265,7 +268,7 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data, } /* wait for request to complete */ - tsleep((caddr_t)request, PRIBIO, "atprq", 0); + await(PRIBIO, 0); splx(s); error = request->error; free(request, M_ATAPI); @@ -375,13 +378,16 @@ atapi_interrupt(struct atapi_request *request) if (atp->flags & ATAPI_F_DMA_USED) dma_stat = ata_dmadone(atp->controller); - if (atapi_wait(atp, 0) < 0) { + /* is this needed anymore ?? SOS XXX */ +#if NOT_ANY_MORE + if (ata_wait(atp->controller, atp->unit, 0) < 0) { printf("%s: timeout waiting for status", atp->devname); atp->flags &= ~ATAPI_F_DMA_USED; request->result = inb(atp->controller->ioaddr + ATA_ERROR) | ATAPI_SK_RESERVED; goto op_finished; } +#endif if (atp->flags & ATAPI_F_DMA_USED) { atp->flags &= ~ATAPI_F_DMA_USED; @@ -552,64 +558,58 @@ static void atapi_read(struct atapi_request *request, int32_t length) { int8_t **buffer = (int8_t **)&request->data; + int32_t size = min(request->bytecount, length); int32_t resid; if (request->ccb[0] == ATAPI_REQUEST_SENSE) *buffer = (int8_t *)&request->sense; + if (request->device->controller->flags & ATA_USE_16BIT || + (size % sizeof(int32_t))) + insw(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), size / sizeof(int16_t)); + else + insl(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), size / sizeof(int32_t)); + if (request->bytecount < length) { printf("%s: read data overrun %d/%d\n", request->device->devname, length, request->bytecount); -#ifdef ATA_16BIT_ONLY - insw(request->device->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), request->bytecount/sizeof(int16_t)); -#else - insl(request->device->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), request->bytecount/sizeof(int32_t)); -#endif + for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t)) inw(request->device->controller->ioaddr + ATA_DATA); - *buffer += request->bytecount; - request->bytecount = 0; - } - else { - insw(request->device->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); - *buffer += length; - request->bytecount -= length; } + *buffer += size; + request->bytecount -= size; } static void atapi_write(struct atapi_request *request, int32_t length) { int8_t **buffer = (int8_t **)&request->data; + int32_t size = min(request->bytecount, length); int32_t resid; if (request->ccb[0] == ATAPI_REQUEST_SENSE) *buffer = (int8_t *)&request->sense; + if (request->device->controller->flags & ATA_USE_16BIT || + (size % sizeof(int32_t))) + outsw(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), size / sizeof(int16_t)); + else + outsl(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), size / sizeof(int32_t)); + if (request->bytecount < length) { printf("%s: write data underrun %d/%d\n", request->device->devname, length, request->bytecount); -#ifdef ATA_16BIT_ONLY - outsw(request->device->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), request->bytecount/sizeof(int16_t)); -#else - outsl(request->device->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), request->bytecount/sizeof(int32_t)); -#endif + for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t)) outw(request->device->controller->ioaddr + ATA_DATA, 0); - *buffer += request->bytecount; - request->bytecount = 0; - } - else { - outsw(request->device->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); - *buffer += length; - request->bytecount -= length; } + *buffer += size; + request->bytecount -= size; } static void @@ -731,41 +731,6 @@ atapi_skey2str(u_int8_t skey) } } -static int32_t -atapi_wait(struct atapi_softc *atp, u_int8_t mask) -{ - u_int32_t timeout = 0; - - DELAY(1); - while (timeout++ <= 500000) { /* timeout 5 secs */ - atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS); - - /* if drive fails status, reselect the drive just to be sure */ - if (atp->controller->status == 0xff) { - outb(atp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | atp->unit); - DELAY(1); - atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS); - } - if (!(atp->controller->status & ATA_S_BUSY) && - (atp->controller->status & ATA_S_READY)) - break; - DELAY (10); - } - if (timeout <= 0) - return -1; - if (!mask) - return (atp->controller->status & ATA_S_ERROR); - - /* Wait 50 msec for bits wanted. */ - for (timeout=5000; timeout>0; --timeout) { - atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS); - if ((atp->controller->status & mask) == mask) - return (atp->controller->status & ATA_S_ERROR); - DELAY (10); - } - return -1; -} - static void atapi_init(void) { diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 50632f7..458f5a9 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -966,10 +966,13 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) break; case CDRIOCCLOSEDISK: - if (!(cdp->flags & F_WRITTEN) || !(cdp->flags & F_DISK_OPEN)) { + if (!(cdp->flags & F_DISK_OPEN)) { error = EINVAL; printf("acd%d: sequence error (nothing to close)\n", cdp->lun); } + else if (!(cdp->flags & F_WRITTEN)) { + cdp->flags &= ~(F_DISK_OPEN | F_TRACK_OPEN); + } else { error = acd_close_disk(cdp); cdp->flags &= ~(F_WRITTEN | F_DISK_OPEN | F_TRACK_OPEN); |