Module Name: src Committed By: jdolecek Date: Sat Aug 12 09:52:29 UTC 2017
Modified Files: src/sys/dev/ata [jdolecek-ncq]: TODO.ncq ata.c ata_wdc.c atavar.h src/sys/dev/ic [jdolecek-ncq]: mvsata.c wdc.c wdcvar.h src/sys/dev/pci [jdolecek-ncq]: pciide_common.c src/sys/dev/scsipi [jdolecek-ncq]: atapi_wdc.c Log Message: remove all logic around ATACH_IRQ_WAIT and channel-global ch_error/ch_status, so that there is less hidden state shared by commands; primary intent is to make the NCQ and non-NCQ paths more similar, and remove possibility of incorrect handling for the NCQ commands tested both disk and ATAPI - piixide(4) on QEMU, and siisata(4), ahcisata(4), mvsata(4) on real hw To generate a diff of this commit: cvs rdiff -u -r1.1.2.32 -r1.1.2.33 src/sys/dev/ata/TODO.ncq cvs rdiff -u -r1.132.8.24 -r1.132.8.25 src/sys/dev/ata/ata.c cvs rdiff -u -r1.105.6.6 -r1.105.6.7 src/sys/dev/ata/ata_wdc.c cvs rdiff -u -r1.92.8.21 -r1.92.8.22 src/sys/dev/ata/atavar.h cvs rdiff -u -r1.35.6.19 -r1.35.6.20 src/sys/dev/ic/mvsata.c cvs rdiff -u -r1.283.2.10 -r1.283.2.11 src/sys/dev/ic/wdc.c cvs rdiff -u -r1.97.26.1 -r1.97.26.2 src/sys/dev/ic/wdcvar.h cvs rdiff -u -r1.62.4.1 -r1.62.4.2 src/sys/dev/pci/pciide_common.c cvs rdiff -u -r1.123.4.10 -r1.123.4.11 src/sys/dev/scsipi/atapi_wdc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ata/TODO.ncq diff -u src/sys/dev/ata/TODO.ncq:1.1.2.32 src/sys/dev/ata/TODO.ncq:1.1.2.33 --- src/sys/dev/ata/TODO.ncq:1.1.2.32 Tue Aug 1 22:04:48 2017 +++ src/sys/dev/ata/TODO.ncq Sat Aug 12 09:52:28 2017 @@ -7,9 +7,6 @@ test wd* at umass?, confirm the ata_chan do proper NCQ error recovery - update mvsata to do same as ahcisata/siisata (read log ext, timeouts, et.al) -- update also ic/wdc.c, scsipi/atapi_wdc.c, ata/ata_wdc.c to not use - ch_status/ch_error/ATACH_IRQ_WAIT -- retest ATAPI do biodone() in wddone() starting the dump to not leak bufs when dumping from active system? make sure to not trigger atastart() @@ -18,6 +15,8 @@ active system? make sure to not trigger kill active transfers after software drive reset - race timeout vs. error recovery +atabus_thread() protect run by mutex/condvar + Other random notes (do outside the NCQ branch): ----------------------------------------------------- implement support for PM FIS-based switching, remove restriction in atastart() Index: src/sys/dev/ata/ata.c diff -u src/sys/dev/ata/ata.c:1.132.8.24 src/sys/dev/ata/ata.c:1.132.8.25 --- src/sys/dev/ata/ata.c:1.132.8.24 Tue Aug 1 21:41:25 2017 +++ src/sys/dev/ata/ata.c Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ata.c,v 1.132.8.24 2017/08/01 21:41:25 jdolecek Exp $ */ +/* $NetBSD: ata.c,v 1.132.8.25 2017/08/12 09:52:28 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.24 2017/08/01 21:41:25 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.25 2017/08/12 09:52:28 jdolecek Exp $"); #include "opt_ata.h" @@ -622,15 +622,16 @@ atabus_thread(void *arg) ata_reset_channel(chp, AT_WAIT | chp->ch_reset_flags); } else if (chq->queue_active > 0 && chq->queue_freeze == 1) { /* - * Caller has bumped queue_freeze, decrease it. + * Caller has bumped queue_freeze, decrease it. This + * flow shalt never be executed for NCQ commands. */ + KASSERT((chp->ch_flags & ATACH_NCQ) == 0); + KASSERT(chq->queue_active == 1); + ata_channel_thaw(chp); - u_int active __diagused = 0; - TAILQ_FOREACH(xfer, &chq->active_xfers, c_activechain) { - (*xfer->c_start)(xfer->c_chp, xfer); - active++; - } - KASSERT(active == chq->queue_active); + xfer = ata_queue_get_active_xfer(chp); + KASSERT(xfer != NULL); + (*xfer->c_start)(xfer->c_chp, xfer); } else if (chq->queue_freeze > 1) panic("ata_thread: queue_freeze"); } @@ -1430,7 +1431,7 @@ ata_free_xfer(struct ata_channel *chp, s /* finish the busmastering PIO */ (*wdc->piobm_done)(wdc->dma_arg, chp->ch_channel, xfer->c_drive); - chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_PIOBM_WAIT | ATACH_IRQ_WAIT); + chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_PIOBM_WAIT); } #endif @@ -1521,7 +1522,7 @@ ata_waitdrain_xfer_check(struct ata_chan /* * Check for race of normal transfer handling vs. timeout. */ -static bool +bool ata_timo_xfer_check(struct ata_xfer *xfer) { struct ata_channel *chp = xfer->c_chp; Index: src/sys/dev/ata/ata_wdc.c diff -u src/sys/dev/ata/ata_wdc.c:1.105.6.6 src/sys/dev/ata/ata_wdc.c:1.105.6.7 --- src/sys/dev/ata/ata_wdc.c:1.105.6.6 Tue Jun 27 18:36:03 2017 +++ src/sys/dev/ata/ata_wdc.c Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ata_wdc.c,v 1.105.6.6 2017/06/27 18:36:03 jdolecek Exp $ */ +/* $NetBSD: ata_wdc.c,v 1.105.6.7 2017/08/12 09:52:28 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001, 2003 Manuel Bouyer. @@ -54,7 +54,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.6 2017/06/27 18:36:03 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.7 2017/08/12 09:52:28 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wdc.h" @@ -111,7 +111,7 @@ static int wdc_ata_bio_intr(struct ata_c static void wdc_ata_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int); static void wdc_ata_bio_done(struct ata_channel *, struct ata_xfer *); -static int wdc_ata_err(struct ata_drive_datas *, struct ata_bio *); +static int wdc_ata_err(struct ata_drive_datas *, struct ata_bio *, int); #define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */ #define WDC_ATA_RECOV 0x01 /* There was a recovered error */ #define WDC_ATA_ERR 0x02 /* Drive reports an error */ @@ -175,7 +175,7 @@ wdc_ata_bio_start(struct ata_channel *ch struct wdc_regs *wdr = &wdc->regs[chp->ch_channel]; struct ata_bio *ata_bio = &xfer->c_bio; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; - int wait_flags; + int wait_flags, tfd; const char *errstring; #ifdef WDC_NO_IDS wait_flags = AT_POLL; @@ -216,15 +216,17 @@ wdc_ata_bio_start(struct ata_channel *ch WDSD_IBM | (xfer->c_drive << 4)); DELAY(10); errstring = "wait"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags, + &tfd)) goto ctrltimeout; wdccommandshort(chp, xfer->c_drive, WDCC_RECAL); /* Wait for at last 400ns for status bit to be valid */ DELAY(1); errstring = "recal"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags, + &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; /* Don't try to set modes if controller can't be adjusted */ if (atac->atac_set_modes == NULL) @@ -235,9 +237,10 @@ wdc_ata_bio_start(struct ata_channel *ch wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0, 0x08 | drvp->PIO_mode, WDSF_SET_MODE); errstring = "piomode"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags, + &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; #if NATA_DMA #if NATA_UDMA @@ -253,9 +256,10 @@ wdc_ata_bio_start(struct ata_channel *ch goto geometry; } errstring = "dmamode"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags, + &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; #endif /* NATA_DMA */ geometry: @@ -267,9 +271,10 @@ geometry: (drvp->lp->d_type == DKTYPE_ST506) ? drvp->lp->d_precompcyl / 4 : 0); errstring = "geometry"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags, + &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; multimode: if (drvp->multi == 1) @@ -277,9 +282,10 @@ multimode: wdccommand(chp, xfer->c_drive, WDCC_SETMULTI, 0, 0, 0, drvp->multi, 0); errstring = "setmulti"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags, + &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; ready: drvp->state = READY; @@ -304,13 +310,13 @@ ctrlerror: printf("%s:%d:%d: %s ", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, errstring); - if (chp->ch_status & WDCS_DWF) { + if (ATACH_ST(tfd) & WDCS_DWF) { printf("drive fault\n"); ata_bio->error = ERR_DF; } else { - printf("error (%x)\n", chp->ch_error); - ata_bio->r_error = chp->ch_error; + ata_bio->r_error = ATACH_ERR(tfd); ata_bio->error = ERROR; + printf("error (%x)\n", ata_bio->r_error); } ctrldone: drvp->state = 0; @@ -335,7 +341,7 @@ _wdc_ata_bio_start(struct ata_channel *c uint8_t head, sect, cmd = 0; int nblks; #if NATA_DMA || NATA_PIOBM - int error, dma_flags = 0; + int error, dma_flags = 0, tfd; #endif ATADEBUG_PRINT(("_wdc_ata_bio_start %s:%d:%d\n", @@ -441,7 +447,8 @@ again: wdc->select(chp, xfer->c_drive); bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM | (xfer->c_drive << 4)); - switch(wdc_wait_for_ready(chp, ATA_DELAY, wait_flags)) { + switch(wdc_wait_for_ready(chp, ATA_DELAY, wait_flags, + &tfd)) { case WDCWAIT_OK: break; case WDCWAIT_TOUT: @@ -521,7 +528,7 @@ again: wdc->select(chp, xfer->c_drive); bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM | (xfer->c_drive << 4)); - switch(wdc_wait_for_ready(chp, ATA_DELAY, wait_flags)) { + switch(wdc_wait_for_ready(chp, ATA_DELAY, wait_flags, &tfd)) { case WDCWAIT_OK: break; case WDCWAIT_TOUT: @@ -556,17 +563,18 @@ again: * we have to busy-wait here, we can't rely on running in * thread context. */ - if (wdc_wait_for_drq(chp, ATA_DELAY, AT_POLL) != 0) { + if (wdc_wait_for_drq(chp, ATA_DELAY, AT_POLL, &tfd) != 0) { printf("%s:%d:%d: timeout waiting for DRQ, " "st=0x%02x, err=0x%02x\n", device_xname(atac->atac_dev), chp->ch_channel, - xfer->c_drive, chp->ch_status, chp->ch_error); - if (wdc_ata_err(drvp, ata_bio) != WDC_ATA_ERR) + xfer->c_drive, + ATACH_ST(tfd), ATACH_ERR(tfd)); + if (wdc_ata_err(drvp, ata_bio, tfd) != WDC_ATA_ERR) ata_bio->error = TIMEOUT; wdc_ata_bio_done(chp, xfer); return; } - if (wdc_ata_err(drvp, ata_bio) == WDC_ATA_ERR) { + if (wdc_ata_err(drvp, ata_bio, tfd) == WDC_ATA_ERR) { wdc_ata_bio_done(chp, xfer); return; } @@ -588,9 +596,7 @@ again: intr: #endif /* Wait for IRQ (either real or polled) */ - if ((ata_bio->flags & ATA_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; - } else { + if ((ata_bio->flags & ATA_POLL) != 0) { /* Wait for at last 400ns for status bit to be valid */ delay(1); #if NATA_DMA @@ -607,21 +613,22 @@ intr: timeout: printf("%s:%d:%d: not ready, st=0x%02x, err=0x%02x\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, - chp->ch_status, chp->ch_error); - if (wdc_ata_err(drvp, ata_bio) != WDC_ATA_ERR) + ATACH_ST(tfd), ATACH_ERR(tfd)); + if (wdc_ata_err(drvp, ata_bio, tfd) != WDC_ATA_ERR) ata_bio->error = TIMEOUT; wdc_ata_bio_done(chp, xfer); return; } static int -wdc_ata_bio_intr(struct ata_channel *chp, struct ata_xfer *xfer, int irq) +wdc_ata_bio_intr(struct ata_channel *chp, struct ata_xfer *xfer, int is) { struct atac_softc *atac = chp->ch_atac; struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct ata_bio *ata_bio = &xfer->c_bio; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; - int drv_err; + int drv_err, tfd; + bool poll = ((xfer->c_flags & C_POLL) != 0); ATADEBUG_PRINT(("wdc_ata_bio_intr %s:%d:%d\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive), @@ -655,8 +662,8 @@ wdc_ata_bio_intr(struct ata_channel *chp #endif /* Ack interrupt done by wdc_wait_for_unbusy */ - if (wdc_wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 0, AT_POLL) < 0) { - if (irq && (xfer->c_flags & C_TIMEOU) == 0) + if (wdc_wait_for_unbusy(chp, poll ? ATA_DELAY : 0, AT_POLL, &tfd) < 0) { + if (!poll && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, @@ -668,7 +675,7 @@ wdc_ata_bio_intr(struct ata_channel *chp if (wdc->irqack) wdc->irqack(chp); - drv_err = wdc_ata_err(drvp, ata_bio); + drv_err = wdc_ata_err(drvp, ata_bio, tfd); #if NATA_DMA /* If we were using DMA, Turn off the DMA channel and check for error */ @@ -681,12 +688,12 @@ wdc_ata_bio_intr(struct ata_channel *chp * asserted for DMA transfers, so poll for DRDY. */ if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY, - ATA_DELAY, ATA_POLL) == WDCWAIT_TOUT) { + ATA_DELAY, ATA_POLL, &tfd) == WDCWAIT_TOUT) { printf("%s:%d:%d: polled transfer timed out " "(st=0x%x)\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, - chp->ch_status); + ATACH_ST(tfd)); ata_bio->error = TIMEOUT; drv_err = WDC_ATA_ERR; } @@ -697,12 +704,12 @@ wdc_ata_bio_intr(struct ata_channel *chp drv_err = WDC_ATA_ERR; } } - if (chp->ch_status & WDCS_DRQ) { + if (ATACH_ST(tfd) & WDCS_DRQ) { if (drv_err != WDC_ATA_ERR) { printf("%s:%d:%d: intr with DRQ (st=0x%x)\n", device_xname(atac->atac_dev), chp->ch_channel, - xfer->c_drive, chp->ch_status); + xfer->c_drive, ATACH_ST(tfd)); ata_bio->error = TIMEOUT; drv_err = WDC_ATA_ERR; } @@ -722,7 +729,7 @@ wdc_ata_bio_intr(struct ata_channel *chp /* If this was a read and not using DMA, fetch the data. */ if ((ata_bio->flags & ATA_READ) != 0) { - if ((chp->ch_status & WDCS_DRQ) != WDCS_DRQ) { + if ((ATACH_ST(tfd) & WDCS_DRQ) != WDCS_DRQ) { printf("%s:%d:%d: read intr before drq\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive); @@ -737,7 +744,7 @@ wdc_ata_bio_intr(struct ata_channel *chp chp->ch_channel, xfer->c_drive, xfer->c_skip, ata_bio->nbytes, WDC_PIOBM_XFER_IRQ); - chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT | ATACH_IRQ_WAIT; + chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT; return 1; } else #endif @@ -830,30 +837,29 @@ wdc_ata_bio_done(struct ata_channel *chp } static int -wdc_ata_err(struct ata_drive_datas *drvp, struct ata_bio *ata_bio) +wdc_ata_err(struct ata_drive_datas *drvp, struct ata_bio *ata_bio, int tfd) { - struct ata_channel *chp = drvp->chnl_softc; ata_bio->error = 0; - if (chp->ch_status & WDCS_BSY) { + if (ATACH_ST(tfd) & WDCS_BSY) { ata_bio->error = TIMEOUT; return WDC_ATA_ERR; } - if (chp->ch_status & WDCS_DWF) { + if (ATACH_ST(tfd) & WDCS_DWF) { ata_bio->error = ERR_DF; return WDC_ATA_ERR; } - if (chp->ch_status & WDCS_ERR) { + if (ATACH_ST(tfd) & WDCS_ERR) { ata_bio->error = ERROR; - ata_bio->r_error = chp->ch_error; + ata_bio->r_error = ATACH_ERR(tfd); if (ata_bio->r_error & (WDCE_BBK | WDCE_UNC | WDCE_IDNF | WDCE_ABRT | WDCE_TK0NF | WDCE_AMNF)) return WDC_ATA_ERR; return WDC_ATA_NOERR; } - if (chp->ch_status & WDCS_CORR) + if (ATACH_ST(tfd) & WDCS_CORR) ata_bio->flags |= ATA_CORR; return WDC_ATA_NOERR; } Index: src/sys/dev/ata/atavar.h diff -u src/sys/dev/ata/atavar.h:1.92.8.21 src/sys/dev/ata/atavar.h:1.92.8.22 --- src/sys/dev/ata/atavar.h:1.92.8.21 Tue Aug 1 21:39:51 2017 +++ src/sys/dev/ata/atavar.h Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: atavar.h,v 1.92.8.21 2017/08/01 21:39:51 jdolecek Exp $ */ +/* $NetBSD: atavar.h,v 1.92.8.22 2017/08/12 09:52:28 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -148,9 +148,6 @@ struct ata_xfer { int c_skip; /* bytes already transferred */ int c_dscpoll; /* counter for dsc polling (ATAPI) */ int c_lenoff; /* offset to c_bcount (ATAPI) */ -#if 0 /* for now */ - int c_ata_status; /* copy of ATA error + status */ -#endif #define ATACH_ERR_ST(error, status) ((error) << 8 | (status)) #define ATACH_ERR(val) (((val) >> 8) & 0xff) #define ATACH_ST(val) (((val) >> 0) & 0xff) @@ -391,7 +388,6 @@ struct ata_channel { /* Our state */ volatile int ch_flags; #define ATACH_SHUTDOWN 0x02 /* channel is shutting down */ -#define ATACH_IRQ_WAIT 0x10 /* controller is waiting for irq */ #define ATACH_DMA_WAIT 0x20 /* controller is waiting for DMA */ #define ATACH_PIOBM_WAIT 0x40 /* controller is waiting for busmastering PIO */ #define ATACH_DISABLED 0x80 /* channel is disabled */ @@ -399,10 +395,6 @@ struct ata_channel { #define ATACH_TH_RESET 0x200 /* someone ask the thread to reset */ #define ATACH_TH_RESCAN 0x400 /* rescan requested */ #define ATACH_NCQ 0x800 /* channel executing NCQ commands */ -#if 1 /* for now */ - uint8_t ch_status; /* copy of status register */ - uint8_t ch_error; /* copy of error register */ -#endif /* for the reset callback */ int ch_reset_flags; @@ -516,6 +508,7 @@ void ata_deactivate_xfer(struct ata_chan void ata_exec_xfer(struct ata_channel *, struct ata_xfer *); void ata_timeout(void *); +bool ata_timo_xfer_check(struct ata_xfer *); void ata_kill_pending(struct ata_drive_datas *); void ata_kill_active(struct ata_channel *, int, int); void ata_reset_channel(struct ata_channel *, int); Index: src/sys/dev/ic/mvsata.c diff -u src/sys/dev/ic/mvsata.c:1.35.6.19 src/sys/dev/ic/mvsata.c:1.35.6.20 --- src/sys/dev/ic/mvsata.c:1.35.6.19 Sat Aug 12 09:38:58 2017 +++ src/sys/dev/ic/mvsata.c Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsata.c,v 1.35.6.19 2017/08/12 09:38:58 jdolecek Exp $ */ +/* $NetBSD: mvsata.c,v 1.35.6.20 2017/08/12 09:52:28 jdolecek Exp $ */ /* * Copyright (c) 2008 KIYOHARA Takashi * All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.19 2017/08/12 09:38:58 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.20 2017/08/12 09:52:28 jdolecek Exp $"); #include "opt_mvsata.h" @@ -135,7 +135,7 @@ static void mvsata_wdc_cmd_start(struct static int mvsata_wdc_cmd_intr(struct ata_channel *, struct ata_xfer *, int); static void mvsata_wdc_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *, int); -static void mvsata_wdc_cmd_done(struct ata_channel *, struct ata_xfer *); +static void mvsata_wdc_cmd_done(struct ata_channel *, struct ata_xfer *, int); static void mvsata_wdc_cmd_done_end(struct ata_channel *, struct ata_xfer *); #if NATAPIBUS > 0 static void mvsata_atapi_start(struct ata_channel *, struct ata_xfer *); @@ -448,11 +448,7 @@ mvsata_nondma_handle(struct mvsata_port KASSERT(quetag < MVSATA_EDMAQ_LEN); xfer = ata_queue_hwslot_to_xfer(chp, quetag); - chp->ch_flags &= ~ATACH_IRQ_WAIT; - KASSERT(xfer->c_intr != NULL); ret = xfer->c_intr(chp, xfer, 1); - if (ret == 0) /* irq was not for us, still waiting for irq */ - chp->ch_flags |= ATACH_IRQ_WAIT; return (ret); } @@ -603,11 +599,11 @@ mvsata_reset_drive(struct ata_drive_data (edma_c & EDMA_CMD_EENEDMA) ? "" : "not ")); if (edma_c & EDMA_CMD_EENEDMA) - mvsata_edma_disable(mvport, 10000, flags & AT_WAIT); + mvsata_edma_disable(mvport, 10000, flags); mvsata_pmp_select(mvport, drvp->drive); - sig = mvsata_softreset(mvport, flags & AT_WAIT); + sig = mvsata_softreset(mvport, flags); if (sigp) *sigp = sig; @@ -934,9 +930,8 @@ mvsata_atapi_probe_device(struct atapibu } } else { DPRINTF(("%s:%d: mvsata_atapi_probe_device:" - " ATAPI_IDENTIFY_DEVICE failed for drive %d: error 0x%x\n", - device_xname(atac->atac_dev), chp->ch_channel, target, - chp->ch_error)); + " ATAPI_IDENTIFY_DEVICE failed for drive %d: error\n", + device_xname(atac->atac_dev), chp->ch_channel, target)); s = splbio(); drvp->drive_type = ATA_DRIVET_NONE; splx(s); @@ -1079,10 +1074,10 @@ mvsata_bio_start(struct ata_channel *chp struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct ata_bio *ata_bio = &xfer->c_bio; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; - int wait_flags = ata_bio->flags & AT_WAIT; + int wait_flags = ata_bio->flags & (AT_WAIT|AT_POLL); u_int16_t cyl; u_int8_t head, sect, cmd = 0; - int nblks, error; + int nblks, error, tfd; DPRINTFN(2, ("%s:%d: mvsata_bio_start: drive=%d\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive)); @@ -1169,7 +1164,7 @@ mvsata_bio_start(struct ata_channel *chp /* start timeout machinery */ if ((xfer->c_flags & C_POLL) == 0) callout_reset(&xfer->c_timo_callout, - ATA_DELAY / 1000 * hz, + mstohz(ATA_DELAY), mvsata_edma_timeout, xfer); /* wait for irq */ goto intr; @@ -1237,7 +1232,7 @@ do_pio: /* Initiate command! */ MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM); - switch(wdc_wait_for_ready(chp, ATA_DELAY, wait_flags)) { + switch(wdc_wait_for_ready(chp, ATA_DELAY, wait_flags, &tfd)) { case WDCWAIT_OK: break; case WDCWAIT_TOUT: @@ -1257,7 +1252,7 @@ do_pio: /* start timeout machinery */ if ((xfer->c_flags & C_POLL) == 0) callout_reset(&xfer->c_timo_callout, - ATA_DELAY / 1000 * hz, wdctimeout, xfer); + mstohz(ATA_DELAY), wdctimeout, xfer); } else if (ata_bio->nblks > 1) { /* The number of blocks in the last stretch may be smaller. */ nblks = xfer->c_bcount / drvp->lp->d_secsize; @@ -1272,19 +1267,19 @@ do_pio: * we have to busy-wait here, we can't rely on running in * thread context. */ - if (wdc_wait_for_drq(chp, ATA_DELAY, AT_POLL) != 0) { + if (wdc_wait_for_drq(chp, ATA_DELAY, AT_POLL, &tfd) != 0) { aprint_error_dev(atac->atac_dev, "channel %d: drive %d timeout waiting for DRQ," " st=0x%02x, err=0x%02x\n", - chp->ch_channel, xfer->c_drive, chp->ch_status, - chp->ch_error); + chp->ch_channel, xfer->c_drive, ATACH_ST(tfd), + ATACH_ERR(tfd)); ata_bio->error = TIMEOUT; mvsata_bio_done(chp, xfer); return; } - if (chp->ch_status & WDCS_ERR) { + if (ATACH_ST(tfd) & WDCS_ERR) { ata_bio->error = ERROR; - ata_bio->r_error = chp->ch_error; + ata_bio->r_error = ATACH_ERR(tfd); mvsata_bio_done(chp, xfer); return; } @@ -1295,9 +1290,7 @@ do_pio: intr: /* Wait for IRQ (either real or polled) */ - if ((ata_bio->flags & ATA_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; - } else { + if ((ata_bio->flags & ATA_POLL) != 0) { /* Wait for at last 400ns for status bit to be valid */ delay(1); if (chp->ch_flags & ATACH_DMA_WAIT) { @@ -1313,7 +1306,7 @@ intr: timeout: aprint_error_dev(atac->atac_dev, "channel %d: drive %d not ready, st=0x%02x, err=0x%02x\n", - chp->ch_channel, xfer->c_drive, chp->ch_status, chp->ch_error); + chp->ch_channel, xfer->c_drive, ATACH_ST(tfd), ATACH_ERR(tfd)); ata_bio->error = TIMEOUT; mvsata_bio_done(chp, xfer); return; @@ -1326,11 +1319,13 @@ mvsata_bio_intr(struct ata_channel *chp, struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct ata_bio *ata_bio = &xfer->c_bio; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; + int tfd; - DPRINTFN(2, ("%s:%d: mvsata_bio_intr: drive=%d\n", - device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive)); + DPRINTFN(2, ("%s:%d: %s: drive=%d\n", + device_xname(atac->atac_dev), chp->ch_channel, __func__, + xfer->c_drive)); - chp->ch_flags &= ~(ATACH_IRQ_WAIT|ATACH_DMA_WAIT); + chp->ch_flags &= ~(ATACH_DMA_WAIT); /* * If we missed an interrupt transfer, reset and restart. @@ -1345,14 +1340,14 @@ mvsata_bio_intr(struct ata_channel *chp, /* Is it not a transfer, but a control operation? */ if (!(xfer->c_flags & C_DMA) && drvp->state < READY) { aprint_error_dev(atac->atac_dev, - "channel %d: drive %d bad state %d in mvsata_bio_intr\n", - chp->ch_channel, xfer->c_drive, drvp->state); - panic("mvsata_bio_intr: bad state"); + "channel %d: drive %d bad state %d in %s\n", + chp->ch_channel, xfer->c_drive, drvp->state, __func__); + panic("%s: bad state", __func__); } /* Ack interrupt done by wdc_wait_for_unbusy */ if (!(xfer->c_flags & C_DMA) && - (wdc_wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 0, AT_POLL) + (wdc_wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 0, AT_POLL, &tfd) == WDCWAIT_TOUT)) { if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ @@ -1381,7 +1376,7 @@ mvsata_bio_intr(struct ata_channel *chp, /* If this was a read and not using DMA, fetch the data. */ if ((ata_bio->flags & ATA_READ) != 0) { - if ((chp->ch_status & WDCS_DRQ) != WDCS_DRQ) { + if ((ATACH_ST(tfd) & WDCS_DRQ) != WDCS_DRQ) { aprint_error_dev(atac->atac_dev, "channel %d: drive %d read intr before drq\n", chp->ch_channel, xfer->c_drive); @@ -1497,6 +1492,7 @@ mvsata_bio_ready(struct mvsata_port *mvp struct atac_softc *atac = chp->ch_atac; struct ata_drive_datas *drvp = &chp->ch_drive[drive]; const char *errstring; + int tfd; flags |= AT_POLL; /* XXX */ @@ -1508,15 +1504,15 @@ mvsata_bio_ready(struct mvsata_port *mvp MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM); DELAY(10); errstring = "wait"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags, &tfd)) goto ctrltimeout; wdccommandshort(chp, 0, WDCC_RECAL); /* Wait for at least 400ns for status bit to be valid */ DELAY(1); errstring = "recal"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags, &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; /* Don't try to set modes if controller can't be adjusted */ if (atac->atac_set_modes == NULL) @@ -1526,10 +1522,10 @@ mvsata_bio_ready(struct mvsata_port *mvp goto geometry; wdccommand(chp, 0, SET_FEATURES, 0, 0, 0, 0x08 | drvp->PIO_mode, WDSF_SET_MODE); - errstring = "piomode"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags)) + errstring = "piomode-bio"; + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags, &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; if (drvp->drive_flags & ATA_DRIVE_UDMA) wdccommand(chp, 0, SET_FEATURES, 0, 0, 0, @@ -1539,10 +1535,10 @@ mvsata_bio_ready(struct mvsata_port *mvp 0x20 | drvp->DMA_mode, WDSF_SET_MODE); else goto geometry; - errstring = "dmamode"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags)) + errstring = "dmamode-bio"; + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags, &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; geometry: if (ata_bio->flags & ATA_LBA) @@ -1552,18 +1548,18 @@ geometry: (drvp->lp->d_type == DKTYPE_ST506) ? drvp->lp->d_precompcyl / 4 : 0); errstring = "geometry"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags, &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; multimode: if (drvp->multi == 1) goto ready; wdccommand(chp, 0, WDCC_SETMULTI, 0, 0, 0, drvp->multi, 0); errstring = "setmulti"; - if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags)) + if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags, &tfd)) goto ctrltimeout; - if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) + if (ATACH_ST(tfd) & (WDCS_ERR | WDCS_DWF)) goto ctrlerror; ready: drvp->state = READY; @@ -1582,13 +1578,13 @@ ctrltimeout: ctrlerror: aprint_error_dev(atac->atac_dev, "channel %d: drive %d %s ", chp->ch_channel, drive, errstring); - if (chp->ch_status & WDCS_DWF) { + if (ATACH_ST(tfd) & WDCS_DWF) { aprint_error("drive fault\n"); ata_bio->error = ERR_DF; } else { - aprint_error("error (%x)\n", chp->ch_error); - ata_bio->r_error = chp->ch_error; + ata_bio->r_error = ATACH_ERR(tfd); ata_bio->error = ERROR; + aprint_error("error (%x)\n", ata_bio->r_error); } ctrldone: drvp->state = 0; @@ -1603,6 +1599,7 @@ mvsata_wdc_cmd_start(struct ata_channel int drive = xfer->c_drive; int wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0; struct ata_command *ata_c = &xfer->c_ata_c; + int tfd; DPRINTFN(1, ("%s:%d: mvsata_cmd_start: drive=%d\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, drive)); @@ -1615,12 +1612,12 @@ mvsata_wdc_cmd_start(struct ata_channel MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM); switch(wdcwait(chp, ata_c->r_st_bmask | WDCS_DRQ, - ata_c->r_st_bmask, ata_c->timeout, wait_flags)) { + ata_c->r_st_bmask, ata_c->timeout, wait_flags, &tfd)) { case WDCWAIT_OK: break; case WDCWAIT_TOUT: ata_c->flags |= AT_TIMEOU; - mvsata_wdc_cmd_done(chp, xfer); + mvsata_wdc_cmd_done(chp, xfer, tfd); return; case WDCWAIT_THR: return; @@ -1643,7 +1640,6 @@ mvsata_wdc_cmd_start(struct ata_channel } if ((ata_c->flags & AT_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */ callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz, wdctimeout, xfer); return; @@ -1666,6 +1662,7 @@ mvsata_wdc_cmd_intr(struct ata_channel * char *data = ata_c->data; int wflags; int drive_flags; + int tfd; if (ata_c->r_command == WDCC_IDENTIFY || ata_c->r_command == ATAPI_IDENTIFY_DEVICE) @@ -1691,8 +1688,9 @@ mvsata_wdc_cmd_intr(struct ata_channel * wflags = AT_POLL; again: - DPRINTFN(1, ("%s:%d: mvsata_cmd_intr: drive=%d\n", - device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, xfer->c_drive)); + DPRINTFN(1, ("%s:%d: %s: drive=%d\n", + device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, + __func__, xfer->c_drive)); /* * after a ATAPI_SOFT_RESET, the device will have released the bus. @@ -1709,8 +1707,8 @@ again: * in its initial state */ if (wdcwait(chp, ata_c->r_st_bmask | WDCS_DRQ, - ata_c->r_st_bmask, (irq == 0) ? ata_c->timeout : 0, - wflags) == WDCWAIT_TOUT) { + ata_c->r_st_bmask, (irq == 0) ? ata_c->timeout : 0, + wflags, &tfd) == WDCWAIT_TOUT) { if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ ata_c->flags |= AT_TIMEOU; @@ -1718,7 +1716,7 @@ again: goto out; } if (wdcwait(chp, ata_c->r_st_pmask, ata_c->r_st_pmask, - (irq == 0) ? ata_c->timeout : 0, wflags) == WDCWAIT_TOUT) { + (irq == 0) ? ata_c->timeout : 0, wflags, &tfd) == WDCWAIT_TOUT) { if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ ata_c->flags |= AT_TIMEOU; @@ -1726,7 +1724,7 @@ again: } delay(20); /* XXXXX: Delay more times. */ if (ata_c->flags & AT_READ) { - if ((chp->ch_status & WDCS_DRQ) == 0) { + if ((ATACH_ST(tfd) & WDCS_DRQ) == 0) { ata_c->flags |= AT_TIMEOU; goto out; } @@ -1738,14 +1736,13 @@ again: * hardware to timeout. */ } else if (ata_c->flags & AT_WRITE) { - if ((chp->ch_status & WDCS_DRQ) == 0) { + if ((ATACH_ST(tfd) & WDCS_DRQ) == 0) { ata_c->flags |= AT_TIMEOU; goto out; } wdc->dataout_pio(chp, drive_flags, data, bcount); ata_c->flags |= AT_XFDONE; if ((ata_c->flags & AT_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for intr */ callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout), wdctimeout, xfer); return 1; @@ -1753,7 +1750,7 @@ again: goto again; } out: - mvsata_wdc_cmd_done(chp, xfer); + mvsata_wdc_cmd_done(chp, xfer, tfd); return 1; } @@ -1793,7 +1790,7 @@ mvsata_wdc_cmd_kill_xfer(struct ata_chan } static void -mvsata_wdc_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer) +mvsata_wdc_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer, int tfd) { struct mvsata_port *mvport = (struct mvsata_port *)chp; struct atac_softc *atac = chp->ch_atac; @@ -1806,11 +1803,11 @@ mvsata_wdc_cmd_done(struct ata_channel * if (ata_waitdrain_xfer_check(chp, xfer)) return; - if (chp->ch_status & WDCS_DWF) + if (ATACH_ST(tfd) & WDCS_DWF) ata_c->flags |= AT_DF; - if (chp->ch_status & WDCS_ERR) { + if (ATACH_ST(tfd) & WDCS_ERR) { ata_c->flags |= AT_ERROR; - ata_c->r_error = chp->ch_error; + ata_c->r_error = ATACH_ERR(tfd); } if ((ata_c->flags & AT_READREG) != 0 && device_is_active(atac->atac_dev) && @@ -1895,6 +1892,7 @@ mvsata_atapi_start(struct ata_channel *c struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; const int wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0; const char *errstring; + int tfd; DPRINTFN(2, ("%s:%d:%d: mvsata_atapi_start: scsi flags 0x%x\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, @@ -1931,15 +1929,16 @@ mvsata_atapi_start(struct ata_channel *c if ((drvp->drive_flags & ATA_DRIVE_MODE) == 0) goto ready; errstring = "unbusy"; - if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags)) + if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd)) goto timeout; wdccommand(chp, 0, SET_FEATURES, 0, 0, 0, 0x08 | drvp->PIO_mode, WDSF_SET_MODE); - errstring = "piomode"; - if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags)) + errstring = "piomode-atapi"; + if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags, + &tfd)) goto timeout; - if (chp->ch_status & WDCS_ERR) { - if (chp->ch_error == WDCE_ABRT) { + if (ATACH_ST(tfd) & WDCS_ERR) { + if (ATACH_ERR(tfd) == WDCE_ABRT) { /* * Some ATAPI drives reject PIO settings. * Fall back to PIO mode 3 since that's the @@ -1964,11 +1963,12 @@ mvsata_atapi_start(struct ata_channel *c 0x20 | drvp->DMA_mode, WDSF_SET_MODE); else goto ready; - errstring = "dmamode"; - if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags)) + errstring = "dmamode-atapi"; + if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags, + &tfd)) goto timeout; - if (chp->ch_status & WDCS_ERR) { - if (chp->ch_error == WDCE_ABRT) { + if (ATACH_ST(tfd) & WDCS_ERR) { + if (ATACH_ERR(tfd) == WDCE_ABRT) { if (drvp->drive_flags & ATA_DRIVE_UDMA) goto error; else { @@ -1999,9 +1999,9 @@ ready: wdctimeout, xfer); MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM); - if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags)) { + if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd)) { aprint_error_dev(atac->atac_dev, "not ready, st = %02x\n", - chp->ch_status); + ATACH_ST(tfd)); sc_xfer->error = XS_TIMEOUT; mvsata_atapi_reset(chp, xfer); } @@ -2029,8 +2029,7 @@ ready: /* Wait for at last 400ns for status bit to be valid */ DELAY(1); mvsata_atapi_intr(chp, xfer, 0); - } else - chp->ch_flags |= ATACH_IRQ_WAIT; + } if (sc_xfer->xs_control & XS_CTL_POLL) { if (chp->ch_flags & ATACH_DMA_WAIT) { wdc_dmawait(chp, xfer, sc_xfer->timeout); @@ -2056,9 +2055,9 @@ timeout: error: aprint_error_dev(atac->atac_dev, "channel %d drive %d: %s error (0x%x)\n", - chp->ch_channel, xfer->c_drive, errstring, chp->ch_error); + chp->ch_channel, xfer->c_drive, errstring, ATACH_ERR(tfd)); sc_xfer->error = XS_SHORTSENSE; - sc_xfer->sense.atapi_sense = chp->ch_error; + sc_xfer->sense.atapi_sense = ATACH_ERR(tfd); MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_4BIT); delay(10); /* some drives need a little delay here */ mvsata_atapi_reset(chp, xfer); @@ -2074,6 +2073,7 @@ mvsata_atapi_intr(struct ata_channel *ch struct scsipi_xfer *sc_xfer = xfer->c_scsipi; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; int len, phase, ire, error, retries=0, i; + int tfd; void *cmd; DPRINTFN(1, ("%s:%d:%d: mvsata_atapi_intr\n", @@ -2099,7 +2099,7 @@ mvsata_atapi_intr(struct ata_channel *ch /* Ack interrupt done in wdc_wait_for_unbusy */ MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM); if (wdc_wait_for_unbusy(chp, - (irq == 0) ? sc_xfer->timeout : 0, AT_POLL) == WDCWAIT_TOUT) { + (irq == 0) ? sc_xfer->timeout : 0, AT_POLL, &tfd) == WDCWAIT_TOUT) { if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ aprint_error_dev(atac->atac_dev, @@ -2132,10 +2132,10 @@ again: len = MVSATA_WDC_READ_1(mvport, SRB_LBAM) + 256 * MVSATA_WDC_READ_1(mvport, SRB_LBAH); ire = MVSATA_WDC_READ_1(mvport, SRB_SC); - phase = (ire & (WDCI_CMD | WDCI_IN)) | (chp->ch_status & WDCS_DRQ); + phase = (ire & (WDCI_CMD | WDCI_IN)) | (ATACH_ST(tfd) & WDCS_DRQ); DPRINTF(( "mvsata_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x ire 0x%x :", - xfer->c_bcount, len, chp->ch_status, chp->ch_error, ire)); + xfer->c_bcount, len, ATACH_ST(tfd), ATACH_ERR(tfd), ire)); switch (phase) { case PHASE_CMDOUT: @@ -2168,9 +2168,6 @@ again: mvsata_bdma_start(mvport); chp->ch_flags |= ATACH_DMA_WAIT; } - - if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) - chp->ch_flags |= ATACH_IRQ_WAIT; return 1; case PHASE_DATAOUT: @@ -2205,8 +2202,6 @@ again: xfer->c_skip += len; xfer->c_bcount -= len; - if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) - chp->ch_flags |= ATACH_IRQ_WAIT; return 1; case PHASE_DATAIN: @@ -2241,8 +2236,6 @@ again: xfer->c_skip += len; xfer->c_bcount -= len; - if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) - chp->ch_flags |= ATACH_IRQ_WAIT; return 1; case PHASE_ABORTED: @@ -2257,16 +2250,18 @@ again: default: if (++retries<500) { DELAY(100); - chp->ch_status = MVSATA_WDC_READ_1(mvport, SRB_CS); - chp->ch_error = MVSATA_WDC_READ_1(mvport, SRB_FE); + tfd = ATACH_ERR_ST( + MVSATA_WDC_READ_1(mvport, SRB_FE), + MVSATA_WDC_READ_1(mvport, SRB_CS) + ); goto again; } aprint_error_dev(atac->atac_dev, "channel %d drive %d: unknown phase 0x%x\n", chp->ch_channel, xfer->c_drive, phase); - if (chp->ch_status & WDCS_ERR) { + if (ATACH_ST(tfd) & WDCS_ERR) { sc_xfer->error = XS_SHORTSENSE; - sc_xfer->sense.atapi_sense = chp->ch_error; + sc_xfer->sense.atapi_sense = ATACH_ERR(tfd); } else { if (xfer->c_flags & C_DMA) ata_dmaerr(drvp, @@ -2323,12 +2318,13 @@ mvsata_atapi_reset(struct ata_channel *c struct atac_softc *atac = chp->ch_atac; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; struct scsipi_xfer *sc_xfer = xfer->c_scsipi; + int tfd; mvsata_pmp_select(mvport, xfer->c_drive); wdccommandshort(chp, 0, ATAPI_SOFT_RESET); drvp->state = 0; - if (wdc_wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL) != 0) { + if (wdc_wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL, &tfd) != 0) { printf("%s:%d:%d: reset failed\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive); sc_xfer->error = XS_SELTIMEOUT; @@ -2345,6 +2341,7 @@ mvsata_atapi_phase_complete(struct ata_x struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct scsipi_xfer *sc_xfer = xfer->c_scsipi; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; + int tfd; /* wait for DSC if needed */ if (drvp->drive_flags & ATA_DRIVE_ATAPIDSCW) { @@ -2355,7 +2352,7 @@ mvsata_atapi_phase_complete(struct ata_x if (cold) panic("mvsata_atapi_phase_complete: cold"); - if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10, AT_POLL) == + if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10, AT_POLL, &tfd) == WDCWAIT_TOUT) { /* 10ms not enough, try again in 1 tick */ if (xfer->c_dscpoll++ > mstohz(sc_xfer->timeout)) { @@ -2378,12 +2375,12 @@ mvsata_atapi_phase_complete(struct ata_x * register. If we read some data the sense is valid * anyway, so don't report the error. */ - if (chp->ch_status & WDCS_ERR && + if (ATACH_ST(tfd) & WDCS_ERR && ((sc_xfer->xs_control & XS_CTL_REQSENSE) == 0 || sc_xfer->resid == sc_xfer->datalen)) { /* save the short sense */ sc_xfer->error = XS_SHORTSENSE; - sc_xfer->sense.atapi_sense = chp->ch_error; + sc_xfer->sense.atapi_sense = ATACH_ERR(tfd); if ((sc_xfer->xs_periph->periph_quirks & PQUIRK_NOSENSE) == 0) { /* ask scsipi to send a REQUEST_SENSE */ sc_xfer->error = XS_BUSY; @@ -2547,6 +2544,7 @@ mvsata_edma_handle(struct mvsata_port *m struct ata_xfer *xfer; uint32_t reg; int erqqip, erqqop, erpqip, erpqop, prev_erpqop, quetag, handled = 0, n; + int st, err, tfd; /* First, Sync for Request Queue buffer */ reg = MVSATA_EDMA_READ_4(mvport, EDMA_REQQOP); @@ -2613,16 +2611,19 @@ mvsata_edma_handle(struct mvsata_port *m mvport->port_reqtbl[xfer->c_slot].eprd_offset, MVSATA_EPRD_MAX_SIZE, BUS_DMASYNC_POSTWRITE); - chp->ch_status = CRPB_CDEVSTS(le16toh(crpb->rspflg)); - chp->ch_error = CRPB_CEDMASTS(le16toh(crpb->rspflg)); + st = CRPB_CDEVSTS(le16toh(crpb->rspflg)); + err = CRPB_CEDMASTS(le16toh(crpb->rspflg)); + + tfd = ATACH_ERR_ST(err, st); + ata_bio = &xfer->c_bio; ata_bio->error = NOERROR; ata_bio->r_error = 0; - if (chp->ch_status & WDCS_ERR) + if (ATACH_ST(tfd) & WDCS_ERR) ata_bio->error = ERROR; - if (chp->ch_status & WDCS_BSY) + if (ATACH_ST(tfd) & WDCS_BSY) ata_bio->error = TIMEOUT; - if (chp->ch_error) + if (ATACH_ERR(tfd)) ata_bio->error = ERR_DMA; mvsata_dma_bufunload(mvport, quetag, ata_bio->flags); @@ -2632,7 +2633,7 @@ mvsata_edma_handle(struct mvsata_port *m erqqip = (MVSATA_EDMA_READ_4(mvport, EDMA_REQQIP) & EDMA_REQQP_ERQQP_MASK) >> EDMA_REQQP_ERQQP_SHIFT; if (erpqop == erqqip) - chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_IRQ_WAIT); + chp->ch_flags &= ~(ATACH_DMA_WAIT); #endif mvsata_bio_intr(chp, xfer, 1); if (xfer1 == NULL) @@ -2664,7 +2665,7 @@ mvsata_edma_handle(struct mvsata_port *m erqqip = (MVSATA_EDMA_READ_4(mvport, EDMA_REQQIP) & EDMA_REQQP_ERQQP_MASK) >> EDMA_REQQP_ERQQP_SHIFT; if (erpqop == erqqip) - chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_IRQ_WAIT); + chp->ch_flags &= ~(ATACH_DMA_WAIT); #endif return handled; @@ -2697,11 +2698,17 @@ mvsata_edma_timeout(void *arg) s = splbio(); DPRINTF(("mvsata_edma_timeout: %p\n", xfer)); - if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) { - mvsata_edma_rqq_remove(mvport, xfer); - xfer->c_flags |= C_TIMEOU; - mvsata_bio_intr(chp, xfer, 1); + + if (ata_timo_xfer_check(xfer)) { + /* Already logged */ + goto out; } + + mvsata_edma_rqq_remove(mvport, xfer); + xfer->c_flags |= C_TIMEOU; + mvsata_bio_intr(chp, xfer, 0); + +out: splx(s); } @@ -3217,9 +3224,6 @@ mvsata_reset_hc(struct mvsata_hc *mvhc) #endif } -#define WDCDELAY 100 /* 100 microseconds */ -#define WDCNDELAY_RST (WDC_RESET_WAIT * 1000 / WDCDELAY) - static uint32_t mvsata_softreset(struct mvsata_port *mvport, int flags) { @@ -3234,7 +3238,7 @@ mvsata_softreset(struct mvsata_port *mvp delay(10); /* wait for BSY to deassert */ - for (timeout = 0; timeout < WDCNDELAY_RST; timeout++) { + for (timeout = 0; timeout < WDC_RESET_WAIT / 10; timeout++) { st0 = MVSATA_WDC_READ_1(mvport, SRB_CS); if ((st0 & WDCS_BSY) == 0) { @@ -3244,9 +3248,13 @@ mvsata_softreset(struct mvsata_port *mvp sig0 |= MVSATA_WDC_READ_1(mvport, SRB_LBAH) << 24; goto out; } - ata_delay(WDCDELAY, "atarst", flags); + ata_delay(10, "atarst", flags); } - + + aprint_error("%s:%d:%d: %s: timeout\n", + device_xname(MVSATA_DEV2(mvport)), + mvport->port_hc->hc, mvport->port, __func__); + out: MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_4BIT); return sig0; Index: src/sys/dev/ic/wdc.c diff -u src/sys/dev/ic/wdc.c:1.283.2.10 src/sys/dev/ic/wdc.c:1.283.2.11 --- src/sys/dev/ic/wdc.c:1.283.2.10 Tue Jun 27 18:36:04 2017 +++ src/sys/dev/ic/wdc.c Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: wdc.c,v 1.283.2.10 2017/06/27 18:36:04 jdolecek Exp $ */ +/* $NetBSD: wdc.c,v 1.283.2.11 2017/08/12 09:52:28 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved. @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.10 2017/06/27 18:36:04 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.11 2017/08/12 09:52:28 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wdc.h" @@ -146,13 +146,13 @@ static int wdcprobe1(struct ata_channel static int wdcreset(struct ata_channel *, int); static void __wdcerror(struct ata_channel *, const char *); static int __wdcwait_reset(struct ata_channel *, int, int); -static void __wdccommand_done(struct ata_channel *, struct ata_xfer *); +static void __wdccommand_done(struct ata_channel *, struct ata_xfer *, int); static void __wdccommand_done_end(struct ata_channel *, struct ata_xfer *); static void __wdccommand_kill_xfer(struct ata_channel *, struct ata_xfer *, int); static void __wdccommand_start(struct ata_channel *, struct ata_xfer *); static int __wdccommand_intr(struct ata_channel *, struct ata_xfer *, int); -static int __wdcwait(struct ata_channel *, int, int, int); +static int __wdcwait(struct ata_channel *, int, int, int, int *); static void wdc_datain_pio(struct ata_channel *, int, void *, size_t); static void wdc_dataout_pio(struct ata_channel *, int, void *, size_t); @@ -289,7 +289,7 @@ wdc_drvprobe(struct ata_channel *chp) struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct wdc_regs *wdr = &wdc->regs[chp->ch_channel]; u_int8_t st0 = 0, st1 = 0; - int i, j, error, s; + int i, j, error, s, tfd; if (atabus_alloc_drives(chp, wdc->wdc_maxdrives) != 0) return; @@ -437,7 +437,8 @@ wdc_drvprobe(struct ata_channel *chp) splx(s); continue; } - if (wdc_wait_for_ready(chp, 10000, 0) == WDCWAIT_TOUT) { + if (wdc_wait_for_ready(chp, 10000, 0, &tfd) == + WDCWAIT_TOUT) { ATADEBUG_PRINT(("%s:%d:%d: not ready\n", device_xname(atac->atac_dev), chp->ch_channel, i), DEBUG_PROBE); @@ -449,7 +450,8 @@ wdc_drvprobe(struct ata_channel *chp) bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_command], 0, WDCC_RECAL); delay(10); /* 400ns delay */ - if (wdc_wait_for_ready(chp, 10000, 0) == WDCWAIT_TOUT) { + if (wdc_wait_for_ready(chp, 10000, 0, &tfd) == + WDCWAIT_TOUT) { ATADEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n", device_xname(atac->atac_dev), chp->ch_channel, i), DEBUG_PROBE); @@ -864,7 +866,9 @@ wdcintr(void *arg) DEBUG_INTR); return (0); } - if ((chp->ch_flags & ATACH_IRQ_WAIT) == 0) { + + xfer = ata_queue_get_active_xfer(chp); + if (xfer == NULL) { ATADEBUG_PRINT(("wdcintr: inactive controller\n"), DEBUG_INTR); /* try to clear the pending interrupt anyway */ (void)bus_space_read_1(wdr->cmd_iot, @@ -873,15 +877,8 @@ wdcintr(void *arg) } ATADEBUG_PRINT(("wdcintr\n"), DEBUG_INTR); - xfer = ata_queue_get_active_xfer(chp); KASSERT(xfer != NULL); -#ifdef DIAGNOSTIC - if (xfer->c_chp != chp) { - printf("channel %d expected %d\n", xfer->c_chp->ch_channel, - chp->ch_channel); - panic("wdcintr: wrong channel"); - } -#endif + #if NATA_DMA || NATA_PIOBM if (chp->ch_flags & ATACH_DMA_WAIT) { wdc->dma_status = @@ -894,11 +891,8 @@ wdcintr(void *arg) chp->ch_flags &= ~ATACH_DMA_WAIT; } #endif - chp->ch_flags &= ~ATACH_IRQ_WAIT; KASSERT(xfer->c_intr != NULL); ret = xfer->c_intr(chp, xfer, 1); - if (ret == 0) /* irq was not for us, still waiting for irq */ - chp->ch_flags |= ATACH_IRQ_WAIT; return (ret); } @@ -925,8 +919,6 @@ wdc_reset_channel(struct ata_channel *ch struct wdc_softc *wdc = CHAN_TO_WDC(chp); #endif - chp->ch_flags &= ~ATACH_IRQ_WAIT; - /* * if the current command is on an ATAPI device, issue a * ATAPI_SOFT_RESET @@ -1162,22 +1154,23 @@ end: * return -1 for a timeout after "timeout" ms. */ static int -__wdcwait(struct ata_channel *chp, int mask, int bits, int timeout) +__wdcwait(struct ata_channel *chp, int mask, int bits, int timeout, int *tfd) { struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct wdc_regs *wdr = &wdc->regs[chp->ch_channel]; - u_char status; + u_char status, error = 0; int xtime = 0; + int rv; ATADEBUG_PRINT(("__wdcwait %s:%d\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel), DEBUG_STATUS); - chp->ch_error = 0; + *tfd = 0; timeout = timeout * 1000 / WDCDELAY; /* delay uses microseconds */ for (;;) { - chp->ch_status = status = + status = bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_status], 0); if ((status & (WDCS_BSY | mask)) == bits) break; @@ -1188,7 +1181,8 @@ __wdcwait(struct ata_channel *chp, int m bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_error], 0), mask, bits), DEBUG_STATUS | DEBUG_PROBE | DEBUG_DELAY); - return(WDCWAIT_TOUT); + rv = WDCWAIT_TOUT; + goto out; } delay(WDCDELAY); } @@ -1197,7 +1191,7 @@ __wdcwait(struct ata_channel *chp, int m printf("__wdcwait: did busy-wait, time=%d\n", xtime); #endif if (status & WDCS_ERR) - chp->ch_error = bus_space_read_1(wdr->cmd_iot, + error = bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_error], 0); #ifdef WDCNDELAY_DEBUG /* After autoconfig, there should be no long delays. */ @@ -1216,7 +1210,11 @@ __wdcwait(struct ata_channel *chp, int m WDCDELAY * xtime); } #endif - return(WDCWAIT_OK); + rv = WDCWAIT_OK; + +out: + *tfd = ATACH_ERR_ST(error, status); + return rv; } /* @@ -1224,15 +1222,16 @@ __wdcwait(struct ata_channel *chp, int m * thread if possible */ int -wdcwait(struct ata_channel *chp, int mask, int bits, int timeout, int flags) +wdcwait(struct ata_channel *chp, int mask, int bits, int timeout, int flags, + int *tfd) { int error, i, timeout_hz = mstohz(timeout); if (timeout_hz == 0 || (flags & (AT_WAIT | AT_POLL)) == AT_POLL) - error = __wdcwait(chp, mask, bits, timeout); + error = __wdcwait(chp, mask, bits, timeout, tfd); else { - error = __wdcwait(chp, mask, bits, WDCDELAY_POLL); + error = __wdcwait(chp, mask, bits, WDCDELAY_POLL, tfd); if (error != 0) { if ((chp->ch_flags & ATACH_TH_RUN) || (flags & AT_WAIT)) { @@ -1242,7 +1241,7 @@ wdcwait(struct ata_channel *chp, int mas */ for (i = 0; i < timeout_hz; i++) { if (__wdcwait(chp, mask, bits, - WDCDELAY_POLL) == 0) { + WDCDELAY_POLL, tfd) == 0) { error = 0; break; } @@ -1255,6 +1254,7 @@ wdcwait(struct ata_channel *chp, int mas */ ata_channel_freeze(chp); wakeup(&chp->ch_thread); +printf("wdcwait_thr"); return(WDCWAIT_THR); } } @@ -1302,34 +1302,38 @@ wdctimeout(void *arg) s = splbio(); KASSERT(xfer != NULL); - if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) { - __wdcerror(chp, "lost interrupt"); - printf("\ttype: %s tc_bcount: %d tc_skip: %d\n", - (xfer->c_flags & C_ATAPI) ? "atapi" : "ata", - xfer->c_bcount, xfer->c_skip); + + if (ata_timo_xfer_check(xfer)) { + /* Already logged */ + goto out; + } + + __wdcerror(chp, "lost interrupt"); + printf("\ttype: %s tc_bcount: %d tc_skip: %d\n", + (xfer->c_flags & C_ATAPI) ? "atapi" : "ata", + xfer->c_bcount, xfer->c_skip); #if NATA_DMA || NATA_PIOBM - if (chp->ch_flags & ATACH_DMA_WAIT) { - wdc->dma_status = - (*wdc->dma_finish)(wdc->dma_arg, chp->ch_channel, - xfer->c_drive, WDC_DMAEND_ABRT); - chp->ch_flags &= ~ATACH_DMA_WAIT; - } + if (chp->ch_flags & ATACH_DMA_WAIT) { + wdc->dma_status = + (*wdc->dma_finish)(wdc->dma_arg, chp->ch_channel, + xfer->c_drive, WDC_DMAEND_ABRT); + chp->ch_flags &= ~ATACH_DMA_WAIT; + } #endif - /* - * Call the interrupt routine. If we just missed an interrupt, - * it will do what's needed. Else, it will take the needed - * action (reset the device). - * Before that we need to reinstall the timeout callback, - * in case it will miss another irq while in this transfer - * We arbitray chose it to be 1s - */ - callout_reset(&xfer->c_timo_callout, hz, wdctimeout, xfer); - xfer->c_flags |= C_TIMEOU; - chp->ch_flags &= ~ATACH_IRQ_WAIT; - KASSERT(xfer->c_intr != NULL); - xfer->c_intr(chp, xfer, 1); - } else - __wdcerror(chp, "missing untimeout"); + /* + * Call the interrupt routine. If we just missed an interrupt, + * it will do what's needed. Else, it will take the needed + * action (reset the device). + * Before that we need to reinstall the timeout callback, + * in case it will miss another irq while in this transfer + * We arbitray chose it to be 1s + */ + callout_reset(&xfer->c_timo_callout, hz, wdctimeout, xfer); + xfer->c_flags |= C_TIMEOU; + KASSERT(xfer->c_intr != NULL); + xfer->c_intr(chp, xfer, 1); + +out: splx(s); } @@ -1389,6 +1393,7 @@ __wdccommand_start(struct ata_channel *c int drive = xfer->c_drive; int wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0; struct ata_command *ata_c = &xfer->c_ata_c; + int tfd; ATADEBUG_PRINT(("__wdccommand_start %s:%d:%d\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, @@ -1399,12 +1404,12 @@ __wdccommand_start(struct ata_channel *c bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM | (drive << 4)); switch(wdcwait(chp, ata_c->r_st_bmask | WDCS_DRQ, - ata_c->r_st_bmask, ata_c->timeout, wait_flags)) { + ata_c->r_st_bmask, ata_c->timeout, wait_flags, &tfd)) { case WDCWAIT_OK: break; case WDCWAIT_TOUT: ata_c->flags |= AT_TIMEOU; - __wdccommand_done(chp, xfer); + __wdccommand_done(chp, xfer, tfd); return; case WDCWAIT_THR: return; @@ -1431,7 +1436,6 @@ __wdccommand_start(struct ata_channel *c } if ((ata_c->flags & AT_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */ callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz, wdctimeout, xfer); return; @@ -1452,7 +1456,7 @@ __wdccommand_intr(struct ata_channel *ch struct ata_command *ata_c = &xfer->c_ata_c; int bcount = ata_c->bcount; char *data = ata_c->data; - int wflags; + int wflags, tfd; int drive_flags; if (ata_c->r_command == WDCC_IDENTIFY || @@ -1505,7 +1509,7 @@ __wdccommand_intr(struct ata_channel *ch */ if (wdcwait(chp, ata_c->r_st_bmask | WDCS_DRQ, ata_c->r_st_bmask, (irq == 0) ? ata_c->timeout : 0, - wflags) == WDCWAIT_TOUT) { + wflags, &tfd) == WDCWAIT_TOUT) { if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ ata_c->flags |= AT_TIMEOU; @@ -1513,7 +1517,7 @@ __wdccommand_intr(struct ata_channel *ch goto out; } if (wdcwait(chp, ata_c->r_st_pmask, ata_c->r_st_pmask, - (irq == 0) ? ata_c->timeout : 0, wflags) == WDCWAIT_TOUT) { + (irq == 0) ? ata_c->timeout : 0, wflags, &tfd) == WDCWAIT_TOUT) { if (irq && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ ata_c->flags |= AT_TIMEOU; @@ -1522,7 +1526,7 @@ __wdccommand_intr(struct ata_channel *ch if (wdc->irqack) wdc->irqack(chp); if (ata_c->flags & AT_READ) { - if ((chp->ch_status & WDCS_DRQ) == 0) { + if ((ATACH_ST(tfd) & WDCS_DRQ) == 0) { ata_c->flags |= AT_TIMEOU; goto out; } @@ -1534,14 +1538,13 @@ __wdccommand_intr(struct ata_channel *ch * hardware to timeout. */ } else if (ata_c->flags & AT_WRITE) { - if ((chp->ch_status & WDCS_DRQ) == 0) { + if ((ATACH_ST(tfd) & WDCS_DRQ) == 0) { ata_c->flags |= AT_TIMEOU; goto out; } wdc->dataout_pio(chp, drive_flags, data, bcount); ata_c->flags |= AT_XFDONE; if ((ata_c->flags & AT_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */ callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout), wdctimeout, xfer); return 1; @@ -1550,12 +1553,12 @@ __wdccommand_intr(struct ata_channel *ch } } out: - __wdccommand_done(chp, xfer); + __wdccommand_done(chp, xfer, tfd); return 1; } static void -__wdccommand_done(struct ata_channel *chp, struct ata_xfer *xfer) +__wdccommand_done(struct ata_channel *chp, struct ata_xfer *xfer, int tfd) { struct atac_softc *atac = chp->ch_atac; struct wdc_softc *wdc = CHAN_TO_WDC(chp); @@ -1572,11 +1575,11 @@ __wdccommand_done(struct ata_channel *ch goto out; } - if (chp->ch_status & WDCS_DWF) + if (ATACH_ST(tfd) & WDCS_DWF) ata_c->flags |= AT_DF; - if (chp->ch_status & WDCS_ERR) { + if (ATACH_ST(tfd) & WDCS_ERR) { ata_c->flags |= AT_ERROR; - ata_c->r_error = chp->ch_error; + ata_c->r_error = ATACH_ST(tfd); } if ((ata_c->flags & AT_READREG) != 0 && device_is_active(atac->atac_dev) && Index: src/sys/dev/ic/wdcvar.h diff -u src/sys/dev/ic/wdcvar.h:1.97.26.1 src/sys/dev/ic/wdcvar.h:1.97.26.2 --- src/sys/dev/ic/wdcvar.h:1.97.26.1 Sat Apr 15 17:14:11 2017 +++ src/sys/dev/ic/wdcvar.h Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: wdcvar.h,v 1.97.26.1 2017/04/15 17:14:11 jdolecek Exp $ */ +/* $NetBSD: wdcvar.h,v 1.97.26.2 2017/08/12 09:52:28 jdolecek Exp $ */ /*- * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc. @@ -155,7 +155,7 @@ void wdc_drvprobe(struct ata_channel *); void wdcrestart(void*); -int wdcwait(struct ata_channel *, int, int, int, int); +int wdcwait(struct ata_channel *, int, int, int, int, int *); #define WDCWAIT_OK 0 /* we have what we asked */ #define WDCWAIT_TOUT -1 /* timed out */ #define WDCWAIT_THR 1 /* return, the kernel thread has been awakened */ @@ -179,12 +179,12 @@ int wdc_exec_command(struct ata_drive_da * ST506 spec says that if READY or SEEKCMPLT go off, then the read or write * command is aborted. */ -#define wdc_wait_for_drq(chp, timeout, flags) \ - wdcwait((chp), WDCS_DRQ, WDCS_DRQ, (timeout), (flags)) -#define wdc_wait_for_unbusy(chp, timeout, flags) \ - wdcwait((chp), 0, 0, (timeout), (flags)) -#define wdc_wait_for_ready(chp, timeout, flags) \ - wdcwait((chp), WDCS_DRDY, WDCS_DRDY, (timeout), (flags)) +#define wdc_wait_for_drq(chp, timeout, flags, tfd) \ + wdcwait((chp), WDCS_DRQ, WDCS_DRQ, (timeout), (flags), (tfd)) +#define wdc_wait_for_unbusy(chp, timeout, flags, tfd) \ + wdcwait((chp), 0, 0, (timeout), (flags), (tfd)) +#define wdc_wait_for_ready(chp, timeout, flags, tfd) \ + wdcwait((chp), WDCS_DRDY, WDCS_DRDY, (timeout), (flags), (tfd)) /* ATA/ATAPI specs says a device can take 31s to reset */ #define WDC_RESET_WAIT 31000 Index: src/sys/dev/pci/pciide_common.c diff -u src/sys/dev/pci/pciide_common.c:1.62.4.1 src/sys/dev/pci/pciide_common.c:1.62.4.2 --- src/sys/dev/pci/pciide_common.c:1.62.4.1 Mon Apr 10 22:57:03 2017 +++ src/sys/dev/pci/pciide_common.c Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: pciide_common.c,v 1.62.4.1 2017/04/10 22:57:03 jdolecek Exp $ */ +/* $NetBSD: pciide_common.c,v 1.62.4.2 2017/08/12 09:52:28 jdolecek Exp $ */ /* @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pciide_common.c,v 1.62.4.1 2017/04/10 22:57:03 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pciide_common.c,v 1.62.4.2 2017/08/12 09:52:28 jdolecek Exp $"); #include <sys/param.h> @@ -552,9 +552,6 @@ pciide_pci_intr(void *arg) /* If a compat channel skip. */ if (cp->compat) continue; - /* if this channel not waiting for intr, skip */ - if ((wdc_cp->ch_flags & ATACH_IRQ_WAIT) == 0) - continue; crv = wdcintr(wdc_cp); if (crv == 0) Index: src/sys/dev/scsipi/atapi_wdc.c diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.10 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.11 --- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.10 Sat Jul 29 09:04:39 2017 +++ src/sys/dev/scsipi/atapi_wdc.c Sat Aug 12 09:52:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: atapi_wdc.c,v 1.123.4.10 2017/07/29 09:04:39 jdolecek Exp $ */ +/* $NetBSD: atapi_wdc.c,v 1.123.4.11 2017/08/12 09:52:28 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.10 2017/07/29 09:04:39 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.11 2017/08/12 09:52:28 jdolecek Exp $"); #ifndef ATADEBUG #define ATADEBUG @@ -481,6 +481,7 @@ wdc_atapi_start(struct ata_channel *chp, struct scsipi_xfer *sc_xfer = xfer->c_scsipi; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; int wait_flags = (sc_xfer->xs_control & XS_CTL_POLL) ? AT_POLL : 0; + int tfd; const char *errstring; ATADEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x \n", @@ -516,15 +517,16 @@ wdc_atapi_start(struct ata_channel *chp, if ((drvp->drive_flags & ATA_DRIVE_MODE) == 0) goto ready; errstring = "unbusy"; - if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags)) + if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd)) goto timeout; wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0, 0x08 | drvp->PIO_mode, WDSF_SET_MODE); errstring = "piomode"; - if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags)) + if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags, + &tfd)) goto timeout; - if (chp->ch_status & WDCS_ERR) { - if (chp->ch_error == WDCE_ABRT) { + if (ATACH_ST(tfd) & WDCS_ERR) { + if (ATACH_ST(tfd) == WDCE_ABRT) { /* * Some ATAPI drives reject PIO settings. * Fall back to PIO mode 3 since that's the @@ -554,10 +556,11 @@ wdc_atapi_start(struct ata_channel *chp, goto ready; } errstring = "dmamode"; - if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags)) + if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags, + &tfd)) goto timeout; - if (chp->ch_status & WDCS_ERR) { - if (chp->ch_error == WDCE_ABRT) { + if (ATACH_ST(tfd) & WDCS_ERR) { + if (ATACH_ERR(tfd) == WDCE_ABRT) { #if NATA_UDMA if (drvp->drive_flags & ATA_DRIVE_UDMA) goto error; @@ -595,12 +598,12 @@ ready: wdc->select(chp, xfer->c_drive); bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM | (xfer->c_drive << 4)); - switch (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags)) { + switch (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd)) { case WDCWAIT_OK: break; case WDCWAIT_TOUT: printf("wdc_atapi_start: not ready, st = %02x\n", - chp->ch_status); + ATACH_ST(tfd)); sc_xfer->error = XS_TIMEOUT; wdc_atapi_reset(chp, xfer); return; @@ -669,8 +672,6 @@ ready: /* Wait for at last 400ns for status bit to be valid */ DELAY(1); wdc_atapi_intr(chp, xfer, 0); - } else { - chp->ch_flags |= ATACH_IRQ_WAIT; } if (sc_xfer->xs_control & XS_CTL_POLL) { #if NATA_DMA @@ -699,9 +700,9 @@ error: printf("%s:%d:%d: %s ", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive, errstring); - printf("error (0x%x)\n", chp->ch_error); + printf("error (0x%x)\n", ATACH_ERR(tfd)); sc_xfer->error = XS_SHORTSENSE; - sc_xfer->sense.atapi_sense = chp->ch_error; + sc_xfer->sense.atapi_sense = ATACH_ERR(tfd); bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT); delay(10); /* some drives need a little delay here */ wdc_atapi_reset(chp, xfer); @@ -709,7 +710,7 @@ error: } static int -wdc_atapi_intr(struct ata_channel *chp, struct ata_xfer *xfer, int irq) +wdc_atapi_intr(struct ata_channel *chp, struct ata_xfer *xfer, int is) { struct atac_softc *atac = chp->ch_atac; struct wdc_softc *wdc = CHAN_TO_WDC(chp); @@ -717,7 +718,8 @@ wdc_atapi_intr(struct ata_channel *chp, struct scsipi_xfer *sc_xfer = xfer->c_scsipi; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; int len, phase, i, retries=0; - int ire; + int ire, tfd; + int poll = ((xfer->c_flags & C_POLL) != 0); #if NATA_DMA int error; #endif @@ -770,8 +772,8 @@ wdc_atapi_intr(struct ata_channel *chp, bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0, WDSD_IBM | (xfer->c_drive << 4)); if (wdc_wait_for_unbusy(chp, - (irq == 0) ? sc_xfer->timeout : 0, AT_POLL) == WDCWAIT_TOUT) { - if (irq && (xfer->c_flags & C_TIMEOU) == 0) + poll ? sc_xfer->timeout : 0, AT_POLL, &tfd) == WDCWAIT_TOUT) { + if (!poll && (xfer->c_flags & C_TIMEOU) == 0) return 0; /* IRQ was not for us */ printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n", device_xname(atac->atac_dev), chp->ch_channel, @@ -815,10 +817,10 @@ again: len = bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_cyl_lo], 0) + 256 * bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_cyl_hi], 0); ire = bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_ireason], 0); - phase = (ire & (WDCI_CMD | WDCI_IN)) | (chp->ch_status & WDCS_DRQ); + phase = (ire & (WDCI_CMD | WDCI_IN)) | (ATACH_ST(tfd) & WDCS_DRQ); ATADEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x " "ire 0x%x :", xfer->c_bcount, - len, chp->ch_status, chp->ch_error, ire), DEBUG_INTR); + len, ATACH_ST(tfd), ATACH_ERR(tfd), ire), DEBUG_INTR); switch (phase) { case PHASE_CMDOUT: @@ -859,10 +861,6 @@ again: chp->ch_flags |= ATACH_DMA_WAIT; } #endif - - if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; - } return 1; case PHASE_DATAOUT: @@ -894,8 +892,7 @@ again: (*wdc->piobm_start)(wdc->dma_arg, chp->ch_channel, xfer->c_drive, xfer->c_skip, len, WDC_PIOBM_XFER_IRQ); - chp->ch_flags |= ATACH_DMA_WAIT | ATACH_IRQ_WAIT | - ATACH_PIOBM_WAIT; + chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT; return 1; } #endif @@ -911,9 +908,6 @@ again: xfer->c_skip += len; xfer->c_bcount -= len; - if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; - } return 1; case PHASE_DATAIN: @@ -945,8 +939,7 @@ again: (*wdc->piobm_start)(wdc->dma_arg, chp->ch_channel, xfer->c_drive, xfer->c_skip, len, WDC_PIOBM_XFER_IRQ); - chp->ch_flags |= ATACH_DMA_WAIT | ATACH_IRQ_WAIT | - ATACH_PIOBM_WAIT; + chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT; return 1; } #endif @@ -961,9 +954,6 @@ again: xfer->c_skip += len; xfer->c_bcount -= len; - if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) { - chp->ch_flags |= ATACH_IRQ_WAIT; - } return 1; case PHASE_ABORTED: @@ -981,16 +971,18 @@ again: default: if (++retries<500) { DELAY(100); - chp->ch_status = bus_space_read_1(wdr->cmd_iot, - wdr->cmd_iohs[wd_status], 0); - chp->ch_error = bus_space_read_1(wdr->cmd_iot, - wdr->cmd_iohs[wd_error], 0); + tfd = ATACH_ERR_ST( + bus_space_read_1(wdr->cmd_iot, + wdr->cmd_iohs[wd_error], 0), + bus_space_read_1(wdr->cmd_iot, + wdr->cmd_iohs[wd_status], 0) + ); goto again; } printf("wdc_atapi_intr: unknown phase 0x%x\n", phase); - if (chp->ch_status & WDCS_ERR) { + if (ATACH_ST(tfd) & WDCS_ERR) { sc_xfer->error = XS_SHORTSENSE; - sc_xfer->sense.atapi_sense = chp->ch_error; + sc_xfer->sense.atapi_sense = ATACH_ERR(tfd); } else { #if NATA_DMA if (xfer->c_flags & C_DMA) { @@ -1020,6 +1012,7 @@ wdc_atapi_phase_complete(struct ata_xfer #endif struct scsipi_xfer *sc_xfer = xfer->c_scsipi; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; + int tfd; /* wait for DSC if needed */ if (drvp->drive_flags & ATA_DRIVE_ATAPIDSCW) { @@ -1032,7 +1025,7 @@ wdc_atapi_phase_complete(struct ata_xfer panic("wdc_atapi_phase_complete: cold"); #endif if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10, - AT_POLL) == WDCWAIT_TOUT) { + AT_POLL, &tfd) == WDCWAIT_TOUT) { /* 10ms not enough, try again in 1 tick */ if (xfer->c_dscpoll++ > mstohz(sc_xfer->timeout)) { @@ -1056,12 +1049,12 @@ wdc_atapi_phase_complete(struct ata_xfer * register. If we read some data the sense is valid * anyway, so don't report the error. */ - if (chp->ch_status & WDCS_ERR && + if (ATACH_ST(tfd) & WDCS_ERR && ((sc_xfer->xs_control & XS_CTL_REQSENSE) == 0 || sc_xfer->resid == sc_xfer->datalen)) { /* save the short sense */ sc_xfer->error = XS_SHORTSENSE; - sc_xfer->sense.atapi_sense = chp->ch_error; + sc_xfer->sense.atapi_sense = ATACH_ERR(tfd); if ((sc_xfer->xs_periph->periph_quirks & PQUIRK_NOSENSE) == 0) { /* ask scsipi to send a REQUEST_SENSE */ @@ -1126,10 +1119,11 @@ wdc_atapi_reset(struct ata_channel *chp, struct atac_softc *atac = chp->ch_atac; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; struct scsipi_xfer *sc_xfer = xfer->c_scsipi; + int tfd; wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET); drvp->state = 0; - if (wdc_wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL) != 0) { + if (wdc_wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL, &tfd) != 0) { printf("%s:%d:%d: reset failed\n", device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive);