diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 6f933122f1e1..e8b66aa01e19 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 3ab34ced3680..8b5bdc44f787 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 aa97a6df3073..639198265720 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 13ea2f927b01..37b0ced80415 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 3385b6776609..46ebbd1e9f9a 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -524,7 +524,7 @@ ata_dmainit(struct ata_softc *scp, int device, (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 @@ ata_dmainit(struct ata_softc *scp, int device, 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,