Module Name: src Committed By: jdolecek Date: Sat Sep 22 09:23:00 UTC 2018
Modified Files: src/sys/dev/ata [jdolecek-ncqfixes]: TODO.ncq ata.c ata_subr.c atavar.h satapmp_subr.c wd.c wdvar.h src/sys/dev/ic [jdolecek-ncqfixes]: ahcisata_core.c mvsata.c siisata.c src/sys/dev/scsipi [jdolecek-ncqfixes]: atapi_wdc.c src/sys/dev/usb [jdolecek-ncqfixes]: umass_isdata.c Log Message: separate ata_xfer slot allocation and the memory allocation, so that there can be more queued xfers than number of supported slots by controller, and use a pool instead of custom pre-allocation primarily to help PR kern/52614 remove no longer needed custom wd(4) logic for flush cache switch also wd(4) trim/suspend/setcache/wdioctlstrategy to sleep waiting for the memory, they are all called from process context and this avoids spurious failures To generate a diff of this commit: cvs rdiff -u -r1.4.2.3 -r1.4.2.4 src/sys/dev/ata/TODO.ncq cvs rdiff -u -r1.141.6.5 -r1.141.6.6 src/sys/dev/ata/ata.c cvs rdiff -u -r1.6.2.4 -r1.6.2.5 src/sys/dev/ata/ata_subr.c cvs rdiff -u -r1.99.2.4 -r1.99.2.5 src/sys/dev/ata/atavar.h cvs rdiff -u -r1.14 -r1.14.2.1 src/sys/dev/ata/satapmp_subr.c cvs rdiff -u -r1.441.2.3 -r1.441.2.4 src/sys/dev/ata/wd.c cvs rdiff -u -r1.46.6.1 -r1.46.6.2 src/sys/dev/ata/wdvar.h cvs rdiff -u -r1.62.2.4 -r1.62.2.5 src/sys/dev/ic/ahcisata_core.c cvs rdiff -u -r1.41.2.3 -r1.41.2.4 src/sys/dev/ic/mvsata.c cvs rdiff -u -r1.35.6.4 -r1.35.6.5 src/sys/dev/ic/siisata.c cvs rdiff -u -r1.129.6.3 -r1.129.6.4 src/sys/dev/scsipi/atapi_wdc.c cvs rdiff -u -r1.36 -r1.36.6.1 src/sys/dev/usb/umass_isdata.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.4.2.3 src/sys/dev/ata/TODO.ncq:1.4.2.4 --- src/sys/dev/ata/TODO.ncq:1.4.2.3 Mon Sep 17 20:54:41 2018 +++ src/sys/dev/ata/TODO.ncq Sat Sep 22 09:22:59 2018 @@ -1,16 +1,13 @@ jdolecek-ncqfixes goals: -- make ata_xfer dynamically allocated using a pool - - will fix: queue is allocated regardless if there are any drives, fix? - - malloc() -> kmem_zalloc() in ata_queue_alloc() once this is done -- remove limit of queued ata_xfers, allow any number of pending xfers; - this should fix kern/52614 AKA wdc-attached ATAPI cd(4) -- remove the wd(4) flush condition, just allocate a dynamic ata_xfer -- change wd(4) dump code to use on-stack ata_xfer to not rely on pool having - memory +- add to wd(4) a callout to restart buf queue processing when ata_get_xfer() + call fails and remove ata_channel_start() +- change wd(4) dump code to use preallocated or on-stack ata_xfer to not rely + on pool having memory - re-fix QEMU ahci(4) bug workaround (no READ LOG EXT support) - now it triggers KASSERT() - fix ahci(4) error handling under paralles - invalid bio via WD_CHAOS_MONKEY ends up being handled as NOERROR, triggering KASSERT() in wd(4) +- weed out remaining KM_NOSLEEP Bugs ---- Index: src/sys/dev/ata/ata.c diff -u src/sys/dev/ata/ata.c:1.141.6.5 src/sys/dev/ata/ata.c:1.141.6.6 --- src/sys/dev/ata/ata.c:1.141.6.5 Mon Sep 17 20:54:41 2018 +++ src/sys/dev/ata/ata.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ata.c,v 1.141.6.5 2018/09/17 20:54:41 jdolecek Exp $ */ +/* $NetBSD: ata.c,v 1.141.6.6 2018/09/22 09:22:59 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.141.6.5 2018/09/17 20:54:41 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.141.6.6 2018/09/22 09:22:59 jdolecek Exp $"); #include "opt_ata.h" @@ -84,6 +84,7 @@ int atadebug_mask = ATADEBUG_MASK; #endif static ONCE_DECL(ata_init_ctrl); +static struct pool ata_xfer_pool; /* * A queue of atabus instances, used to ensure the same bus probe order @@ -142,6 +143,8 @@ static int atabus_init(void) { + pool_init(&ata_xfer_pool, sizeof(struct ata_xfer), 0, 0, 0, + "ataspl", NULL, IPL_BIO); TAILQ_INIT(&atabus_initq_head); mutex_init(&atabus_qlock, MUTEX_DEFAULT, IPL_NONE); cv_init(&atabus_qcv, "atainitq"); @@ -779,7 +782,7 @@ ata_get_params(struct ata_drive_datas *d ATADEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); - xfer = ata_get_xfer(chp); + xfer = ata_get_xfer(chp, false); if (xfer == NULL) { ATADEBUG_PRINT(("%s: no xfer\n", __func__), DEBUG_FUNCS|DEBUG_PROBE); @@ -884,7 +887,7 @@ ata_set_mode(struct ata_drive_datas *drv ATADEBUG_PRINT(("ata_set_mode=0x%x\n", mode), DEBUG_FUNCS); - xfer = ata_get_xfer(chp); + xfer = ata_get_xfer(chp, false); if (xfer == NULL) { ATADEBUG_PRINT(("%s: no xfer\n", __func__), DEBUG_FUNCS|DEBUG_PROBE); @@ -919,7 +922,7 @@ int ata_read_log_ext_ncq(struct ata_drive_datas *drvp, uint8_t flags, uint8_t *slot, uint8_t *status, uint8_t *err) { - struct ata_xfer *xfer; + struct ata_xfer *xfer = &drvp->recovery_xfer; int rv; struct ata_channel *chp = drvp->chnl_softc; struct atac_softc *atac = chp->ch_atac; @@ -932,7 +935,7 @@ ata_read_log_ext_ncq(struct ata_drive_da (drvp->drive_flags & ATA_DRIVE_NCQ) == 0) return EOPNOTSUPP; - xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0); + memset(xfer, 0, sizeof(*xfer)); tb = drvp->recovery_blk; memset(tb, 0, sizeof(drvp->recovery_blk)); @@ -994,7 +997,6 @@ ata_read_log_ext_ncq(struct ata_drive_da rv = 0; out: - ata_free_xfer(chp, xfer); return rv; } @@ -1128,13 +1130,6 @@ atastart(struct ata_channel *chp) ata_channel_lock(chp); again: - KASSERT(chq->queue_active <= chq->queue_openings); - if (chq->queue_active == chq->queue_openings) { - ATADEBUG_PRINT(("%s(chp=%p): channel %d completely busy\n", - __func__, chp, chp->ch_channel), DEBUG_XFERS); - goto out; - } - /* is there a xfer ? */ if ((xfer = SIMPLEQ_FIRST(&chp->ch_queue->queue_xfer)) == NULL) { ATADEBUG_PRINT(("%s(chp=%p): channel %d queue_xfer is empty\n", @@ -1142,6 +1137,18 @@ again: goto out; } + /* + * if someone is waiting for the command to be active, wake it up + * and let it process the command + */ + if (__predict_false(xfer->c_flags & C_WAITACT)) { + ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d " + "wait active\n", xfer, chp->ch_channel, xfer->c_drive), + DEBUG_XFERS); + cv_broadcast(&chp->ch_queue->c_active); + goto out; + } + recovery = ISSET(xfer->c_flags, C_RECOVERY); /* is the queue frozen? */ @@ -1179,20 +1186,37 @@ again: struct ata_drive_datas * const drvp = &chp->ch_drive[xfer->c_drive]; /* - * if someone is waiting for the command to be active, wake it up - * and let it process the command + * Are we on limit of active xfers ? + * For recovery, we must leave one slot available at all times. */ - if (xfer->c_flags & C_WAITACT) { - ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d " - "wait active\n", xfer, chp->ch_channel, xfer->c_drive), - DEBUG_XFERS); - cv_broadcast(&chp->ch_queue->c_active); + KASSERT(chq->queue_active <= chq->queue_openings); + const uint8_t chq_openings = (!recovery && chq->queue_openings > 1) + ? (chq->queue_openings - 1) : chq->queue_openings; + const uint8_t drv_openings = ISSET(xfer->c_flags, C_NCQ) + ? drvp->drv_openings : ATA_MAX_OPENINGS; + if (chq->queue_active >= MIN(chq_openings, drv_openings)) { + if (recovery) { + panic("%s: channel %d busy, recovery not possible", + __func__, chp->ch_channel); + } + + ATADEBUG_PRINT(("%s(chp=%p): channel %d completely busy\n", + __func__, chp, chp->ch_channel), DEBUG_XFERS); goto out; } - if (atac->atac_claim_hw) - if (!atac->atac_claim_hw(chp, 0)) + /* Slot allocation can fail if drv_openings < ch_openings */ + if (!ata_queue_alloc_slot(chp, &xfer->c_slot, drv_openings)) + goto out; + + if (__predict_false(atac->atac_claim_hw)) { + if (!atac->atac_claim_hw(chp, 0)) { + ata_queue_free_slot(chp, xfer->c_slot); goto out; + } + } + + /* Now committed to start the xfer */ ATADEBUG_PRINT(("%s(chp=%p): xfer %p channel %d drive %d\n", __func__, chp, xfer, chp->ch_channel, xfer->c_drive), DEBUG_XFERS); @@ -1273,7 +1297,13 @@ ata_activate_xfer_locked(struct ata_chan KASSERT(mutex_owned(&chp->ch_lock)); - KASSERT(chq->queue_active < chq->queue_openings); + /* + * When openings is just 1, can't reserve anything for + * recovery. KASSERT() here is to catch code which naively + * relies on C_RECOVERY to work under this condition. + */ + KASSERT((xfer->c_flags & C_RECOVERY) == 0 || chq->queue_openings > 1); + KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0); if ((xfer->c_flags & C_RECOVERY) == 0) @@ -1290,6 +1320,64 @@ ata_activate_xfer_locked(struct ata_chan chq->queue_active++; } +/* + * Does it's own locking, does not require splbio(). + * flags - whether to block waiting for free xfer + */ +struct ata_xfer * +ata_get_xfer(struct ata_channel *chp, bool waitok) +{ + struct ata_xfer *xfer; + + xfer = pool_get(&ata_xfer_pool, waitok ? PR_WAITOK : PR_NOWAIT); + KASSERT(!waitok || xfer != NULL); + + if (xfer != NULL) { + /* zero everything */ + memset(xfer, 0, sizeof(*xfer)); + } + + return xfer; +} + +/* + * ata_deactivate_xfer() must be always called prior to ata_free_xfer() + */ +void +ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer) +{ + struct ata_queue *chq = chp->ch_queue; + + ata_channel_lock(chp); + + if (xfer->c_flags & (C_WAITACT|C_WAITTIMO)) { + /* Someone is waiting for this xfer, so we can't free now */ + xfer->c_flags |= C_FREE; + cv_broadcast(&chq->c_active); + ata_channel_unlock(chp); + return; + } + + /* XXX move PIOBM and free_gw to deactivate? */ +#if NATA_PIOBM /* XXX wdc dependent code */ + if (xfer->c_flags & C_PIOBM) { + struct wdc_softc *wdc = CHAN_TO_WDC(chp); + + /* 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); + } +#endif + + if (__predict_false(chp->ch_atac->atac_free_hw)) + chp->ch_atac->atac_free_hw(chp); + + ata_channel_unlock(chp); + + pool_put(&ata_xfer_pool, xfer); +} + void ata_deactivate_xfer(struct ata_channel *chp, struct ata_xfer *xfer) { @@ -1311,6 +1399,8 @@ ata_deactivate_xfer(struct ata_channel * chq->active_xfers_used &= ~__BIT(xfer->c_slot); chq->queue_active--; + ata_queue_free_slot(chp, xfer->c_slot); + if (xfer->c_flags & C_WAIT) cv_broadcast(&chq->c_cmd_finish); Index: src/sys/dev/ata/ata_subr.c diff -u src/sys/dev/ata/ata_subr.c:1.6.2.4 src/sys/dev/ata/ata_subr.c:1.6.2.5 --- src/sys/dev/ata/ata_subr.c:1.6.2.4 Mon Sep 17 20:54:41 2018 +++ src/sys/dev/ata/ata_subr.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ata_subr.c,v 1.6.2.4 2018/09/17 20:54:41 jdolecek Exp $ */ +/* $NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -25,14 +25,13 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.4 2018/09/17 20:54:41 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $"); #include "opt_ata.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> -#include <sys/malloc.h> #include <sys/device.h> #include <sys/conf.h> #include <sys/fcntl.h> @@ -167,37 +166,30 @@ ata_queue_alloc(uint8_t openings) if (openings > ATA_MAX_OPENINGS) openings = ATA_MAX_OPENINGS; - /* XXX convert to kmem_zalloc() once ata_xfer is moved to pool */ - struct ata_queue *chq = malloc(offsetof(struct ata_queue, queue_xfers[openings]), - M_DEVBUF, M_WAITOK | M_ZERO); + struct ata_queue *chq = kmem_zalloc(sizeof(*chq), KM_SLEEP); chq->queue_openings = openings; ata_queue_reset(chq); - cv_init(&chq->queue_busy, "ataqbusy"); cv_init(&chq->queue_drain, "atdrn"); cv_init(&chq->queue_idle, "qidl"); cv_init(&chq->c_active, "ataact"); cv_init(&chq->c_cmd_finish, "atafin"); - for (uint8_t i = 0; i < openings; i++) - chq->queue_xfers[i].c_slot = i; - return chq; } void ata_queue_free(struct ata_queue *chq) { - cv_destroy(&chq->queue_busy); cv_destroy(&chq->queue_drain); cv_destroy(&chq->queue_idle); cv_destroy(&chq->c_active); cv_destroy(&chq->c_cmd_finish); - free(chq, M_DEVBUF); + kmem_free(chq, sizeof(*chq)); } void @@ -231,135 +223,6 @@ ata_channel_destroy(struct ata_channel * cv_destroy(&chp->ch_thr_idle); } -/* - * Does it's own locking, does not require splbio(). - * flags - whether to block waiting for free xfer - * openings - limit of openings supported by device, <= 0 means tag not - * relevant, and any available xfer can be returned - */ -struct ata_xfer * -ata_get_xfer_ext(struct ata_channel *chp, int flags, uint8_t openings) -{ - struct ata_queue *chq = chp->ch_queue; - struct ata_xfer *xfer = NULL; - uint32_t avail, slot, mask; - int error; - - ATADEBUG_PRINT(("%s: channel %d fl 0x%x op %d qavail 0x%x qact %d", - __func__, chp->ch_channel, flags, openings, - chq->queue_xfers_avail, chq->queue_active), - DEBUG_XFERS); - - ata_channel_lock(chp); - - /* - * When openings is just 1, can't reserve anything for - * recovery. KASSERT() here is to catch code which naively - * relies on C_RECOVERY to work under this condition. - */ - KASSERT((flags & C_RECOVERY) == 0 || chq->queue_openings > 1); - - if (flags & C_RECOVERY) { - mask = UINT32_MAX; - } else { - if (openings <= 0 || openings > chq->queue_openings) - openings = chq->queue_openings; - - if (openings > 1) { - mask = __BIT(openings - 1) - 1; - } else { - mask = UINT32_MAX; - } - } - -retry: - avail = ffs32(chq->queue_xfers_avail & mask); - if (avail == 0) { - /* - * Catch code which tries to get another recovery xfer while - * already holding one (wrong recursion). - */ - KASSERTMSG((flags & C_RECOVERY) == 0, - "recovery xfer busy openings %d mask %x avail %x", - openings, mask, chq->queue_xfers_avail); - - if (flags & C_WAIT) { - chq->queue_flags |= QF_NEED_XFER; - error = cv_wait_sig(&chq->queue_busy, &chp->ch_lock); - if (error == 0) - goto retry; - } - - goto out; - } - - slot = avail - 1; - xfer = &chq->queue_xfers[slot]; - chq->queue_xfers_avail &= ~__BIT(slot); - - KASSERT((chq->active_xfers_used & __BIT(slot)) == 0); - - /* zero everything after the callout member */ - memset(&xfer->c_startzero, 0, - sizeof(struct ata_xfer) - offsetof(struct ata_xfer, c_startzero)); - -out: - ata_channel_unlock(chp); - - ATADEBUG_PRINT((" xfer %p\n", xfer), DEBUG_XFERS); - return xfer; -} - -/* - * ata_deactivate_xfer() must be always called prior to ata_free_xfer() - */ -void -ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer) -{ - struct ata_queue *chq = chp->ch_queue; - - ata_channel_lock(chp); - - if (xfer->c_flags & (C_WAITACT|C_WAITTIMO)) { - /* Someone is waiting for this xfer, so we can't free now */ - xfer->c_flags |= C_FREE; - cv_broadcast(&chq->c_active); - goto out; - } - - /* XXX move PIOBM and free_gw to deactivate? */ -#if NATA_PIOBM /* XXX wdc dependent code */ - if (xfer->c_flags & C_PIOBM) { - struct wdc_softc *wdc = CHAN_TO_WDC(chp); - - /* 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); - } -#endif - - if (chp->ch_atac->atac_free_hw) - chp->ch_atac->atac_free_hw(chp); - - KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0); - KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0); - chq->queue_xfers_avail |= __BIT(xfer->c_slot); - -out: - if (chq->queue_flags & QF_NEED_XFER) { - chq->queue_flags &= ~QF_NEED_XFER; - cv_broadcast(&chq->queue_busy); - } - - ata_channel_unlock(chp); - - ATADEBUG_PRINT(("%s: channel %d xfer %p qavail 0x%x qact %d\n", - __func__, chp->ch_channel, xfer, chq->queue_xfers_avail, - chq->queue_active), - DEBUG_XFERS); -} - void ata_timeout(void *v) { @@ -472,18 +335,49 @@ atachannel_debug(struct ata_channel *chp chq->queue_flags, chq->queue_xfers_avail, chq->active_xfers_used); printf(" act %d freez %d open %u\n", chq->queue_active, chq->queue_freeze, chq->queue_openings); - -#if 0 - printf(" xfers:\n"); - for(int i=0; i < chq->queue_openings; i++) { - struct ata_xfer *xfer = &chq->queue_xfers[i]; - - printf(" #%d sl %d drv %d retr %d fl %x", - i, xfer->c_slot, xfer->c_drive, xfer->c_retries, - xfer->c_flags); - printf(" data %p bcount %d skip %d\n", - xfer->c_databuf, xfer->c_bcount, xfer->c_skip); - } -#endif } #endif /* ATADEBUG */ + +bool +ata_queue_alloc_slot(struct ata_channel *chp, uint8_t *c_slot, + uint8_t drv_openings) +{ + struct ata_queue *chq = chp->ch_queue; + uint32_t avail, mask; + + KASSERT(mutex_owned(&chp->ch_lock)); + KASSERT(chq->queue_active < chq->queue_openings); + + ATADEBUG_PRINT(("%s: channel %d qavail 0x%x qact %d", + __func__, chp->ch_channel, + chq->queue_xfers_avail, chq->queue_active), + DEBUG_XFERS); + + mask = __BIT(MIN(chq->queue_openings, drv_openings)) - 1; + + avail = ffs32(chq->queue_xfers_avail & mask); + if (avail == 0) + return false; + + KASSERT(avail > 0); + KASSERT(avail <= drv_openings); + + *c_slot = avail - 1; + chq->queue_xfers_avail &= ~__BIT(*c_slot); + + KASSERT((chq->active_xfers_used & __BIT(*c_slot)) == 0); + return true; +} + +void +ata_queue_free_slot(struct ata_channel *chp, uint8_t c_slot) +{ + struct ata_queue *chq = chp->ch_queue; + + KASSERT(mutex_owned(&chp->ch_lock)); + + KASSERT((chq->active_xfers_used & __BIT(c_slot)) == 0); + KASSERT((chq->queue_xfers_avail & __BIT(c_slot)) == 0); + + chq->queue_xfers_avail |= __BIT(c_slot); +} Index: src/sys/dev/ata/atavar.h diff -u src/sys/dev/ata/atavar.h:1.99.2.4 src/sys/dev/ata/atavar.h:1.99.2.5 --- src/sys/dev/ata/atavar.h:1.99.2.4 Mon Sep 17 19:30:25 2018 +++ src/sys/dev/ata/atavar.h Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: atavar.h,v 1.99.2.4 2018/09/17 19:30:25 jdolecek Exp $ */ +/* $NetBSD: atavar.h,v 1.99.2.5 2018/09/22 09:22:59 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -134,7 +134,6 @@ struct ata_xfer_ops; struct ata_xfer { int8_t c_slot; /* queue slot # */ -#define c_startzero c_chp /* Channel and drive that are to process the request. */ struct ata_channel *c_chp; uint16_t c_drive; @@ -228,7 +227,6 @@ struct ata_queue { uint8_t queue_openings; /* max number of active xfers */ SIMPLEQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */ 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 */ @@ -236,7 +234,6 @@ struct ata_queue { uint32_t queue_xfers_avail; /* available xfers mask */ kcondvar_t c_active; /* somebody actively waiting for xfer */ kcondvar_t c_cmd_finish; /* somebody waiting for cmd finish */ - struct ata_xfer queue_xfers[0]; /* xfers */ }; #endif @@ -340,6 +337,7 @@ struct ata_drive_datas { daddr_t badsect[127]; /* 126 plus trailing -1 marker */ /* Recovery buffer */ + struct ata_xfer recovery_xfer; uint8_t recovery_blk[ATA_BSIZE]; }; @@ -534,8 +532,7 @@ int ata_read_log_ext_ncq(struct ata_driv #define CMD_ERR 1 #define CMD_AGAIN 2 -struct ata_xfer *ata_get_xfer_ext(struct ata_channel *, int, uint8_t); -#define ata_get_xfer(chp) ata_get_xfer_ext((chp), C_WAIT, 0) +struct ata_xfer *ata_get_xfer(struct ata_channel *, bool); void ata_free_xfer(struct ata_channel *, struct ata_xfer *); void ata_deactivate_xfer(struct ata_channel *, struct ata_xfer *); void ata_exec_xfer(struct ata_channel *, struct ata_xfer *); @@ -578,6 +575,8 @@ struct ata_xfer * ata_queue_get_active_xfer_locked(struct ata_channel *); struct ata_xfer * ata_queue_drive_active_xfer(struct ata_channel *, int); +bool ata_queue_alloc_slot(struct ata_channel *, uint8_t *, uint8_t); +void ata_queue_free_slot(struct ata_channel *, uint8_t); void ata_delay(struct ata_channel *, int, const char *, int); Index: src/sys/dev/ata/satapmp_subr.c diff -u src/sys/dev/ata/satapmp_subr.c:1.14 src/sys/dev/ata/satapmp_subr.c:1.14.2.1 --- src/sys/dev/ata/satapmp_subr.c:1.14 Sun Jul 29 14:11:30 2018 +++ src/sys/dev/ata/satapmp_subr.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: satapmp_subr.c,v 1.14 2018/07/29 14:11:30 jdolecek Exp $ */ +/* $NetBSD: satapmp_subr.c,v 1.14.2.1 2018/09/22 09:22:59 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.14 2018/07/29 14:11:30 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.14.2.1 2018/09/22 09:22:59 jdolecek Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -276,7 +276,7 @@ satapmp_attach(struct ata_channel *chp) uint32_t id, rev, inf; struct ata_xfer *xfer; - xfer = ata_get_xfer(chp); + xfer = ata_get_xfer(chp, false); if (xfer == NULL) { aprint_normal_dev(chp->atabus, "no available xfer\n"); return; Index: src/sys/dev/ata/wd.c diff -u src/sys/dev/ata/wd.c:1.441.2.3 src/sys/dev/ata/wd.c:1.441.2.4 --- src/sys/dev/ata/wd.c:1.441.2.3 Mon Sep 17 20:54:41 2018 +++ src/sys/dev/ata/wd.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: wd.c,v 1.441.2.3 2018/09/17 20:54:41 jdolecek Exp $ */ +/* $NetBSD: wd.c,v 1.441.2.4 2018/09/22 09:22:59 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -54,7 +54,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.3 2018/09/17 20:54:41 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.4 2018/09/22 09:22:59 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wd.h" @@ -745,8 +745,7 @@ wd_diskstart(device_t dev, struct buf *b mutex_enter(&wd->sc_lock); - xfer = ata_get_xfer_ext(wd->drvp->chnl_softc, 0, - WD_USE_NCQ(wd) ? WD_MAX_OPENINGS(wd) : 0); + xfer = ata_get_xfer(wd->drvp->chnl_softc, false); if (xfer == NULL) { ATADEBUG_PRINT(("wd_diskstart %s no xfer\n", dksc->sc_xname), DEBUG_XFERS); @@ -776,22 +775,6 @@ wdstart(device_t self) if (!device_is_active(dksc->sc_dev)) return; - mutex_enter(&wd->sc_lock); - - /* - * Do not queue any transfers until flush is finished, so that - * once flush is pending, it will get handled as soon as xfer - * is available. - */ - if (ISSET(wd->sc_flags, WDF_FLUSH_PEND)) { - ATADEBUG_PRINT(("wdstart %s flush pend\n", - dksc->sc_xname), DEBUG_XFERS); - mutex_exit(&wd->sc_lock); - return; - } - - mutex_exit(&wd->sc_lock); - dk_start(dksc, NULL); } @@ -1486,7 +1469,7 @@ wd_dumpblocks(device_t dev, void *va, da wd->drvp->state = RESET; } - xfer = ata_get_xfer_ext(wd->drvp->chnl_softc, 0, 0); + xfer = ata_get_xfer(wd->drvp->chnl_softc, false); if (xfer == NULL) { printf("%s: no xfer\n", __func__); return EAGAIN; @@ -1677,9 +1660,7 @@ wd_setcache(struct wd_softc *wd, int bit (bits & DKCACHE_SAVE) != 0) return EOPNOTSUPP; - xfer = ata_get_xfer(wd->drvp->chnl_softc); - if (xfer == NULL) - return EINTR; + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); xfer->c_ata_c.r_command = SET_FEATURES; xfer->c_ata_c.r_st_bmask = 0; @@ -1720,9 +1701,7 @@ wd_standby(struct wd_softc *wd, int flag struct ata_xfer *xfer; int error; - xfer = ata_get_xfer(wd->drvp->chnl_softc); - if (xfer == NULL) - return EINTR; + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); xfer->c_ata_c.r_command = WDCC_STANDBY_IMMED; xfer->c_ata_c.r_st_bmask = WDCS_DRDY; @@ -1779,20 +1758,7 @@ wd_flushcache(struct wd_softc *wd, int f wd->sc_params.atap_cmd_set2 == 0xffff)) return ENODEV; - mutex_enter(&wd->sc_lock); - SET(wd->sc_flags, WDF_FLUSH_PEND); - mutex_exit(&wd->sc_lock); - - xfer = ata_get_xfer(wd->drvp->chnl_softc); - - mutex_enter(&wd->sc_lock); - CLR(wd->sc_flags, WDF_FLUSH_PEND); - mutex_exit(&wd->sc_lock); - - if (xfer == NULL) { - error = EINTR; - goto out; - } + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0 && (wd->sc_params.atap_cmd2_en & ATA_CMD2_FCE) != 0) { @@ -1830,7 +1796,6 @@ wd_flushcache(struct wd_softc *wd, int f out_xfer: ata_free_xfer(wd->drvp->chnl_softc, xfer); -out: /* start again I/O processing possibly stopped due to no xfer */ ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, start_self); @@ -1845,9 +1810,7 @@ wd_trim(struct wd_softc *wd, daddr_t bno int error; unsigned char *req; - xfer = ata_get_xfer(wd->drvp->chnl_softc); - if (xfer == NULL) - return EINTR; + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); req = kmem_zalloc(512, KM_SLEEP); req[0] = bno & 0xff; @@ -2012,11 +1975,7 @@ wdioctlstrategy(struct buf *bp) goto out2; } - xfer = ata_get_xfer(wi->wi_softc->drvp->chnl_softc); - if (xfer == NULL) { - error = EINTR; - goto out2; - } + xfer = ata_get_xfer(wi->wi_softc->drvp->chnl_softc, true); /* * Abort if physio broke up the transfer @@ -2134,19 +2093,6 @@ wd_sysctl_attach(struct wd_softc *wd) return; } - wd->drv_max_tags = ATA_MAX_OPENINGS; - if ((error = sysctl_createv(&wd->nodelog, 0, NULL, NULL, - CTLFLAG_READWRITE, CTLTYPE_INT, "max_tags", - SYSCTL_DESCR("max number of NCQ tags to use"), - NULL, 0, &wd->drv_max_tags, 0, - CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL)) - != 0) { - aprint_error_dev(dksc->sc_dev, - "could not create %s.%s.max_tags sysctl - error %d\n", - "hw", dksc->sc_xname, error); - return; - } - wd->drv_ncq = true; if ((error = sysctl_createv(&wd->nodelog, 0, NULL, NULL, CTLFLAG_READWRITE, CTLTYPE_BOOL, "use_ncq", Index: src/sys/dev/ata/wdvar.h diff -u src/sys/dev/ata/wdvar.h:1.46.6.1 src/sys/dev/ata/wdvar.h:1.46.6.2 --- src/sys/dev/ata/wdvar.h:1.46.6.1 Fri Aug 31 19:08:03 2018 +++ src/sys/dev/ata/wdvar.h Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: wdvar.h,v 1.46.6.1 2018/08/31 19:08:03 jdolecek Exp $ */ +/* $NetBSD: wdvar.h,v 1.46.6.2 2018/09/22 09:22:59 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -53,7 +53,6 @@ struct wd_softc { #define WDF_WAIT 0x020 /* waiting for resources */ #define WDF_LBA 0x040 /* using LBA mode */ #define WDF_LBA48 0x100 /* using 48-bit LBA mode */ -#define WDF_FLUSH_PEND 0x200 /* cache flush waits for free xfer */ #define WDF_OPEN 0x400 /* device is open */ uint64_t sc_capacity; /* full capacity of the device */ uint64_t sc_capacity512; /* ... in DEV_BSIZE blocks */ @@ -74,9 +73,6 @@ struct wd_softc { /* Sysctl nodes specific for the disk */ struct sysctllog *nodelog; - int drv_max_tags; -#define WD_MAX_OPENINGS(wd) \ - (MAX(1, MIN((wd)->drvp->drv_openings, (wd)->drv_max_tags))) bool drv_ncq; #define WD_USE_NCQ(wd) \ ((wd)->drv_ncq && ((wd)->drvp->drive_flags & ATA_DRIVE_NCQ)) Index: src/sys/dev/ic/ahcisata_core.c diff -u src/sys/dev/ic/ahcisata_core.c:1.62.2.4 src/sys/dev/ic/ahcisata_core.c:1.62.2.5 --- src/sys/dev/ic/ahcisata_core.c:1.62.2.4 Mon Sep 17 19:30:25 2018 +++ src/sys/dev/ic/ahcisata_core.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ahcisata_core.c,v 1.62.2.4 2018/09/17 19:30:25 jdolecek Exp $ */ +/* $NetBSD: ahcisata_core.c,v 1.62.2.5 2018/09/22 09:22:59 jdolecek Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.62.2.4 2018/09/17 19:30:25 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.62.2.5 2018/09/22 09:22:59 jdolecek Exp $"); #include <sys/types.h> #include <sys/malloc.h> @@ -59,7 +59,7 @@ static void ahci_setup_channel(struct at 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 *, - struct ata_xfer *xfer); + uint8_t); 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 *); @@ -681,24 +681,28 @@ 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); + uint8_t c_slot; ata_channel_lock(chp); + /* get a slot for running the command on */ + if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) { + panic("%s: %s: failed to get xfer for reset, port %d\n", + device_xname(sc->sc_atac.atac_dev), + __func__, chp->ch_channel); + /* NOTREACHED */ + } + 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, xfer) != 0) + if (ahci_do_reset_drive(chp, drvp->drive, flags, sigp, c_slot) != 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); + ata_queue_free_slot(chp, c_slot); - return; + ata_channel_unlock(chp); } /* return error code from ata_bio */ @@ -755,7 +759,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, struct ata_xfer *xfer) + uint32_t *sigp, uint8_t c_slot) { struct ahci_channel *achp = (struct ahci_channel *)chp; struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; @@ -790,8 +794,8 @@ again: /* polled command, assume interrupts are disabled */ - cmd_h = &achp->ahcic_cmdh[xfer->c_slot]; - cmd_tbl = achp->ahcic_cmd_tbl[xfer->c_slot]; + cmd_h = &achp->ahcic_cmdh[c_slot]; + cmd_tbl = achp->ahcic_cmd_tbl[c_slot]; cmd_h->cmdh_flags = htole16(AHCI_CMDH_F_RST | AHCI_CMDH_F_CBSY | RHD_FISLEN / 4 | (drive << AHCI_CMDH_F_PMP_SHIFT)); cmd_h->cmdh_prdbc = 0; @@ -799,7 +803,7 @@ again: cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE; cmd_tbl->cmdt_cfis[rhd_c] = drive; cmd_tbl->cmdt_cfis[rhd_control] = WDCTL_RST; - switch(ahci_exec_fis(chp, 100, flags, xfer->c_slot)) { + switch(ahci_exec_fis(chp, 100, flags, c_slot)) { case ERR_DF: case TIMEOUT: aprint_error("%s channel %d: setting WDCTL_RST failed " @@ -817,7 +821,7 @@ again: cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE; cmd_tbl->cmdt_cfis[rhd_c] = drive; cmd_tbl->cmdt_cfis[rhd_control] = 0; - switch(ahci_exec_fis(chp, 310, flags, xfer->c_slot)) { + switch(ahci_exec_fis(chp, 310, flags, c_slot)) { case ERR_DF: case TIMEOUT: if ((sc->sc_ahci_quirks & AHCI_QUIRK_BADPMPRESET) != 0 && @@ -943,17 +947,18 @@ 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; + uint8_t c_slot; + + ata_channel_lock(chp); - xfer = ata_get_xfer_ext(chp, 0, 0); - if (xfer == NULL) { + /* get a slot for running the command on */ + if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) { aprint_error_dev(sc->sc_atac.atac_dev, "%s: failed to get xfer port %d\n", __func__, chp->ch_channel); + ata_channel_unlock(chp); 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), @@ -966,9 +971,9 @@ ahci_probe_drive(struct ata_channel *chp 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, - xfer); + c_slot); } else { - ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, xfer); + ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, c_slot); } sata_interpret_sig(chp, 0, sig); /* if we have a PMP attached, inform the controller */ @@ -980,7 +985,7 @@ ahci_probe_drive(struct ata_channel *chp } /* clear port interrupt register */ AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff); - + /* and enable interrupts */ AHCI_WRITE(sc, AHCI_P_IE(chp->ch_channel), AHCI_P_IX_TFES | AHCI_P_IX_HBFS | AHCI_P_IX_HBDS | @@ -994,6 +999,9 @@ ahci_probe_drive(struct ata_channel *chp default: break; } + + ata_queue_free_slot(chp, c_slot); + ata_channel_unlock(chp); } @@ -1866,7 +1874,7 @@ ahci_atapi_scsipi_request(struct scsipi_ scsipi_done(sc_xfer); return; } - xfer = ata_get_xfer_ext(atac->atac_channels[channel], 0, 0); + xfer = ata_get_xfer(atac->atac_channels[channel], false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/ic/mvsata.c diff -u src/sys/dev/ic/mvsata.c:1.41.2.3 src/sys/dev/ic/mvsata.c:1.41.2.4 --- src/sys/dev/ic/mvsata.c:1.41.2.3 Mon Sep 17 19:30:25 2018 +++ src/sys/dev/ic/mvsata.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsata.c,v 1.41.2.3 2018/09/17 19:30:25 jdolecek Exp $ */ +/* $NetBSD: mvsata.c,v 1.41.2.4 2018/09/22 09:22:59 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.41.2.3 2018/09/17 19:30:25 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.41.2.4 2018/09/22 09:22:59 jdolecek Exp $"); #include "opt_mvsata.h" @@ -2081,7 +2081,7 @@ mvsata_atapi_scsipi_request(struct scsip scsipi_done(sc_xfer); return; } - xfer = ata_get_xfer_ext(chp, false, 0); + xfer = ata_get_xfer(chp, false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/ic/siisata.c diff -u src/sys/dev/ic/siisata.c:1.35.6.4 src/sys/dev/ic/siisata.c:1.35.6.5 --- src/sys/dev/ic/siisata.c:1.35.6.4 Mon Sep 17 19:30:26 2018 +++ src/sys/dev/ic/siisata.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: siisata.c,v 1.35.6.4 2018/09/17 19:30:26 jdolecek Exp $ */ +/* $NetBSD: siisata.c,v 1.35.6.5 2018/09/22 09:22:59 jdolecek Exp $ */ /* from ahcisata_core.c */ @@ -79,7 +79,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.35.6.4 2018/09/17 19:30:26 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.35.6.5 2018/09/22 09:22:59 jdolecek Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -725,32 +725,38 @@ siisata_reset_drive(struct ata_drive_dat struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac; struct siisata_channel *schp = (struct siisata_channel *)chp; struct siisata_prb *prb; - struct ata_xfer *xfer; + uint8_t c_slot; uint32_t pss, pis; int i; bool timed_out; siisata_reinit_port(chp, drvp->drive); - xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0); + ata_channel_lock(chp); - prb = schp->sch_prb[xfer->c_slot]; + /* get a slot for running the command on */ + if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) { + panic("%s: %s: failed to get xfer for reset, port %d\n", + device_xname(sc->sc_atac.atac_dev), + __func__, chp->ch_channel); + /* NOTREACHED */ + } + + prb = schp->sch_prb[c_slot]; memset(prb, 0, SIISATA_CMD_SIZE); prb->prb_control = htole16(PRB_CF_SOFT_RESET | PRB_CF_INTERRUPT_MASK); 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); + siisata_activate_prb(schp, c_slot); timed_out = true; for(i = 0; i < WDC_RESET_WAIT / 10; i++) { pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)); - if ((pss & PR_PXSS(xfer->c_slot)) == 0) { + if ((pss & PR_PXSS(c_slot)) == 0) { timed_out = false; break; } @@ -759,17 +765,17 @@ siisata_reset_drive(struct ata_drive_dat ata_delay(chp, 10, "siiprb", flags); } - siisata_deactivate_prb(schp, xfer->c_slot); + siisata_deactivate_prb(schp, c_slot); if ((pss & PR_PSS_ATTENTION) != 0) { pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS)); const uint32_t ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS)); const u_int slot = PR_PS_ACTIVE_SLOT(ps); - if (slot != xfer->c_slot) + if (slot != c_slot) device_printf(sc->sc_atac.atac_dev, "%s port %d " "drive %d slot %d c_slot %d", __func__, - chp->ch_channel, drvp->drive, slot, xfer->c_slot); + chp->ch_channel, drvp->drive, slot, c_slot); PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), pis & PR_PIS_CMDERRR); @@ -788,14 +794,16 @@ siisata_reset_drive(struct ata_drive_dat /* read the signature out of the FIS */ if (sigp) { *sigp = 0; - *sigp |= (PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot, + *sigp |= (PRREAD(sc, PRSX(chp->ch_channel, c_slot, PRSO_FIS+0x4)) & 0x00ffffff) << 8; - *sigp |= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot, + *sigp |= PRREAD(sc, PRSX(chp->ch_channel, c_slot, PRSO_FIS+0xc)) & 0xff; } } - ata_free_xfer(chp, xfer); + ata_channel_lock(chp); + ata_queue_free_slot(chp, c_slot); + ata_channel_unlock(chp); return; } @@ -851,21 +859,22 @@ siisata_probe_drive(struct ata_channel * uint32_t sig; struct siisata_prb *prb; bool timed_out; - struct ata_xfer *xfer; + uint8_t c_slot; SIISATA_DEBUG_PRINT(("%s: %s: port %d start\n", SIISATANAME(sc), __func__, chp->ch_channel), DEBUG_FUNCS); - xfer = ata_get_xfer_ext(chp, 0, 0); - if (xfer == NULL) { + ata_channel_lock(chp); + + /* get a slot for running the command on */ + if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) { aprint_error_dev(sc->sc_atac.atac_dev, "%s: failed to get xfer port %d\n", __func__, chp->ch_channel); + ata_channel_unlock(chp); return; } - ata_channel_lock(chp); - /* * disable port interrupt as we're polling for PHY up and * prb completion @@ -897,17 +906,17 @@ siisata_probe_drive(struct ata_channel * siisata_reinit_port(chp, -1); } - prb = schp->sch_prb[xfer->c_slot]; + prb = schp->sch_prb[c_slot]; memset(prb, 0, SIISATA_CMD_SIZE); prb->prb_control = htole16(PRB_CF_SOFT_RESET); prb->prb_fis[rhd_c] = PMP_PORT_CTL; - siisata_activate_prb(schp, xfer->c_slot); + siisata_activate_prb(schp, c_slot); timed_out = 1; for(i = 0; i < WDC_RESET_WAIT / 10; i++) { if ((PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) & - PR_PXSS(xfer->c_slot)) == 0) { + PR_PXSS(c_slot)) == 0) { /* prb completed */ timed_out = 0; break; @@ -921,7 +930,7 @@ siisata_probe_drive(struct ata_channel * ata_delay(chp, 10, "siiprb", AT_WAIT); } - siisata_deactivate_prb(schp, xfer->c_slot); + siisata_deactivate_prb(schp, c_slot); if (timed_out) { aprint_error_dev(sc->sc_atac.atac_dev, @@ -936,9 +945,9 @@ siisata_probe_drive(struct ata_channel * /* read the signature out of the FIS */ sig = 0; - sig |= (PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot, + sig |= (PRREAD(sc, PRSX(chp->ch_channel, c_slot, PRSO_FIS+0x4)) & 0x00ffffff) << 8; - sig |= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot, + sig |= PRREAD(sc, PRSX(chp->ch_channel, c_slot, PRSO_FIS+0xc)) & 0xff; SIISATA_DEBUG_PRINT(("%s: %s: sig=0x%08x\n", SIISATANAME(sc), @@ -955,9 +964,9 @@ siisata_probe_drive(struct ata_channel * siisata_enable_port_interrupt(chp); - ata_channel_unlock(chp); + ata_queue_free_slot(chp, c_slot); - ata_free_xfer(chp, xfer); + ata_channel_unlock(chp); SIISATA_DEBUG_PRINT(("%s: %s: port %d done\n", SIISATANAME(sc), __func__, chp->ch_channel), DEBUG_PROBE); @@ -1826,7 +1835,7 @@ siisata_atapi_scsipi_request(struct scsi scsipi_done(sc_xfer); return; } - xfer = ata_get_xfer_ext(atac->atac_channels[channel], 0, 0); + xfer = ata_get_xfer(atac->atac_channels[channel], false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/scsipi/atapi_wdc.c diff -u src/sys/dev/scsipi/atapi_wdc.c:1.129.6.3 src/sys/dev/scsipi/atapi_wdc.c:1.129.6.4 --- src/sys/dev/scsipi/atapi_wdc.c:1.129.6.3 Mon Sep 17 19:30:26 2018 +++ src/sys/dev/scsipi/atapi_wdc.c Sat Sep 22 09:22:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: atapi_wdc.c,v 1.129.6.3 2018/09/17 19:30:26 jdolecek Exp $ */ +/* $NetBSD: atapi_wdc.c,v 1.129.6.4 2018/09/22 09:22:59 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.129.6.3 2018/09/17 19:30:26 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.129.6.4 2018/09/22 09:22:59 jdolecek Exp $"); #ifndef ATADEBUG #define ATADEBUG @@ -208,7 +208,7 @@ wdc_atapi_get_params(struct scsipi_chann struct ata_xfer *xfer; int rv; - xfer = ata_get_xfer(chp); + xfer = ata_get_xfer(chp, false); if (xfer == NULL) { printf("wdc_atapi_get_params: no xfer\n"); return EBUSY; @@ -395,7 +395,7 @@ wdc_atapi_scsipi_request(struct scsipi_c return; } - xfer = ata_get_xfer_ext(atac->atac_channels[channel], false, 0); + xfer = ata_get_xfer(atac->atac_channels[channel], false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/usb/umass_isdata.c diff -u src/sys/dev/usb/umass_isdata.c:1.36 src/sys/dev/usb/umass_isdata.c:1.36.6.1 --- src/sys/dev/usb/umass_isdata.c:1.36 Fri Oct 20 07:06:08 2017 +++ src/sys/dev/usb/umass_isdata.c Sat Sep 22 09:23:00 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: umass_isdata.c,v 1.36 2017/10/20 07:06:08 jdolecek Exp $ */ +/* $NetBSD: umass_isdata.c,v 1.36.6.1 2018/09/22 09:23:00 jdolecek Exp $ */ /* * TODO: @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.36 2017/10/20 07:06:08 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.36.6.1 2018/09/22 09:23:00 jdolecek Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -540,7 +540,7 @@ uisdata_get_params(struct ata_drive_data memset(tb, 0, DEV_BSIZE); memset(prms, 0, sizeof(struct ataparams)); - xfer = ata_get_xfer(drvp->chnl_softc); + xfer = ata_get_xfer(drvp->chnl_softc, false); if (!xfer) { rv = CMD_AGAIN; goto out;