Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/jdolecek-ncq]: src/sys/dev add ata_channel lock, use it to protect queue...
details: https://anonhg.NetBSD.org/src/rev/3d1e8f49c4aa
branches: jdolecek-ncq
changeset: 352679:3d1e8f49c4aa
user: jdolecek <jdolecek%NetBSD.org@localhost>
date: Mon Jun 19 21:00:00 2017 +0000
description:
add ata_channel lock, use it to protect queue manipulation (only that for now);
add ata_channel_detach() to destroy the locks
change ata_get_xfer() so that it can wait for xfer, convert all on-stack
xfer code to use the blocking variant
fix siisata_reset_drive() to use polled reset and not try ata_activate_xfer(),
convert drive probe code also over from slot0 XXX to ata_get_xfer()
drive reset and PMP now works on siisata(4) too; changes tested also
on piixide(4), ahci(4), mvsata(4)
diffstat:
sys/dev/ata/TODO.ncq | 10 +-
sys/dev/ata/ata.c | 88 ++++++++++++++++---
sys/dev/ata/atavar.h | 22 ++--
sys/dev/ata/satapmp_subr.c | 80 +++++++++--------
sys/dev/ata/wd.c | 200 ++++++++++++++++++++++++--------------------
sys/dev/ic/ahcisata_core.c | 8 +-
sys/dev/ic/mvsata.c | 6 +-
sys/dev/ic/siisata.c | 51 +++++++---
sys/dev/ic/wdc.c | 5 +-
sys/dev/scsipi/atapi_wdc.c | 34 ++++---
sys/dev/usb/umass_isdata.c | 29 +++--
11 files changed, 324 insertions(+), 209 deletions(-)
diffs (truncated from 1292 to 300 lines):
diff -r fa3e7e856d86 -r 3d1e8f49c4aa sys/dev/ata/TODO.ncq
--- a/sys/dev/ata/TODO.ncq Mon Jun 19 17:11:24 2017 +0000
+++ b/sys/dev/ata/TODO.ncq Mon Jun 19 21:00:00 2017 +0000
@@ -6,11 +6,11 @@
siisata - fix all new XXX and unmergable bits, fix PMP
test crashdump with siisata
-
-reset channel and PMP doesn't work with siisata - siisata_reset_drive()
-uses ata_get_xfer() and this can clash on slot 0 with on-stack xfers
+- fails with recursive panic via pmap_kremove_local() regardless if
+ drive connected via PMP or direct
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
@@ -30,6 +30,10 @@
to have active or pending transfers (e.g. when non-NCQ device is attached
while there is already NCQ device present)
+add mechanics to re-check queue when xfer is finished - needed on PMP
+and for IDE disks, when one drive uses up all available xfers nothing
+ever restarts queue for the other drives
+
Other random notes (do outside the NCQ branch):
-----------------------------------------------------
change wd(4) to use dk_open()
diff -r fa3e7e856d86 -r 3d1e8f49c4aa sys/dev/ata/ata.c
--- a/sys/dev/ata/ata.c Mon Jun 19 17:11:24 2017 +0000
+++ b/sys/dev/ata/ata.c Mon Jun 19 21:00:00 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ata.c,v 1.132.8.10 2017/06/17 14:01:36 jdolecek Exp $ */
+/* $NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 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.10 2017/06/17 14:01:36 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 jdolecek Exp $");
#include "opt_ata.h"
@@ -129,6 +129,9 @@
static bool atabus_suspend(device_t, const pmf_qual_t *);
static void atabusconfig_thread(void *);
+static void ata_xfer_init(struct ata_xfer *, bool);
+static void ata_xfer_destroy(struct ata_xfer *);
+
/*
* atabus_init:
*
@@ -221,7 +224,7 @@
return TAILQ_FIRST(&chq->active_xfers);
}
-void
+static void
ata_xfer_init(struct ata_xfer *xfer, bool zero)
{
if (zero)
@@ -230,7 +233,7 @@
callout_init(&xfer->c_timo_callout, 0); /* XXX MPSAFE */
}
-void
+static void
ata_xfer_destroy(struct ata_xfer *xfer)
{
callout_halt(&xfer->c_timo_callout, NULL); /* XXX MPSAFE */
@@ -257,6 +260,8 @@
chq->queue_openings = openings;
ata_queue_reset(chq);
+ cv_init(&chq->queue_busy, "ataqbusy");
+
for (uint8_t i = 0; i < openings; i++)
ata_xfer_init(&chq->queue_xfers[i], false);
@@ -283,6 +288,12 @@
free(chq, M_DEVBUF);
}
+void
+ata_channel_init(struct ata_channel *chp)
+{
+ mutex_init(&chp->ch_lock, MUTEX_DEFAULT, IPL_BIO);
+}
+
/*
* ata_channel_attach:
*
@@ -291,17 +302,37 @@
void
ata_channel_attach(struct ata_channel *chp)
{
- struct ata_queue * const chq = chp->ch_queue;
-
if (chp->ch_flags & ATACH_DISABLED)
return;
- ata_queue_reset(chq);
+ KASSERT(chp->ch_queue != NULL);
+
+ ata_channel_init(chp);
chp->atabus = config_found_ia(chp->ch_atac->atac_dev, "ata", chp,
atabusprint);
}
+void
+ata_channel_destroy(struct ata_channel *chp)
+{
+ mutex_destroy(&chp->ch_lock);
+}
+
+/*
+ * ata_channel_detach:
+ *
+ * Common parts of detaching an atabus to an ATA controller channel.
+ */
+void
+ata_channel_detach(struct ata_channel *chp)
+{
+ if (chp->ch_flags & ATACH_DISABLED)
+ return;
+
+ ata_channel_destroy(chp);
+}
+
static void
atabusconfig(struct atabus_softc *atabus_sc)
{
@@ -1130,17 +1161,27 @@
}
struct ata_xfer *
-ata_get_xfer(struct ata_channel *chp)
+ata_get_xfer(struct ata_channel *chp, bool wait)
{
struct ata_queue *chq = chp->ch_queue;
struct ata_xfer *xfer = NULL;
- int s;
uint32_t avail, slot;
+ int error;
+
+ mutex_enter(&chp->ch_lock);
- s = splbio();
+retry:
avail = ffs32(chq->queue_xfers_avail);
- if (avail == 0)
+ if (avail == 0) {
+ if (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];
@@ -1154,7 +1195,7 @@
xfer->c_slot = slot;
out:
- splx(s);
+ mutex_exit(&chp->ch_lock);
return xfer;
}
@@ -1165,13 +1206,14 @@
ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ata_queue *chq = chp->ch_queue;
- int s;
+
+ mutex_enter(&chp->ch_lock);
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);
- return;
+ goto out;
}
#if NATA_PIOBM /* XXX wdc dependent code */
@@ -1185,11 +1227,17 @@
}
#endif
- s = splbio();
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);
- splx(s);
+
+out:
+ if (chq->queue_flags & QF_NEED_XFER) {
+ chq->queue_flags &= ~QF_NEED_XFER;
+ cv_broadcast(&chq->queue_busy);
+ }
+
+ mutex_exit(&chp->ch_lock);
}
void
@@ -1197,6 +1245,8 @@
{
struct ata_queue * const chq = chp->ch_queue;
+ mutex_enter(&chp->ch_lock);
+
KASSERT(chq->queue_active < chq->queue_openings);
KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
@@ -1204,6 +1254,8 @@
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
@@ -1211,6 +1263,8 @@
{
struct ata_queue * const chq = chp->ch_queue;
+ mutex_enter(&chp->ch_lock);
+
KASSERT(chq->queue_active > 0);
KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);
@@ -1219,6 +1273,8 @@
TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
chq->active_xfers_used &= ~__BIT(xfer->c_slot);
chq->queue_active--;
+
+ mutex_exit(&chp->ch_lock);
}
diff -r fa3e7e856d86 -r 3d1e8f49c4aa sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h Mon Jun 19 17:11:24 2017 +0000
+++ b/sys/dev/ata/atavar.h Mon Jun 19 21:00:00 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.92.8.9 2017/06/16 20:40:49 jdolecek Exp $ */
+/* $NetBSD: atavar.h,v 1.92.8.10 2017/06/19 21:00:00 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -186,12 +186,14 @@
/* Per-channel queue of ata_xfers */
struct ata_queue {
TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */
- int queue_freeze; /* freeze count for the queue */
- int queue_flags; /* flags for this queue */
-#define QF_IDLE_WAIT 0x01 /* someone wants the controller idle */
- int queue_active; /* number of active transfers */
- int queue_openings; /* max number of active transfers */
+ int queue_freeze; /* freeze count for the queue */
+ int8_t queue_flags; /* flags for this queue */
+#define QF_IDLE_WAIT 0x01 /* someone wants the controller idle */
+#define QF_NEED_XFER 0x02 /* someone wants xfer */
+ int8_t queue_active; /* number of active transfers */
+ int8_t queue_openings; /* max number of active transfers */
#ifdef ATABUS_PRIVATE
+ kcondvar_t queue_busy; /* c: waiting of xfer */
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 */
@@ -358,6 +360,7 @@
struct ata_channel {
int ch_channel; /* location */
struct atac_softc *ch_atac; /* ATA controller softc */
+ kmutex_t ch_lock; /* channel lock - queue */
/* Our state */
volatile int ch_flags;
@@ -457,6 +460,9 @@
#ifdef _KERNEL
void ata_channel_attach(struct ata_channel *);
+void ata_channel_init(struct ata_channel *);
+void ata_channel_detach(struct ata_channel *);
+void ata_channel_destroy(struct ata_channel *);
int atabusprint(void *aux, const char *);
int ataprint(void *aux, const char *);
@@ -471,7 +477,7 @@
Home |
Main Index |
Thread Index |
Old Index