Module Name: src Committed By: jdolecek Date: Wed Jun 21 22:40:43 UTC 2017
Modified Files: src/sys/dev/ata [jdolecek-ncq]: TODO.ncq ata.c atavar.h Log Message: hold channel lock for ata_exec_xfer() and most of atastart(), convert C_WAITACT handling to use condvar add comment for the code block with C_FREE and ata_free_xfer() explaining why it's not abstraction layer violation To generate a diff of this commit: cvs rdiff -u -r1.1.2.20 -r1.1.2.21 src/sys/dev/ata/TODO.ncq cvs rdiff -u -r1.132.8.14 -r1.132.8.15 src/sys/dev/ata/ata.c cvs rdiff -u -r1.92.8.13 -r1.92.8.14 src/sys/dev/ata/atavar.h 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.20 src/sys/dev/ata/TODO.ncq:1.1.2.21 --- src/sys/dev/ata/TODO.ncq:1.1.2.20 Tue Jun 20 21:55:09 2017 +++ src/sys/dev/ata/TODO.ncq Wed Jun 21 22:40:43 2017 @@ -12,9 +12,6 @@ test crashdump with siisata test wd* at umass?, confirm the ata_channel kludge works + add detach code (channel detach, free queue) -is ata_exec_xfer() + POLL safe wrt. more outstanding I/Os? why is it waiting -until xfer is head of queue? also layer violation with the ata_xfer_free() call - test device error handling (currently appears to not work well, at least in NCQ case) do proper NCQ error recovery (currently not even really attempted) Index: src/sys/dev/ata/ata.c diff -u src/sys/dev/ata/ata.c:1.132.8.14 src/sys/dev/ata/ata.c:1.132.8.15 --- src/sys/dev/ata/ata.c:1.132.8.14 Wed Jun 21 22:34:46 2017 +++ src/sys/dev/ata/ata.c Wed Jun 21 22:40:43 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ata.c,v 1.132.8.14 2017/06/21 22:34:46 jdolecek Exp $ */ +/* $NetBSD: ata.c,v 1.132.8.15 2017/06/21 22:40:43 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.14 2017/06/21 22:34:46 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.15 2017/06/21 22:40:43 jdolecek Exp $"); #include "opt_ata.h" @@ -130,6 +130,7 @@ static bool atabus_suspend(device_t, con static void atabusconfig_thread(void *); static void ata_channel_idle(struct ata_channel *); +static void ata_activate_xfer_locked(struct ata_channel *, struct ata_xfer *); /* * atabus_init: @@ -246,6 +247,7 @@ ata_xfer_init(struct ata_xfer *xfer, boo if (zero) memset(xfer, 0, sizeof(*xfer)); + cv_init(&xfer->c_active, "ataact"); callout_init(&xfer->c_timo_callout, 0); /* XXX MPSAFE */ } @@ -254,6 +256,7 @@ ata_xfer_destroy(struct ata_xfer *xfer) { callout_halt(&xfer->c_timo_callout, NULL); /* XXX MPSAFE */ callout_destroy(&xfer->c_timo_callout); + cv_destroy(&xfer->c_active); } struct ata_queue * @@ -1058,6 +1061,8 @@ ata_exec_xfer(struct ata_channel *chp, s /* complete xfer setup */ xfer->c_chp = chp; + mutex_enter(&chp->ch_lock); + /* insert at the end of command list */ TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain); ATADEBUG_PRINT(("atastart from ata_exec_xfer, flags 0x%x\n", @@ -1070,14 +1075,22 @@ ata_exec_xfer(struct ata_channel *chp, s while (chp->ch_queue->queue_active > 0 || TAILQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) { xfer->c_flags |= C_WAITACT; - tsleep(xfer, PRIBIO, "ataact", 0); + cv_wait(&xfer->c_active, &chp->ch_lock); xfer->c_flags &= ~C_WAITACT; + + /* + * Free xfer now if it there was attempt to free it + * while we were waiting. + */ if (xfer->c_flags & C_FREE) { ata_free_xfer(chp, xfer); return; } } } + + mutex_exit(&chp->ch_lock); + atastart(chp); } @@ -1108,8 +1121,10 @@ atastart(struct ata_channel *chp) splx(spl1); #endif /* ATA_DEBUG */ + mutex_enter(&chp->ch_lock); + if (chq->queue_active == chq->queue_openings) { - return; /* channel completely busy */ + goto out; /* channel completely busy */ } /* is the queue frozen? */ @@ -1118,12 +1133,12 @@ atastart(struct ata_channel *chp) chq->queue_flags &= ~QF_IDLE_WAIT; wakeup(&chq->queue_flags); } - return; /* queue frozen */ + goto out; /* queue frozen */ } /* is there a xfer ? */ if ((xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer)) == NULL) - return; + goto out; /* * Can only take NCQ command if there are no current active @@ -1132,7 +1147,7 @@ atastart(struct ata_channel *chp) */ axfer = TAILQ_FIRST(&chp->ch_queue->active_xfers); if (axfer && (axfer->c_flags & C_NCQ) == 0) - return; + goto out; /* adjust chp, in case we have a shared queue */ chp = xfer->c_chp; @@ -1148,9 +1163,10 @@ atastart(struct ata_channel *chp) ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d " "wait active\n", xfer, chp->ch_channel, xfer->c_drive), DEBUG_XFERS); - wakeup(xfer); - return; + cv_signal(&xfer->c_active); + goto out; } + #ifdef DIAGNOSTIC if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0 && chp->ch_queue->queue_openings == 1) @@ -1163,12 +1179,22 @@ atastart(struct ata_channel *chp) drvp->state = 0; } - ata_activate_xfer(chp, xfer); + ata_activate_xfer_locked(chp, xfer); if (atac->atac_cap & ATAC_CAP_NOIRQ) KASSERT(xfer->c_flags & C_POLL); + mutex_exit(&chp->ch_lock); + + /* + * XXX MPSAFE can't keep the lock, xfer->c_start() might call the done + * routine for polled commands. + */ xfer->c_start(chp, xfer); + return; + +out: + mutex_exit(&chp->ch_lock); } /* @@ -1233,7 +1259,7 @@ ata_free_xfer(struct ata_channel *chp, s if (xfer->c_flags & C_WAITACT) { /* Someone is waiting for this xfer, so we can't free now */ xfer->c_flags |= C_FREE; - wakeup(xfer); + cv_signal(&xfer->c_active); goto out; } @@ -1261,12 +1287,12 @@ out: mutex_exit(&chp->ch_lock); } -void -ata_activate_xfer(struct ata_channel *chp, struct ata_xfer *xfer) +static void +ata_activate_xfer_locked(struct ata_channel *chp, struct ata_xfer *xfer) { struct ata_queue * const chq = chp->ch_queue; - mutex_enter(&chp->ch_lock); + KASSERT(mutex_owned(&chp->ch_lock)); KASSERT(chq->queue_active < chq->queue_openings); KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0); @@ -1275,8 +1301,6 @@ ata_activate_xfer(struct ata_channel *ch TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain); chq->active_xfers_used |= __BIT(xfer->c_slot); chq->queue_active++; - - mutex_exit(&chp->ch_lock); } void Index: src/sys/dev/ata/atavar.h diff -u src/sys/dev/ata/atavar.h:1.92.8.13 src/sys/dev/ata/atavar.h:1.92.8.14 --- src/sys/dev/ata/atavar.h:1.92.8.13 Wed Jun 21 19:38:43 2017 +++ src/sys/dev/ata/atavar.h Wed Jun 21 22:40:43 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: atavar.h,v 1.92.8.13 2017/06/21 19:38:43 jdolecek Exp $ */ +/* $NetBSD: atavar.h,v 1.92.8.14 2017/06/21 22:40:43 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -134,6 +134,7 @@ struct scsipi_xfer; */ struct ata_xfer { struct callout c_timo_callout; /* timeout callout handle */ + kcondvar_t c_active; /* somebody actively waiting for xfer */ #define c_startzero c_chp /* Channel and drive that are to process the request. */ @@ -490,7 +491,6 @@ struct ata_xfer *ata_get_xfer_ext(struct #define ata_get_xfer(chp) ata_get_xfer_ext((chp), true, 0); void ata_free_xfer(struct ata_channel *, struct ata_xfer *); -void ata_activate_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 *);