Module Name: src Committed By: jdolecek Date: Tue Sep 19 21:06:25 UTC 2017
Modified Files: src/sys/dev/ata [jdolecek-ncq]: TODO.ncq ata.c atavar.h sata_subr.c satapmp_subr.c satapmpvar.h src/sys/dev/ic [jdolecek-ncq]: ahcisata_core.c mvsata.c siisata.c wdc.c Log Message: replace all remaining tsleep()/wakeup() calls with condition variables, or calls to ata_delay(), as appropriate; change ata_delay() to require the channel lock on entry, and pass the lock to kpause() for unlocking while sleeping To generate a diff of this commit: cvs rdiff -u -r1.1.2.41 -r1.1.2.42 src/sys/dev/ata/TODO.ncq cvs rdiff -u -r1.132.8.32 -r1.132.8.33 src/sys/dev/ata/ata.c cvs rdiff -u -r1.92.8.25 -r1.92.8.26 src/sys/dev/ata/atavar.h cvs rdiff -u -r1.21 -r1.21.24.1 src/sys/dev/ata/sata_subr.c cvs rdiff -u -r1.12.24.5 -r1.12.24.6 src/sys/dev/ata/satapmp_subr.c cvs rdiff -u -r1.3 -r1.3.30.1 src/sys/dev/ata/satapmpvar.h cvs rdiff -u -r1.57.6.28 -r1.57.6.29 src/sys/dev/ic/ahcisata_core.c cvs rdiff -u -r1.35.6.25 -r1.35.6.26 src/sys/dev/ic/mvsata.c cvs rdiff -u -r1.30.4.37 -r1.30.4.38 src/sys/dev/ic/siisata.c cvs rdiff -u -r1.283.2.15 -r1.283.2.16 src/sys/dev/ic/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.41 src/sys/dev/ata/TODO.ncq:1.1.2.42 --- src/sys/dev/ata/TODO.ncq:1.1.2.41 Wed Sep 13 19:55:12 2017 +++ src/sys/dev/ata/TODO.ncq Tue Sep 19 21:06:25 2017 @@ -4,10 +4,6 @@ test wd* at umass?, confirm the ata_chan mvsata - resest MVSATA_WITHOUTDMA -the changes to lock channel lock cause now mi_switch() with spinlock held -when invoking ata_delay() (which calls kpause()) or on tsleep, need -to refactor - Other random notes (do outside the NCQ branch): ----------------------------------------------------- do biodone() in wddone() starting the dump to not leak bufs when dumping from Index: src/sys/dev/ata/ata.c diff -u src/sys/dev/ata/ata.c:1.132.8.32 src/sys/dev/ata/ata.c:1.132.8.33 --- src/sys/dev/ata/ata.c:1.132.8.32 Mon Sep 11 22:16:18 2017 +++ src/sys/dev/ata/ata.c Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ata.c,v 1.132.8.32 2017/09/11 22:16:18 jdolecek Exp $ */ +/* $NetBSD: ata.c,v 1.132.8.33 2017/09/19 21:06:25 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.32 2017/09/11 22:16:18 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.33 2017/09/19 21:06:25 jdolecek Exp $"); #include "opt_ata.h" @@ -279,6 +279,7 @@ ata_xfer_init(struct ata_xfer *xfer, uin xfer->c_slot = slot; cv_init(&xfer->c_active, "ataact"); + cv_init(&xfer->c_finish, "atafin"); callout_init(&xfer->c_timo_callout, 0); /* XXX MPSAFE */ callout_init(&xfer->c_retry_callout, 0); /* XXX MPSAFE */ } @@ -291,6 +292,7 @@ ata_xfer_destroy(struct ata_xfer *xfer) callout_halt(&xfer->c_retry_callout, NULL); /* XXX MPSAFE */ callout_destroy(&xfer->c_retry_callout); cv_destroy(&xfer->c_active); + cv_destroy(&xfer->c_finish); } struct ata_queue * @@ -310,6 +312,7 @@ ata_queue_alloc(uint8_t openings) cv_init(&chq->queue_busy, "ataqbusy"); cv_init(&chq->queue_drain, "atdrn"); + cv_init(&chq->queue_idle, "qidl"); for (uint8_t i = 0; i < openings; i++) ata_xfer_init(&chq->queue_xfers[i], i); @@ -1194,13 +1197,13 @@ ata_dmaerr(struct ata_drive_datas *drvp, static void ata_channel_idle(struct ata_channel *chp) { - int s = splbio(); - ata_channel_freeze(chp); + ata_channel_lock(chp); + ata_channel_freeze_locked(chp); while (chp->ch_queue->queue_active > 0) { chp->ch_queue->queue_flags |= QF_IDLE_WAIT; - tsleep(&chp->ch_queue->queue_flags, PRIBIO, "qidl", 0); + cv_timedwait(&chp->ch_queue->queue_idle, &chp->ch_lock, 1); } - splx(s); + ata_channel_unlock(chp); } /* @@ -1246,6 +1249,8 @@ ata_exec_xfer(struct ata_channel *chp, s * while we were waiting. */ if ((xfer->c_flags & (C_FREE|C_WAITTIMO)) == C_FREE) { + ata_channel_unlock(chp); + ata_free_xfer(chp, xfer); return; } @@ -1305,7 +1310,7 @@ again: if (__predict_false(!recovery && chq->queue_freeze > 0)) { if (chq->queue_flags & QF_IDLE_WAIT) { chq->queue_flags &= ~QF_IDLE_WAIT; - wakeup(&chq->queue_flags); + cv_signal(&chp->ch_queue->queue_idle); } goto out; /* queue frozen */ } @@ -1673,7 +1678,7 @@ out: /* * Kill off all active xfers for a ata_channel. * - * Must be called at splbio(). + * Must be called with channel lock held. */ void ata_kill_active(struct ata_channel *chp, int reason, int flags) @@ -1681,6 +1686,8 @@ ata_kill_active(struct ata_channel *chp, struct ata_queue * const chq = chp->ch_queue; struct ata_xfer *xfer, *xfernext; + KASSERT(mutex_owned(&chp->ch_lock)); + TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) { (*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason); } @@ -2000,7 +2007,7 @@ ata_probe_caps(struct ata_drive_datas *d struct ata_channel *chp = drvp->chnl_softc; struct atac_softc *atac = chp->ch_atac; device_t drv_dev = drvp->drv_softc; - int i, printed = 0, s; + int i, printed = 0; const char *sep = ""; int cf_flags; @@ -2015,15 +2022,15 @@ ata_probe_caps(struct ata_drive_datas *d * Re-do an IDENTIFY with 32-bit transfers, * and compare results. */ - s = splbio(); + ata_channel_lock(chp); drvp->drive_flags |= ATA_DRIVE_CAP32; - splx(s); + ata_channel_unlock(chp); ata_get_params(drvp, AT_WAIT, ¶ms2); if (memcmp(¶ms, ¶ms2, sizeof(struct ataparams)) != 0) { /* Not good. fall back to 16bits */ - s = splbio(); + ata_channel_lock(chp); drvp->drive_flags &= ~ATA_DRIVE_CAP32; - splx(s); + ata_channel_unlock(chp); } else { aprint_verbose_dev(drv_dev, "32-bit data port\n"); } @@ -2101,9 +2108,9 @@ ata_probe_caps(struct ata_drive_datas *d */ return; } - s = splbio(); + ata_channel_lock(chp); drvp->drive_flags |= ATA_DRIVE_MODE; - splx(s); + ata_channel_unlock(chp); printed = 0; for (i = 7; i >= 0; i--) { if ((params.atap_dmamode_supp & (1 << i)) == 0) @@ -2127,9 +2134,9 @@ ata_probe_caps(struct ata_drive_datas *d continue; drvp->DMA_mode = i; drvp->DMA_cap = i; - s = splbio(); + ata_channel_lock(chp); drvp->drive_flags |= ATA_DRIVE_DMA; - splx(s); + ata_channel_unlock(chp); } #endif break; @@ -2168,9 +2175,9 @@ ata_probe_caps(struct ata_drive_datas *d continue; drvp->UDMA_mode = i; drvp->UDMA_cap = i; - s = splbio(); + ata_channel_lock(chp); drvp->drive_flags |= ATA_DRIVE_UDMA; - splx(s); + ata_channel_unlock(chp); } #endif break; @@ -2178,7 +2185,7 @@ ata_probe_caps(struct ata_drive_datas *d } } - s = splbio(); + ata_channel_lock(chp); drvp->drive_flags &= ~ATA_DRIVE_NOSTREAM; if (drvp->drive_type == ATA_DRIVET_ATAPI) { if (atac->atac_cap & ATAC_CAP_ATAPI_NOSTREAM) @@ -2187,7 +2194,7 @@ ata_probe_caps(struct ata_drive_datas *d if (atac->atac_cap & ATAC_CAP_ATA_NOSTREAM) drvp->drive_flags |= ATA_DRIVE_NOSTREAM; } - splx(s); + ata_channel_unlock(chp); /* Try to guess ATA version here, if it didn't get reported */ if (drvp->ata_vers == 0) { @@ -2201,11 +2208,11 @@ ata_probe_caps(struct ata_drive_datas *d } cf_flags = device_cfdata(drv_dev)->cf_flags; if (cf_flags & ATA_CONFIG_PIO_SET) { - s = splbio(); + ata_channel_lock(chp); drvp->PIO_mode = (cf_flags & ATA_CONFIG_PIO_MODES) >> ATA_CONFIG_PIO_OFF; drvp->drive_flags |= ATA_DRIVE_MODE; - splx(s); + ata_channel_unlock(chp); } #if NATA_DMA if ((atac->atac_cap & ATAC_CAP_DMA) == 0) { @@ -2213,7 +2220,7 @@ ata_probe_caps(struct ata_drive_datas *d return; } if (cf_flags & ATA_CONFIG_DMA_SET) { - s = splbio(); + ata_channel_lock(chp); if ((cf_flags & ATA_CONFIG_DMA_MODES) == ATA_CONFIG_DMA_DISABLE) { drvp->drive_flags &= ~ATA_DRIVE_DMA; @@ -2222,7 +2229,7 @@ ata_probe_caps(struct ata_drive_datas *d ATA_CONFIG_DMA_OFF; drvp->drive_flags |= ATA_DRIVE_DMA | ATA_DRIVE_MODE; } - splx(s); + ata_channel_unlock(chp); } /* @@ -2239,7 +2246,7 @@ ata_probe_caps(struct ata_drive_datas *d } /* Probe NCQ support - READ/WRITE FPDMA QUEUED command support */ - s = splbio(); + ata_channel_lock(chp); drvp->drv_openings = 1; if (params.atap_sata_caps & SATA_NATIVE_CMDQ) { if (atac->atac_cap & ATAC_CAP_NCQ) @@ -2254,7 +2261,7 @@ ata_probe_caps(struct ata_drive_datas *d aprint_verbose(" w/PRIO"); } } - splx(s); + ata_channel_unlock(chp); if (printed) aprint_verbose("\n"); @@ -2265,7 +2272,7 @@ ata_probe_caps(struct ata_drive_datas *d return; } if (cf_flags & ATA_CONFIG_UDMA_SET) { - s = splbio(); + ata_channel_lock(chp); if ((cf_flags & ATA_CONFIG_UDMA_MODES) == ATA_CONFIG_UDMA_DISABLE) { drvp->drive_flags &= ~ATA_DRIVE_UDMA; @@ -2274,7 +2281,7 @@ ata_probe_caps(struct ata_drive_datas *d ATA_CONFIG_UDMA_OFF; drvp->drive_flags |= ATA_DRIVE_UDMA | ATA_DRIVE_MODE; } - splx(s); + ata_channel_unlock(chp); } #endif /* NATA_UDMA */ #endif /* NATA_DMA */ @@ -2472,8 +2479,10 @@ atabus_rescan(device_t self, const char } void -ata_delay(int ms, const char *msg, int flags) +ata_delay(struct ata_channel *chp, int ms, const char *msg, int flags) { + KASSERT(mutex_owned(&chp->ch_lock)); + if ((flags & (AT_WAIT | AT_POLL)) == AT_POLL) { /* * can't use kpause(), we may be in interrupt context @@ -2482,7 +2491,7 @@ ata_delay(int ms, const char *msg, int f delay(ms * 1000); } else { int pause = mstohz(ms); - kpause(msg, false, pause > 0 ? pause : 1, NULL); + kpause(msg, false, pause > 0 ? pause : 1, &chp->ch_lock); } } @@ -2580,3 +2589,19 @@ ata_channel_lock_owned(struct ata_channe { KASSERT(mutex_owned(&chp->ch_lock)); } + +void +ata_wait_xfer(struct ata_channel *chp, struct ata_xfer *xfer) +{ + KASSERT(mutex_owned(&chp->ch_lock)); + + cv_wait(&xfer->c_finish, &chp->ch_lock); +} + +void +ata_wake_xfer(struct ata_channel *chp, struct ata_xfer *xfer) +{ + KASSERT(mutex_owned(&chp->ch_lock)); + + cv_signal(&xfer->c_finish); +} Index: src/sys/dev/ata/atavar.h diff -u src/sys/dev/ata/atavar.h:1.92.8.25 src/sys/dev/ata/atavar.h:1.92.8.26 --- src/sys/dev/ata/atavar.h:1.92.8.25 Sun Sep 10 19:31:15 2017 +++ src/sys/dev/ata/atavar.h Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: atavar.h,v 1.92.8.25 2017/09/10 19:31:15 jdolecek Exp $ */ +/* $NetBSD: atavar.h,v 1.92.8.26 2017/09/19 21:06:25 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -134,6 +134,7 @@ struct ata_xfer { struct callout c_timo_callout; /* timeout callout handle */ struct callout c_retry_callout; /* retry callout handle */ kcondvar_t c_active; /* somebody actively waiting for xfer */ + kcondvar_t c_finish; /* somebody waiting for xfer finish */ int8_t c_slot; /* queue slot # */ #define c_startzero c_chp @@ -182,7 +183,7 @@ struct ata_xfer { #define C_TIMEOU 0x0002 /* xfer processing timed out */ #define C_POLL 0x0004 /* command is polled */ #define C_DMA 0x0008 /* command uses DMA */ -#define C_WAIT 0x0010 /* can use tsleep */ +#define C_WAIT 0x0010 /* can use kpause */ #define C_WAITACT 0x0020 /* wakeup when active */ #define C_FREE 0x0040 /* call ata_free_xfer() asap */ #define C_PIOBM 0x0080 /* command uses busmastering PIO */ @@ -220,6 +221,7 @@ struct ata_queue { int queue_freeze; /* freeze count for the queue */ kcondvar_t queue_busy; /* c: waiting of xfer */ kcondvar_t queue_drain; /* c: waiting of queue drain */ + kcondvar_t queue_idle; /* c: waiting of queue idle */ TAILQ_HEAD(, ata_xfer) active_xfers; /* active commands */ uint32_t active_xfers_used; /* mask of active commands */ uint32_t queue_xfers_avail; /* available xfers mask */ @@ -515,6 +517,8 @@ void ata_free_xfer(struct ata_channel *, void ata_deactivate_xfer(struct ata_channel *, struct ata_xfer *); void ata_exec_xfer(struct ata_channel *, struct ata_xfer *); int ata_xfer_start(struct ata_xfer *xfer); +void ata_wait_xfer(struct ata_channel *, struct ata_xfer *xfer); +void ata_wake_xfer(struct ata_channel *, struct ata_xfer *xfer); void ata_timeout(void *); bool ata_timo_xfer_check(struct ata_xfer *); @@ -550,7 +554,7 @@ struct ata_xfer * struct ata_xfer * ata_queue_drive_active_xfer(struct ata_channel *, int); -void ata_delay(int, const char *, int); +void ata_delay(struct ata_channel *, int, const char *, int); bool ata_waitdrain_xfer_check(struct ata_channel *, struct ata_xfer *); Index: src/sys/dev/ata/sata_subr.c diff -u src/sys/dev/ata/sata_subr.c:1.21 src/sys/dev/ata/sata_subr.c:1.21.24.1 --- src/sys/dev/ata/sata_subr.c:1.21 Wed Apr 3 17:15:07 2013 +++ src/sys/dev/ata/sata_subr.c Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sata_subr.c,v 1.21 2013/04/03 17:15:07 bouyer Exp $ */ +/* $NetBSD: sata_subr.c,v 1.21.24.1 2017/09/19 21:06:25 jdolecek Exp $ */ /*- * Copyright (c) 2004 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ * Common functions for Serial ATA. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sata_subr.c,v 1.21 2013/04/03 17:15:07 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sata_subr.c,v 1.21.24.1 2017/09/19 21:06:25 jdolecek Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -85,6 +85,8 @@ sata_reset_interface(struct ata_channel uint32_t scontrol, sstatus; int i; + ata_channel_lock_owned(chp); + /* bring the PHYs online. * The work-around for errata #1 of the Intel GD31244 says that we must * write 0 to the port first to be sure of correctly initializing @@ -92,19 +94,19 @@ sata_reset_interface(struct ata_channel */ bus_space_write_4(sata_t, scontrol_r, 0, 0); scontrol = SControl_IPM_NONE | SControl_SPD_ANY | SControl_DET_INIT; - bus_space_write_4 (sata_t, scontrol_r, 0, scontrol); + bus_space_write_4(sata_t, scontrol_r, 0, scontrol); - ata_delay(50, "sataup", flags); + ata_delay(chp, 50, "sataup", flags); scontrol &= ~SControl_DET_INIT; bus_space_write_4(sata_t, scontrol_r, 0, scontrol); - ata_delay(50, "sataup", flags); + ata_delay(chp, 50, "sataup", flags); /* wait up to 1s for device to come up */ for (i = 0; i < 100; i++) { sstatus = bus_space_read_4(sata_t, sstatus_r, 0); if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV) break; - ata_delay(10, "sataup", flags); + ata_delay(chp, 10, "sataup", flags); } /* * if we have a link up without device, wait a few more seconds @@ -112,7 +114,7 @@ sata_reset_interface(struct ata_channel */ if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV_NE) { for (i = 0; i < 500; i++) { - ata_delay(10, "sataup", flags); + ata_delay(chp, 10, "sataup", flags); sstatus = bus_space_read_4(sata_t, sstatus_r, 0); if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV) break; @@ -152,7 +154,8 @@ void sata_interpret_sig(struct ata_channel *chp, int port, uint32_t sig) { int err; - int s; + + ata_channel_lock_owned(chp); /* some ATAPI devices have bogus lower two bytes, sigh */ if ((sig & 0xffff0000) == 0xeb140000) { @@ -169,7 +172,6 @@ sata_interpret_sig(struct ata_channel *c } KASSERT(port < chp->ch_ndrives); - s = splbio(); switch(sig) { case 0x96690101: KASSERT(port == 0 || port == PMP_PORT_CTL); @@ -195,5 +197,4 @@ sata_interpret_sig(struct ata_channel *c "Assuming it's a disk.\n", sig, port); break; } - splx(s); } Index: src/sys/dev/ata/satapmp_subr.c diff -u src/sys/dev/ata/satapmp_subr.c:1.12.24.5 src/sys/dev/ata/satapmp_subr.c:1.12.24.6 --- src/sys/dev/ata/satapmp_subr.c:1.12.24.5 Wed Jul 26 18:12:12 2017 +++ src/sys/dev/ata/satapmp_subr.c Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: satapmp_subr.c,v 1.12.24.5 2017/07/26 18:12:12 jdolecek Exp $ */ +/* $NetBSD: satapmp_subr.c,v 1.12.24.6 2017/09/19 21:06:25 jdolecek Exp $ */ /* * Copyright (c) 2012 Manuel Bouyer. All rights reserved. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.12.24.5 2017/07/26 18:12:12 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.12.24.6 2017/09/19 21:06:25 jdolecek Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -48,9 +48,9 @@ __KERNEL_RCSID(0, "$NetBSD: satapmp_subr #include <dev/ata/satareg.h> static int -satapmp_read_8(struct ata_channel *chp, int port, int reg, uint64_t *value) +satapmp_read_8(struct ata_channel *chp, int port, int reg, uint64_t *value, + struct ata_xfer *xfer) { - struct ata_xfer *xfer; struct atac_softc *atac = chp->ch_atac; struct ata_drive_datas *drvp; int error = 0; @@ -60,10 +60,7 @@ satapmp_read_8(struct ata_channel *chp, KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES); drvp = &chp->ch_drive[PMP_PORT_CTL]; KASSERT(drvp->drive == PMP_PORT_CTL); - - xfer = ata_get_xfer(chp); - if (xfer == NULL) - return EINTR; + ata_channel_lock_owned(chp); xfer->c_ata_c.r_command = PMPC_READ_PORT; xfer->c_ata_c.r_features = reg; @@ -73,6 +70,7 @@ satapmp_read_8(struct ata_channel *chp, xfer->c_ata_c.r_st_pmask = WDCS_DRDY; xfer->c_ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT; + ata_channel_unlock(chp); if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, xfer) != ATACMD_COMPLETE) { aprint_error_dev(chp->atabus, @@ -101,17 +99,18 @@ satapmp_read_8(struct ata_channel *chp, ((uint64_t)((xfer->c_ata_c.r_count >> 0) & 0xff) << 0); out: - ata_free_xfer(chp, xfer); + ata_channel_lock(chp); return error; } static inline int -satapmp_read(struct ata_channel *chp, int port, int reg, uint32_t *value) +satapmp_read(struct ata_channel *chp, int port, int reg, uint32_t *value, + struct ata_xfer *xfer) { uint64_t value64; int ret; - ret = satapmp_read_8(chp, port, reg, &value64); + ret = satapmp_read_8(chp, port, reg, &value64, xfer); if (ret) return ret; @@ -120,9 +119,9 @@ satapmp_read(struct ata_channel *chp, in } static int -satapmp_write_8(struct ata_channel *chp, int port, int reg, uint64_t value) +satapmp_write_8(struct ata_channel *chp, int port, int reg, uint64_t value, + struct ata_xfer *xfer) { - struct ata_xfer *xfer; struct atac_softc *atac = chp->ch_atac; struct ata_drive_datas *drvp; int error = 0; @@ -132,10 +131,7 @@ satapmp_write_8(struct ata_channel *chp, KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES); drvp = &chp->ch_drive[PMP_PORT_CTL]; KASSERT(drvp->drive == PMP_PORT_CTL); - - xfer = ata_get_xfer(chp); - if (xfer == NULL) - return EINTR; + ata_channel_lock_owned(chp); xfer->c_ata_c.r_command = PMPC_WRITE_PORT; xfer->c_ata_c.r_features = reg; @@ -149,6 +145,7 @@ satapmp_write_8(struct ata_channel *chp, xfer->c_ata_c.r_st_pmask = WDCS_DRDY; xfer->c_ata_c.flags = AT_LBA48 | AT_WAIT; + ata_channel_unlock(chp); if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, xfer) != ATACMD_COMPLETE) { aprint_error_dev(chp->atabus, @@ -172,14 +169,15 @@ satapmp_write_8(struct ata_channel *chp, } out: - ata_free_xfer(chp, xfer); + ata_channel_lock(chp); return error; } static inline int -satapmp_write(struct ata_channel *chp, int port, int reg, uint32_t value) +satapmp_write(struct ata_channel *chp, int port, int reg, uint32_t value, + struct ata_xfer *xfer) { - return satapmp_write_8(chp, port, reg, value); + return satapmp_write_8(chp, port, reg, value, xfer); } /* @@ -187,30 +185,34 @@ satapmp_write(struct ata_channel *chp, i * XXX duplicate of sata_reset_interface() */ static uint32_t -satapmp_reset_device_port(struct ata_channel *chp, int port) +satapmp_reset_device_port(struct ata_channel *chp, int port, + struct ata_xfer *xfer) { uint32_t scontrol, sstatus; int i; + ata_channel_lock_owned(chp); + /* bring the PHY online */ scontrol = SControl_IPM_NONE | SControl_SPD_ANY | SControl_DET_INIT; - if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0) + if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol, xfer) != 0) return 0; - tsleep(chp, PRIBIO, "sataup", mstohz(50)); + ata_delay(chp, 50, "sataup", AT_WAIT); scontrol &= ~SControl_DET_INIT; - if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0) + if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol, xfer) != 0) return 0; - tsleep(chp, PRIBIO, "sataup", mstohz(50)); + ata_delay(chp, 50, "sataup", AT_WAIT); /* wait up to 1s for device to come up */ for (i = 0; i < 100; i++) { - if (satapmp_read(chp, port, PMP_PSCR_SStatus, &sstatus) != 0) + if (satapmp_read(chp, port, PMP_PSCR_SStatus, &sstatus, + xfer) != 0) return 0; if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV) break; - tsleep(chp, PRIBIO, "sataup", mstohz(10)); + ata_delay(chp, 10, "sataup", AT_WAIT); } switch (sstatus & SStatus_DET_mask) { @@ -238,25 +240,31 @@ satapmp_reset_device_port(struct ata_cha } void -satapmp_rescan(struct ata_channel *chp) { +satapmp_rescan(struct ata_channel *chp, struct ata_xfer *xfer) +{ int i; uint32_t sig; KASSERT(chp->ch_satapmp_nports <= PMP_PORT_CTL); KASSERT(chp->ch_satapmp_nports <= chp->ch_ndrives); + ata_channel_lock_owned(chp); for (i = 0; i < chp->ch_satapmp_nports; i++) { if (chp->ch_drive[i].drive_type != ATA_DRIVET_NONE || - satapmp_reset_device_port(chp, i) != SStatus_DET_DEV) { + satapmp_reset_device_port(chp, i, xfer) + != SStatus_DET_DEV) { continue; } - if (satapmp_write(chp, i, PMP_PSCR_SError, 0xffffffff) != 0) { + if (satapmp_write(chp, i, PMP_PSCR_SError, 0xffffffff, xfer) + != 0) { aprint_error("%s PMP port %d: can't write SError\n", device_xname(chp->atabus), i); continue; } + ata_channel_unlock(chp); chp->ch_atac->atac_bustype_ata->ata_reset_drive( &chp->ch_drive[i], AT_WAIT, &sig); + ata_channel_lock(chp); sata_interpret_sig(chp, i, sig); } @@ -266,14 +274,23 @@ void satapmp_attach(struct ata_channel *chp) { uint32_t id, rev, inf; + struct ata_xfer *xfer; - if (satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_ID, &id) != 0 || - satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_REV, &rev) != 0 || - satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_INF, &inf) != 0) { - aprint_normal_dev(chp->atabus, "can't read PMP registers\n"); + xfer = ata_get_xfer(chp); + if (xfer == NULL) { + aprint_normal_dev(chp->atabus, "no available xfer\n"); return; } + ata_channel_lock(chp); + + if (satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_ID, &id, xfer) != 0 || + satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_REV, &rev, xfer) != 0 || + satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_INF, &inf, xfer) != 0) { + aprint_normal_dev(chp->atabus, "can't read PMP registers\n"); + goto out; + } + aprint_normal("%s at %s channel %d: SATA port multiplier, %d ports\n", device_xname(chp->atabus), device_xname(chp->ch_atac->atac_dev), chp->ch_channel, @@ -293,5 +310,9 @@ satapmp_attach(struct ata_channel *chp) chp->ch_satapmp_nports = PMP_INF_NPORTS(inf); /* reset and bring up PHYs */ - satapmp_rescan(chp); + satapmp_rescan(chp, xfer); + +out: + ata_channel_unlock(chp); + ata_free_xfer(chp, xfer); } Index: src/sys/dev/ata/satapmpvar.h diff -u src/sys/dev/ata/satapmpvar.h:1.3 src/sys/dev/ata/satapmpvar.h:1.3.30.1 --- src/sys/dev/ata/satapmpvar.h:1.3 Wed Aug 1 09:02:03 2012 +++ src/sys/dev/ata/satapmpvar.h Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: satapmpvar.h,v 1.3 2012/08/01 09:02:03 bouyer Exp $ */ +/* $NetBSD: satapmpvar.h,v 1.3.30.1 2017/09/19 21:06:25 jdolecek Exp $ */ /* @@ -29,7 +29,7 @@ #define _DEV_ATA_SATAPMPVAR_H_ void satapmp_attach(struct ata_channel *); -void satapmp_rescan(struct ata_channel *); +void satapmp_rescan(struct ata_channel *, struct ata_xfer *); #endif /* _DEV_ATA_SATAPMPVAR_H_ */ Index: src/sys/dev/ic/ahcisata_core.c diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.28 src/sys/dev/ic/ahcisata_core.c:1.57.6.29 --- src/sys/dev/ic/ahcisata_core.c:1.57.6.28 Tue Sep 19 17:52:52 2017 +++ src/sys/dev/ic/ahcisata_core.c Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ahcisata_core.c,v 1.57.6.28 2017/09/19 17:52:52 jdolecek Exp $ */ +/* $NetBSD: ahcisata_core.c,v 1.57.6.29 2017/09/19 21:06:25 jdolecek Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.28 2017/09/19 17:52:52 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.29 2017/09/19 21:06:25 jdolecek Exp $"); #include <sys/types.h> #include <sys/malloc.h> @@ -58,7 +58,8 @@ static void ahci_probe_drive(struct ata_ static void ahci_setup_channel(struct ata_channel *); static int ahci_ata_bio(struct ata_drive_datas *, struct ata_xfer *); -static int ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *); +static int ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *, + struct ata_xfer *xfer); static void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *); static void ahci_reset_channel(struct ata_channel *, int); static int ahci_exec_command(struct ata_drive_datas *, struct ata_xfer *); @@ -678,12 +679,23 @@ ahci_reset_drive(struct ata_drive_datas { struct ata_channel *chp = drvp->chnl_softc; struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; + struct ata_xfer *xfer; + + xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0); + + ata_channel_lock(chp); + AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) & ~AHCI_GHC_IE); ahci_channel_stop(sc, chp, flags); - if (ahci_do_reset_drive(chp, drvp->drive, flags, sigp) != 0) + if (ahci_do_reset_drive(chp, drvp->drive, flags, sigp, xfer) != 0) ata_reset_channel(chp, flags); AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE); + + ata_channel_unlock(chp); + + ata_free_xfer(chp, xfer); + return; } @@ -731,7 +743,7 @@ ahci_exec_fis(struct ata_channel *chp, i AHCINAME(sc), chp->ch_channel, is); return ERR_DF; } - ata_delay(10, "ahcifis", flags); + ata_delay(chp, 10, "ahcifis", flags); } aprint_debug("%s channel %d: timeout sending FIS\n", @@ -741,7 +753,7 @@ ahci_exec_fis(struct ata_channel *chp, i static int ahci_do_reset_drive(struct ata_channel *chp, int drive, int flags, - uint32_t *sigp) + uint32_t *sigp, struct ata_xfer *xfer) { struct ahci_channel *achp = (struct ahci_channel *)chp; struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; @@ -749,9 +761,10 @@ ahci_do_reset_drive(struct ata_channel * struct ahci_cmd_header *cmd_h; int i; uint32_t sig; - struct ata_xfer *xfer = NULL; KASSERT((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR) == 0); + ata_channel_lock_owned(chp); + again: /* clear port interrupt register */ AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff); @@ -774,8 +787,6 @@ again: goto skip_reset; /* polled command, assume interrupts are disabled */ - /* use available slot to send reset, if none available fail */ - xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0); cmd_h = &achp->ahcic_cmdh[xfer->c_slot]; cmd_tbl = achp->ahcic_cmd_tbl[xfer->c_slot]; @@ -837,7 +848,7 @@ skip_reset: sig = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel)); if ((__SHIFTOUT(sig, AHCI_P_TFD_ST) & WDCS_BSY) == 0) break; - ata_delay(10, "ahcid2h", flags); + ata_delay(chp, 10, "ahcid2h", flags); } if (i == AHCI_RST_WAIT) { aprint_error("%s: BSY never cleared, TD 0x%x\n", @@ -855,10 +866,8 @@ skip_reset: AHCINAME(sc), chp->ch_channel, sig, AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel))), DEBUG_PROBE); end: - if (xfer != NULL) - ata_free_xfer(chp, xfer); ahci_channel_stop(sc, chp, flags); - ata_delay(500, "ahcirst", flags); + ata_delay(chp, 500, "ahcirst", flags); /* clear port interrupt register */ AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff); ahci_channel_start(sc, chp, flags, @@ -873,6 +882,8 @@ ahci_reset_channel(struct ata_channel *c struct ahci_channel *achp = (struct ahci_channel *)chp; int i, tfd; + ata_channel_lock(chp); + ahci_channel_stop(sc, chp, flags); if (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol, achp->ahcic_sstatus, flags) != SStatus_DET_DEV) { @@ -880,7 +891,7 @@ ahci_reset_channel(struct ata_channel *c /* XXX and then ? */ } ata_kill_active(chp, KILL_RESET, flags); - ata_delay(500, "ahcirst", flags); + ata_delay(chp, 500, "ahcirst", flags); /* clear port interrupt register */ AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff); /* clear SErrors and start operations */ @@ -891,7 +902,7 @@ ahci_reset_channel(struct ata_channel *c tfd = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel)); if ((AHCI_TFD_ST(tfd) & WDCS_BSY) == 0) break; - ata_delay(10, "ahcid2h", flags); + ata_delay(chp, 10, "ahcid2h", flags); } if ((AHCI_TFD_ST(tfd) & WDCS_BSY) != 0) aprint_error("%s: BSY never cleared, TD 0x%x\n", @@ -901,6 +912,8 @@ ahci_reset_channel(struct ata_channel *c /* clear port interrupt register */ AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff); + ata_channel_unlock(chp); + return; } @@ -928,6 +941,17 @@ ahci_probe_drive(struct ata_channel *chp struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; struct ahci_channel *achp = (struct ahci_channel *)chp; uint32_t sig; + struct ata_xfer *xfer; + + xfer = ata_get_xfer_ext(chp, 0, 0); + if (xfer == NULL) { + aprint_error_dev(sc->sc_atac.atac_dev, + "%s: failed to get xfer port %d\n", + __func__, chp->ch_channel); + return; + } + + ata_channel_lock(chp); /* bring interface up, accept FISs, power up and spin up device */ AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel), @@ -937,11 +961,12 @@ ahci_probe_drive(struct ata_channel *chp switch (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol, achp->ahcic_sstatus, AT_WAIT)) { case SStatus_DET_DEV: - tsleep(&sc, PRIBIO, "ahcidv", mstohz(500)); + ata_delay(chp, 500, "ahcidv", AT_WAIT); if (sc->sc_ahci_cap & AHCI_CAP_SPM) { - ahci_do_reset_drive(chp, PMP_PORT_CTL, AT_WAIT, &sig); + ahci_do_reset_drive(chp, PMP_PORT_CTL, AT_WAIT, &sig, + xfer); } else { - ahci_do_reset_drive(chp, 0, AT_WAIT, &sig); + ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, xfer); } sata_interpret_sig(chp, 0, sig); /* if we have a PMP attached, inform the controller */ @@ -961,12 +986,13 @@ ahci_probe_drive(struct ata_channel *chp AHCI_P_IX_OFS | AHCI_P_IX_DPS | AHCI_P_IX_UFS | AHCI_P_IX_PSS | AHCI_P_IX_DHRS | AHCI_P_IX_SDBS); /* wait 500ms before actually starting operations */ - tsleep(&sc, PRIBIO, "ahciprb", mstohz(500)); + ata_delay(chp, 500, "ahciprb", AT_WAIT); break; default: break; } + ata_channel_unlock(chp); } static void @@ -1010,9 +1036,12 @@ ahci_exec_command(struct ata_drive_datas ret = ATACMD_COMPLETE; } else { if (ata_c->flags & AT_WAIT) { - while ((ata_c->flags & AT_DONE) == 0) { - tsleep(ata_c, PRIBIO, "ahcicmd", 0); + ata_channel_lock(chp); + if ((ata_c->flags & AT_DONE) == 0) { + ata_wait_xfer(chp, xfer); + KASSERT((ata_c->flags & AT_DONE) != 0); } + ata_channel_unlock(chp); ret = ATACMD_COMPLETE; } else { ret = ATACMD_QUEUED; @@ -1089,14 +1118,18 @@ ahci_cmd_poll(struct ata_channel *chp, s struct ahci_softc *sc = AHCI_CH2SC(chp); struct ahci_channel *achp = (struct ahci_channel *)chp; + ata_channel_lock(chp); + /* * Polled command. */ for (int i = 0; i < xfer->c_ata_c.timeout / 10; i++) { if (xfer->c_ata_c.flags & AT_DONE) break; + ata_channel_unlock(chp); ahci_intr_port(sc, achp); - ata_delay(10, "ahcipl", xfer->c_ata_c.flags); + ata_channel_lock(chp); + ata_delay(chp, 10, "ahcipl", xfer->c_ata_c.flags); } AHCIDEBUG_PRINT(("%s port %d poll end GHC 0x%x IS 0x%x list 0x%x%x fis 0x%x%x CMD 0x%x CI 0x%x\n", AHCINAME(sc), chp->ch_channel, AHCI_READ(sc, AHCI_GHC), AHCI_READ(sc, AHCI_IS), @@ -1107,6 +1140,9 @@ ahci_cmd_poll(struct ata_channel *chp, s AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)), AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))), DEBUG_XFERS); + + ata_channel_unlock(chp); + if ((xfer->c_ata_c.flags & AT_DONE) == 0) { xfer->c_ata_c.flags |= AT_TIMEOU; xfer->c_intr(chp, xfer, 0); @@ -1239,11 +1275,15 @@ static void ahci_cmd_done_end(struct ata_channel *chp, struct ata_xfer *xfer) { struct ata_command *ata_c = &xfer->c_ata_c; - + + ata_channel_lock(chp); + ata_c->flags |= AT_DONE; if (ata_c->flags & AT_WAIT) - wakeup(ata_c); + ata_wake_xfer(chp, xfer); + + ata_channel_unlock(chp); return; } @@ -1482,7 +1522,7 @@ ahci_channel_stop(struct ahci_softc *sc, if ((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR) == 0) break; - ata_delay(10, "ahcistop", flags); + ata_delay(chp, 10, "ahcistop", flags); } if (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR) { printf("%s: channel wouldn't stop\n", AHCINAME(sc)); @@ -1514,7 +1554,7 @@ ahci_channel_start(struct ahci_softc *sc if ((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CLO) == 0) break; - ata_delay(10, "ahciclo", flags); + ata_delay(chp, 10, "ahciclo", flags); } if (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CLO) { printf("%s: channel wouldn't CLO\n", AHCINAME(sc)); Index: src/sys/dev/ic/mvsata.c diff -u src/sys/dev/ic/mvsata.c:1.35.6.25 src/sys/dev/ic/mvsata.c:1.35.6.26 --- src/sys/dev/ic/mvsata.c:1.35.6.25 Sun Sep 10 19:31:15 2017 +++ src/sys/dev/ic/mvsata.c Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsata.c,v 1.35.6.25 2017/09/10 19:31:15 jdolecek Exp $ */ +/* $NetBSD: mvsata.c,v 1.35.6.26 2017/09/19 21:06:25 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.25 2017/09/10 19:31:15 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.26 2017/09/19 21:06:25 jdolecek Exp $"); #include "opt_mvsata.h" @@ -677,6 +677,8 @@ mvsata_probe_drive(struct ata_channel *c struct mvsata_port * const mvport = (struct mvsata_port *)chp; uint32_t sstat, sig; + ata_channel_lock(chp); + sstat = sata_reset_interface(chp, mvport->port_iot, mvport->port_sata_scontrol, mvport->port_sata_sstatus, AT_WAIT); switch (sstat) { @@ -688,6 +690,8 @@ mvsata_probe_drive(struct ata_channel *c default: break; } + + ata_channel_unlock(chp); } #ifndef MVSATA_WITHOUTDMA @@ -699,6 +703,8 @@ mvsata_reset_drive(struct ata_drive_data uint32_t edma_c; uint32_t sig; + ata_channel_lock(chp); + edma_c = MVSATA_EDMA_READ_4(mvport, EDMA_CMD); DPRINTF(DEBUG_FUNCS, @@ -720,6 +726,9 @@ mvsata_reset_drive(struct ata_drive_data mvsata_edma_reset_qptr(mvport); mvsata_edma_enable(mvport); } + + ata_channel_unlock(chp); + return; } @@ -733,6 +742,8 @@ mvsata_reset_channel(struct ata_channel DPRINTF(DEBUG_FUNCS, ("%s: mvsata_reset_channel: channel=%d\n", device_xname(MVSATA_DEV2(mvport)), chp->ch_channel)); + ata_channel_lock(chp); + mvsata_hreset_port(mvport); sstat = sata_reset_interface(chp, mvport->port_iot, mvport->port_sata_scontrol, mvport->port_sata_sstatus, flags); @@ -760,6 +771,9 @@ mvsata_reset_channel(struct ata_channel mvsata_edma_config(mvport, mvport->port_edmamode_curr); mvsata_edma_reset_qptr(mvport); mvsata_edma_enable(mvport); + + ata_channel_unlock(chp); + return; } @@ -1689,8 +1703,12 @@ mvsata_exec_command(struct ata_drive_dat rv = ATACMD_COMPLETE; else { if (ata_c->flags & AT_WAIT) { - while ((ata_c->flags & AT_DONE) == 0) - tsleep(ata_c, PRIBIO, "mvsatacmd", 0); + ata_channel_lock(chp); + if ((ata_c->flags & AT_DONE) == 0) { + ata_wait_xfer(chp, xfer); + KASSERT((ata_c->flags & AT_DONE) != 0); + } + ata_channel_unlock(chp); rv = ATACMD_COMPLETE; } else rv = ATACMD_QUEUED; @@ -1801,7 +1819,7 @@ mvsata_wdc_cmd_intr(struct ata_channel * drive_flags = chp->ch_drive[xfer->c_drive].drive_flags; if ((ata_c->flags & (AT_WAIT | AT_POLL)) == (AT_WAIT | AT_POLL)) - /* both wait and poll, we can tsleep here */ + /* both wait and poll, we can kpause here */ wflags = AT_WAIT | AT_POLL; else wflags = AT_POLL; @@ -2009,9 +2027,11 @@ mvsata_wdc_cmd_done_end(struct ata_chann mvsata_edma_enable(mvport); } + ata_channel_lock(chp); ata_c->flags |= AT_DONE; if (ata_c->flags & AT_WAIT) - wakeup(ata_c); + ata_wake_xfer(chp, xfer); + ata_channel_unlock(chp); } #if NATAPIBUS > 0 @@ -3481,10 +3501,13 @@ mvsata_reset_hc(struct mvsata_hc *mvhc) static uint32_t mvsata_softreset(struct mvsata_port *mvport, int flags) { + struct ata_channel *chp = &mvport->port_ata_channel; uint32_t sig0 = ~0; int timeout; uint8_t st0; + ata_channel_lock_owned(chp); + MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_RST | WDCTL_IDS | WDCTL_4BIT); delay(10); (void) MVSATA_WDC_READ_1(mvport, SRB_FE); @@ -3502,7 +3525,7 @@ mvsata_softreset(struct mvsata_port *mvp sig0 |= MVSATA_WDC_READ_1(mvport, SRB_LBAH) << 24; goto out; } - ata_delay(10, "atarst", flags); + ata_delay(chp, 10, "atarst", flags); } aprint_error("%s:%d:%d: %s: timeout\n", @@ -3541,6 +3564,7 @@ mvsata_edma_enable(struct mvsata_port *m static int mvsata_edma_disable(struct mvsata_port *mvport, int timeout, int wflags) { + struct ata_channel *chp = &mvport->port_ata_channel; uint32_t status, command; int ms; @@ -3549,7 +3573,7 @@ mvsata_edma_disable(struct mvsata_port * status = MVSATA_EDMA_READ_4(mvport, EDMA_S); if (status & EDMA_S_EDMAIDLE) break; - ata_delay(1, "mvsata_edma1", wflags); + ata_delay(chp, 1, "mvsata_edma1", wflags); } if (ms == timeout) { aprint_error("%s:%d:%d: unable to disable EDMA\n", @@ -3565,7 +3589,7 @@ mvsata_edma_disable(struct mvsata_port * command = MVSATA_EDMA_READ_4(mvport, EDMA_CMD); if (!(command & EDMA_CMD_EENEDMA)) break; - ata_delay(1, "mvsata_edma2", wflags); + ata_delay(chp, 1, "mvsata_edma2", wflags); } if (ms == timeout) { aprint_error("%s:%d:%d: unable to re-enable EDMA\n", Index: src/sys/dev/ic/siisata.c diff -u src/sys/dev/ic/siisata.c:1.30.4.37 src/sys/dev/ic/siisata.c:1.30.4.38 --- src/sys/dev/ic/siisata.c:1.30.4.37 Sun Sep 10 19:31:15 2017 +++ src/sys/dev/ic/siisata.c Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: siisata.c,v 1.30.4.37 2017/09/10 19:31:15 jdolecek Exp $ */ +/* $NetBSD: siisata.c,v 1.30.4.38 2017/09/19 21:06:25 jdolecek Exp $ */ /* from ahcisata_core.c */ @@ -79,7 +79,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.37 2017/09/10 19:31:15 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.38 2017/09/19 21:06:25 jdolecek Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -743,6 +743,8 @@ siisata_reset_drive(struct ata_drive_dat KASSERT(drvp->drive <= PMP_PORT_CTL); prb->prb_fis[rhd_c] = drvp->drive; + ata_channel_lock(chp); + siisata_disable_port_interrupt(chp); siisata_activate_prb(schp, xfer->c_slot); @@ -756,7 +758,7 @@ siisata_reset_drive(struct ata_drive_dat } if (pss & PR_PSS_ATTENTION) break; - ata_delay(10, "siiprb", flags); + ata_delay(chp, 10, "siiprb", flags); } siisata_deactivate_prb(schp, xfer->c_slot); @@ -777,6 +779,8 @@ siisata_reset_drive(struct ata_drive_dat siisata_enable_port_interrupt(chp); + ata_channel_unlock(chp); + if (timed_out) { /* timeout */ siisata_device_reset(chp); /* XXX is this right? */ @@ -857,11 +861,13 @@ siisata_probe_drive(struct ata_channel * xfer = ata_get_xfer_ext(chp, 0, 0); if (xfer == NULL) { aprint_error_dev(sc->sc_atac.atac_dev, - "failed to get xfer port %d\n", - chp->ch_channel); + "%s: failed to get xfer port %d\n", + __func__, chp->ch_channel); return; } + ata_channel_lock(chp); + /* * disable port interrupt as we're polling for PHY up and * prb completion @@ -884,7 +890,7 @@ siisata_probe_drive(struct ata_channel * break; } - ata_delay(10, "siiprbrd", AT_WAIT); + ata_delay(chp, 10, "siiprbrd", AT_WAIT); } if (timed_out) { aprint_error_dev(sc->sc_atac.atac_dev, @@ -914,7 +920,7 @@ siisata_probe_drive(struct ata_channel * break; } - ata_delay(10, "siiprb", AT_WAIT); + ata_delay(chp, 10, "siiprb", AT_WAIT); } siisata_deactivate_prb(schp, xfer->c_slot); @@ -951,6 +957,8 @@ siisata_probe_drive(struct ata_channel * siisata_enable_port_interrupt(chp); + ata_channel_unlock(chp); + ata_free_xfer(chp, xfer); SIISATA_DEBUG_PRINT(("%s: %s: port %d done\n", SIISATANAME(sc), @@ -999,13 +1007,16 @@ siisata_exec_command(struct ata_drive_da ret = ATACMD_COMPLETE; } else { if (ata_c->flags & AT_WAIT) { - while ((ata_c->flags & AT_DONE) == 0) { + ata_channel_lock(chp); + if ((ata_c->flags & AT_DONE) == 0) { SIISATA_DEBUG_PRINT(("%s: %s: sleeping\n", SIISATANAME( (struct siisata_softc *)chp->ch_atac), __func__), DEBUG_FUNCS); - tsleep(ata_c, PRIBIO, "siicmd", 0); + ata_wait_xfer(chp, xfer); + KASSERT((ata_c->flags & AT_DONE) != 0); } + ata_channel_unlock(chp); ret = ATACMD_COMPLETE; } else { ret = ATACMD_QUEUED; @@ -1213,8 +1224,6 @@ siisata_cmd_done(struct ata_channel *chp ata_c->flags |= AT_XFDONE; siisata_cmd_done_end(chp, xfer); - if ((ATACH_ST(tfd) & WDCS_ERR) == 0) - atastart(chp); } static void @@ -1222,10 +1231,14 @@ siisata_cmd_done_end(struct ata_channel { struct ata_command *ata_c = &xfer->c_ata_c; + ata_channel_lock(chp); + ata_c->flags |= AT_DONE; if (ata_c->flags & AT_WAIT) - wakeup(ata_c); + ata_wake_xfer(chp, xfer); + + ata_channel_unlock(chp); return; } Index: src/sys/dev/ic/wdc.c diff -u src/sys/dev/ic/wdc.c:1.283.2.15 src/sys/dev/ic/wdc.c:1.283.2.16 --- src/sys/dev/ic/wdc.c:1.283.2.15 Mon Sep 11 22:19:23 2017 +++ src/sys/dev/ic/wdc.c Tue Sep 19 21:06:25 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: wdc.c,v 1.283.2.15 2017/09/11 22:19:23 jdolecek Exp $ */ +/* $NetBSD: wdc.c,v 1.283.2.16 2017/09/19 21:06:25 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.15 2017/09/11 22:19:23 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.16 2017/09/19 21:06:25 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wdc.h" @@ -107,7 +107,7 @@ __KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.28 #define WDCNDELAY_DEBUG 50 #endif -/* When polling wait that much and then tsleep for 1/hz seconds */ +/* When polling wait that much and then kpause for 1/hz seconds */ #define WDCDELAY_POLL 1 /* ms */ /* timeout for the control commands */ @@ -140,7 +140,7 @@ const struct ata_bustype wdc_ata_bustype /* Flags to wdcreset(). */ #define RESET_POLL 1 -#define RESET_SLEEP 0 /* wdcreset() will use tsleep() */ +#define RESET_SLEEP 0 /* wdcreset() will use kpause() */ static int wdcprobe1(struct ata_channel *, int); static int wdcreset(struct ata_channel *, int); @@ -206,10 +206,14 @@ wdc_sataprobe(struct ata_channel *chp) { struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp); uint8_t st = 0, sc __unused, sn __unused, cl, ch; - int i, s; + int i; KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL); + /* do this before we take lock */ + + ata_channel_lock(chp); + /* reset the PHY and bring online */ switch (sata_reset_interface(chp, wdr->sata_iot, wdr->sata_control, wdr->sata_status, AT_WAIT)) { @@ -223,7 +227,7 @@ wdc_sataprobe(struct ata_channel *chp) wdr->cmd_iohs[wd_status], 0); if ((st & WDCS_BSY) == 0) break; - tsleep(&chp, PRIBIO, "sataprb", 1); + ata_delay(chp, 1, "sataprb", AT_WAIT); } if (i == WDC_PROBE_WAIT * hz) aprint_error_dev(chp->ch_atac->atac_dev, @@ -246,12 +250,10 @@ wdc_sataprobe(struct ata_channel *chp) * sc and sn are supposed to be 0x1 for ATAPI, but in some * cases we get wrong values here, so ignore it. */ - s = splbio(); if (cl == 0x14 && ch == 0xeb) chp->ch_drive[0].drive_type = ATA_DRIVET_ATAPI; else chp->ch_drive[0].drive_type = ATA_DRIVET_ATA; - splx(s); /* * issue a reset in case only the interface part of the drive @@ -264,6 +266,8 @@ wdc_sataprobe(struct ata_channel *chp) default: break; } + + ata_channel_unlock(chp); } #endif /* NSATA > 0 */ @@ -290,7 +294,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, tfd; + int i, j, error, tfd; if (atabus_alloc_drives(chp, wdc->wdc_maxdrives) != 0) return; @@ -300,7 +304,7 @@ wdc_drvprobe(struct ata_channel *chp) return; } - s = splbio(); + ata_channel_lock(chp); /* for ATA/OLD drives, wait for DRDY, 3s timeout */ for (i = 0; i < mstohz(3000); i++) { /* @@ -335,12 +339,12 @@ wdc_drvprobe(struct ata_channel *chp) (st1 & WDCS_DRDY))) break; #ifdef WDC_NO_IDS - /* cannot tsleep here (can't enable IPL_BIO interrups), + /* cannot kpause here (can't enable IPL_BIO interrups), * delay instead */ delay(1000000 / hz); #else - tsleep(¶ms, PRIBIO, "atadrdy", 1); + ata_delay(chp, 1, "atadrdy", AT_WAIT); #endif } if ((st0 & WDCS_DRDY) == 0 && @@ -349,7 +353,7 @@ wdc_drvprobe(struct ata_channel *chp) if (chp->ch_ndrives > 1 && (st1 & WDCS_DRDY) == 0 && chp->ch_drive[1].drive_type != ATA_DRIVET_ATAPI) chp->ch_drive[1].drive_type = ATA_DRIVET_NONE; - splx(s); + ata_channel_unlock(chp); ATADEBUG_PRINT(("%s:%d: wait DRDY st0 0x%x st1 0x%x\n", device_xname(atac->atac_dev), @@ -370,9 +374,9 @@ wdc_drvprobe(struct ata_channel *chp) /* If controller can't do 16bit flag the drives as 32bit */ if ((atac->atac_cap & (ATAC_CAP_DATA16 | ATAC_CAP_DATA32)) == ATAC_CAP_DATA32) { - s = splbio(); + ata_channel_lock(chp); chp->ch_drive[i].drive_flags |= ATA_DRIVE_CAP32; - splx(s); + ata_channel_unlock(chp); } if (chp->ch_drive[i].drive_type == ATA_DRIVET_NONE) continue; @@ -390,7 +394,9 @@ wdc_drvprobe(struct ata_channel *chp) error = ata_get_params(&chp->ch_drive[i], AT_WAIT | AT_POLL, ¶ms); if (error != CMD_OK) { - tsleep(¶ms, PRIBIO, "atacnf", mstohz(1000)); + ata_channel_lock(chp); + ata_delay(chp, 1000, "atacnf", AT_WAIT); + ata_channel_unlock(chp); /* Shortcut in case we've been shutdown */ if (chp->ch_flags & ATACH_SHUTDOWN) @@ -403,14 +409,13 @@ wdc_drvprobe(struct ata_channel *chp) ATADEBUG_PRINT(("%s:%d:%d: IDENTIFY failed (%d)\n", device_xname(atac->atac_dev), chp->ch_channel, i, error), DEBUG_PROBE); - s = splbio(); + ata_channel_lock(chp); if (chp->ch_drive[i].drive_type != ATA_DRIVET_ATA || (wdc->cap & WDC_CAPABILITY_PREATA) == 0) { chp->ch_drive[i].drive_type = ATA_DRIVET_NONE; - splx(s); + ata_channel_unlock(chp); continue; } - splx(s); /* * Pre-ATA drive ? * Test registers writability (Error register not @@ -433,9 +438,8 @@ wdc_drvprobe(struct ata_channel *chp) "writability failed\n", device_xname(atac->atac_dev), chp->ch_channel, i), DEBUG_PROBE); - s = splbio(); chp->ch_drive[i].drive_type = ATA_DRIVET_NONE; - splx(s); + ata_channel_unlock(chp); continue; } if (wdc_wait_for_ready(chp, 10000, 0, &tfd) == @@ -443,9 +447,8 @@ wdc_drvprobe(struct ata_channel *chp) ATADEBUG_PRINT(("%s:%d:%d: not ready\n", device_xname(atac->atac_dev), chp->ch_channel, i), DEBUG_PROBE); - s = splbio(); chp->ch_drive[i].drive_type = ATA_DRIVET_NONE; - splx(s); + ata_channel_unlock(chp); continue; } bus_space_write_1(wdr->cmd_iot, @@ -456,11 +459,9 @@ wdc_drvprobe(struct ata_channel *chp) ATADEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n", device_xname(atac->atac_dev), chp->ch_channel, i), DEBUG_PROBE); - s = splbio(); chp->ch_drive[i].drive_type = ATA_DRIVET_NONE; - splx(s); + ata_channel_unlock(chp); } else { - s = splbio(); for (j = 0; j < chp->ch_ndrives; j++) { if (chp->ch_drive[i].drive_type != ATA_DRIVET_NONE) { @@ -468,7 +469,7 @@ wdc_drvprobe(struct ata_channel *chp) ATA_DRIVET_OLD; } } - splx(s); + ata_channel_unlock(chp); } } } @@ -493,7 +494,6 @@ wdcprobe1(struct ata_channel *chp, int p u_int8_t st0 = 0, st1 = 0, sc __unused, sn __unused, cl, ch; u_int8_t ret_value = 0x03; u_int8_t drive; - int s; /* XXX if poll, wdc_probe_count is 0. */ int wdc_probe_count = poll ? (WDC_PROBE_WAIT / WDCDELAY) @@ -503,7 +503,7 @@ wdcprobe1(struct ata_channel *chp, int p * Sanity check to see if the wdc channel responds at all. */ - s = splbio(); + ata_channel_lock(chp); if ((wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) { while (wdc_probe_count-- > 0) { if (wdc->select) @@ -656,7 +656,7 @@ wdcprobe1(struct ata_channel *chp, int p } if (ret_value == 0) { - splx(s); + ata_channel_unlock(chp); return 0; } } @@ -697,16 +697,14 @@ wdcprobe1(struct ata_channel *chp, int p #ifdef WDC_NO_IDS ret_value = __wdcwait_reset(chp, ret_value, RESET_POLL); #else - splx(s); ret_value = __wdcwait_reset(chp, ret_value, poll); - s = splbio(); #endif ATADEBUG_PRINT(("%s:%d: after reset, ret_value=%#x\n", __func__, chp->ch_channel, ret_value), DEBUG_PROBE); /* if reset failed, there's nothing here */ if (ret_value == 0) { - splx(s); + ata_channel_unlock(chp); return 0; } @@ -759,7 +757,7 @@ wdcprobe1(struct ata_channel *chp, int p (void)bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_status], 0); } - splx(s); + ata_channel_unlock(chp); return (ret_value); } @@ -925,12 +923,12 @@ wdc_reset_channel(struct ata_channel *ch * ATAPI_SOFT_RESET */ xfer = ata_queue_get_active_xfer(chp); + + ata_channel_lock(chp); + if (xfer && xfer->c_chp == chp && (xfer->c_flags & C_ATAPI)) { wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET); - if (flags & AT_WAIT) - tsleep(&flags, PRIBIO, "atardl", mstohz(1) + 1); - else - delay(1000); + ata_delay(chp, 1000, "atardl", flags); } /* reset the channel */ @@ -943,10 +941,7 @@ wdc_reset_channel(struct ata_channel *ch * wait a bit after reset; in case the DMA engines needs some time * to recover. */ - if (flags & AT_WAIT) - tsleep(&flags, PRIBIO, "atardl", mstohz(1) + 1); - else - delay(1000); + ata_delay(chp, 1000, "atardl", flags); /* * Look for pending xfers. If we have a shared queue, we'll also reset @@ -955,9 +950,11 @@ wdc_reset_channel(struct ata_channel *ch * it is queued for retry immediatelly without waiting for I/O timeout. */ if (xfer) { - if (xfer->c_chp != chp) + if (xfer->c_chp != chp) { + ata_channel_unlock(chp); ata_reset_channel(xfer->c_chp, flags); - else { + ata_channel_lock(chp); + } else { #if NATA_DMA || NATA_PIOBM /* * If we're waiting for DMA, stop the @@ -974,6 +971,8 @@ wdc_reset_channel(struct ata_channel *ch } ata_kill_active(chp, KILL_RESET, flags); + + ata_channel_unlock(chp); } static int @@ -984,6 +983,8 @@ wdcreset(struct ata_channel *chp, int po struct wdc_regs *wdr = &wdc->regs[chp->ch_channel]; int drv_mask1, drv_mask2; + ata_channel_lock_owned(chp); + #ifdef WDC_NO_IDS poll = RESET_POLL; #endif @@ -1051,6 +1052,7 @@ __wdcwait_reset(struct ata_channel *chp, struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct wdc_regs *wdr = &wdc->regs[chp->ch_channel]; int timeout, nloop; + int wflags = poll ? AT_POLL : AT_WAIT; u_int8_t st0 = 0, st1 = 0; #ifdef ATADEBUG u_int8_t sc0 = 0, sn0 = 0, cl0 = 0, ch0 = 0; @@ -1123,10 +1125,7 @@ __wdcwait_reset(struct ata_channel *chp, goto end; } } - if (poll) - delay(WDCDELAY); - else - tsleep(&nloop, PRIBIO, "atarst", 1); + ata_delay(chp, WDCDELAY, "atarst", wflags); } /* Reset timed out. Maybe it's because drv_mask was not right */ if (st0 & WDCS_BSY) @@ -1219,7 +1218,7 @@ out: } /* - * Call __wdcwait(), polling using tsleep() or waking up the kernel + * Call __wdcwait(), polling using kpause() or waking up the kernel * thread if possible */ int @@ -1376,9 +1375,12 @@ wdc_exec_command(struct ata_drive_datas ret = ATACMD_COMPLETE; } else { if (ata_c->flags & AT_WAIT) { - while ((ata_c->flags & AT_DONE) == 0) { - tsleep(ata_c, PRIBIO, "wdccmd", 0); + ata_channel_lock(chp); + if ((ata_c->flags & AT_DONE) == 0) { + ata_wait_xfer(chp, xfer); + KASSERT((ata_c->flags & AT_DONE) != 0); } + ata_channel_unlock(chp); ret = ATACMD_COMPLETE; } else { ret = ATACMD_QUEUED; @@ -1490,7 +1492,7 @@ __wdccommand_intr(struct ata_channel *ch wflags = AT_POLL; #else if ((ata_c->flags & (AT_WAIT | AT_POLL)) == (AT_WAIT | AT_POLL)) { - /* both wait and poll, we can tsleep here */ + /* both wait and poll, we can kpause here */ wflags = AT_WAIT | AT_POLL; } else { wflags = AT_POLL; @@ -1676,10 +1678,11 @@ __wdccommand_done_end(struct ata_channel { struct ata_command *ata_c = &xfer->c_ata_c; + ata_channel_lock(chp); ata_c->flags |= AT_DONE; if (ata_c->flags & AT_WAIT) - wakeup(ata_c); - return; + ata_wake_xfer(chp, xfer); + ata_channel_unlock(chp); } static void