Module Name: src
Committed By: jdolecek
Date: Sun Sep 10 19:31:15 UTC 2017
Modified Files:
src/sys/dev/ata [jdolecek-ncq]: TODO.ncq ata.c ata_wdc.c atavar.h
src/sys/dev/ic [jdolecek-ncq]: ahcisata_core.c mvsata.c siisata.c wdc.c
src/sys/dev/scsipi [jdolecek-ncq]: atapi_wdc.c
Log Message:
refactor code so that xfer c_start() hook is called with channel mutex held,
and hence the controller submit code no longer relies on spl
tested all the affected drivers - wdc (via piixide), ahci, mvsata, siisata,
both disk and atapi I/O
To generate a diff of this commit:
cvs rdiff -u -r1.1.2.37 -r1.1.2.38 src/sys/dev/ata/TODO.ncq
cvs rdiff -u -r1.132.8.30 -r1.132.8.31 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.105.6.8 -r1.105.6.9 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.92.8.24 -r1.92.8.25 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.57.6.26 -r1.57.6.27 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35.6.24 -r1.35.6.25 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30.4.36 -r1.30.4.37 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283.2.13 -r1.283.2.14 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.123.4.12 -r1.123.4.13 src/sys/dev/scsipi/atapi_wdc.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ata/TODO.ncq
diff -u src/sys/dev/ata/TODO.ncq:1.1.2.37 src/sys/dev/ata/TODO.ncq:1.1.2.38
--- src/sys/dev/ata/TODO.ncq:1.1.2.37 Tue Aug 29 13:38:38 2017
+++ src/sys/dev/ata/TODO.ncq Sun Sep 10 19:31:15 2017
@@ -2,11 +2,13 @@ Bugs
----
test wd* at umass?, confirm the ata_channel kludge works
-c_start() needs to be called on splbio to avoid spurious irq during reset,
-is not e.g. in ata thread and may not in atastart() neither
+revise calls to atastart() - now called alsoafter ATASTART_ABORT(), call
+only from intr routine
- wdc.c never calls atastart() (start always false)
- ata_wdc.c calls atastart() regardless if error
+reconsider freeze/thaw in error recovery - can it screw up with thread?
+
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.30 src/sys/dev/ata/ata.c:1.132.8.31
--- src/sys/dev/ata/ata.c:1.132.8.30 Sun Sep 10 19:22:56 2017
+++ src/sys/dev/ata/ata.c Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata.c,v 1.132.8.30 2017/09/10 19:22:56 jdolecek Exp $ */
+/* $NetBSD: ata.c,v 1.132.8.31 2017/09/10 19:31:15 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.30 2017/09/10 19:22:56 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.31 2017/09/10 19:31:15 jdolecek Exp $");
#include "opt_ata.h"
@@ -130,8 +130,12 @@ static bool atabus_suspend(device_t, con
static void atabusconfig_thread(void *);
static void ata_channel_idle(struct ata_channel *);
+static void ata_channel_thaw_locked(struct ata_channel *);
static void ata_activate_xfer_locked(struct ata_channel *, struct ata_xfer *);
static void ata_channel_freeze_locked(struct ata_channel *);
+static struct ata_xfer *ata_queue_get_active_xfer_locked(struct ata_channel *);
+static void ata_thread_wake_locked(struct ata_channel *);
+
/*
* atabus_init:
*
@@ -200,7 +204,7 @@ ata_queue_hwslot_to_xfer(struct ata_chan
struct ata_queue *chq = chp->ch_queue;
struct ata_xfer *xfer = NULL;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
KASSERTMSG(hwslot < chq->queue_openings, "hwslot %d > openings %d",
hwslot, chq->queue_openings);
@@ -212,7 +216,7 @@ ata_queue_hwslot_to_xfer(struct ata_chan
break;
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
KASSERTMSG((xfer != NULL),
"%s: xfer with slot %d not found (active %x)", __func__,
@@ -221,6 +225,13 @@ ata_queue_hwslot_to_xfer(struct ata_chan
return xfer;
}
+static struct ata_xfer *
+ata_queue_get_active_xfer_locked(struct ata_channel *chp)
+{
+ KASSERT(mutex_owned(&chp->ch_lock));
+ return TAILQ_FIRST(&chp->ch_queue->active_xfers);
+}
+
/*
* This interface is supposed only to be used when there is exactly
* one outstanding command, when there is no information about the slot,
@@ -232,12 +243,12 @@ ata_queue_get_active_xfer(struct ata_cha
{
struct ata_xfer *xfer = NULL;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
KASSERT(chp->ch_queue->queue_active <= 1);
- xfer = TAILQ_FIRST(&chp->ch_queue->active_xfers);
+ xfer = ata_queue_get_active_xfer_locked(chp);
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
return xfer;
}
@@ -247,7 +258,7 @@ ata_queue_drive_active_xfer(struct ata_c
{
struct ata_xfer *xfer = NULL;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
TAILQ_FOREACH(xfer, &chp->ch_queue->active_xfers, c_activechain) {
if (xfer->c_drive == drive)
@@ -255,7 +266,7 @@ ata_queue_drive_active_xfer(struct ata_c
}
KASSERT(xfer != NULL);
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
return xfer;
}
@@ -374,9 +385,9 @@ atabusconfig(struct atabus_softc *atabus
int i, error;
/* we are in the atabus's thread context */
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
chp->ch_flags |= ATACH_TH_RUN;
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
/*
* Probe for the drives attached to controller, unless a PMP
@@ -393,9 +404,9 @@ atabusconfig(struct atabus_softc *atabus
}
/* next operations will occurs in a separate thread */
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
chp->ch_flags &= ~ATACH_TH_RUN;
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
/* Make sure the devices probe in atabus order to avoid jitter. */
mutex_enter(&atabus_qlock);
@@ -407,7 +418,7 @@ atabusconfig(struct atabus_softc *atabus
}
mutex_exit(&atabus_qlock);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
/* If no drives, abort here */
if (chp->ch_drive == NULL)
@@ -423,7 +434,7 @@ atabusconfig(struct atabus_softc *atabus
if (chp->ch_flags & ATACH_SHUTDOWN)
goto out;
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
if ((error = kthread_create(PRI_NONE, 0, NULL, atabusconfig_thread,
atabus_sc, &atabus_cfg_lwp,
@@ -433,7 +444,7 @@ atabusconfig(struct atabus_softc *atabus
return;
out:
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
mutex_enter(&atabus_qlock);
TAILQ_REMOVE(&atabus_initq_head, atabus_initq, atabus_initq);
@@ -586,9 +597,9 @@ atabus_thread(void *arg)
struct ata_channel *chp = sc->sc_chan;
struct ata_queue *chq = chp->ch_queue;
struct ata_xfer *xfer;
- int i, s;
+ int i, rv, s;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
chp->ch_flags |= ATACH_TH_RUN;
/*
@@ -602,11 +613,11 @@ atabus_thread(void *arg)
chp->ch_drive[i].drive_flags = 0;
chp->ch_drive[i].drive_type = ATA_DRIVET_NONE;
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
atabusconfig(sc);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
for (;;) {
if ((chp->ch_flags & (ATACH_TH_RESET | ATACH_SHUTDOWN)) == 0 &&
(chq->queue_active == 0 || chq->queue_freeze == 0)) {
@@ -619,21 +630,21 @@ atabus_thread(void *arg)
}
if (chp->ch_flags & ATACH_TH_RESCAN) {
chp->ch_flags &= ~ATACH_TH_RESCAN;
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
atabusconfig(sc);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
}
if (chp->ch_flags & ATACH_TH_RESET) {
/*
* ata_reset_channel() will freeze 2 times, so
* unfreeze one time. Not a problem as we're at splbio
*/
- mutex_exit(&chp->ch_lock);
- ata_channel_thaw(chp);
+ ata_channel_thaw_locked(chp);
+ ata_channel_unlock(chp);
s = splbio();
ata_reset_channel(chp, AT_WAIT | chp->ch_reset_flags);
splx(s);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
} else if (chq->queue_active > 0 && chq->queue_freeze == 1) {
/*
* Caller has bumped queue_freeze, decrease it. This
@@ -641,31 +652,39 @@ atabus_thread(void *arg)
*/
KASSERT((chp->ch_flags & ATACH_NCQ) == 0);
KASSERT(chq->queue_active == 1);
- mutex_exit(&chp->ch_lock);
- ata_channel_thaw(chp);
- xfer = ata_queue_get_active_xfer(chp);
+ ata_channel_thaw_locked(chp);
+ xfer = ata_queue_get_active_xfer_locked(chp);
+
KASSERT(xfer != NULL);
- s = splbio();
- (*xfer->c_start)(xfer->c_chp, xfer);
- splx(s);
- mutex_enter(&chp->ch_lock);
+ KASSERT((xfer->c_flags & C_POLL) == 0);
+
+ switch ((rv = ata_xfer_start(xfer))) {
+ case ATASTART_STARTED:
+ case ATASTART_POLL:
+ case ATASTART_ABORT:
+ break;
+ case ATASTART_TH:
+ default:
+ panic("%s: ata_xfer_start() unexpected rv %d",
+ __func__, rv);
+ /* NOTREACHED */
+ }
} else if (chq->queue_freeze > 1)
panic("%s: queue_freeze", __func__);
}
chp->ch_thread = NULL;
cv_signal(&chp->ch_thr_idle);
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
kthread_exit(0);
}
-void
-ata_thread_wake(struct ata_channel *chp)
+static void
+ata_thread_wake_locked(struct ata_channel *chp)
{
- mutex_enter(&chp->ch_lock);
+ KASSERT(mutex_owned(&chp->ch_lock));
ata_channel_freeze_locked(chp);
cv_signal(&chp->ch_thr_idle);
- mutex_exit(&chp->ch_lock);
}
/*
@@ -743,13 +762,13 @@ atabus_detach(device_t self, int flags)
int i, error = 0;
/* Shutdown the channel. */
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
chp->ch_flags |= ATACH_SHUTDOWN;
while (chp->ch_thread != NULL) {
cv_signal(&chp->ch_thr_idle);
cv_wait(&chp->ch_thr_idle, &chp->ch_lock);
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
/*
* Detach atapibus and its children.
@@ -1199,7 +1218,7 @@ ata_exec_xfer(struct ata_channel *chp, s
/* complete xfer setup */
xfer->c_chp = chp;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
/*
* Standard commands are added to the end of command list, but
@@ -1235,7 +1254,7 @@ ata_exec_xfer(struct ata_channel *chp, s
}
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
atastart(chp);
}
@@ -1268,9 +1287,9 @@ atastart(struct ata_channel *chp)
splx(spl1);
#endif /* ATA_DEBUG */
-again:
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
+again:
KASSERT(chq->queue_active <= chq->queue_openings);
if (chq->queue_active == chq->queue_openings) {
goto out; /* channel completely busy */
@@ -1340,22 +1359,57 @@ again:
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);
+ switch (ata_xfer_start(xfer)) {
+ case ATASTART_TH:
+ case ATASTART_ABORT:
+ /* don't start any further commands in this case */
+ goto out;
+ default:
+ /* nothing to do */
+ break;
+ }
/* Queue more commands if possible, but not during recovery */
if (!recovery && chq->queue_active < chq->queue_openings)
goto again;
- return;
-
out:
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
+}
+
+int
+ata_xfer_start(struct ata_xfer *xfer)
+{
+ struct ata_channel *chp = xfer->c_chp;
+ int rv;
+
+ KASSERT(mutex_owned(&chp->ch_lock));
+
+ rv = xfer->c_start(chp, xfer);
+ switch (rv) {
+ case ATASTART_STARTED:
+ /* nothing to do */
+ break;
+ case ATASTART_TH:
+ /* postpone xfer to thread */
+ ata_thread_wake_locked(chp);
+ break;
+ case ATASTART_POLL:
+ /* can happen even in thread context for some ATAPI devices */
+ ata_channel_unlock(chp);
+ KASSERT(xfer->c_poll != NULL);
+ xfer->c_poll(chp, xfer);
+ ata_channel_lock(chp);
+ break;
+ case ATASTART_ABORT:
+ ata_channel_unlock(chp);
+ KASSERT(xfer->c_abort != NULL);
+ xfer->c_abort(chp, xfer);
+ ata_channel_lock(chp);
+ break;
+ }
+
+ return rv;
}
/*
@@ -1376,7 +1430,7 @@ ata_get_xfer_ext(struct ata_channel *chp
__func__, chp->ch_channel, flags, openings),
DEBUG_XFERS);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
/*
* When openings is just 1, can't reserve anything for
@@ -1430,7 +1484,7 @@ retry:
sizeof(struct ata_xfer) - offsetof(struct ata_xfer, c_startzero));
out:
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
return xfer;
}
@@ -1442,7 +1496,7 @@ ata_free_xfer(struct ata_channel *chp, s
{
struct ata_queue *chq = chp->ch_queue;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
if (xfer->c_flags & (C_WAITACT|C_WAITTIMO)) {
/* Someone is waiting for this xfer, so we can't free now */
@@ -1472,7 +1526,7 @@ out:
cv_broadcast(&chq->queue_busy);
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
}
static void
@@ -1496,7 +1550,7 @@ ata_deactivate_xfer(struct ata_channel *
{
struct ata_queue * const chq = chp->ch_queue;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
KASSERT(chq->queue_active > 0);
KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);
@@ -1510,7 +1564,7 @@ ata_deactivate_xfer(struct ata_channel *
chq->active_xfers_used &= ~__BIT(xfer->c_slot);
chq->queue_active--;
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
}
/*
@@ -1528,20 +1582,20 @@ ata_waitdrain_xfer_check(struct ata_chan
int drive = xfer->c_drive;
bool draining = false;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
(*xfer->c_kill_xfer)(chp, xfer, KILL_GONE);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
cv_signal(&chp->ch_queue->queue_drain);
draining = true;
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
return draining;
}
@@ -1555,7 +1609,7 @@ ata_timo_xfer_check(struct ata_xfer *xfe
struct ata_channel *chp = xfer->c_chp;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
callout_ack(&xfer->c_timo_callout);
@@ -1565,7 +1619,7 @@ ata_timo_xfer_check(struct ata_xfer *xfe
/* Handle race vs. ata_free_xfer() */
if (xfer->c_flags & C_FREE) {
xfer->c_flags &= ~C_FREE;
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
aprint_normal_dev(drvp->drv_softc,
"xfer %d freed while invoking timeout\n",
@@ -1577,7 +1631,7 @@ ata_timo_xfer_check(struct ata_xfer *xfe
/* Handle race vs. callout_stop() in ata_deactivate_xfer() */
if (!callout_expired(&xfer->c_timo_callout)) {
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
aprint_normal_dev(drvp->drv_softc,
"xfer %d deactivated while invoking timeout\n",
@@ -1586,7 +1640,7 @@ ata_timo_xfer_check(struct ata_xfer *xfe
}
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
/* No race, proceed with timeout handling */
return false;
@@ -1645,7 +1699,7 @@ ata_kill_pending(struct ata_drive_datas
struct ata_queue * const chq = chp->ch_queue;
struct ata_xfer *xfer, *xfernext;
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
/* Kill all pending transfers */
TAILQ_FOREACH_SAFE(xfer, &chq->queue_xfer, c_xferchain, xfernext) {
@@ -1687,7 +1741,7 @@ ata_kill_pending(struct ata_drive_datas
cv_wait(&chq->queue_drain, &chp->ch_lock);
}
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
}
static void
@@ -1699,17 +1753,25 @@ ata_channel_freeze_locked(struct ata_cha
void
ata_channel_freeze(struct ata_channel *chp)
{
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
ata_channel_freeze_locked(chp);
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
+}
+
+static void
+ata_channel_thaw_locked(struct ata_channel *chp)
+{
+ KASSERT(mutex_owned(&chp->ch_lock));
+
+ chp->ch_queue->queue_freeze--;
}
void
ata_channel_thaw(struct ata_channel *chp)
{
- mutex_enter(&chp->ch_lock);
- chp->ch_queue->queue_freeze--;
- mutex_exit(&chp->ch_lock);
+ ata_channel_lock(chp);
+ ata_channel_thaw_locked(chp);
+ ata_channel_unlock(chp);
}
/*
@@ -1752,23 +1814,23 @@ ata_reset_channel(struct ata_channel *ch
ata_channel_thaw(chp);
return;
}
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
chp->ch_flags |= ATACH_TH_RESET;
chp->ch_reset_flags = flags & AT_RST_EMERG;
cv_signal(&chp->ch_thr_idle);
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
return;
}
(*atac->atac_bustype_ata->ata_reset_channel)(chp, flags);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
for (drive = 0; drive < chp->ch_ndrives; drive++)
chp->ch_drive[drive].state = 0;
chp->ch_flags &= ~ATACH_TH_RESET;
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
if (flags & AT_RST_EMERG) {
/* make sure that we can use polled commands */
@@ -2350,13 +2412,13 @@ atabus_resume(device_t dv, const pmf_qua
* XXX joerg: with wdc, the first channel unfreezes the controler.
* Move this the reset and queue idling into wdc.
*/
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
if (chp->ch_queue->queue_freeze == 0) {
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
goto out;
}
KASSERT(chp->ch_queue->queue_freeze > 0);
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
/* unfreeze the queue and reset drives */
ata_channel_thaw(chp);
@@ -2401,10 +2463,10 @@ atabus_rescan(device_t self, const char
mutex_exit(&atabus_qlock);
config_pending_incr(sc->sc_dev);
- mutex_enter(&chp->ch_lock);
+ ata_channel_lock(chp);
chp->ch_flags |= ATACH_TH_RESCAN;
cv_signal(&chp->ch_thr_idle);
- mutex_exit(&chp->ch_lock);
+ ata_channel_unlock(chp);
return 0;
}
@@ -2500,3 +2562,21 @@ ata_channel_start(struct ata_channel *ch
splx(s);
#undef ATA_DRIVE_START
}
+
+void
+ata_channel_lock(struct ata_channel *chp)
+{
+ mutex_enter(&chp->ch_lock);
+}
+
+void
+ata_channel_unlock(struct ata_channel *chp)
+{
+ mutex_exit(&chp->ch_lock);
+}
+
+void
+ata_channel_lock_owned(struct ata_channel *chp)
+{
+ KASSERT(mutex_owned(&chp->ch_lock));
+}
Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.105.6.8 src/sys/dev/ata/ata_wdc.c:1.105.6.9
--- src/sys/dev/ata/ata_wdc.c:1.105.6.8 Sat Aug 12 14:41:54 2017
+++ src/sys/dev/ata/ata_wdc.c Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata_wdc.c,v 1.105.6.8 2017/08/12 14:41:54 jdolecek Exp $ */
+/* $NetBSD: ata_wdc.c,v 1.105.6.9 2017/09/10 19:31:15 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
@@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.8 2017/08/12 14:41:54 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.9 2017/09/10 19:31:15 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -104,8 +104,9 @@ extern int wdcdebug_wd_mask; /* inited i
#define ATA_DELAY 10000 /* 10s for a drive I/O */
static int wdc_ata_bio(struct ata_drive_datas*, struct ata_xfer *);
-static void wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
-static void _wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
+static int wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
+static int _wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
+static void wdc_ata_bio_poll(struct ata_channel *,struct ata_xfer *);
static int wdc_ata_bio_intr(struct ata_channel *, struct ata_xfer *,
int);
static void wdc_ata_bio_kill_xfer(struct ata_channel *,
@@ -161,13 +162,15 @@ wdc_ata_bio(struct ata_drive_datas *drvp
xfer->c_databuf = ata_bio->databuf;
xfer->c_bcount = ata_bio->bcount;
xfer->c_start = wdc_ata_bio_start;
+ xfer->c_poll = wdc_ata_bio_poll;
+ xfer->c_abort = wdc_ata_bio_done;
xfer->c_intr = wdc_ata_bio_intr;
xfer->c_kill_xfer = wdc_ata_bio_kill_xfer;
ata_exec_xfer(chp, xfer);
return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED;
}
-static void
+static int
wdc_ata_bio_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct atac_softc *atac = chp->ch_atac;
@@ -189,6 +192,8 @@ wdc_ata_bio_start(struct ata_channel *ch
drvp->state, drvp->drive_flags, xfer->c_flags, chp->ch_flags),
DEBUG_XFERS);
+ ata_channel_lock_owned(chp);
+
/* Do control operations specially. */
if (__predict_false(drvp->state < READY)) {
/*
@@ -199,8 +204,7 @@ wdc_ata_bio_start(struct ata_channel *ch
/* If it's not a polled command, we need the kernel thread */
if ((xfer->c_flags & C_POLL) == 0 &&
(chp->ch_flags & ATACH_TH_RUN) == 0) {
- ata_thread_wake(chp);
- return;
+ return ATASTART_TH;
}
/*
* disable interrupts, all commands here should be quick
@@ -297,8 +301,7 @@ ready:
delay(10); /* some drives need a little delay here */
}
- _wdc_ata_bio_start(chp, xfer);
- return;
+ return _wdc_ata_bio_start(chp, xfer);
ctrltimeout:
printf("%s:%d:%d: %s timed out\n",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
@@ -319,15 +322,14 @@ ctrlerror:
}
ctrldone:
drvp->state = 0;
- wdc_ata_bio_done(chp, xfer);
if (! (wdc->cap & WDC_CAPABILITY_NO_AUXCTL))
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
WDCTL_4BIT);
- return;
+ return ATASTART_ABORT;
}
-static void
+static int
_wdc_ata_bio_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct atac_softc *atac = chp->ch_atac;
@@ -358,7 +360,6 @@ _wdc_ata_bio_start(struct ata_channel *c
dma_flags |= WDC_DMA_LBA48;
}
#endif
-again:
/*
*
* When starting a multi-sector transfer, or doing single-sector
@@ -438,8 +439,7 @@ again:
}
ata_bio->error = ERR_DMA;
ata_bio->r_error = 0;
- wdc_ata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
/* Initiate command */
if (wdc->select)
@@ -453,7 +453,7 @@ again:
case WDCWAIT_TOUT:
goto timeout;
case WDCWAIT_THR:
- return;
+ return ATASTART_TH;
}
if (ata_bio->flags & ATA_LBA48) {
uint8_t device = WDSD_LBA;
@@ -505,8 +505,7 @@ again:
} else {
ata_bio->error = ERR_DMA;
ata_bio->r_error = 0;
- wdc_ata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
}
}
@@ -533,7 +532,7 @@ again:
case WDCWAIT_TOUT:
goto timeout;
case WDCWAIT_THR:
- return;
+ return ATASTART_TH;
}
if (ata_bio->flags & ATA_LBA48) {
wdccommandext(chp, xfer->c_drive, atacmd_to48(cmd),
@@ -570,12 +569,10 @@ again:
ATACH_ST(tfd), ATACH_ERR(tfd));
if (wdc_ata_err(drvp, ata_bio, tfd) != WDC_ATA_ERR)
ata_bio->error = TIMEOUT;
- wdc_ata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
if (wdc_ata_err(drvp, ata_bio, tfd) == WDC_ATA_ERR) {
- wdc_ata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
#if NATA_PIOBM
if (xfer->c_flags & C_PIOBM) {
@@ -595,28 +592,29 @@ again:
intr:
#endif
/* Wait for IRQ (either real or polled) */
- if ((ata_bio->flags & ATA_POLL) != 0) {
- /* Wait for at last 400ns for status bit to be valid */
- delay(1);
-#if NATA_DMA
- if (chp->ch_flags & ATACH_DMA_WAIT) {
- wdc_dmawait(chp, xfer, ATA_DELAY);
- chp->ch_flags &= ~ATACH_DMA_WAIT;
- }
-#endif
- wdc_ata_bio_intr(chp, xfer, 0);
- if ((ata_bio->flags & ATA_ITSDONE) == 0)
- goto again;
- }
- return;
+ return (ata_bio->flags & ATA_POLL) ? ATASTART_POLL : ATASTART_STARTED;
+
timeout:
printf("%s:%d:%d: not ready, st=0x%02x, err=0x%02x\n",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
ATACH_ST(tfd), ATACH_ERR(tfd));
if (wdc_ata_err(drvp, ata_bio, tfd) != WDC_ATA_ERR)
ata_bio->error = TIMEOUT;
- wdc_ata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
+}
+
+static void
+wdc_ata_bio_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ /* Wait for at last 400ns for status bit to be valid */
+ delay(1);
+#if NATA_DMA
+ if (chp->ch_flags & ATACH_DMA_WAIT) {
+ wdc_dmawait(chp, xfer, ATA_DELAY);
+ chp->ch_flags &= ~ATACH_DMA_WAIT;
+ }
+#endif
+ wdc_ata_bio_intr(chp, xfer, 0);
}
static int
@@ -633,6 +631,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive),
DEBUG_INTR | DEBUG_XFERS);
+ ata_channel_lock(chp);
/* Is it not a transfer, but a control operation? */
if (drvp->state < READY) {
@@ -648,6 +647,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
*/
if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) {
ata_bio->error = TIMEOUT;
+ ata_channel_unlock(chp);
wdc_ata_bio_done(chp, xfer);
return 1;
}
@@ -668,6 +668,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
xfer->c_bcount, xfer->c_skip);
ata_bio->error = TIMEOUT;
+ ata_channel_unlock(chp);
wdc_ata_bio_done(chp, xfer);
return 1;
}
@@ -722,6 +723,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
/* if we had an error, end */
if (drv_err == WDC_ATA_ERR) {
+ ata_channel_unlock(chp);
wdc_ata_bio_done(chp, xfer);
return 1;
}
@@ -733,6 +735,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
device_xname(atac->atac_dev), chp->ch_channel,
xfer->c_drive);
ata_bio->error = TIMEOUT;
+ ata_channel_unlock(chp);
wdc_ata_bio_done(chp, xfer);
return 1;
}
@@ -744,6 +747,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
xfer->c_skip, ata_bio->nbytes,
WDC_PIOBM_XFER_IRQ);
chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT;
+ ata_channel_unlock(chp);
return 1;
} else
#endif
@@ -758,17 +762,19 @@ end:
ata_bio->blkdone += ata_bio->nblks;
xfer->c_skip += ata_bio->nbytes;
xfer->c_bcount -= ata_bio->nbytes;
+
/* See if this transfer is complete. */
if (xfer->c_bcount > 0) {
if ((ata_bio->flags & ATA_POLL) == 0) {
/* Start the next operation */
- _wdc_ata_bio_start(chp, xfer);
+ ata_xfer_start(xfer);
} else {
/* Let _wdc_ata_bio_start do the loop */
- return 1;
}
+ ata_channel_unlock(chp);
} else { /* Done with this transfer */
ata_bio->error = NOERROR;
+ ata_channel_unlock(chp);
wdc_ata_bio_done(chp, xfer);
}
return 1;
Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92.8.24 src/sys/dev/ata/atavar.h:1.92.8.25
--- src/sys/dev/ata/atavar.h:1.92.8.24 Sat Aug 12 22:12:04 2017
+++ src/sys/dev/ata/atavar.h Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.92.8.24 2017/08/12 22:12:04 jdolecek Exp $ */
+/* $NetBSD: atavar.h,v 1.92.8.25 2017/09/10 19:31:15 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -166,7 +166,13 @@ struct ata_xfer {
TAILQ_ENTRY(ata_xfer) c_activechain;
/* Low-level protocol handlers. */
- void (*c_start)(struct ata_channel *, struct ata_xfer *);
+ int (*c_start)(struct ata_channel *, struct ata_xfer *);
+#define ATASTART_STARTED 0 /* xfer started, waiting for intr */
+#define ATASTART_TH 1 /* xfer needs to be run in thread */
+#define ATASTART_POLL 2 /* xfer needs to be polled */
+#define ATASTART_ABORT 3 /* error occurred, abort xfer */
+ void (*c_poll)(struct ata_channel *, struct ata_xfer *);
+ void (*c_abort)(struct ata_channel *, struct ata_xfer *);
int (*c_intr)(struct ata_channel *, struct ata_xfer *, int);
void (*c_kill_xfer)(struct ata_channel *, struct ata_xfer *, int);
};
@@ -508,6 +514,7 @@ struct ata_xfer *ata_get_xfer_ext(struct
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 *);
+int ata_xfer_start(struct ata_xfer *xfer);
void ata_timeout(void *);
bool ata_timo_xfer_check(struct ata_xfer *);
@@ -517,7 +524,9 @@ void ata_reset_channel(struct ata_channe
void ata_channel_freeze(struct ata_channel *);
void ata_channel_thaw(struct ata_channel *);
void ata_channel_start(struct ata_channel *, int);
-void ata_thread_wake(struct ata_channel *);
+void ata_channel_lock(struct ata_channel *);
+void ata_channel_unlock(struct ata_channel *);
+void ata_channel_lock_owned(struct ata_channel *);
int ata_addref(struct ata_channel *);
void ata_delref(struct ata_channel *);
Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.26 src/sys/dev/ic/ahcisata_core.c:1.57.6.27
--- src/sys/dev/ic/ahcisata_core.c:1.57.6.26 Sat Aug 12 22:12:04 2017
+++ src/sys/dev/ic/ahcisata_core.c Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ahcisata_core.c,v 1.57.6.26 2017/08/12 22:12:04 jdolecek Exp $ */
+/* $NetBSD: ahcisata_core.c,v 1.57.6.27 2017/09/10 19:31:15 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.26 2017/08/12 22:12:04 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.27 2017/09/10 19:31:15 jdolecek Exp $");
#include <sys/types.h>
#include <sys/malloc.h>
@@ -66,12 +66,16 @@ static int ahci_ata_addref(struct ata_d
static void ahci_ata_delref(struct ata_drive_datas *);
static void ahci_killpending(struct ata_drive_datas *);
-static void ahci_cmd_start(struct ata_channel *, struct ata_xfer *);
+static int ahci_cmd_start(struct ata_channel *, struct ata_xfer *);
static int ahci_cmd_complete(struct ata_channel *, struct ata_xfer *, int);
-static void ahci_cmd_done(struct ata_channel *, struct ata_xfer *, int);
+static void ahci_cmd_poll(struct ata_channel *, struct ata_xfer *);
+static void ahci_cmd_abort(struct ata_channel *, struct ata_xfer *);
+static void ahci_cmd_done(struct ata_channel *, struct ata_xfer *);
static void ahci_cmd_done_end(struct ata_channel *, struct ata_xfer *);
static void ahci_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
-static void ahci_bio_start(struct ata_channel *, struct ata_xfer *);
+static int ahci_bio_start(struct ata_channel *, struct ata_xfer *);
+static void ahci_bio_poll(struct ata_channel *, struct ata_xfer *);
+static void ahci_bio_abort(struct ata_channel *, struct ata_xfer *);
static int ahci_bio_complete(struct ata_channel *, struct ata_xfer *, int);
static void ahci_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int) ;
static void ahci_channel_stop(struct ahci_softc *, struct ata_channel *, int);
@@ -86,7 +90,9 @@ static void ahci_atapi_kill_pending(stru
static void ahci_atapi_minphys(struct buf *);
static void ahci_atapi_scsipi_request(struct scsipi_channel *,
scsipi_adapter_req_t, void *);
-static void ahci_atapi_start(struct ata_channel *, struct ata_xfer *);
+static int ahci_atapi_start(struct ata_channel *, struct ata_xfer *);
+static void ahci_atapi_poll(struct ata_channel *, struct ata_xfer *);
+static void ahci_atapi_abort(struct ata_channel *, struct ata_xfer *);
static int ahci_atapi_complete(struct ata_channel *, struct ata_xfer *, int);
static void ahci_atapi_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
static void ahci_atapi_probe_device(struct atapibus_softc *, int);
@@ -984,6 +990,8 @@ ahci_exec_command(struct ata_drive_datas
xfer->c_databuf = ata_c->data;
xfer->c_bcount = ata_c->bcount;
xfer->c_start = ahci_cmd_start;
+ xfer->c_poll = ahci_cmd_poll;
+ xfer->c_abort = ahci_cmd_abort;
xfer->c_intr = ahci_cmd_complete;
xfer->c_kill_xfer = ahci_cmd_kill_xfer;
s = splbio();
@@ -1009,7 +1017,7 @@ ahci_exec_command(struct ata_drive_datas
return ret;
}
-static void
+static int
ahci_cmd_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ahci_softc *sc = AHCI_CH2SC(chp);
@@ -1018,13 +1026,13 @@ ahci_cmd_start(struct ata_channel *chp,
int slot = xfer->c_slot;
struct ahci_cmd_tbl *cmd_tbl;
struct ahci_cmd_header *cmd_h;
- int i;
AHCIDEBUG_PRINT(("ahci_cmd_start CI 0x%x timo %d\n slot %d",
AHCI_READ(sc, AHCI_P_CI(chp->ch_channel)),
ata_c->timeout, slot),
DEBUG_XFERS);
+ ata_channel_lock_owned(chp);
KASSERT((achp->ahcic_cmds_active & (1 << slot)) == 0);
cmd_tbl = achp->ahcic_cmd_tbl[slot];
@@ -1043,8 +1051,7 @@ ahci_cmd_start(struct ata_channel *chp,
ata_c->bcount,
(ata_c->flags & AT_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) {
ata_c->flags |= AT_DF;
- xfer->c_intr(chp, xfer, 0);
- return;
+ return ATASTART_ABORT;
}
cmd_h->cmdh_flags = htole16(
((ata_c->flags & AT_WRITE) ? AHCI_CMDH_F_WR : 0) |
@@ -1066,16 +1073,25 @@ ahci_cmd_start(struct ata_channel *chp,
if ((ata_c->flags & AT_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),
ata_timeout, xfer);
- return;
- }
+ return ATASTART_STARTED;
+ } else
+ return ATASTART_POLL;
+}
+
+static void
+ahci_cmd_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ struct ahci_softc *sc = AHCI_CH2SC(chp);
+ struct ahci_channel *achp = (struct ahci_channel *)chp;
+
/*
* Polled command.
*/
- for (i = 0; i < ata_c->timeout / 10; i++) {
- if (ata_c->flags & AT_DONE)
+ for (int i = 0; i < xfer->c_ata_c.timeout / 10; i++) {
+ if (xfer->c_ata_c.flags & AT_DONE)
break;
ahci_intr_port(sc, achp);
- ata_delay(10, "ahcipl", ata_c->flags);
+ ata_delay(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),
@@ -1086,8 +1102,8 @@ ahci_cmd_start(struct ata_channel *chp,
AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)),
AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
DEBUG_XFERS);
- if ((ata_c->flags & AT_DONE) == 0) {
- ata_c->flags |= AT_TIMEOU;
+ if ((xfer->c_ata_c.flags & AT_DONE) == 0) {
+ xfer->c_ata_c.flags |= AT_TIMEOU;
xfer->c_intr(chp, xfer, 0);
}
/* reenable interrupts */
@@ -1095,6 +1111,12 @@ ahci_cmd_start(struct ata_channel *chp,
}
static void
+ahci_cmd_abort(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ ahci_cmd_complete(chp, xfer, 0);
+}
+
+static void
ahci_cmd_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
{
struct ahci_channel *achp = (struct ahci_channel *)chp;
@@ -1164,17 +1186,18 @@ ahci_cmd_complete(struct ata_channel *ch
if (ata_c->flags & AT_READREG)
satafis_rdh_cmd_readreg(ata_c, achp->ahcic_rfis->rfis_rfis);
- ahci_cmd_done(chp, xfer, tfd);
+ ahci_cmd_done(chp, xfer);
return 0;
}
static void
-ahci_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer, int tfd)
+ahci_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
struct ahci_channel *achp = (struct ahci_channel *)chp;
struct ata_command *ata_c = &xfer->c_ata_c;
uint16_t *idwordbuf;
+ int flags = ata_c->flags;
int i;
AHCIDEBUG_PRINT(("ahci_cmd_done channel %d flags %#x/%#x\n",
@@ -1203,7 +1226,7 @@ ahci_cmd_done(struct ata_channel *chp, s
if (achp->ahcic_cmdh[xfer->c_slot].cmdh_prdbc)
ata_c->flags |= AT_XFDONE;
ahci_cmd_done_end(chp, xfer);
- if ((AHCI_TFD_ST(tfd) & WDCS_ERR) == 0)
+ if ((flags & (AT_TIMEOU|AT_ERROR)) == 0)
atastart(chp);
}
@@ -1235,13 +1258,15 @@ ahci_ata_bio(struct ata_drive_datas *drv
xfer->c_databuf = ata_bio->databuf;
xfer->c_bcount = ata_bio->bcount;
xfer->c_start = ahci_bio_start;
+ xfer->c_poll = ahci_bio_poll;
+ xfer->c_abort = ahci_bio_abort;
xfer->c_intr = ahci_bio_complete;
xfer->c_kill_xfer = ahci_bio_kill_xfer;
ata_exec_xfer(chp, xfer);
return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED;
}
-static void
+static int
ahci_bio_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -1249,11 +1274,12 @@ ahci_bio_start(struct ata_channel *chp,
struct ata_bio *ata_bio = &xfer->c_bio;
struct ahci_cmd_tbl *cmd_tbl;
struct ahci_cmd_header *cmd_h;
- int i;
AHCIDEBUG_PRINT(("ahci_bio_start CI 0x%x\n",
AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))), DEBUG_XFERS);
+ ata_channel_lock_owned(chp);
+
cmd_tbl = achp->ahcic_cmd_tbl[xfer->c_slot];
AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
cmd_tbl), DEBUG_XFERS);
@@ -1268,8 +1294,7 @@ ahci_bio_start(struct ata_channel *chp,
(ata_bio->flags & ATA_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) {
ata_bio->error = ERR_DMA;
ata_bio->r_error = 0;
- xfer->c_intr(chp, xfer, 0);
- return;
+ return ATASTART_ABORT;
}
cmd_h->cmdh_flags = htole16(
((ata_bio->flags & ATA_READ) ? 0 : AHCI_CMDH_F_WR) |
@@ -1293,13 +1318,22 @@ ahci_bio_start(struct ata_channel *chp,
if ((xfer->c_flags & C_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),
ata_timeout, xfer);
- return;
- }
+ return ATASTART_STARTED;
+ } else
+ return ATASTART_POLL;
+}
+
+static void
+ahci_bio_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
+ struct ahci_channel *achp = (struct ahci_channel *)chp;
+
/*
* Polled command.
*/
- for (i = 0; i < ATA_DELAY * 10; i++) {
- if (ata_bio->flags & ATA_ITSDONE)
+ for (int i = 0; i < ATA_DELAY * 10; i++) {
+ if (xfer->c_bio.flags & ATA_ITSDONE)
break;
ahci_intr_port(sc, achp);
delay(100);
@@ -1313,8 +1347,8 @@ ahci_bio_start(struct ata_channel *chp,
AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)),
AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
DEBUG_XFERS);
- if ((ata_bio->flags & ATA_ITSDONE) == 0) {
- ata_bio->error = TIMEOUT;
+ if ((xfer->c_bio.flags & ATA_ITSDONE) == 0) {
+ xfer->c_bio.error = TIMEOUT;
xfer->c_intr(chp, xfer, 0);
}
/* reenable interrupts */
@@ -1322,6 +1356,12 @@ ahci_bio_start(struct ata_channel *chp,
}
static void
+ahci_bio_abort(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ ahci_bio_complete(chp, xfer, 0);
+}
+
+static void
ahci_bio_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
{
int drive = xfer->c_drive;
@@ -1787,6 +1827,8 @@ ahci_atapi_scsipi_request(struct scsipi_
xfer->c_databuf = sc_xfer->data;
xfer->c_bcount = sc_xfer->datalen;
xfer->c_start = ahci_atapi_start;
+ xfer->c_poll = ahci_atapi_poll;
+ xfer->c_abort = ahci_atapi_abort;
xfer->c_intr = ahci_atapi_complete;
xfer->c_kill_xfer = ahci_atapi_kill_xfer;
xfer->c_dscpoll = 0;
@@ -1806,7 +1848,7 @@ ahci_atapi_scsipi_request(struct scsipi_
}
}
-static void
+static int
ahci_atapi_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -1814,11 +1856,12 @@ ahci_atapi_start(struct ata_channel *chp
struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
struct ahci_cmd_tbl *cmd_tbl;
struct ahci_cmd_header *cmd_h;
- int i;
AHCIDEBUG_PRINT(("ahci_atapi_start CI 0x%x\n",
AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))), DEBUG_XFERS);
+ ata_channel_lock_owned(chp);
+
cmd_tbl = achp->ahcic_cmd_tbl[xfer->c_slot];
AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
cmd_tbl), DEBUG_XFERS);
@@ -1837,8 +1880,7 @@ ahci_atapi_start(struct ata_channel *chp
(sc_xfer->xs_control & XS_CTL_DATA_IN) ?
BUS_DMA_READ : BUS_DMA_WRITE)) {
sc_xfer->error = XS_DRIVER_STUFFUP;
- xfer->c_intr(chp, xfer, 0);
- return;
+ return ATASTART_ABORT;
}
cmd_h->cmdh_flags = htole16(
((sc_xfer->xs_control & XS_CTL_DATA_OUT) ? AHCI_CMDH_F_WR : 0) |
@@ -1861,13 +1903,22 @@ ahci_atapi_start(struct ata_channel *chp
if ((xfer->c_flags & C_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
ata_timeout, xfer);
- return;
- }
+ return ATASTART_STARTED;
+ } else
+ return ATASTART_POLL;
+}
+
+static void
+ahci_atapi_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
+ struct ahci_channel *achp = (struct ahci_channel *)chp;
+
/*
* Polled command.
*/
- for (i = 0; i < ATA_DELAY / 10; i++) {
- if (sc_xfer->xs_status & XS_STS_DONE)
+ for (int i = 0; i < ATA_DELAY / 10; i++) {
+ if (xfer->c_scsipi->xs_status & XS_STS_DONE)
break;
ahci_intr_port(sc, achp);
delay(10000);
@@ -1881,14 +1932,20 @@ ahci_atapi_start(struct ata_channel *chp
AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)),
AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
DEBUG_XFERS);
- if ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
- sc_xfer->error = XS_TIMEOUT;
+ if ((xfer->c_scsipi->xs_status & XS_STS_DONE) == 0) {
+ xfer->c_scsipi->error = XS_TIMEOUT;
xfer->c_intr(chp, xfer, 0);
}
/* reenable interrupts */
AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
}
+static void
+ahci_atapi_abort(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ ahci_atapi_complete(chp, xfer, 0);
+}
+
static int
ahci_atapi_complete(struct ata_channel *chp, struct ata_xfer *xfer, int tfd)
{
@@ -1908,8 +1965,6 @@ ahci_atapi_complete(struct ata_channel *
if (xfer->c_flags & C_TIMEOU) {
sc_xfer->error = XS_TIMEOUT;
- } else if ((AHCI_TFD_ST(tfd) & WDCS_ERR) == 0) {
- sc_xfer->error = XS_NOERROR;
}
if (xfer->c_bcount > 0) {
Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.35.6.24 src/sys/dev/ic/mvsata.c:1.35.6.25
--- src/sys/dev/ic/mvsata.c:1.35.6.24 Sun Sep 10 18:37:21 2017
+++ src/sys/dev/ic/mvsata.c Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsata.c,v 1.35.6.24 2017/09/10 18:37:21 jdolecek Exp $ */
+/* $NetBSD: mvsata.c,v 1.35.6.25 2017/09/10 19:31:15 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.24 2017/09/10 18:37:21 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.25 2017/09/10 19:31:15 jdolecek Exp $");
#include "opt_mvsata.h"
@@ -129,21 +129,24 @@ static void mvsata_atapi_kill_pending(st
static void mvsata_setup_channel(struct ata_channel *);
#ifndef MVSATA_WITHOUTDMA
-static void mvsata_bio_start(struct ata_channel *, struct ata_xfer *);
+static int mvsata_bio_start(struct ata_channel *, struct ata_xfer *);
static int mvsata_bio_intr(struct ata_channel *, struct ata_xfer *, int);
+static void mvsata_bio_poll(struct ata_channel *, struct ata_xfer *);
static void mvsata_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
static void mvsata_bio_done(struct ata_channel *, struct ata_xfer *);
static int mvsata_bio_ready(struct mvsata_port *, struct ata_bio *, int,
int);
-static void mvsata_wdc_cmd_start(struct ata_channel *, struct ata_xfer *);
+static int mvsata_wdc_cmd_start(struct ata_channel *, struct ata_xfer *);
static int mvsata_wdc_cmd_intr(struct ata_channel *, struct ata_xfer *, int);
+static void mvsata_wdc_cmd_poll(struct ata_channel *, struct ata_xfer *);
static void mvsata_wdc_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *,
int);
-static void mvsata_wdc_cmd_done(struct ata_channel *, struct ata_xfer *, int);
+static void mvsata_wdc_cmd_done(struct ata_channel *, struct ata_xfer *);
static void mvsata_wdc_cmd_done_end(struct ata_channel *, struct ata_xfer *);
#if NATAPIBUS > 0
-static void mvsata_atapi_start(struct ata_channel *, struct ata_xfer *);
+static int mvsata_atapi_start(struct ata_channel *, struct ata_xfer *);
static int mvsata_atapi_intr(struct ata_channel *, struct ata_xfer *, int);
+static void mvsata_atapi_poll(struct ata_channel *, struct ata_xfer *);
static void mvsata_atapi_kill_xfer(struct ata_channel *, struct ata_xfer *,
int);
static void mvsata_atapi_reset(struct ata_channel *, struct ata_xfer *);
@@ -1088,12 +1091,14 @@ mvsata_bio(struct ata_drive_datas *drvp,
xfer->c_bcount = ata_bio->bcount;
xfer->c_start = mvsata_bio_start;
xfer->c_intr = mvsata_bio_intr;
+ xfer->c_poll = mvsata_bio_poll;
+ xfer->c_abort = mvsata_bio_done;
xfer->c_kill_xfer = mvsata_bio_kill_xfer;
ata_exec_xfer(chp, xfer);
return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED;
}
-static void
+static int
mvsata_bio_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct mvsata_port *mvport = (struct mvsata_port *)chp;
@@ -1110,6 +1115,8 @@ mvsata_bio_start(struct ata_channel *chp
DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("%s:%d: mvsata_bio_start: drive=%d\n",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive));
+ ata_channel_lock_owned(chp);
+
if (xfer->c_flags & C_DMA)
if (drvp->n_xfers <= NXFER)
drvp->n_xfers++;
@@ -1185,8 +1192,7 @@ mvsata_bio_start(struct ata_channel *chp
}
ata_bio->error = ERR_DMA;
ata_bio->r_error = 0;
- mvsata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
chp->ch_flags |= ATACH_DMA_WAIT;
/* start timeout machinery */
@@ -1248,13 +1254,11 @@ do_pio:
*/
if ((xfer->c_flags & C_POLL) == 0 &&
(chp->ch_flags & ATACH_TH_RUN) == 0) {
- ata_thread_wake(chp);
- return;
+ return ATASTART_TH;
}
if (mvsata_bio_ready(mvport, ata_bio, xfer->c_drive,
(xfer->c_flags & C_POLL) ? AT_POLL : 0) != 0) {
- mvsata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
}
@@ -1266,7 +1270,7 @@ do_pio:
case WDCWAIT_TOUT:
goto timeout;
case WDCWAIT_THR:
- return;
+ return ATASTART_TH;
}
if (ata_bio->flags & ATA_LBA48)
wdccommandext(chp, 0, atacmd_to48(cmd),
@@ -1302,14 +1306,13 @@ do_pio:
chp->ch_channel, xfer->c_drive, ATACH_ST(tfd),
ATACH_ERR(tfd));
ata_bio->error = TIMEOUT;
- mvsata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
if (ATACH_ST(tfd) & WDCS_ERR) {
ata_bio->error = ERROR;
ata_bio->r_error = ATACH_ERR(tfd);
mvsata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
}
wdc->dataout_pio(chp, drvp->drive_flags,
@@ -1318,26 +1321,35 @@ do_pio:
intr:
/* Wait for IRQ (either real or polled) */
- if ((ata_bio->flags & ATA_POLL) != 0) {
- /* Wait for at last 400ns for status bit to be valid */
- delay(1);
- if (chp->ch_flags & ATACH_DMA_WAIT) {
- mvsata_edma_wait(mvport, xfer, ATA_DELAY);
- sc->sc_enable_intr(mvport, 1 /*on*/);
- chp->ch_flags &= ~ATACH_DMA_WAIT;
- }
- if ((ata_bio->flags & ATA_ITSDONE) == 0)
- mvsata_bio_intr(chp, xfer, 0);
- }
- return;
+ if ((ata_bio->flags & ATA_POLL) != 0)
+ return ATASTART_POLL;
+ else
+ return ATASTART_STARTED;
timeout:
aprint_error_dev(atac->atac_dev,
"channel %d: drive %d not ready, st=0x%02x, err=0x%02x\n",
chp->ch_channel, xfer->c_drive, ATACH_ST(tfd), ATACH_ERR(tfd));
ata_bio->error = TIMEOUT;
- mvsata_bio_done(chp, xfer);
- return;
+ return ATASTART_ABORT;
+}
+
+static void
+mvsata_bio_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ struct mvsata_port *mvport = (struct mvsata_port *)chp;
+ struct mvsata_softc *sc = device_private(MVSATA_DEV2(mvport));
+
+ /* Wait for at last 400ns for status bit to be valid */
+ delay(1);
+ if (chp->ch_flags & ATACH_DMA_WAIT) {
+ mvsata_edma_wait(mvport, xfer, ATA_DELAY);
+ sc->sc_enable_intr(mvport, 1 /*on*/);
+ chp->ch_flags &= ~ATACH_DMA_WAIT;
+ }
+
+ if ((xfer->c_bio.flags & ATA_ITSDONE) == 0)
+ mvsata_bio_intr(chp, xfer, 0);
}
static int
@@ -1353,6 +1365,8 @@ mvsata_bio_intr(struct ata_channel *chp,
device_xname(atac->atac_dev), chp->ch_channel, __func__,
xfer->c_drive));
+ ata_channel_lock(chp);
+
chp->ch_flags &= ~(ATACH_DMA_WAIT);
/*
@@ -1361,6 +1375,7 @@ mvsata_bio_intr(struct ata_channel *chp,
*/
if (xfer->c_flags & C_TIMEOU) {
ata_bio->error = TIMEOUT;
+ ata_channel_unlock(chp);
mvsata_bio_done(chp, xfer);
return 1;
}
@@ -1384,6 +1399,7 @@ mvsata_bio_intr(struct ata_channel *chp,
chp->ch_channel, xfer->c_drive, xfer->c_bcount,
xfer->c_skip);
ata_bio->error = TIMEOUT;
+ ata_channel_unlock(chp);
mvsata_bio_done(chp, xfer);
return 1;
}
@@ -1398,6 +1414,7 @@ mvsata_bio_intr(struct ata_channel *chp,
/* if we had an error, end */
if (ata_bio->error != NOERROR) {
+ ata_channel_unlock(chp);
mvsata_bio_done(chp, xfer);
return 1;
}
@@ -1409,6 +1426,7 @@ mvsata_bio_intr(struct ata_channel *chp,
"channel %d: drive %d read intr before drq\n",
chp->ch_channel, xfer->c_drive);
ata_bio->error = TIMEOUT;
+ ata_channel_unlock(chp);
mvsata_bio_done(chp, xfer);
return 1;
}
@@ -1421,16 +1439,19 @@ end:
ata_bio->blkdone += ata_bio->nblks;
xfer->c_skip += ata_bio->nbytes;
xfer->c_bcount -= ata_bio->nbytes;
+
/* See if this transfer is complete. */
if (xfer->c_bcount > 0) {
- if ((ata_bio->flags & ATA_POLL) == 0)
+ if ((ata_bio->flags & ATA_POLL) == 0) {
/* Start the next operation */
- mvsata_bio_start(chp, xfer);
- else
+ ata_xfer_start(xfer);
+ } else {
/* Let mvsata_bio_start do the loop */
- return 1;
+ }
+ ata_channel_unlock(chp);
} else { /* Done with this transfer */
ata_bio->error = NOERROR;
+ ata_channel_unlock(chp);
mvsata_bio_done(chp, xfer);
}
return 1;
@@ -1654,6 +1675,8 @@ mvsata_exec_command(struct ata_drive_dat
xfer->c_bcount = ata_c->bcount;
xfer->c_start = mvsata_wdc_cmd_start;
xfer->c_intr = mvsata_wdc_cmd_intr;
+ xfer->c_poll = mvsata_wdc_cmd_poll;
+ xfer->c_abort = mvsata_wdc_cmd_done;
xfer->c_kill_xfer = mvsata_wdc_cmd_kill_xfer;
s = splbio();
ata_exec_xfer(chp, xfer);
@@ -1676,7 +1699,7 @@ mvsata_exec_command(struct ata_drive_dat
return rv;
}
-static void
+static int
mvsata_wdc_cmd_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct mvsata_port *mvport = (struct mvsata_port *)chp;
@@ -1689,6 +1712,8 @@ mvsata_wdc_cmd_start(struct ata_channel
("%s:%d: mvsata_cmd_start: drive=%d\n",
device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, drive));
+ ata_channel_lock_owned(chp);
+
/* First, EDMA disable, if enabled this channel. */
KASSERT((chp->ch_flags & ATACH_NCQ) == 0);
if (mvport->port_edmamode_curr != nodma)
@@ -1703,10 +1728,9 @@ mvsata_wdc_cmd_start(struct ata_channel
break;
case WDCWAIT_TOUT:
ata_c->flags |= AT_TIMEOU;
- mvsata_wdc_cmd_done(chp, xfer, tfd);
- return;
+ return ATASTART_ABORT;
case WDCWAIT_THR:
- return;
+ return ATASTART_TH;
}
if (ata_c->flags & AT_POLL)
/* polled command, disable interrupts */
@@ -1728,8 +1752,15 @@ mvsata_wdc_cmd_start(struct ata_channel
if ((ata_c->flags & AT_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz,
wdctimeout, xfer);
- return;
+ return ATASTART_STARTED;
}
+
+ return ATASTART_POLL;
+}
+
+static void
+mvsata_wdc_cmd_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
/*
* Polled command. Wait for drive ready or drq. Done in intr().
* Wait for at last 400ns for status bit to be valid.
@@ -1750,6 +1781,8 @@ mvsata_wdc_cmd_intr(struct ata_channel *
int drive_flags;
int tfd;
+ ata_channel_lock(chp);
+
if (ata_c->r_command == WDCC_IDENTIFY ||
ata_c->r_command == ATAPI_IDENTIFY_DEVICE)
/*
@@ -1795,16 +1828,20 @@ again:
if (wdcwait(chp, ata_c->r_st_bmask | WDCS_DRQ,
ata_c->r_st_bmask, (irq == 0) ? ata_c->timeout : 0,
wflags, &tfd) == WDCWAIT_TOUT) {
- if (irq && (xfer->c_flags & C_TIMEOU) == 0)
+ if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
+ ata_channel_unlock(chp);
return 0; /* IRQ was not for us */
+ }
ata_c->flags |= AT_TIMEOU;
}
goto out;
}
if (wdcwait(chp, ata_c->r_st_pmask, ata_c->r_st_pmask,
(irq == 0) ? ata_c->timeout : 0, wflags, &tfd) == WDCWAIT_TOUT) {
- if (irq && (xfer->c_flags & C_TIMEOU) == 0)
- return 0; /* IRQ was not for us */
+ if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
+ ata_channel_unlock(chp);
+ return 0; /* IRQ was not for us */
+ }
ata_c->flags |= AT_TIMEOU;
goto out;
}
@@ -1831,12 +1868,24 @@ again:
if ((ata_c->flags & AT_POLL) == 0) {
callout_reset(&xfer->c_timo_callout,
mstohz(ata_c->timeout), wdctimeout, xfer);
+ ata_channel_unlock(chp);
return 1;
} else
goto again;
}
out:
- mvsata_wdc_cmd_done(chp, xfer, tfd);
+ if (ATACH_ST(tfd) & WDCS_DWF)
+ ata_c->flags |= AT_DF;
+ if (ATACH_ST(tfd) & WDCS_ERR) {
+ ata_c->flags |= AT_ERROR;
+ ata_c->r_error = ATACH_ERR(tfd);
+ }
+ ata_channel_unlock(chp);
+ mvsata_wdc_cmd_done(chp, xfer);
+
+ if ((ATACH_ST(tfd) & WDCS_ERR) == 0)
+ atastart(chp);
+
return 1;
}
@@ -1880,7 +1929,7 @@ mvsata_wdc_cmd_kill_xfer(struct ata_chan
}
static void
-mvsata_wdc_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer, int tfd)
+mvsata_wdc_cmd_done(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct mvsata_port *mvport = (struct mvsata_port *)chp;
struct atac_softc *atac = chp->ch_atac;
@@ -1894,12 +1943,6 @@ mvsata_wdc_cmd_done(struct ata_channel *
if (ata_waitdrain_xfer_check(chp, xfer))
return;
- if (ATACH_ST(tfd) & WDCS_DWF)
- ata_c->flags |= AT_DF;
- if (ATACH_ST(tfd) & WDCS_ERR) {
- ata_c->flags |= AT_ERROR;
- ata_c->r_error = ATACH_ERR(tfd);
- }
if ((ata_c->flags & AT_READREG) != 0 &&
device_is_active(atac->atac_dev) &&
(ata_c->flags & (AT_ERROR | AT_DF)) == 0) {
@@ -1952,8 +1995,6 @@ mvsata_wdc_cmd_done(struct ata_channel *
}
mvsata_wdc_cmd_done_end(chp, xfer);
- if ((ATACH_ST(tfd) & WDCS_ERR) == 0)
- atastart(chp);
}
static void
@@ -2017,6 +2058,8 @@ mvsata_atapi_scsipi_request(struct scsip
xfer->c_bcount = sc_xfer->datalen;
xfer->c_start = mvsata_atapi_start;
xfer->c_intr = mvsata_atapi_intr;
+ xfer->c_poll = mvsata_atapi_poll;
+ xfer->c_abort = mvsata_atapi_reset;
xfer->c_kill_xfer = mvsata_atapi_kill_xfer;
xfer->c_dscpoll = 0;
s = splbio();
@@ -2036,7 +2079,7 @@ mvsata_atapi_scsipi_request(struct scsip
}
}
-static void
+static int
mvsata_atapi_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct mvsata_softc *sc = (struct mvsata_softc *)chp->ch_atac;
@@ -2053,6 +2096,8 @@ mvsata_atapi_start(struct ata_channel *c
device_xname(chp->ch_atac->atac_dev), chp->ch_channel,
xfer->c_drive, sc_xfer->xs_control));
+ ata_channel_lock_owned(chp);
+
KASSERT((chp->ch_flags & ATACH_NCQ) == 0);
if (mvport->port_edmamode_curr != nodma)
mvsata_edma_disable(mvport, 10 /* ms */, wait_flags);
@@ -2067,8 +2112,7 @@ mvsata_atapi_start(struct ata_channel *c
/* If it's not a polled command, we need the kernel thread */
if ((sc_xfer->xs_control & XS_CTL_POLL) == 0 &&
(chp->ch_flags & ATACH_TH_RUN) == 0) {
- ata_thread_wake(chp);
- return;
+ return ATASTART_TH;
}
/*
* disable interrupts, all commands here should be quick
@@ -2154,11 +2198,11 @@ ready:
wdctimeout, xfer);
MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM);
- if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd)) {
+ if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd) != 0) {
aprint_error_dev(atac->atac_dev, "not ready, st = %02x\n",
ATACH_ST(tfd));
sc_xfer->error = XS_TIMEOUT;
- mvsata_atapi_reset(chp, xfer);
+ return ATASTART_ABORT;
}
/*
@@ -2176,27 +2220,13 @@ ready:
/*
* If there is no interrupt for CMD input, busy-wait for it (done in
- * the interrupt routine. If it is a polled command, call the interrupt
- * routine until command is done.
+ * the interrupt routine. Poll routine will exit early in this case.
*/
if ((sc_xfer->xs_periph->periph_cap & ATAPI_CFG_DRQ_MASK) !=
- ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL)) {
- /* Wait for at last 400ns for status bit to be valid */
- DELAY(1);
- mvsata_atapi_intr(chp, xfer, 0);
- }
- if (sc_xfer->xs_control & XS_CTL_POLL) {
- if (chp->ch_flags & ATACH_DMA_WAIT) {
- wdc_dmawait(chp, xfer, sc_xfer->timeout);
- chp->ch_flags &= ~ATACH_DMA_WAIT;
- }
- while ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
- /* Wait for at last 400ns for status bit to be valid */
- DELAY(1);
- mvsata_atapi_intr(chp, xfer, 0);
- }
- }
- return;
+ ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL))
+ return ATASTART_POLL;
+ else
+ return ATASTART_STARTED;
timeout:
aprint_error_dev(atac->atac_dev, "channel %d drive %d: %s timed out\n",
@@ -2204,8 +2234,7 @@ timeout:
sc_xfer->error = XS_TIMEOUT;
MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_4BIT);
delay(10); /* some drives need a little delay here */
- mvsata_atapi_reset(chp, xfer);
- return;
+ return ATASTART_ABORT;
error:
aprint_error_dev(atac->atac_dev,
@@ -2215,8 +2244,36 @@ error:
sc_xfer->sense.atapi_sense = ATACH_ERR(tfd);
MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_4BIT);
delay(10); /* some drives need a little delay here */
- mvsata_atapi_reset(chp, xfer);
- return;
+ return ATASTART_ABORT;
+}
+
+static void
+mvsata_atapi_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ /*
+ * If there is no interrupt for CMD input, busy-wait for it (done in
+ * the interrupt routine. If it is a polled command, call the interrupt
+ * routine until command is done.
+ */
+ const bool poll = ((xfer->c_scsipi->xs_control & XS_CTL_POLL) != 0);
+
+ /* Wait for at last 400ns for status bit to be valid */
+ DELAY(1);
+ mvsata_atapi_intr(chp, xfer, 0);
+
+ if (!poll)
+ return;
+
+ if (chp->ch_flags & ATACH_DMA_WAIT) {
+ wdc_dmawait(chp, xfer, xfer->c_scsipi->timeout);
+ chp->ch_flags &= ~ATACH_DMA_WAIT;
+ }
+
+ while ((xfer->c_scsipi->xs_status & XS_STS_DONE) == 0) {
+ /* Wait for at last 400ns for status bit to be valid */
+ DELAY(1);
+ mvsata_atapi_intr(chp, xfer, 0);
+ }
}
static int
@@ -2231,6 +2288,8 @@ mvsata_atapi_intr(struct ata_channel *ch
int tfd;
void *cmd;
+ ata_channel_lock(chp);
+
DPRINTF(DEBUG_FUNCS|DEBUG_XFERS,
("%s:%d:%d: mvsata_atapi_intr\n",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive));
@@ -2247,6 +2306,7 @@ mvsata_atapi_intr(struct ata_channel *ch
* Don't try to continue transfer, we may have missed cycles.
*/
if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) {
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
mvsata_atapi_reset(chp, xfer);
return 1;
@@ -2256,14 +2316,17 @@ mvsata_atapi_intr(struct ata_channel *ch
MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM);
if (wdc_wait_for_unbusy(chp,
(irq == 0) ? sc_xfer->timeout : 0, AT_POLL, &tfd) == WDCWAIT_TOUT) {
- if (irq && (xfer->c_flags & C_TIMEOU) == 0)
+ if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
+ ata_channel_unlock(chp);
return 0; /* IRQ was not for us */
+ }
aprint_error_dev(atac->atac_dev,
"channel %d: device timeout, c_bcount=%d, c_skip=%d\n",
chp->ch_channel, xfer->c_bcount, xfer->c_skip);
if (xfer->c_flags & C_DMA)
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
mvsata_atapi_reset(chp, xfer);
return 1;
@@ -2275,6 +2338,7 @@ mvsata_atapi_intr(struct ata_channel *ch
*/
if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) {
ata_dmaerr(drvp, (xfer->c_flags & C_POLL) ? AT_POLL : 0);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_RESET;
mvsata_atapi_reset(chp, xfer);
return (1);
@@ -2324,6 +2388,7 @@ again:
mvsata_bdma_start(mvport);
chp->ch_flags |= ATACH_DMA_WAIT;
}
+ ata_channel_unlock(chp);
return 1;
case PHASE_DATAOUT:
@@ -2358,6 +2423,7 @@ again:
xfer->c_skip += len;
xfer->c_bcount -= len;
+ ata_channel_unlock(chp);
return 1;
case PHASE_DATAIN:
@@ -2371,6 +2437,7 @@ again:
if (xfer->c_flags & C_DMA)
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
mvsata_atapi_reset(chp, xfer);
return 1;
@@ -2392,6 +2459,7 @@ again:
xfer->c_skip += len;
xfer->c_bcount -= len;
+ ata_channel_unlock(chp);
return 1;
case PHASE_ABORTED:
@@ -2400,6 +2468,7 @@ again:
if (xfer->c_flags & C_DMA)
xfer->c_bcount -= sc_xfer->datalen;
sc_xfer->resid = xfer->c_bcount;
+ /* this will unlock channel lock too */
mvsata_atapi_phase_complete(xfer);
return 1;
@@ -2422,6 +2491,7 @@ again:
if (xfer->c_flags & C_DMA)
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_RESET;
mvsata_atapi_reset(chp, xfer);
return (1);
@@ -2431,6 +2501,7 @@ again:
("mvsata_atapi_intr: %s (end), error 0x%x "
"sense 0x%x\n", __func__,
sc_xfer->error, sc_xfer->sense.atapi_sense));
+ ata_channel_unlock(chp);
mvsata_atapi_done(chp, xfer);
return 1;
}
@@ -2481,6 +2552,8 @@ mvsata_atapi_reset(struct ata_channel *c
struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
int tfd;
+ ata_channel_lock(chp);
+
mvsata_pmp_select(mvport, xfer->c_drive);
wdccommandshort(chp, 0, ATAPI_SOFT_RESET);
@@ -2490,6 +2563,9 @@ mvsata_atapi_reset(struct ata_channel *c
chp->ch_channel, xfer->c_drive);
sc_xfer->error = XS_SELTIMEOUT;
}
+
+ ata_channel_unlock(chp);
+
mvsata_atapi_done(chp, xfer);
return;
}
@@ -2504,6 +2580,8 @@ mvsata_atapi_phase_complete(struct ata_x
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
int tfd;
+ ata_channel_lock_owned(chp);
+
/* wait for DSC if needed */
if (drvp->drive_flags & ATA_DRIVE_ATAPIDSCW) {
DPRINTF(DEBUG_XFERS,
@@ -2520,12 +2598,14 @@ mvsata_atapi_phase_complete(struct ata_x
aprint_error_dev(atac->atac_dev,
"channel %d: wait_for_dsc failed\n",
chp->ch_channel);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
mvsata_atapi_reset(chp, xfer);
- return;
- } else
+ } else {
callout_reset(&xfer->c_timo_callout, 1,
mvsata_atapi_polldsc, xfer);
+ ata_channel_unlock(chp);
+ }
return;
}
}
@@ -2550,6 +2630,7 @@ mvsata_atapi_phase_complete(struct ata_x
if (wdc->dma_status & (WDC_DMAST_NOIRQ | WDC_DMAST_ERR)) {
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_RESET;
mvsata_atapi_reset(chp, xfer);
return;
@@ -2575,6 +2656,7 @@ mvsata_atapi_phase_complete(struct ata_x
" mvsata_atapi_done(), error 0x%x sense 0x%x\n",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
sc_xfer->error, sc_xfer->sense.atapi_sense));
+ ata_channel_unlock(chp);
mvsata_atapi_done(chp, xfer);
}
@@ -2614,8 +2696,13 @@ mvsata_atapi_done(struct ata_channel *ch
static void
mvsata_atapi_polldsc(void *arg)
{
+ struct ata_xfer *xfer = arg;
+ struct ata_channel *chp = xfer->c_chp;
+
+ ata_channel_lock(chp);
- mvsata_atapi_phase_complete(arg);
+ /* this will unlock channel lock too */
+ mvsata_atapi_phase_complete(xfer);
}
#endif /* NATAPIBUS > 0 */
Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30.4.36 src/sys/dev/ic/siisata.c:1.30.4.37
--- src/sys/dev/ic/siisata.c:1.30.4.36 Tue Aug 15 20:12:28 2017
+++ src/sys/dev/ic/siisata.c Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.36 2017/08/15 20:12:28 jakllsch Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.37 2017/09/10 19:31:15 jdolecek Exp $ */
/* from ahcisata_core.c */
@@ -79,7 +79,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.36 2017/08/15 20:12:28 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.37 2017/09/10 19:31:15 jdolecek Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -147,14 +147,18 @@ int siisata_ata_addref(struct ata_drive_
void siisata_ata_delref(struct ata_drive_datas *);
void siisata_killpending(struct ata_drive_datas *);
-void siisata_cmd_start(struct ata_channel *, struct ata_xfer *);
+int siisata_cmd_start(struct ata_channel *, struct ata_xfer *);
int siisata_cmd_complete(struct ata_channel *, struct ata_xfer *, int);
+void siisata_cmd_poll(struct ata_channel *, struct ata_xfer *);
+void siisata_cmd_abort(struct ata_channel *, struct ata_xfer *);
void siisata_cmd_done(struct ata_channel *, struct ata_xfer *, int);
static void siisata_cmd_done_end(struct ata_channel *, struct ata_xfer *);
void siisata_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
-void siisata_bio_start(struct ata_channel *, struct ata_xfer *);
+int siisata_bio_start(struct ata_channel *, struct ata_xfer *);
int siisata_bio_complete(struct ata_channel *, struct ata_xfer *, int);
+void siisata_bio_poll(struct ata_channel *, struct ata_xfer *);
+void siisata_bio_abort(struct ata_channel *, struct ata_xfer *);
void siisata_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
int siisata_exec_command(struct ata_drive_datas *, struct ata_xfer *);
@@ -169,8 +173,10 @@ void siisata_channel_recover(struct ata_
void siisata_atapibus_attach(struct atabus_softc *);
void siisata_atapi_probe_device(struct atapibus_softc *, int);
void siisata_atapi_minphys(struct buf *);
-void siisata_atapi_start(struct ata_channel *,struct ata_xfer *);
+int siisata_atapi_start(struct ata_channel *,struct ata_xfer *);
int siisata_atapi_complete(struct ata_channel *, struct ata_xfer *, int);
+void siisata_atapi_poll(struct ata_channel *, struct ata_xfer *);
+void siisata_atapi_abort(struct ata_channel *, struct ata_xfer *);
void siisata_atapi_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
void siisata_atapi_scsipi_request(struct scsipi_channel *,
scsipi_adapter_req_t, void *);
@@ -979,6 +985,8 @@ siisata_exec_command(struct ata_drive_da
xfer->c_bcount = ata_c->bcount;
xfer->c_start = siisata_cmd_start;
xfer->c_intr = siisata_cmd_complete;
+ xfer->c_poll = siisata_cmd_poll;
+ xfer->c_abort = siisata_cmd_abort;
xfer->c_kill_xfer = siisata_cmd_kill_xfer;
s = splbio();
ata_exec_xfer(chp, xfer);
@@ -1010,19 +1018,20 @@ siisata_exec_command(struct ata_drive_da
return ret;
}
-void
+int
siisata_cmd_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct siisata_channel *schp = (struct siisata_channel *)chp;
struct ata_command *ata_c = &xfer->c_ata_c;
struct siisata_prb *prb;
- int i;
SIISATA_DEBUG_PRINT(("%s: %s port %d drive %d command 0x%x, slot %d\n",
SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__,
chp->ch_channel, xfer->c_drive, ata_c->r_command, xfer->c_slot),
DEBUG_FUNCS|DEBUG_XFERS);
+ ata_channel_lock_owned(chp);
+
prb = schp->sch_prb[xfer->c_slot];
memset(prb, 0, SIISATA_CMD_SIZE);
@@ -1040,8 +1049,7 @@ siisata_cmd_start(struct ata_channel *ch
ata_c->bcount,
(ata_c->flags & AT_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) {
ata_c->flags |= AT_DF;
- siisata_cmd_complete(chp, xfer, 0);
- return;
+ return ATASTART_ABORT;
}
if (xfer->c_flags & C_POLL) {
@@ -1056,30 +1064,42 @@ siisata_cmd_start(struct ata_channel *ch
if ((ata_c->flags & AT_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),
ata_timeout, xfer);
- goto out;
- }
+ return ATASTART_STARTED;
+ } else
+ return ATASTART_POLL;
+}
+
+void
+siisata_cmd_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ struct siisata_channel *schp = (struct siisata_channel *)chp;
/*
* polled command
*/
- for (i = 0; i < ata_c->timeout * 10; i++) {
- if (ata_c->flags & AT_DONE)
+ for (int i = 0; i < xfer->c_ata_c.timeout * 10; i++) {
+ if (xfer->c_ata_c.flags & AT_DONE)
break;
siisata_intr_port(schp);
DELAY(100);
}
- if ((ata_c->flags & AT_DONE) == 0) {
+ if ((xfer->c_ata_c.flags & AT_DONE) == 0) {
ata_timeout(xfer);
}
/* reenable interrupts */
siisata_enable_port_interrupt(chp);
-out:
+
SIISATA_DEBUG_PRINT(("%s: %s: done\n",
SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__),
DEBUG_FUNCS);
- return;
+}
+
+void
+siisata_cmd_abort(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ siisata_cmd_complete(chp, xfer, 0);
}
void
@@ -1228,24 +1248,27 @@ siisata_ata_bio(struct ata_drive_datas *
xfer->c_bcount = ata_bio->bcount;
xfer->c_start = siisata_bio_start;
xfer->c_intr = siisata_bio_complete;
+ xfer->c_poll = siisata_bio_poll;
+ xfer->c_abort = siisata_bio_abort;
xfer->c_kill_xfer = siisata_bio_kill_xfer;
ata_exec_xfer(chp, xfer);
return (ata_bio->flags & ATA_ITSDONE) ?
ATACMD_COMPLETE : ATACMD_QUEUED;
}
-void
+int
siisata_bio_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct siisata_channel *schp = (struct siisata_channel *)chp;
struct siisata_prb *prb;
struct ata_bio *ata_bio = &xfer->c_bio;
- int i;
SIISATA_DEBUG_PRINT(("%s: %s port %d slot %d drive %d\n",
SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__,
chp->ch_channel, xfer->c_slot, xfer->c_drive), DEBUG_FUNCS);
+ ata_channel_lock_owned(chp);
+
prb = schp->sch_prb[xfer->c_slot];
memset(prb, 0, SIISATA_CMD_SIZE);
@@ -1257,8 +1280,7 @@ siisata_bio_start(struct ata_channel *ch
(ata_bio->flags & ATA_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) {
ata_bio->error = ERR_DMA;
ata_bio->r_error = 0;
- siisata_bio_complete(chp, xfer, 0);
- return;
+ return ATASTART_ABORT;
}
if (xfer->c_flags & C_POLL) {
@@ -1272,29 +1294,41 @@ siisata_bio_start(struct ata_channel *ch
if ((ata_bio->flags & ATA_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),
ata_timeout, xfer);
- goto out;
- }
+ return ATASTART_STARTED;
+ } else
+ return ATASTART_POLL;
+}
+
+void
+siisata_bio_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ struct siisata_channel *schp = (struct siisata_channel *)chp;
/*
* polled command
*/
- for (i = 0; i < ATA_DELAY * 10; i++) {
- if (ata_bio->flags & ATA_ITSDONE)
+ for (int i = 0; i < ATA_DELAY * 10; i++) {
+ if (xfer->c_bio.flags & ATA_ITSDONE)
break;
siisata_intr_port(schp);
DELAY(100);
}
- if ((ata_bio->flags & ATA_ITSDONE) == 0) {
+ if ((xfer->c_bio.flags & ATA_ITSDONE) == 0) {
ata_timeout(xfer);
}
siisata_enable_port_interrupt(chp);
-out:
+
SIISATA_DEBUG_PRINT(("%s: %s: done\n",
SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__),
DEBUG_FUNCS);
- return;
+}
+
+void
+siisata_bio_abort(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ siisata_cmd_complete(chp, xfer, 0);
}
void
@@ -1797,6 +1831,8 @@ siisata_atapi_scsipi_request(struct scsi
xfer->c_bcount = sc_xfer->datalen;
xfer->c_start = siisata_atapi_start;
xfer->c_intr = siisata_atapi_complete;
+ xfer->c_poll = siisata_atapi_poll;
+ xfer->c_abort = siisata_atapi_abort;
xfer->c_kill_xfer = siisata_atapi_kill_xfer;
xfer->c_dscpoll = 0;
s = splbio();
@@ -1815,20 +1851,21 @@ siisata_atapi_scsipi_request(struct scsi
}
}
-void
+int
siisata_atapi_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct siisata_channel *schp = (struct siisata_channel *)chp;
struct siisata_prb *prbp;
struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
- int i;
SIISATA_DEBUG_PRINT( ("%s: %s:%d:%d, scsi flags 0x%x\n", __func__,
SIISATANAME((struct siisata_softc *)chp->ch_atac), chp->ch_channel,
chp->ch_drive[xfer->c_drive].drive, sc_xfer->xs_control),
DEBUG_XFERS);
+ ata_channel_lock_owned(chp);
+
prbp = schp->sch_prb[xfer->c_slot];
memset(prbp, 0, SIISATA_CMD_SIZE);
@@ -1851,8 +1888,10 @@ siisata_atapi_start(struct ata_channel *
xfer->c_bcount,
(sc_xfer->xs_control & XS_CTL_DATA_IN) ?
BUS_DMA_READ : BUS_DMA_WRITE)
- )
- panic("%s", __func__);
+ ) {
+ sc_xfer->error = XS_DRIVER_STUFFUP;
+ return ATASTART_ABORT;
+ }
if (xfer->c_flags & C_POLL) {
/* polled command, disable interrupts */
@@ -1865,28 +1904,40 @@ siisata_atapi_start(struct ata_channel *
if ((xfer->c_flags & C_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
ata_timeout, xfer);
- goto out;
- }
+ return ATASTART_STARTED;
+ } else
+ return ATASTART_POLL;
+}
+
+void
+siisata_atapi_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ struct siisata_channel *schp = (struct siisata_channel *)chp;
/*
* polled command
*/
- for (i = 0; i < ATA_DELAY * 10; i++) {
- if (sc_xfer->xs_status & XS_STS_DONE)
+ for (int i = 0; i < ATA_DELAY * 10; i++) {
+ if (xfer->c_scsipi->xs_status & XS_STS_DONE)
break;
siisata_intr_port(schp);
DELAY(100);
}
- if ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
+ if ((xfer->c_scsipi->xs_status & XS_STS_DONE) == 0) {
ata_timeout(xfer);
}
/* reenable interrupts */
siisata_enable_port_interrupt(chp);
-out:
+
SIISATA_DEBUG_PRINT(("%s: %s: done\n",
SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__),
- DEBUG_FUNCS);
- return;
+ DEBUG_FUNCS);
+}
+
+void
+siisata_atapi_abort(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ siisata_atapi_complete(chp, xfer, 0);
}
int
@@ -1909,8 +1960,6 @@ siisata_atapi_complete(struct ata_channe
if (xfer->c_flags & C_TIMEOU) {
sc_xfer->error = XS_TIMEOUT;
- } else if ((ATACH_ST(tfd) & WDCS_ERR) == 0) {
- sc_xfer->error = XS_NOERROR;
}
bus_dmamap_sync(sc->sc_dmat, schp->sch_datad[xfer->c_slot], 0,
Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.283.2.13 src/sys/dev/ic/wdc.c:1.283.2.14
--- src/sys/dev/ic/wdc.c:1.283.2.13 Sat Aug 12 14:41:54 2017
+++ src/sys/dev/ic/wdc.c Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wdc.c,v 1.283.2.13 2017/08/12 14:41:54 jdolecek Exp $ */
+/* $NetBSD: wdc.c,v 1.283.2.14 2017/09/10 19:31:15 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.13 2017/08/12 14:41:54 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.14 2017/09/10 19:31:15 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -146,11 +146,12 @@ static int wdcprobe1(struct ata_channel
static int wdcreset(struct ata_channel *, int);
static void __wdcerror(struct ata_channel *, const char *);
static int __wdcwait_reset(struct ata_channel *, int, int);
-static void __wdccommand_done(struct ata_channel *, struct ata_xfer *, int);
+static void __wdccommand_done(struct ata_channel *, struct ata_xfer *);
+static void __wdccommand_poll(struct ata_channel *, struct ata_xfer *);
static void __wdccommand_done_end(struct ata_channel *, struct ata_xfer *);
static void __wdccommand_kill_xfer(struct ata_channel *,
struct ata_xfer *, int);
-static void __wdccommand_start(struct ata_channel *, struct ata_xfer *);
+static int __wdccommand_start(struct ata_channel *, struct ata_xfer *);
static int __wdccommand_intr(struct ata_channel *, struct ata_xfer *, int);
static int __wdcwait(struct ata_channel *, int, int, int, int *);
@@ -1227,6 +1228,8 @@ wdcwait(struct ata_channel *chp, int mas
{
int error, i, timeout_hz = mstohz(timeout);
+ ata_channel_lock_owned(chp);
+
if (timeout_hz == 0 ||
(flags & (AT_WAIT | AT_POLL)) == AT_POLL)
error = __wdcwait(chp, mask, bits, timeout, tfd);
@@ -1245,14 +1248,14 @@ wdcwait(struct ata_channel *chp, int mas
error = 0;
break;
}
- tsleep(&chp, PRIBIO, "atapoll", 1);
+ kpause("atapoll", true, 1,
+ &chp->ch_lock);
}
} else {
/*
* we're probably in interrupt context,
- * ask the thread to come back here
+ * caller must ask the thread to come back here
*/
- ata_thread_wake(chp);
return(WDCWAIT_THR);
}
}
@@ -1301,10 +1304,10 @@ wdctimeout(void *arg)
s = splbio();
KASSERT(xfer != NULL);
- if (ata_timo_xfer_check(xfer)) {
- /* Already logged */
- goto out;
- }
+ if (ata_timo_xfer_check(xfer)) {
+ /* Already logged */
+ goto out;
+ }
__wdcerror(chp, "lost interrupt");
printf("\ttype: %s tc_bcount: %d tc_skip: %d\n",
@@ -1357,6 +1360,8 @@ wdc_exec_command(struct ata_drive_datas
xfer->c_databuf = ata_c->data;
xfer->c_bcount = ata_c->bcount;
xfer->c_start = __wdccommand_start;
+ xfer->c_poll = __wdccommand_poll;
+ xfer->c_abort = __wdccommand_done;
xfer->c_intr = __wdccommand_intr;
xfer->c_kill_xfer = __wdccommand_kill_xfer;
@@ -1383,7 +1388,7 @@ wdc_exec_command(struct ata_drive_datas
return ret;
}
-static void
+static int
__wdccommand_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
@@ -1407,10 +1412,9 @@ __wdccommand_start(struct ata_channel *c
break;
case WDCWAIT_TOUT:
ata_c->flags |= AT_TIMEOU;
- __wdccommand_done(chp, xfer, tfd);
- return;
+ return ATASTART_ABORT;
case WDCWAIT_THR:
- return;
+ return ATASTART_TH;
}
if (ata_c->flags & AT_POLL) {
/* polled command, disable interrupts */
@@ -1436,13 +1440,20 @@ __wdccommand_start(struct ata_channel *c
if ((ata_c->flags & AT_POLL) == 0) {
callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz,
wdctimeout, xfer);
- return;
+ return ATASTART_STARTED;
}
+
/*
* Polled command. Wait for drive ready or drq. Done in intr().
* Wait for at last 400ns for status bit to be valid.
*/
delay(10); /* 400ns delay */
+ return ATASTART_POLL;
+}
+
+static void
+__wdccommand_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
__wdccommand_intr(chp, xfer, 0);
}
@@ -1486,7 +1497,9 @@ __wdccommand_intr(struct ata_channel *ch
}
#endif
- again:
+ ata_channel_lock(chp);
+
+again:
ATADEBUG_PRINT(("__wdccommand_intr %s:%d:%d\n",
device_xname(chp->ch_atac->atac_dev), chp->ch_channel,
xfer->c_drive), DEBUG_INTR);
@@ -1508,16 +1521,20 @@ __wdccommand_intr(struct ata_channel *ch
if (wdcwait(chp, ata_c->r_st_bmask | WDCS_DRQ,
ata_c->r_st_bmask, (irq == 0) ? ata_c->timeout : 0,
wflags, &tfd) == WDCWAIT_TOUT) {
- if (irq && (xfer->c_flags & C_TIMEOU) == 0)
+ if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
+ ata_channel_unlock(chp);
return 0; /* IRQ was not for us */
+ }
ata_c->flags |= AT_TIMEOU;
}
goto out;
}
if (wdcwait(chp, ata_c->r_st_pmask, ata_c->r_st_pmask,
(irq == 0) ? ata_c->timeout : 0, wflags, &tfd) == WDCWAIT_TOUT) {
- if (irq && (xfer->c_flags & C_TIMEOU) == 0)
+ if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
+ ata_channel_unlock(chp);
return 0; /* IRQ was not for us */
+ }
ata_c->flags |= AT_TIMEOU;
goto out;
}
@@ -1545,18 +1562,28 @@ __wdccommand_intr(struct ata_channel *ch
if ((ata_c->flags & AT_POLL) == 0) {
callout_reset(&xfer->c_timo_callout,
mstohz(ata_c->timeout), wdctimeout, xfer);
+ ata_channel_unlock(chp);
return 1;
} else {
goto again;
}
}
- out:
- __wdccommand_done(chp, xfer, tfd);
+out:
+ if (ATACH_ST(tfd) & WDCS_DWF)
+ ata_c->flags |= AT_DF;
+ if (ATACH_ST(tfd) & WDCS_ERR) {
+ ata_c->flags |= AT_ERROR;
+ ata_c->r_error = ATACH_ST(tfd);
+ }
+
+ ata_channel_unlock(chp);
+
+ __wdccommand_done(chp, xfer);
return 1;
}
static void
-__wdccommand_done(struct ata_channel *chp, struct ata_xfer *xfer, int tfd)
+__wdccommand_done(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct atac_softc *atac = chp->ch_atac;
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
@@ -1573,12 +1600,6 @@ __wdccommand_done(struct ata_channel *ch
goto out;
}
- if (ATACH_ST(tfd) & WDCS_DWF)
- ata_c->flags |= AT_DF;
- if (ATACH_ST(tfd) & WDCS_ERR) {
- ata_c->flags |= AT_ERROR;
- ata_c->r_error = ATACH_ST(tfd);
- }
if ((ata_c->flags & AT_READREG) != 0 &&
device_is_active(atac->atac_dev) &&
(ata_c->flags & (AT_ERROR | AT_DF)) == 0) {
Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.12 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.13
--- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.12 Sat Aug 12 14:41:54 2017
+++ src/sys/dev/scsipi/atapi_wdc.c Sun Sep 10 19:31:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atapi_wdc.c,v 1.123.4.12 2017/08/12 14:41:54 jdolecek Exp $ */
+/* $NetBSD: atapi_wdc.c,v 1.123.4.13 2017/09/10 19:31:15 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.12 2017/08/12 14:41:54 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.13 2017/09/10 19:31:15 jdolecek Exp $");
#ifndef ATADEBUG
#define ATADEBUG
@@ -82,11 +82,12 @@ static int wdc_atapi_get_params(struct s
struct ataparams *);
static void wdc_atapi_probe_device(struct atapibus_softc *, int);
static void wdc_atapi_minphys (struct buf *bp);
-static void wdc_atapi_start(struct ata_channel *,struct ata_xfer *);
+static int wdc_atapi_start(struct ata_channel *,struct ata_xfer *);
static int wdc_atapi_intr(struct ata_channel *, struct ata_xfer *, int);
static void wdc_atapi_kill_xfer(struct ata_channel *,
struct ata_xfer *, int);
static void wdc_atapi_phase_complete(struct ata_xfer *);
+static void wdc_atapi_poll(struct ata_channel *, struct ata_xfer *);
static void wdc_atapi_done(struct ata_channel *, struct ata_xfer *);
static void wdc_atapi_reset(struct ata_channel *, struct ata_xfer *);
static void wdc_atapi_scsipi_request(struct scsipi_channel *,
@@ -453,6 +454,8 @@ wdc_atapi_scsipi_request(struct scsipi_c
xfer->c_bcount = sc_xfer->datalen;
xfer->c_start = wdc_atapi_start;
xfer->c_intr = wdc_atapi_intr;
+ xfer->c_poll = wdc_atapi_poll;
+ xfer->c_abort = wdc_atapi_reset;
xfer->c_kill_xfer = wdc_atapi_kill_xfer;
xfer->c_dscpoll = 0;
s = splbio();
@@ -472,7 +475,7 @@ wdc_atapi_scsipi_request(struct scsipi_c
}
}
-static void
+static int
wdc_atapi_start(struct ata_channel *chp, struct ata_xfer *xfer)
{
struct atac_softc *atac = chp->ch_atac;
@@ -487,6 +490,9 @@ wdc_atapi_start(struct ata_channel *chp,
ATADEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x \n",
device_xname(atac->atac_dev), chp->ch_channel, drvp->drive,
sc_xfer->xs_control), DEBUG_XFERS);
+
+ ata_channel_lock_owned(chp);
+
#if NATA_DMA
if ((xfer->c_flags & C_DMA) && (drvp->n_xfers <= NXFER))
drvp->n_xfers++;
@@ -496,8 +502,7 @@ wdc_atapi_start(struct ata_channel *chp,
/* If it's not a polled command, we need the kernel thread */
if ((sc_xfer->xs_control & XS_CTL_POLL) == 0 &&
(chp->ch_flags & ATACH_TH_RUN) == 0) {
- ata_thread_wake(chp);
- return;
+ return ATASTART_TH;
}
/*
* disable interrupts, all commands here should be quick
@@ -604,10 +609,9 @@ ready:
printf("wdc_atapi_start: not ready, st = %02x\n",
ATACH_ST(tfd));
sc_xfer->error = XS_TIMEOUT;
- wdc_atapi_reset(chp, xfer);
- return;
+ return ATASTART_ABORT;
case WDCWAIT_THR:
- return;
+ return ATASTART_TH;
}
/*
@@ -663,29 +667,14 @@ ready:
#endif
/*
* If there is no interrupt for CMD input, busy-wait for it (done in
- * the interrupt routine. If it is a polled command, call the interrupt
- * routine until command is done.
+ * the interrupt routine. Poll routine will exit early in this case.
*/
if ((sc_xfer->xs_periph->periph_cap & ATAPI_CFG_DRQ_MASK) !=
- ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL)) {
- /* Wait for at last 400ns for status bit to be valid */
- DELAY(1);
- wdc_atapi_intr(chp, xfer, 0);
- }
- if (sc_xfer->xs_control & XS_CTL_POLL) {
-#if NATA_DMA
- if (chp->ch_flags & ATACH_DMA_WAIT) {
- wdc_dmawait(chp, xfer, sc_xfer->timeout);
- chp->ch_flags &= ~ATACH_DMA_WAIT;
- }
-#endif
- while ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
- /* Wait for at last 400ns for status bit to be valid */
- DELAY(1);
- wdc_atapi_intr(chp, xfer, 0);
- }
- }
- return;
+ ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL))
+ return ATASTART_POLL;
+ else
+ return ATASTART_STARTED;
+
timeout:
printf("%s:%d:%d: %s timed out\n",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
@@ -693,8 +682,8 @@ timeout:
sc_xfer->error = XS_TIMEOUT;
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
delay(10); /* some drives need a little delay here */
- wdc_atapi_reset(chp, xfer);
- return;
+ return ATASTART_ABORT;
+
error:
printf("%s:%d:%d: %s ",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
@@ -704,8 +693,37 @@ error:
sc_xfer->sense.atapi_sense = ATACH_ERR(tfd);
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
delay(10); /* some drives need a little delay here */
- wdc_atapi_reset(chp, xfer);
- return;
+ return ATASTART_ABORT;
+}
+
+static void
+wdc_atapi_poll(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+ /*
+ * If there is no interrupt for CMD input, busy-wait for it (done in
+ * the interrupt routine. If it is a polled command, call the interrupt
+ * routine until command is done.
+ */
+ const bool poll = ((xfer->c_scsipi->xs_control & XS_CTL_POLL) != 0);
+
+ /* Wait for at last 400ns for status bit to be valid */
+ DELAY(1);
+ wdc_atapi_intr(chp, xfer, 0);
+
+ if (!poll)
+ return;
+
+#if NATA_DMA
+ if (chp->ch_flags & ATACH_DMA_WAIT) {
+ wdc_dmawait(chp, xfer, xfer->c_scsipi->timeout);
+ chp->ch_flags &= ~ATACH_DMA_WAIT;
+ }
+#endif
+ while ((xfer->c_scsipi->xs_status & XS_STS_DONE) == 0) {
+ /* Wait for at last 400ns for status bit to be valid */
+ DELAY(1);
+ wdc_atapi_intr(chp, xfer, 0);
+ }
}
static int
@@ -731,6 +749,8 @@ wdc_atapi_intr(struct ata_channel *chp,
device_xname(atac->atac_dev), chp->ch_channel, drvp->drive),
DEBUG_INTR);
+ ata_channel_lock(chp);
+
/* Is it not a transfer, but a control operation? */
if (drvp->state < READY) {
printf("%s:%d:%d: bad state %d in wdc_atapi_intr\n",
@@ -743,6 +763,7 @@ wdc_atapi_intr(struct ata_channel *chp,
* Don't try to continue transfer, we may have missed cycles.
*/
if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) {
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_reset(chp, xfer);
return 1;
@@ -772,8 +793,10 @@ wdc_atapi_intr(struct ata_channel *chp,
WDSD_IBM | (xfer->c_drive << 4));
if (wdc_wait_for_unbusy(chp,
poll ? sc_xfer->timeout : 0, AT_POLL, &tfd) == WDCWAIT_TOUT) {
- if (!poll && (xfer->c_flags & C_TIMEOU) == 0)
+ if (!poll && (xfer->c_flags & C_TIMEOU) == 0) {
+ ata_channel_unlock(chp);
return 0; /* IRQ was not for us */
+ }
printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",
device_xname(atac->atac_dev), chp->ch_channel,
xfer->c_drive, xfer->c_bcount, xfer->c_skip);
@@ -783,6 +806,7 @@ wdc_atapi_intr(struct ata_channel *chp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
}
#endif
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_reset(chp, xfer);
return 1;
@@ -797,6 +821,7 @@ wdc_atapi_intr(struct ata_channel *chp,
*/
if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) {
ata_dmaerr(drvp, (xfer->c_flags & C_POLL) ? AT_POLL : 0);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_RESET;
wdc_atapi_reset(chp, xfer);
return (1);
@@ -860,6 +885,7 @@ again:
chp->ch_flags |= ATACH_DMA_WAIT;
}
#endif
+ ata_channel_unlock(chp);
return 1;
case PHASE_DATAOUT:
@@ -873,6 +899,7 @@ again:
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
}
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_reset(chp, xfer);
return 1;
@@ -892,6 +919,7 @@ again:
chp->ch_channel, xfer->c_drive,
xfer->c_skip, len, WDC_PIOBM_XFER_IRQ);
chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT;
+ ata_channel_unlock(chp);
return 1;
}
#endif
@@ -907,6 +935,7 @@ again:
xfer->c_skip += len;
xfer->c_bcount -= len;
+ ata_channel_unlock(chp);
return 1;
case PHASE_DATAIN:
@@ -920,6 +949,7 @@ again:
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
}
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_reset(chp, xfer);
return 1;
@@ -939,6 +969,7 @@ again:
chp->ch_channel, xfer->c_drive,
xfer->c_skip, len, WDC_PIOBM_XFER_IRQ);
chp->ch_flags |= ATACH_DMA_WAIT | ATACH_PIOBM_WAIT;
+ ata_channel_unlock(chp);
return 1;
}
#endif
@@ -953,6 +984,7 @@ again:
xfer->c_skip += len;
xfer->c_bcount -= len;
+ ata_channel_unlock(chp);
return 1;
case PHASE_ABORTED:
@@ -964,6 +996,7 @@ again:
}
#endif
sc_xfer->resid = xfer->c_bcount;
+ /* this will unlock channel lock too */
wdc_atapi_phase_complete(xfer);
return(1);
@@ -989,6 +1022,7 @@ again:
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
}
#endif
+ ata_channel_unlock(chp);
sc_xfer->error = XS_RESET;
wdc_atapi_reset(chp, xfer);
return (1);
@@ -997,6 +1031,7 @@ again:
ATADEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done() (end), error 0x%x "
"sense 0x%x\n", sc_xfer->error, sc_xfer->sense.atapi_sense),
DEBUG_INTR);
+ ata_channel_unlock(chp);
wdc_atapi_done(chp, xfer);
return (1);
}
@@ -1013,6 +1048,8 @@ wdc_atapi_phase_complete(struct ata_xfer
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
int tfd;
+ ata_channel_lock_owned(chp);
+
/* wait for DSC if needed */
if (drvp->drive_flags & ATA_DRIVE_ATAPIDSCW) {
ATADEBUG_PRINT(("wdc_atapi_phase_complete(%s:%d:%d) "
@@ -1032,12 +1069,14 @@ wdc_atapi_phase_complete(struct ata_xfer
"failed\n",
device_xname(atac->atac_dev),
chp->ch_channel, xfer->c_drive);
+ ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_reset(chp, xfer);
- return;
- } else
+ } else {
callout_reset(&xfer->c_timo_callout, 1,
wdc_atapi_polldsc, xfer);
+ ata_channel_unlock(chp);
+ }
return;
}
}
@@ -1067,6 +1106,7 @@ wdc_atapi_phase_complete(struct ata_xfer
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
#endif
+ ata_channel_unlock(chp);
sc_xfer->error = XS_RESET;
wdc_atapi_reset(chp, xfer);
return;
@@ -1086,6 +1126,7 @@ wdc_atapi_phase_complete(struct ata_xfer
ATADEBUG_PRINT(("wdc_atapi_phase_complete: wdc_atapi_done(), "
"error 0x%x sense 0x%x\n", sc_xfer->error,
sc_xfer->sense.atapi_sense), DEBUG_INTR);
+ ata_channel_unlock(chp);
wdc_atapi_done(chp, xfer);
}
@@ -1120,6 +1161,7 @@ wdc_atapi_reset(struct ata_channel *chp,
struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
int tfd;
+ ata_channel_lock(chp);
wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET);
drvp->state = 0;
if (wdc_wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL, &tfd) != 0) {
@@ -1128,6 +1170,7 @@ wdc_atapi_reset(struct ata_channel *chp,
xfer->c_drive);
sc_xfer->error = XS_SELTIMEOUT;
}
+ ata_channel_unlock(chp);
wdc_atapi_done(chp, xfer);
return;
}
@@ -1135,6 +1178,11 @@ wdc_atapi_reset(struct ata_channel *chp,
static void
wdc_atapi_polldsc(void *arg)
{
+ struct ata_xfer *xfer = arg;
+ struct ata_channel *chp = xfer->c_chp;
+
+ ata_channel_lock(chp);
- wdc_atapi_phase_complete(arg);
+ /* this will unlock channel lock too */
+ wdc_atapi_phase_complete(xfer);
}