diff --git a/sys/conf/options b/sys/conf/options index ab19720354a..f130f411d51 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -200,6 +200,7 @@ ISP_DISABLE_2200_SUPPORT opt_isp.h # Options used in the 'ata' ATA/ATAPI driver ATA_STATIC_ID opt_ata.h ATA_16BIT_ONLY opt_ata.h +ATA_ENABLE_ATAPI_DMA opt_ata.h # Resource limits. DFLDSIZ opt_rlimit.h diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index a136b6c6a83..e6e10462655 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -243,6 +243,7 @@ ata_pciattach(device_t dev) u_int32_t cmd; int32_t iobase_1, iobase_2, altiobase_1, altiobase_2; int32_t bmaddr_1 = 0, bmaddr_2 = 0, irq1, irq2; + struct resource *irq = NULL; int32_t lun; /* set up vendor-specific stuff */ @@ -324,7 +325,6 @@ ata_pciattach(device_t dev) alpha_platform_setup_ide_intr(0, ataintr, scp); #endif else { - struct resource *irq; int rid = 0; void *ih; @@ -348,13 +348,14 @@ ata_pciattach(device_t dev) alpha_platform_setup_ide_intr(1, ataintr, scp); #endif else { - struct resource *irq; int rid = 0; void *ih; - if (!(irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, - RF_SHAREABLE | RF_ACTIVE))) - printf("ata_pciattach: Unable to alloc interrupt\n"); + if (irq1 != irq2 || irq == NULL) { + if (!(irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE))) + printf("ata_pciattach: Unable to alloc interrupt\n"); + } bus_setup_intr(dev, irq, INTR_TYPE_BIO, ataintr, scp, &ih); } printf("ata%d at 0x%04x irq %d on ata-pci%d\n", @@ -514,33 +515,37 @@ ataintr(void *data) if (scp->flags & ATA_DMA_ACTIVE) if (!(ata_dmastatus(scp) & ATA_BMSTAT_INTERRUPT)) return; - if ((scp->status = inb(scp->ioaddr + ATA_STATUS)) == ATA_S_BUSY) /*XXX SOS*/ + if ((scp->status = inb(scp->ioaddr + ATA_STATUS)) == ATA_S_BUSY) return; /* find & call the responsible driver to process this interrupt */ switch (scp->active) { #if NATADISK > 0 case ATA_ACTIVE_ATA: - if (scp->running && (ad_interrupt(scp->running) == ATA_OP_CONTINUES)) - return; + if (!scp->running) + return; + if (ad_interrupt(scp->running) == ATA_OP_CONTINUES) + return; break; #endif #if NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0 case ATA_ACTIVE_ATAPI: - if (scp->running && (atapi_interrupt(scp->running) == ATA_OP_CONTINUES)) - return; + if (!scp->running) + return; + if (atapi_interrupt(scp->running) == ATA_OP_CONTINUES) + return; break; #endif case ATA_WAIT_INTR: wakeup((caddr_t)scp); break; + case ATA_WAIT_READY: + break; + case ATA_REINITING: return; - case ATA_IGNORE_INTR: - break; - default: case ATA_IDLE: #ifdef ATA_DEBUG @@ -780,7 +785,7 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command, switch (flags) { case ATA_WAIT_INTR: if (scp->active != ATA_IDLE) - printf("DANGER wait_intr active=%s\n", active2str(scp->active)); + printf("WARNING: WAIT_INTR active=%s\n", active2str(scp->active)); scp->active = ATA_WAIT_INTR; outb(scp->ioaddr + ATA_CMD, command); if (tsleep((caddr_t)scp, PRIBIO, "atacmd", 500)) { @@ -790,12 +795,17 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command, } break; - case ATA_IGNORE_INTR: + case ATA_WAIT_READY: if (scp->active != ATA_IDLE && scp->active != ATA_REINITING) - printf("DANGER ignore_intr active=%s\n", active2str(scp->active)); - if (scp->active != ATA_REINITING) - scp->active = ATA_IGNORE_INTR; + printf("WARNING: WAIT_READY active=%s\n", active2str(scp->active)); + scp->active = ATA_WAIT_READY; outb(scp->ioaddr + ATA_CMD, command); + if (ata_wait(scp, device, ATA_S_READY) < 0) { + printf("ata%d-%s: timeout waiting for command=%02x s=%02x e=%02x\n", + scp->lun, device ? "slave" : "master", command, + scp->status, scp->error); + return -1; + } break; case ATA_IMMEDIATE: @@ -803,7 +813,7 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command, break; default: - printf("DANGER illegal interrupt flag=%s\n", active2str(flags)); + printf("DANGER: illegal interrupt flag=%s\n", active2str(flags)); } #ifdef ATA_DEBUG printf("ata_command: leaving\n"); @@ -838,8 +848,6 @@ active2str(int32_t active) return("ATA_IDLE"); case ATA_WAIT_INTR: return("ATA_WAIT_INTR"); - case ATA_IGNORE_INTR: - return("ATA_IGNORE_INTR"); case ATA_ACTIVE_ATA: return("ATA_ACTIVE_ATA"); case ATA_ACTIVE_ATAPI: diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index c14c98f7815..f91b21c70a5 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -155,7 +155,7 @@ struct ata_softc { #define ATA_IDLE 0x0 #define ATA_IMMEDIATE 0x0 #define ATA_WAIT_INTR 0x1 -#define ATA_IGNORE_INTR 0x2 +#define ATA_WAIT_READY 0x2 #define ATA_ACTIVE_ATA 0x3 #define ATA_ACTIVE_ATAPI 0x4 #define ATA_REINITING 0x5 diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 62bd58f0a3a..9f4bba5d756 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -322,6 +322,7 @@ addump(dev_t dev) adp->flags &= ~AD_F_DMA_ENABLED; while (count > 0) { + DELAY(1000); if (is_physical_memory(addr)) pmap_enter(kernel_pmap, (vm_offset_t)CADDR1, trunc_page(addr), VM_PROT_READ, TRUE); @@ -416,7 +417,11 @@ ad_transfer(struct ad_request *request) if (request->donecount == 0) { /* start timeout for this transfer */ - request->timeout_handle = timeout((timeout_t*)ad_timeout, request, 3*hz); + if (panicstr) + request->timeout_handle.callout = NULL; + else + request->timeout_handle = + timeout((timeout_t*)ad_timeout, request, 3*hz); /* setup transfer parameters */ count = howmany(request->bytecount, DEV_BSIZE); @@ -614,6 +619,7 @@ ad_timeout(struct ad_request *request) { struct ad_softc *adp = request->device; + adp->controller->running = NULL; printf("ata%d-%s: ad_timeout: lost disk contact - resetting\n", adp->controller->lun, (adp->unit == ATA_MASTER) ? "master" : "slave"); diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 28e5970df47..ab46df44569 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -100,7 +100,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, int32_t mask48, new48; error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up UDMA2 mode on PIIX4 chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -139,7 +139,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, pci_write_config(scp->dev, 0x44, new44, 4); } error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up WDMA2 mode on PIIX4 chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -212,7 +212,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, int32_t word54 = pci_read_config(scp->dev, 0x54, 4); error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up UDMA2 mode on Aladdin chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -228,7 +228,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, } else if (wdmamode >= 2 && apiomode >= 4) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up WDMA2 mode on Aladdin chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -248,9 +248,24 @@ ata_dmainit(struct ata_softc *scp, int32_t device, break; devno = (scp->unit << 1) + ((device == ATA_MASTER) ? 0 : 1); + if (udmamode >=4 && type == 0x4d38105a && + !(pci_read_config(scp->dev, 0x50, 2)&(scp->unit ? 1<<11 : 1<<10))) { + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + ATA_UDMA4, ATA_C_FEA_SETXFER, ATA_WAIT_READY); + if (bootverbose) + printf("ata%d: %s: %s setting up UDMA4 mode on Promise chip\n", + scp->lun, (device == ATA_MASTER) ? "master" : "slave", + (error) ? "failed" : "success"); + if (error) + break; + outb(scp->bmaddr + 0x11, inl(scp->bmaddr + 0x11) | scp->unit ? 8:2); + pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004127f3, 4); + scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_UDMA4; + return 0; + } if (udmamode >=2) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up UDMA2 mode on Promise chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -263,7 +278,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, } else if (wdmamode >= 2 && apiomode >= 4) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up WDMA2 mode on Promise chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -291,7 +306,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, devno = (device == ATA_MASTER) ? 0 : 1; if (udmamode >=4 && !(pci_read_config(scp->dev, 0x5a, 1) & 0x2)) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_UDMA4, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_UDMA4, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up UDMA4 mode on HPT366 chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -302,9 +317,9 @@ ata_dmainit(struct ata_softc *scp, int32_t device, scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_UDMA4; return 0; } - else if (udmamode >=3) { + if (udmamode >=3 && !(pci_read_config(scp->dev, 0x5a, 1) & 0x2)) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_UDMA3, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_UDMA3, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up UDMA3 mode on HPT366 chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -315,9 +330,9 @@ ata_dmainit(struct ata_softc *scp, int32_t device, scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_UDMA3; return 0; } - else if (udmamode >=2) { + if (udmamode >=2) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up UDMA2 mode on HPT366 chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -330,7 +345,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, } else if (wdmamode >= 2 && apiomode >= 4) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up WDMA2 mode on HPT366 chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", @@ -361,7 +376,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, ((device == ATA_MASTER) ? ATA_BMSTAT_DMA_SLAVE : ATA_BMSTAT_DMA_MASTER))) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR); + ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_READY); if (bootverbose) printf("ata%d: %s: %s setting up WDMA2 mode on generic chip\n", scp->lun, (device == ATA_MASTER) ? "master" : "slave", diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c index 3368f783af1..fc4bec8a089 100644 --- a/sys/dev/ata/atapi-all.c +++ b/sys/dev/ata/atapi-all.c @@ -49,6 +49,8 @@ /* prototypes */ static void atapi_attach(void *); static int32_t atapi_getparam(struct atapi_softc *); +static void atapi_read(struct atapi_request *, int32_t); +static void atapi_write(struct atapi_request *, int32_t); static void atapi_timeout(struct atapi_request *request); static int8_t *atapi_type(int32_t); static int8_t *atapi_cmd2str(u_int8_t); @@ -135,6 +137,7 @@ atapi_attach(void *notused) udmamode(atp->atapi_parm), atp->atapi_parm->dmaflag); +#ifdef ATA_ENABLE_ATAPI_DMA if (!(atp->atapi_parm->drqtype == ATAPI_DRQT_INTR) && !ata_dmainit(atp->controller, atp->unit, (apiomode(atp->atapi_parm) < 0) ? @@ -145,6 +148,7 @@ atapi_attach(void *notused) wdmamode(atp->atapi_parm), udmamode(atp->atapi_parm))) atp->flags |= ATAPI_F_DMA_ENABLED; +#endif switch (atp->atapi_parm->device_type) { #if NATAPICD > 0 @@ -245,14 +249,16 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data, TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain); if (atp->controller->active == ATA_IDLE) ata_start(atp->controller); - splx(s); /* if callback used, then just return, gets called from interrupt context */ - if (callback) + if (callback) { + splx(s); return 0; + } /* wait for request to complete */ tsleep((caddr_t)request, PRIBIO, "atprq", 0); + splx(s); #ifdef ATAPI_DEBUG printf("atapi: phew, got back from tsleep\n"); @@ -370,7 +376,7 @@ atapi_interrupt(struct atapi_request *request) { struct atapi_softc *atp = request->device; int8_t **buffer = (int8_t **)&request->data; - int32_t length, reason, resid, dma_stat = 0; + int32_t length, reason, dma_stat = 0; if (request->ccb[0] == ATAPI_REQUEST_SENSE) *buffer = (int8_t *)&request->sense; @@ -432,25 +438,7 @@ atapi_interrupt(struct atapi_request *request) atapi_cmd2str(atp->cmd)); goto op_finished; } - if (request->bytecount < length) { - printf("atapi_interrupt: write data underrun %d/%d\n", - length, request->bytecount); -#ifdef ATA_16BIT_ONLY - outsw(atp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); -#else - outsl(atp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int32_t)); -#endif - for (resid=request->bytecount; residcontroller->ioaddr + ATA_DATA, 0); - } - else { - outsw(atp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); - } - request->bytecount -= length; - *buffer += length; + atapi_write(request, length); return ATA_OP_CONTINUES; case ATAPI_P_READ: @@ -462,27 +450,20 @@ atapi_interrupt(struct atapi_request *request) atapi_cmd2str(atp->cmd)); goto op_finished; } - if (request->bytecount < length) { - printf("atapi_interrupt: read data overrun %d/%d\n", - length, request->bytecount); -#ifdef ATA_16BIT_ONLY - insw(atp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); -#else - insl(atp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int32_t)); -#endif - for (resid=request->bytecount; residcontroller->ioaddr + ATA_DATA); - } - else { - insw(atp->controller->ioaddr + ATA_DATA, - (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); - } - request->bytecount -= length; - *buffer += length; + atapi_read(request, length); return ATA_OP_CONTINUES; + case ATAPI_P_DONEDRQ: + printf("ata%d-%s: %s DONEDRQ\n", + atp->controller->lun, + (atp->unit == ATA_MASTER) ? "master" : "slave", + atapi_cmd2str(atp->cmd)); + if (request->flags & A_READ) + atapi_read(request, length); + else + atapi_write(request, length); + /* FALLTHROUGH */ + case ATAPI_P_ABORT: case ATAPI_P_DONE: if (atp->controller->status & (ATA_S_ERROR | ATA_S_DWF)) @@ -590,11 +571,70 @@ atapi_dump(int8_t *label, void *data, int32_t len) printf ("\n"); } +static void +atapi_read(struct atapi_request *request, int32_t length) +{ + int8_t **buffer = (int8_t **)&request->data; + int32_t resid; + + if (request->ccb[0] == ATAPI_REQUEST_SENSE) + *buffer = (int8_t *)&request->sense; + + if (request->bytecount < length) { + printf("atapi_interrupt: read data overrun %d/%d\n", + length, request->bytecount); +#ifdef ATA_16BIT_ONLY + insw(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); +#else + insl(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), length / sizeof(int32_t)); +#endif + for (resid=request->bytecount; residdevice->controller->ioaddr + ATA_DATA); + } + else + insw(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); + request->bytecount -= length; + *buffer += length; +} + +static void +atapi_write(struct atapi_request *request, int32_t length) +{ + int8_t **buffer = (int8_t **)&request->data; + int32_t resid; + + if (request->ccb[0] == ATAPI_REQUEST_SENSE) + *buffer = (int8_t *)&request->sense; + + if (request->bytecount < length) { + printf("atapi_interrupt: write data underrun %d/%d\n", + length, request->bytecount); +#ifdef ATA_16BIT_ONLY + outsw(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); +#else + outsl(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), length / sizeof(int32_t)); +#endif + for (resid=request->bytecount; residdevice->controller->ioaddr + ATA_DATA, 0); + } + else + outsw(request->device->controller->ioaddr + ATA_DATA, + (void *)((uintptr_t)*buffer), length / sizeof(int16_t)); + request->bytecount -= length; + *buffer += length; +} + static void atapi_timeout(struct atapi_request *request) { struct atapi_softc *atp = request->device; + atp->controller->running = NULL; printf("ata%d-%s: atapi_timeout: cmd=%s - resetting\n", atp->controller->lun, (atp->unit == ATA_MASTER) ? "master" : "slave", atapi_cmd2str(request->ccb[0])); diff --git a/sys/dev/ata/atapi-all.h b/sys/dev/ata/atapi-all.h index 29cc3ceca79..6ef75c34e02 100644 --- a/sys/dev/ata/atapi-all.h +++ b/sys/dev/ata/atapi-all.h @@ -34,8 +34,9 @@ #define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN) #define ATAPI_P_WRITE (ATA_S_DRQ) #define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD) +#define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN) +#define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN) #define ATAPI_P_ABORT 0 -#define ATAPI_P_DONE (ATA_I_IN | ATA_I_CMD) /* error register bits */ #define ATAPI_E_MASK 0x0f /* error mask */