Module Name: src
Committed By: jdolecek
Date: Mon Sep 25 22:50:20 UTC 2017
Modified Files:
src/sys/dev/ic [jdolecek-ncq]: mvsata.c
Log Message:
move mvsata_quetag_get() to the start routines, so that it always matches
the active list of ata queue; important during error recovery, fixes
panics when calling
in mvsata_edma_handle() ignore events for non-active xfers
fix some missing ata_channel_unlock() on error path in mvsata_bio_intr()
and mvsata_atapi_intr(), fixes 'locking against myself' with LOCKDEBUG
with this, mvsata(4) finally survives full fio run with wdcdebug_wd_cnt == 200
To generate a diff of this commit:
cvs rdiff -u -r1.35.6.28 -r1.35.6.29 src/sys/dev/ic/mvsata.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/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.35.6.28 src/sys/dev/ic/mvsata.c:1.35.6.29
--- src/sys/dev/ic/mvsata.c:1.35.6.28 Fri Sep 22 20:19:08 2017
+++ src/sys/dev/ic/mvsata.c Mon Sep 25 22:50:20 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsata.c,v 1.35.6.28 2017/09/22 20:19:08 jdolecek Exp $ */
+/* $NetBSD: mvsata.c,v 1.35.6.29 2017/09/25 22:50:20 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.28 2017/09/22 20:19:08 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.29 2017/09/25 22:50:20 jdolecek Exp $");
#include "opt_mvsata.h"
@@ -1086,7 +1086,6 @@ static int
mvsata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
{
struct ata_channel *chp = drvp->chnl_softc;
- struct mvsata_port *mvport = (struct mvsata_port *)chp;
struct atac_softc *atac = chp->ch_atac;
struct ata_bio *ata_bio = &xfer->c_bio;
@@ -1095,8 +1094,6 @@ mvsata_bio(struct ata_drive_datas *drvp,
", bcount=%ld\n", device_xname(atac->atac_dev), chp->ch_channel,
drvp->drive, ata_bio->blkno, ata_bio->bcount));
- mvsata_quetag_get(mvport, xfer->c_slot);
-
if (atac->atac_cap & ATAC_CAP_NOIRQ)
ata_bio->flags |= ATA_POLL;
if (ata_bio->flags & ATA_POLL)
@@ -1135,6 +1132,8 @@ mvsata_bio_start(struct ata_channel *chp
ata_channel_lock_owned(chp);
+ mvsata_quetag_get(mvport, xfer->c_slot);
+
if (xfer->c_flags & C_DMA)
if (drvp->n_xfers <= NXFER)
drvp->n_xfers++;
@@ -1410,8 +1409,10 @@ mvsata_bio_intr(struct ata_channel *chp,
if (!(xfer->c_flags & C_DMA) &&
(wdc_wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 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: drive %d timeout, c_bcount=%d, c_skip%d\n",
chp->ch_channel, xfer->c_drive, xfer->c_bcount,
@@ -1570,6 +1571,8 @@ mvsata_bio_ready(struct mvsata_port *mvp
flags |= AT_POLL; /* XXX */
+ ata_channel_lock_owned(chp);
+
/*
* disable interrupts, all commands here should be quick
* enough to be able to poll, and we don't go here that often
@@ -1682,8 +1685,6 @@ mvsata_exec_command(struct ata_drive_dat
drvp->drive, ata_c->bcount, ata_c->r_lba, ata_c->r_count,
ata_c->r_features, ata_c->r_device, ata_c->r_command));
- mvsata_quetag_get(mvport, xfer->c_slot);
-
if (ata_c->flags & AT_POLL)
xfer->c_flags |= C_POLL;
if (ata_c->flags & AT_WAIT)
@@ -1736,6 +1737,8 @@ mvsata_wdc_cmd_start(struct ata_channel
ata_channel_lock_owned(chp);
+ mvsata_quetag_get(mvport, xfer->c_slot);
+
/* First, EDMA disable, if enabled this channel. */
KASSERT((chp->ch_flags & ATACH_NCQ) == 0);
if (mvport->port_edmamode_curr != nodma)
@@ -2050,7 +2053,6 @@ mvsata_atapi_scsipi_request(struct scsip
struct atac_softc *atac = &sc->sc_wdcdev.sc_atac;
struct ata_channel *chp = atac->atac_channels[chan->chan_channel];
struct ata_xfer *xfer;
- struct mvsata_port *mvport = (struct mvsata_port *)chp;
int drive, s;
switch (req) {
@@ -2071,8 +2073,6 @@ mvsata_atapi_scsipi_request(struct scsip
return;
}
- mvsata_quetag_get(mvport, xfer->c_slot);
-
if (sc_xfer->xs_control & XS_CTL_POLL)
xfer->c_flags |= C_POLL;
xfer->c_drive = drive;
@@ -2122,6 +2122,8 @@ mvsata_atapi_start(struct ata_channel *c
ata_channel_lock_owned(chp);
+ mvsata_quetag_get(mvport, xfer->c_slot);
+
KASSERT((chp->ch_flags & ATACH_NCQ) == 0);
if (mvport->port_edmamode_curr != nodma)
mvsata_edma_disable(mvport, 10 /* ms */, wait_flags);
@@ -2426,6 +2428,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;
@@ -2883,8 +2886,15 @@ mvsata_edma_handle(struct mvsata_port *m
mvsata_print_crpb(mvport, erpqop);
#endif
crpb = mvport->port_crpb + erpqop;
+ MVSATA_EDMAQ_INC(erpqop);
+
quetag = CRPB_CHOSTQUETAG(le16toh(crpb->id));
+ if ((mvport->port_quetagidx & __BIT(quetag)) == 0) {
+ /* not actually executing */
+ continue;
+ }
+
xfer = ata_queue_hwslot_to_xfer(chp, quetag);
bus_dmamap_sync(mvport->port_dmat, mvport->port_eprd_dmamap,
@@ -2905,7 +2915,6 @@ mvsata_edma_handle(struct mvsata_port *m
ata_bio->error = ERR_DMA;
mvsata_dma_bufunload(mvport, quetag, ata_bio->flags);
- MVSATA_EDMAQ_INC(erpqop);
#if 1 /* XXXX: flags clears here, because necessary the atabus layer. */
erqqip = (MVSATA_EDMA_READ_4(mvport, EDMA_REQQIP) &
@@ -3322,7 +3331,11 @@ static inline void
mvsata_quetag_get(struct mvsata_port *mvport, uint8_t quetag)
{
KASSERT(quetag <= 32);
- KASSERT((mvport->port_quetagidx & __BIT(quetag)) == 0);
+
+ /*
+ * Do not check whether it's already set, can happen when
+ * postponing bio or atapi xfer to thread.
+ */
mvport->port_quetagidx |= __BIT(quetag);
}