Module Name: src
Committed By: jdolecek
Date: Wed Apr 19 20:49:17 UTC 2017
Modified Files:
src/sys/dev/ata [jdolecek-ncq]: ata.c ata_wdc.c atavar.h satafis_subr.c
wd.c wdvar.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:
adjust ata code to support more than one active command, including the
timeout handling, add support for NCQ commands
move probe for NCQ and number of tags to middle layer, negotiate mutual
support between drive and controller
implement NCQ support in ahci(4)
To generate a diff of this commit:
cvs rdiff -u -r1.132.8.4 -r1.132.8.5 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.105.6.2 -r1.105.6.3 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.92.8.4 -r1.92.8.5 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.7.28.1 -r1.7.28.2 src/sys/dev/ata/satafis_subr.c
cvs rdiff -u -r1.428.2.6 -r1.428.2.7 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.43.4.3 -r1.43.4.4 src/sys/dev/ata/wdvar.h
cvs rdiff -u -r1.57.6.6 -r1.57.6.7 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35.6.5 -r1.35.6.6 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30.4.4 -r1.30.4.5 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283.2.3 -r1.283.2.4 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.123.4.3 -r1.123.4.4 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/ata.c
diff -u src/sys/dev/ata/ata.c:1.132.8.4 src/sys/dev/ata/ata.c:1.132.8.5
--- src/sys/dev/ata/ata.c:1.132.8.4 Sat Apr 15 17:14:11 2017
+++ src/sys/dev/ata/ata.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata.c,v 1.132.8.4 2017/04/15 17:14:11 jdolecek Exp $ */
+/* $NetBSD: ata.c,v 1.132.8.5 2017/04/19 20:49:17 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.4 2017/04/15 17:14:11 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.5 2017/04/19 20:49:17 jdolecek Exp $");
#include "opt_ata.h"
@@ -195,7 +195,7 @@ ata_queue_hwslot_to_xfer(struct ata_queu
struct ata_xfer *xfer;
KASSERT(hwslot < chq->queue_openings);
- KASSERT(hwslot == 0 || (chq->queue_xfers_avail & __BIT(hwslot)) == 0);
+ KASSERT((chq->active_xfers_used & __BIT(hwslot)) != 0);
/* Usually the first entry will be the one */
TAILQ_FOREACH(xfer, &chq->active_xfers, c_activechain) {
@@ -203,27 +203,71 @@ ata_queue_hwslot_to_xfer(struct ata_queu
return xfer;
}
- panic("%s: xfer with slot %d not found", __func__, hwslot);
+ panic("%s: xfer with slot %d not found (active %x)", __func__, hwslot,
+ chq->active_xfers_used);
+}
+
+void
+ata_xfer_init(struct ata_xfer *xfer, bool zero)
+{
+ if (zero)
+ memset(xfer, 0, sizeof(*xfer));
+
+ callout_init(&xfer->c_timo_callout, 0); /* XXX MPSAFE */
+}
+
+void
+ata_xfer_destroy(struct ata_xfer *xfer)
+{
+ callout_halt(&xfer->c_timo_callout, NULL); /* XXX MPSAFE */
+ callout_destroy(&xfer->c_timo_callout);
}
struct ata_queue *
-ata_queue_alloc(int openings)
+ata_queue_alloc(uint8_t openings)
{
if (openings == 0)
openings = 1;
+
+ /*
+ * While hw supports up to 32 tags, in practice we must never
+ * allow 32 active commands, since that would signal same as
+ * channel error. So just limit this to 31.
+ */
+ if (openings > 31)
+ openings = 31;
+
struct ata_queue *chq = malloc(offsetof(struct ata_queue, queue_xfers[openings]),
M_DEVBUF, M_WAITOK | M_ZERO);
- if (chq != NULL) {
- chq->queue_openings = openings;
- chq->queue_xfers_avail = (1 << openings) - 1;
- ata_queue_reset(chq);
- }
+
+ chq->queue_openings = openings;
+ chq->queue_xfers_avail = (1 << openings) - 1;
+ ata_queue_reset(chq);
+
+ for (uint8_t i = 0; i < openings; i++)
+ ata_xfer_init(&chq->queue_xfers[i], false);
+
return chq;
}
+static void
+ata_queue_downsize(struct ata_queue *chq, uint8_t openings)
+{
+ KASSERT(chq->queue_active == 0);
+ KASSERT(TAILQ_FIRST(&chq->queue_xfer) == NULL);
+ KASSERT(openings < chq->queue_openings);
+
+ chq->queue_openings = openings;
+ chq->queue_xfers_avail = (1 << openings) - 1;
+ ata_queue_reset(chq);
+}
+
void
ata_queue_free(struct ata_queue *chq)
{
+ for (uint8_t i = 0; i < chq->queue_openings; i++)
+ ata_xfer_destroy(&chq->queue_xfers[i]);
+
free(chq, M_DEVBUF);
}
@@ -240,11 +284,6 @@ ata_channel_attach(struct ata_channel *c
if (chp->ch_flags & ATACH_DISABLED)
return;
- /* XXX callout_destroy */
- callout_init(&chp->ch_callout, 0);
-
- chq->queue_openings = 1; /* XXX */
-
ata_queue_reset(chq);
chp->atabus = config_found_ia(chp->ch_atac->atac_dev, "ata", chp,
@@ -397,7 +436,6 @@ atabusconfig_thread(void *arg)
memset(&adev, 0, sizeof(struct ata_device));
adev.adev_bustype = atac->atac_bustype_ata;
adev.adev_channel = chp->ch_channel;
- adev.adev_openings = chp->ch_queue->queue_openings;
adev.adev_drv_data = &chp->ch_drive[i];
chp->ch_drive[i].drv_softc = config_found_ia(atabus_sc->sc_dev,
"ata_hl", &adev, ataprint);
@@ -787,7 +825,7 @@ ata_get_params(struct ata_drive_datas *d
tb = kmem_zalloc(DEV_BSIZE, KM_SLEEP);
memset(prms, 0, sizeof(struct ataparams));
- memset(&xfer, 0, sizeof(xfer));
+ ata_xfer_init(&xfer, true);
if (drvp->drive_type == ATA_DRIVET_ATA) {
xfer.c_ata_c.r_command = WDCC_IDENTIFY;
@@ -870,6 +908,7 @@ ata_get_params(struct ata_drive_datas *d
rv = CMD_OK;
out:
kmem_free(tb, DEV_BSIZE);
+ ata_xfer_destroy(&xfer);
return rv;
}
@@ -877,11 +916,13 @@ int
ata_set_mode(struct ata_drive_datas *drvp, uint8_t mode, uint8_t flags)
{
struct ata_xfer xfer;
+ int rv;
struct ata_channel *chp = drvp->chnl_softc;
struct atac_softc *atac = chp->ch_atac;
ATADEBUG_PRINT(("ata_set_mode=0x%x\n", mode), DEBUG_FUNCS);
- memset(&xfer, 0, sizeof(xfer));
+
+ ata_xfer_init(&xfer, true);
xfer.c_ata_c.r_command = SET_FEATURES;
xfer.c_ata_c.r_st_bmask = 0;
@@ -891,12 +932,20 @@ ata_set_mode(struct ata_drive_datas *drv
xfer.c_ata_c.flags = flags;
xfer.c_ata_c.timeout = 1000; /* 1s */
if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
- &xfer) != ATACMD_COMPLETE)
- return CMD_AGAIN;
+ &xfer) != ATACMD_COMPLETE) {
+ rv = CMD_AGAIN;
+ goto out;
+ }
if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
- return CMD_ERR;
+ rv = CMD_ERR;
+ goto out;
}
- return CMD_OK;
+
+ rv = CMD_OK;
+
+out:
+ ata_xfer_destroy(&xfer);
+ return rv;
}
#if NATA_DMA
@@ -990,7 +1039,7 @@ atastart(struct ata_channel *chp)
{
struct atac_softc *atac = chp->ch_atac;
struct ata_queue *chq = chp->ch_queue;
- struct ata_xfer *xfer;
+ struct ata_xfer *xfer, *axfer;
#ifdef ATA_DEBUG
int spl1, spl2;
@@ -1024,6 +1073,15 @@ atastart(struct ata_channel *chp)
KASSERT(chp->ch_ndrives == 1 || chq->queue_openings == 1);
+ /*
+ * Can only take NCQ command if there are no current active
+ * commands, or if the active commands are NCQ. Need only check
+ * first xfer.
+ */
+ axfer = TAILQ_FIRST(&chp->ch_queue->active_xfers);
+ if (axfer && (axfer->c_flags & C_NCQ) == 0)
+ return;
+
/* adjust chp, in case we have a shared queue */
chp = xfer->c_chp;
KASSERT(chp->ch_queue == chq);
@@ -1042,7 +1100,8 @@ atastart(struct ata_channel *chp)
return;
}
#ifdef DIAGNOSTIC
- if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0)
+ if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0
+ && chp->ch_queue->queue_openings == 1)
panic("atastart: channel waiting for irq");
#endif
ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d\n", xfer,
@@ -1077,7 +1136,9 @@ ata_get_xfer(struct ata_channel *chp)
xfer = &chq->queue_xfers[slot];
chq->queue_xfers_avail &= ~__BIT(slot);
- memset(xfer, 0, sizeof(struct ata_xfer));
+ /* zero everything after the callout member */
+ memset(&xfer->c_startzero, 0,
+ sizeof(struct ata_xfer) - offsetof(struct ata_xfer, c_startzero));
xfer->c_slot = slot;
out:
@@ -1137,8 +1198,7 @@ ata_deactivate_xfer(struct ata_channel *
KASSERT(chq->queue_active > 0);
KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);
- //if ((xfer->c_flags & C_TIMEOU) == 0)
- callout_stop(&chp->ch_callout);
+ callout_stop(&xfer->c_timo_callout);
TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
chq->active_xfers_used &= ~__BIT(xfer->c_slot);
@@ -1360,6 +1420,13 @@ ata_print_modes(struct ata_channel *chp)
#endif
)
aprint_verbose(" (using DMA)");
+
+ if (drvp->drive_flags & ATA_DRIVE_NCQ)
+ aprint_verbose(", NCQ (%d tags)",
+ chp->ch_queue->queue_openings);
+ else if (drvp->drive_flags & ATA_DRIVE_WFUA)
+ aprint_verbose(", WRITE DMA FUA EXT");
+
#endif /* NATA_DMA || NATA_PIOBM */
aprint_verbose("\n");
}
@@ -1433,7 +1500,7 @@ ata_probe_caps(struct ata_drive_datas *d
struct ata_channel *chp = drvp->chnl_softc;
struct atac_softc *atac = chp->ch_atac;
device_t drv_dev = drvp->drv_softc;
- int i, printed, s;
+ int i, printed = 0, s;
const char *sep = "";
int cf_flags;
@@ -1485,7 +1552,6 @@ ata_probe_caps(struct ata_drive_datas *d
*/
if (params.atap_extensions != 0xffff &&
(params.atap_extensions & WDC_EXT_MODES)) {
- printed = 0;
/*
* XXX some drives report something wrong here (they claim to
* support PIO mode 8 !). As mode is coded on 3 bits in
@@ -1610,7 +1676,6 @@ ata_probe_caps(struct ata_drive_datas *d
break;
}
}
- aprint_verbose("\n");
}
s = splbio();
@@ -1659,6 +1724,37 @@ ata_probe_caps(struct ata_drive_datas *d
}
splx(s);
}
+
+ /*
+ * Probe WRITE DMA FUA EXT. Support is mandatory for devices
+ * supporting LBA48, but nevertheless confirm with the feature flag.
+ */
+ if (drvp->drive_flags & ATA_DRIVE_DMA) {
+ if ((params.atap_cmd2_en & ATA_CMD2_LBA48) != 0
+ && (params.atap_cmd_def & ATA_CMDE_WFE)) {
+ drvp->drive_flags |= ATA_DRIVE_WFUA;
+ aprint_verbose("%s WRITE DMA FUA", sep);
+ sep = ",";
+ }
+ }
+
+ /* Probe NCQ support - READ/WRITE FPDMA QUEUED command support */
+ s = splbio();
+ drvp->drv_openings = 1;
+ if (params.atap_sata_caps & SATA_NATIVE_CMDQ) {
+ if (atac->atac_cap & ATAC_CAP_NCQ)
+ drvp->drive_flags |= ATA_DRIVE_NCQ;
+ drvp->drv_openings = (params.atap_queuedepth & 0x0f) + 1;
+ aprint_verbose("%s NCQ (%d tags)", sep, drvp->drv_openings);
+ sep = ",";
+ }
+ if (drvp->drv_openings < chp->ch_queue->queue_openings)
+ ata_queue_downsize(chp->ch_queue, drvp->drv_openings);
+ splx(s);
+
+ if (printed)
+ aprint_verbose("\n");
+
#if NATA_UDMA
if ((atac->atac_cap & ATAC_CAP_UDMA) == 0) {
/* don't care about UDMA modes */
@@ -1879,3 +1975,23 @@ ata_delay(int ms, const char *msg, int f
kpause(msg, false, mstohz(ms), NULL);
}
}
+
+void
+atacmd_toncq(struct ata_xfer *xfer, uint8_t *cmd, uint16_t *count,
+ uint16_t *features, uint8_t *device)
+{
+ if ((xfer->c_flags & C_NCQ) == 0)
+ return;
+
+ *cmd = (xfer->c_bio.flags & ATA_READ) ?
+ WDCC_READ_FPDMA_QUEUED : WDCC_WRITE_FPDMA_QUEUED;
+
+ /* for FPDMA the block count is in features */
+ *features = *count;
+
+ /* NCQ tag */
+ *count = (xfer->c_slot << 3);
+
+ /* other device flags */
+ /* XXX FUA handling */
+}
Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.105.6.2 src/sys/dev/ata/ata_wdc.c:1.105.6.3
--- src/sys/dev/ata/ata_wdc.c:1.105.6.2 Sat Apr 15 12:01:23 2017
+++ src/sys/dev/ata/ata_wdc.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata_wdc.c,v 1.105.6.2 2017/04/15 12:01:23 jdolecek Exp $ */
+/* $NetBSD: ata_wdc.c,v 1.105.6.3 2017/04/19 20:49:17 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.2 2017/04/15 12:01:23 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.3 2017/04/19 20:49:17 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -409,6 +409,8 @@ again:
}
#if NATA_DMA
if (xfer->c_flags & C_DMA) {
+ uint16_t count = nblks, features = 0;
+
ata_bio->nblks = nblks;
ata_bio->nbytes = xfer->c_bcount;
cmd = (ata_bio->flags & ATA_READ) ?
@@ -448,11 +450,17 @@ again:
return;
}
if (ata_bio->flags & ATA_LBA48) {
- wdccommandext(chp, xfer->c_drive, atacmd_to48(cmd),
- ata_bio->blkno, nblks, 0, WDSD_LBA);
+ uint8_t device = WDSD_LBA;
+ cmd = atacmd_to48(cmd);
+
+ atacmd_toncq(xfer, &cmd, &count, &features,
+ &device);
+
+ wdccommandext(chp, xfer->c_drive, cmd,
+ ata_bio->blkno, count, features, device);
} else {
wdccommand(chp, xfer->c_drive, cmd, cyl,
- head, sect, nblks, 0);
+ head, sect, count, features);
}
/* start the DMA channel */
(*wdc->dma_start)(wdc->dma_arg,
@@ -460,8 +468,8 @@ again:
chp->ch_flags |= ATACH_DMA_WAIT;
/* start timeout machinery */
if ((xfer->c_flags & C_POLL) == 0)
- callout_reset(&chp->ch_callout,
- ATA_DELAY / 1000 * hz, wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout,
+ ATA_DELAY / 1000 * hz, wdctimeout, xfer);
/* wait for irq */
goto intr;
} /* else not DMA */
@@ -532,8 +540,8 @@ again:
}
/* start timeout machinery */
if ((xfer->c_flags & C_POLL) == 0)
- callout_reset(&chp->ch_callout,
- ATA_DELAY / 1000 * hz, wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout,
+ ATA_DELAY / 1000 * hz, wdctimeout, xfer);
} else if (ata_bio->nblks > 1) {
/* The number of blocks in the last stretch may be smaller. */
nblks = xfer->c_bcount / drvp->lp->d_secsize;
@@ -796,7 +804,7 @@ wdc_ata_bio_done(struct ata_channel *chp
xfer->c_drive, (u_int)xfer->c_flags),
DEBUG_XFERS);
- callout_stop(&chp->ch_callout);
+ callout_stop(&xfer->c_timo_callout);
/* feed back residual bcount to our caller */
ata_bio->bcount = xfer->c_bcount;
Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92.8.4 src/sys/dev/ata/atavar.h:1.92.8.5
--- src/sys/dev/ata/atavar.h:1.92.8.4 Sat Apr 15 17:14:11 2017
+++ src/sys/dev/ata/atavar.h Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.92.8.4 2017/04/15 17:14:11 jdolecek Exp $ */
+/* $NetBSD: atavar.h,v 1.92.8.5 2017/04/19 20:49:17 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -131,13 +131,15 @@ struct scsipi_xfer;
* commands are queued in a list.
*/
struct ata_xfer {
- volatile u_int c_flags; /* command state flags */
+ struct callout c_timo_callout; /* timeout callout handle */
+#define c_startzero c_chp
/* Channel and drive that are to process the request. */
struct ata_channel *c_chp;
uint16_t c_drive;
int8_t c_slot; /* queue slot # */
+ volatile u_int c_flags; /* command state flags */
void *c_databuf; /* pointer to data buffer */
int c_bcount; /* byte count left */
int c_skip; /* bytes already transferred */
@@ -173,6 +175,7 @@ struct ata_xfer {
#define C_WAITACT 0x0020 /* wakeup when active */
#define C_FREE 0x0040 /* call ata_free_xfer() asap */
#define C_PIOBM 0x0080 /* command uses busmastering PIO */
+#define C_NCQ 0x0100 /* command is queued */
/* reasons for c_kill_xfer() */
#define KILL_GONE 1 /* device is gone */
@@ -219,7 +222,7 @@ struct ata_drive_datas {
uint8_t drive; /* drive number */
int8_t ata_vers; /* ATA version supported */
uint16_t drive_flags; /* bitmask for drives present/absent and cap */
-#define ATA_DRIVE_CAP32 0x0001
+#define ATA_DRIVE_CAP32 0x0001 /* 32-bit transfer capable */
#define ATA_DRIVE_DMA 0x0002
#define ATA_DRIVE_UDMA 0x0004
#define ATA_DRIVE_MODE 0x0008 /* the drive reported its mode */
@@ -227,6 +230,8 @@ struct ata_drive_datas {
#define ATA_DRIVE_WAITDRAIN 0x0020 /* device is waiting for the queue to drain */
#define ATA_DRIVE_NOSTREAM 0x0040 /* no stream methods on this drive */
#define ATA_DRIVE_ATAPIDSCW 0x0080 /* needs to wait for DSC in phase_complete */
+#define ATA_DRIVE_WFUA 0x0100 /* drive supports WRITE DMA FUA EXT */
+#define ATA_DRIVE_NCQ 0x0200 /* drive supports NCQ */
uint8_t drive_type;
#define ATA_DRIVET_NONE 0
@@ -267,6 +272,8 @@ struct ata_drive_datas {
#define READY 1
#if NATA_DMA
+ uint8_t drv_openings; /* # of command tags */
+
/* numbers of xfers and DMA errs. Used by ata_dmaerr() */
uint8_t n_dmaerrs;
uint32_t n_xfers;
@@ -340,7 +347,6 @@ struct ata_bustype {
struct ata_device {
const struct ata_bustype *adev_bustype;
int adev_channel;
- int adev_openings;
struct ata_drive_datas *adev_drv_data;
};
@@ -348,7 +354,6 @@ struct ata_device {
* Per-channel data
*/
struct ata_channel {
- struct callout ch_callout; /* callout handle */
int ch_channel; /* location */
struct atac_softc *ch_atac; /* ATA controller softc */
@@ -413,6 +418,7 @@ struct atac_softc {
#define ATAC_CAP_ATAPI_NOSTREAM 0x0080 /* don't use stream funcs on ATAPI */
#define ATAC_CAP_NOIRQ 0x1000 /* controller never interrupts */
#define ATAC_CAP_RAID 0x4000 /* controller "supports" RAID */
+#define ATAC_CAP_NCQ 0x8000 /* controller supports NCQ */
uint8_t atac_pio_cap; /* highest PIO mode supported */
#if NATA_DMA
@@ -489,8 +495,10 @@ void ata_probe_caps(struct ata_drive_dat
void ata_dmaerr(struct ata_drive_datas *, int);
#endif
void ata_queue_idle(struct ata_queue *);
+void ata_xfer_init(struct ata_xfer *, bool);
+void ata_xfer_destroy(struct ata_xfer *);
struct ata_queue *
- ata_queue_alloc(int openings);
+ ata_queue_alloc(uint8_t openings);
void ata_queue_free(struct ata_queue *);
struct ata_xfer *
ata_queue_hwslot_to_xfer(struct ata_queue *, int);
@@ -499,6 +507,10 @@ void ata_delay(int, const char *, int);
bool ata_waitdrain_check(struct ata_channel *, int);
bool ata_waitdrain_xfer_check(struct ata_channel *, struct ata_xfer *);
+
+void atacmd_toncq(struct ata_xfer *, uint8_t *, uint16_t *, uint16_t *,
+ uint8_t *);
+
#endif /* _KERNEL */
#endif /* _DEV_ATA_ATAVAR_H_ */
Index: src/sys/dev/ata/satafis_subr.c
diff -u src/sys/dev/ata/satafis_subr.c:1.7.28.1 src/sys/dev/ata/satafis_subr.c:1.7.28.2
--- src/sys/dev/ata/satafis_subr.c:1.7.28.1 Sat Apr 15 12:01:23 2017
+++ src/sys/dev/ata/satafis_subr.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: satafis_subr.c,v 1.7.28.1 2017/04/15 12:01:23 jdolecek Exp $ */
+/* $NetBSD: satafis_subr.c,v 1.7.28.2 2017/04/19 20:49:17 jdolecek Exp $ */
/*-
* Copyright (c) 2009 Jonathan A. Kollasch.
@@ -51,7 +51,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: satafis_subr.c,v 1.7.28.1 2017/04/15 12:01:23 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: satafis_subr.c,v 1.7.28.2 2017/04/19 20:49:17 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -102,9 +102,12 @@ satafis_rhd_construct_bio(struct ata_xfe
{
struct ata_bio *ata_bio = &xfer->c_bio;
struct ata_drive_datas *drvp = &xfer->c_chp->ch_drive[xfer->c_drive];
- int nblks;
+ uint16_t count, features;
+ uint8_t device;
- nblks = xfer->c_bcount / drvp->lp->d_secsize;
+ count = xfer->c_bcount / drvp->lp->d_secsize;
+ features = 0;
+ device = WDSD_LBA;
memset(fis, 0, RHD_FISLEN);
@@ -113,27 +116,32 @@ satafis_rhd_construct_bio(struct ata_xfe
if (ata_bio->flags & ATA_LBA48) {
fis[rhd_command] = (ata_bio->flags & ATA_READ) ?
WDCC_READDMA_EXT : WDCC_WRITEDMA_EXT;
+
+ atacmd_toncq(xfer, &fis[rhd_command], &count, &features,
+ &device);
} else {
fis[rhd_command] =
(ata_bio->flags & ATA_READ) ? WDCC_READDMA : WDCC_WRITEDMA;
}
+ fis[rhd_features0] = (features >> 0) & 0xff;
fis[rhd_lba0] = (ata_bio->blkno >> 0) & 0xff;
fis[rhd_lba1] = (ata_bio->blkno >> 8) & 0xff;
fis[rhd_lba2] = (ata_bio->blkno >> 16) & 0xff;
if ((ata_bio->flags & ATA_LBA48) != 0) {
- fis[rhd_dh] = WDSD_LBA;
+ fis[rhd_dh] = device;
fis[rhd_lba3] = (ata_bio->blkno >> 24) & 0xff;
fis[rhd_lba4] = (ata_bio->blkno >> 32) & 0xff;
fis[rhd_lba5] = (ata_bio->blkno >> 40) & 0xff;
+ fis[rhd_features1] = (features >> 8) & 0xff;
} else {
fis[rhd_dh] = ((ata_bio->blkno >> 24) & 0x0f) |
(((ata_bio->flags & ATA_LBA) != 0) ? WDSD_LBA : 0);
}
- fis[rhd_count0] = nblks & 0xff;
+ fis[rhd_count0] = count & 0xff;
if ((ata_bio->flags & ATA_LBA48) != 0) {
- fis[rhd_count1] = (nblks >> 8) & 0xff;
+ fis[rhd_count1] = (count >> 8) & 0xff;
}
}
Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.428.2.6 src/sys/dev/ata/wd.c:1.428.2.7
--- src/sys/dev/ata/wd.c:1.428.2.6 Sat Apr 15 20:22:41 2017
+++ src/sys/dev/ata/wd.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wd.c,v 1.428.2.6 2017/04/15 20:22:41 jdolecek Exp $ */
+/* $NetBSD: wd.c,v 1.428.2.7 2017/04/19 20:49:17 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.6 2017/04/15 20:22:41 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.7 2017/04/19 20:49:17 jdolecek Exp $");
#include "opt_ata.h"
@@ -426,32 +426,6 @@ wdattach(device_t parent, device_t self,
"might not actually work\n", wd->sc_blksize);
}
- /*
- * Probe WRITE DMA FUA EXT. Support is mandatory for devices
- * supporting LBA48, but nevertheless confirm with the feature flag.
- */
- if (wd->sc_flags & WDF_LBA48
- && (wd->sc_params.atap_cmd_def & ATA_CMDE_WFE)) {
- wd->sc_flags |= WDF_WFUA;
- }
-
- /* Probe NCQ support - READ/WRITE FPDMA QUEUED command support */
- uint8_t max_depth = 1;
- if (wd->sc_params.atap_sata_caps & SATA_NATIVE_CMDQ) {
- wd->sc_flags |= WDF_NCQ;
-
- max_depth = (wd->sc_params.atap_queuedepth & 0x0f) + 1;
-
- /* XXX adjust adev_openings */
- }
-
- aprint_verbose_dev(self,
- "drive supports %sFUA, %sNCQ (queue depth max %d, using %u)\n",
- (wd->sc_flags & (WDF_WFUA|WDF_NCQ)) ? "" : "no ",
- (wd->sc_flags & WDF_NCQ) ? "" : "no ",
- max_depth, adev->adev_openings);
-
-
out:
/*
* Initialize and attach the disk structure.
@@ -823,6 +797,13 @@ fail:
xfer->c_bio.bcount / wd->sc_dk.dk_label->d_secsize) >
wd->sc_capacity28)
xfer->c_bio.flags |= ATA_LBA48;
+
+ /* If NCQ was negotiated, always use it */
+ if (wd->drvp->drive_flags & ATA_DRIVE_NCQ) {
+ xfer->c_bio.flags |= ATA_LBA48;
+ xfer->c_flags |= C_NCQ;
+ }
+
if (wd->sc_flags & WDF_LBA)
xfer->c_bio.flags |= ATA_LBA;
if (bp->b_flags & B_READ)
@@ -1917,6 +1898,7 @@ wd_setcache(struct wd_softc *wd, int bit
{
struct ataparams params;
struct ata_xfer xfer;
+ int error;
if (wd_get_params(wd, AT_WAIT, ¶ms) != 0)
return EIO;
@@ -1930,7 +1912,7 @@ wd_setcache(struct wd_softc *wd, int bit
(bits & DKCACHE_SAVE) != 0)
return EOPNOTSUPP;
- memset(&xfer, 0, sizeof(xfer));
+ ata_xfer_init(&xfer, true);
xfer.c_ata_c.r_command = SET_FEATURES;
xfer.c_ata_c.r_st_bmask = 0;
xfer.c_ata_c.r_st_pmask = 0;
@@ -1943,23 +1925,32 @@ wd_setcache(struct wd_softc *wd, int bit
if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) {
aprint_error_dev(wd->sc_dev,
"wd_setcache command not complete\n");
- return EIO;
+ error = EIO;
+ goto out;
}
+
if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
char sbuf[sizeof(at_errbits) + 64];
snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
aprint_error_dev(wd->sc_dev, "wd_setcache: status=%s\n", sbuf);
- return EIO;
+ error = EIO;
+ goto out;
}
- return 0;
+
+ error = 0;
+
+out:
+ ata_xfer_destroy(&xfer);
+ return error;
}
static int
wd_standby(struct wd_softc *wd, int flags)
{
struct ata_xfer xfer;
+ int error;
- memset(&xfer, 0, sizeof(xfer));
+ ata_xfer_init(&xfer, true);
xfer.c_ata_c.r_command = WDCC_STANDBY_IMMED;
xfer.c_ata_c.r_st_bmask = WDCS_DRDY;
xfer.c_ata_c.r_st_pmask = WDCS_DRDY;
@@ -1968,27 +1959,35 @@ wd_standby(struct wd_softc *wd, int flag
if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) {
aprint_error_dev(wd->sc_dev,
"standby immediate command didn't complete\n");
- return EIO;
+ error = EIO;
+ goto out;
}
if (xfer.c_ata_c.flags & AT_ERROR) {
if (xfer.c_ata_c.r_error == WDCE_ABRT) {
/* command not supported */
- return ENODEV;
+ error = ENODEV;
+ goto out;
}
}
if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
char sbuf[sizeof(at_errbits) + 64];
snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
aprint_error_dev(wd->sc_dev, "wd_standby: status=%s\n", sbuf);
- return EIO;
+ error = EIO;
+ goto out;
}
- return 0;
+ error = 0;
+
+out:
+ ata_xfer_destroy(&xfer);
+ return error;
}
int
wd_flushcache(struct wd_softc *wd, int flags)
{
struct ata_xfer xfer;
+ int error;
/*
* WDCC_FLUSHCACHE is here since ATA-4, but some drives report
@@ -1998,7 +1997,8 @@ wd_flushcache(struct wd_softc *wd, int f
((wd->sc_params.atap_cmd_set2 & WDC_CMD2_FC) == 0 ||
wd->sc_params.atap_cmd_set2 == 0xffff))
return ENODEV;
- memset(&xfer, 0, sizeof(xfer));
+
+ ata_xfer_init(&xfer, true);
if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0 &&
(wd->sc_params.atap_cmd2_en & ATA_CMD2_FCE) != 0) {
xfer.c_ata_c.r_command = WDCC_FLUSHCACHE_EXT;
@@ -2012,12 +2012,14 @@ wd_flushcache(struct wd_softc *wd, int f
if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) {
aprint_error_dev(wd->sc_dev,
"flush cache command didn't complete\n");
- return EIO;
+ error = EIO;
+ goto out;
}
if (xfer.c_ata_c.flags & AT_ERROR) {
if (xfer.c_ata_c.r_error == WDCE_ABRT) {
/* command not supported */
- return ENODEV;
+ error = ENODEV;
+ goto out;
}
}
if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
@@ -2025,15 +2027,21 @@ wd_flushcache(struct wd_softc *wd, int f
snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
aprint_error_dev(wd->sc_dev, "wd_flushcache: status=%s\n",
sbuf);
- return EIO;
+ error = EIO;
+ goto out;
}
- return 0;
+ error = 0;
+
+out:
+ ata_xfer_destroy(&xfer);
+ return error;
}
int
wd_trim(struct wd_softc *wd, int part, daddr_t bno, long size)
{
struct ata_xfer xfer;
+ int error;
unsigned char *req;
if (part != RAW_PART)
@@ -2049,7 +2057,7 @@ wd_trim(struct wd_softc *wd, int part, d
req[6] = size & 0xff;
req[7] = (size >> 8) & 0xff;
- memset(&xfer, 0, sizeof(xfer));
+ ata_xfer_init(&xfer, true);
xfer.c_ata_c.r_command = ATA_DATA_SET_MANAGEMENT;
xfer.c_ata_c.r_count = 1;
xfer.c_ata_c.r_features = ATA_SUPPORT_DSM_TRIM;
@@ -2063,13 +2071,15 @@ wd_trim(struct wd_softc *wd, int part, d
aprint_error_dev(wd->sc_dev,
"trim command didn't complete\n");
kmem_free(req, 512);
- return EIO;
+ error = EIO;
+ goto out;
}
kmem_free(req, 512);
if (xfer.c_ata_c.flags & AT_ERROR) {
if (xfer.c_ata_c.r_error == WDCE_ABRT) {
/* command not supported */
- return ENODEV;
+ error = ENODEV;
+ goto out;
}
}
if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
@@ -2077,9 +2087,14 @@ wd_trim(struct wd_softc *wd, int part, d
snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
aprint_error_dev(wd->sc_dev, "wd_trim: status=%s\n",
sbuf);
- return EIO;
+ error = EIO;
+ goto out;
}
- return 0;
+ error = 0;
+
+out:
+ ata_xfer_destroy(&xfer);
+ return error;
}
bool
@@ -2211,10 +2226,10 @@ wdioctlstrategy(struct buf *bp)
printf("wdioctlstrategy: "
"No matching ioctl request found in queue\n");
error = EINVAL;
- goto bad;
+ goto out;
}
- memset(&xfer, 0, sizeof(xfer));
+ ata_xfer_init(&xfer, true);
/*
* Abort if physio broke up the transfer
@@ -2223,7 +2238,7 @@ wdioctlstrategy(struct buf *bp)
if (bp->b_bcount != wi->wi_atareq.datalen) {
printf("physio split wd ioctl request... cannot proceed\n");
error = EIO;
- goto bad;
+ goto out;
}
/*
@@ -2235,7 +2250,7 @@ wdioctlstrategy(struct buf *bp)
(bp->b_bcount / wi_sector_size(wi)) >=
(1 << NBBY)) {
error = EINVAL;
- goto bad;
+ goto out;
}
/*
@@ -2244,7 +2259,7 @@ wdioctlstrategy(struct buf *bp)
if (wi->wi_atareq.timeout == 0) {
error = EINVAL;
- goto bad;
+ goto out;
}
if (wi->wi_atareq.flags & ATACMD_READ)
@@ -2275,7 +2290,8 @@ wdioctlstrategy(struct buf *bp)
if (wi->wi_softc->atabus->ata_exec_command(wi->wi_softc->drvp, &xfer)
!= ATACMD_COMPLETE) {
wi->wi_atareq.retsts = ATACMD_ERROR;
- goto bad;
+ error = EIO;
+ goto out;
}
if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
@@ -2301,11 +2317,10 @@ wdioctlstrategy(struct buf *bp)
}
}
- bp->b_error = 0;
- biodone(bp);
- return;
-bad:
+out:
+ ata_xfer_destroy(&xfer);
bp->b_error = error;
- bp->b_resid = bp->b_bcount;
+ if (error)
+ bp->b_resid = bp->b_bcount;
biodone(bp);
}
Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.43.4.3 src/sys/dev/ata/wdvar.h:1.43.4.4
--- src/sys/dev/ata/wdvar.h:1.43.4.3 Sat Apr 15 18:02:09 2017
+++ src/sys/dev/ata/wdvar.h Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wdvar.h,v 1.43.4.3 2017/04/15 18:02:09 jdolecek Exp $ */
+/* $NetBSD: wdvar.h,v 1.43.4.4 2017/04/19 20:49:17 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -58,8 +58,6 @@ struct wd_softc {
#define WDF_LBA 0x040 /* using LBA mode */
#define WDF_KLABEL 0x080 /* retain label after 'full' close */
#define WDF_LBA48 0x100 /* using 48-bit LBA mode */
-#define WDF_WFUA 0x200 /* supports FUA via WRITE DMA FUA EXT */
-#define WDF_NCQ 0x400 /* supports NCQ feature set */
uint64_t sc_capacity; /* full capacity of the device */
uint64_t sc_capacity512; /* ... in DEV_BSIZE blocks */
uint32_t sc_capacity28; /* capacity accessible with LBA28 commands */
Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.6 src/sys/dev/ic/ahcisata_core.c:1.57.6.7
--- src/sys/dev/ic/ahcisata_core.c:1.57.6.6 Sat Apr 15 23:58:31 2017
+++ src/sys/dev/ic/ahcisata_core.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ahcisata_core.c,v 1.57.6.6 2017/04/15 23:58:31 jdolecek Exp $ */
+/* $NetBSD: ahcisata_core.c,v 1.57.6.7 2017/04/19 20:49:17 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.6 2017/04/15 23:58:31 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.7 2017/04/19 20:49:17 jdolecek Exp $");
#include <sys/types.h>
#include <sys/malloc.h>
@@ -299,7 +299,8 @@ ahci_attach(struct ahci_softc *sc)
(sc->sc_atac.atac_nchannels == 1 ? "" : "s"),
sc->sc_ncmds, (sc->sc_ncmds == 1 ? "" : "s"), buf);
- sc->sc_atac.atac_cap = ATAC_CAP_DATA16 | ATAC_CAP_DMA | ATAC_CAP_UDMA;
+ sc->sc_atac.atac_cap = ATAC_CAP_DATA16 | ATAC_CAP_DMA | ATAC_CAP_UDMA
+ | ((sc->sc_ahci_cap & AHCI_CAP_NCQ) ? ATAC_CAP_NCQ : 0);
sc->sc_atac.atac_cap |= sc->sc_atac_capflags;
sc->sc_atac.atac_pio_cap = 4;
sc->sc_atac.atac_dma_cap = 2;
@@ -365,7 +366,7 @@ ahci_attach(struct ahci_softc *sc)
sc->sc_chanarray[i] = chp;
chp->ch_channel = i;
chp->ch_atac = &sc->sc_atac;
- chp->ch_queue = ata_queue_alloc(1); // XXX sc_ncmds
+ chp->ch_queue = ata_queue_alloc(sc->sc_ncmds);
if (chp->ch_queue == NULL) {
aprint_error("%s port %d: can't allocate memory for "
"command queue", AHCINAME(sc), i);
@@ -566,19 +567,19 @@ ahci_intr_port(struct ahci_softc *sc, st
chp->ch_channel, is, AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
DEBUG_INTR);
- slot = (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel))
- & AHCI_P_CMD_CCS_MASK) >> AHCI_P_CMD_CCS_SHIFT;
- if ((achp->ahcic_cmds_active & (1 << slot)) == 0)
- return;
-
if (is & (AHCI_P_IX_TFES | AHCI_P_IX_HBFS | AHCI_P_IX_IFS |
AHCI_P_IX_OFS | AHCI_P_IX_UFS)) {
+#if 1
+ printf("ahci_intr_port %s port %d is 0x%x CI 0x%x\n", AHCINAME(sc),
+ chp->ch_channel, is, AHCI_READ(sc, AHCI_P_CI(chp->ch_channel)));
+#endif
+ slot = (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel))
+ & AHCI_P_CMD_CCS_MASK) >> AHCI_P_CMD_CCS_SHIFT;
+ /* XXX iterate */
+ if ((achp->ahcic_cmds_active & (1 << slot)) == 0)
+ return;
/* stop channel */
ahci_channel_stop(sc, chp, 0);
- if (slot != 0) {
- printf("ahci_intr_port: slot %d\n", slot);
- panic("ahci_intr_port");
- }
xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, slot);
if (is & AHCI_P_IX_TFES) {
tfd = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));
@@ -601,10 +602,17 @@ ahci_intr_port(struct ahci_softc *sc, st
== 0)
ahci_channel_start(sc, chp, 0, 0);
} else {
- xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, slot);
- if ((AHCI_READ(sc, AHCI_P_CI(chp->ch_channel)) & (1 << slot))
- == 0) {
- xfer->c_intr(chp, xfer, 0);
+ uint32_t clear = AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))
+ | AHCI_READ(sc, AHCI_P_SACT(chp->ch_channel));
+
+ for (slot=0; slot < sc->sc_ncmds; slot++) {
+ if ((achp->ahcic_cmds_active & (1 << slot)) == 0)
+ return;
+ if ((clear & (1 << slot)) == 0) {
+ xfer = ata_queue_hwslot_to_xfer(chp->ch_queue,
+ slot);
+ xfer->c_intr(chp, xfer, 0);
+ }
}
}
}
@@ -896,7 +904,7 @@ ahci_probe_drive(struct ata_channel *chp
AHCI_WRITE(sc, AHCI_P_IE(chp->ch_channel),
AHCI_P_IX_TFES | AHCI_P_IX_HBFS | AHCI_P_IX_IFS |
AHCI_P_IX_OFS | AHCI_P_IX_DPS | AHCI_P_IX_UFS |
- AHCI_P_IX_PSS | AHCI_P_IX_DHRS);
+ AHCI_P_IX_PSS | AHCI_P_IX_DHRS | AHCI_P_IX_SDBS);
/* wait 500ms before actually starting operations */
tsleep(&sc, PRIBIO, "ahciprb", mstohz(500));
break;
@@ -1015,8 +1023,8 @@ ahci_cmd_start(struct ata_channel *chp,
if ((ata_c->flags & AT_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, mstohz(ata_c->timeout),
- ahci_timeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),
+ ahci_timeout, xfer);
return;
}
/*
@@ -1216,6 +1224,8 @@ ahci_bio_start(struct ata_channel *chp,
}
chp->ch_flags |= ATACH_IRQ_WAIT;
chp->ch_status = 0;
+ if (xfer->c_flags & C_NCQ)
+ AHCI_WRITE(sc, AHCI_P_SACT(chp->ch_channel), 1 << xfer->c_slot);
/* start command */
AHCI_WRITE(sc, AHCI_P_CI(chp->ch_channel), 1 << xfer->c_slot);
/* and says we started this command */
@@ -1223,8 +1233,8 @@ ahci_bio_start(struct ata_channel *chp,
if ((xfer->c_flags & C_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, mstohz(ATA_DELAY),
- ahci_timeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),
+ ahci_timeout, xfer);
return;
}
/*
@@ -1409,18 +1419,34 @@ ahci_channel_start(struct ahci_softc *sc
static void
ahci_timeout(void *v)
{
- struct ata_channel *chp = (struct ata_channel *)v;
- struct ata_xfer *xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0); /* XXX slot */
-#ifdef AHCI_DEBUG
+ struct ata_xfer *xfer = v;
+ struct ata_channel *chp = xfer->c_chp;
+ struct ahci_channel *achp = (struct ahci_channel *)chp;
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
-#endif
- int s = splbio();
- AHCIDEBUG_PRINT(("ahci_timeout xfer %p intr %#x ghc %08x is %08x\n", xfer, AHCI_READ(sc, AHCI_P_IS(chp->ch_channel)), AHCI_READ(sc, AHCI_GHC), AHCI_READ(sc, AHCI_IS)), DEBUG_INTR);
-
- if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) {
+ int s;
+
+ s = splbio();
+ AHCIDEBUG_PRINT(("ahci_timeout intr %#x ghc %08x is %08x\n",
+ AHCI_READ(sc, AHCI_P_IS(chp->ch_channel)),
+ AHCI_READ(sc, AHCI_GHC),
+ AHCI_READ(sc, AHCI_IS)), DEBUG_INTR);
+
+ uint32_t active = AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))
+ | AHCI_READ(sc, AHCI_P_SACT(chp->ch_channel));
+ aprint_error_dev(sc->sc_atac.atac_dev,
+ "timeout xfer slot %d active 0x%x\n", xfer->c_slot, active);
+
+ /*
+ * The command must be active - otherwise the timeout should have been
+ * stopped.
+ */
+ KASSERT((achp->ahcic_cmds_active & (1 << xfer->c_slot)) != 0);
+
+ /* Mark as timed out unless the xfer is actually finished */
+ if ((active & (1 << xfer->c_slot)) != 0)
xfer->c_flags |= C_TIMEOU;
- xfer->c_intr(chp, xfer, 0);
- }
+ xfer->c_intr(chp, xfer, 0);
+
splx(s);
}
@@ -1637,8 +1663,8 @@ ahci_atapi_start(struct ata_channel *chp
if ((xfer->c_flags & C_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, mstohz(sc_xfer->timeout),
- ahci_timeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
+ ahci_timeout, xfer);
return;
}
/*
Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.35.6.5 src/sys/dev/ic/mvsata.c:1.35.6.6
--- src/sys/dev/ic/mvsata.c:1.35.6.5 Sat Apr 15 17:14:11 2017
+++ src/sys/dev/ic/mvsata.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsata.c,v 1.35.6.5 2017/04/15 17:14:11 jdolecek Exp $ */
+/* $NetBSD: mvsata.c,v 1.35.6.6 2017/04/19 20:49:17 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.5 2017/04/15 17:14:11 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.6 2017/04/19 20:49:17 jdolecek Exp $");
#include "opt_mvsata.h"
@@ -1139,7 +1139,7 @@ again:
chp->ch_flags |= ATACH_DMA_WAIT;
/* start timeout machinery */
if ((xfer->c_flags & C_POLL) == 0)
- callout_reset(&chp->ch_callout,
+ callout_reset(&xfer->c_timo_callout,
ATA_DELAY / 1000 * hz,
mvsata_edma_timeout, xfer);
/* wait for irq */
@@ -1226,8 +1226,8 @@ do_pio:
/* start timeout machinery */
if ((xfer->c_flags & C_POLL) == 0)
- callout_reset(&chp->ch_callout,
- ATA_DELAY / 1000 * hz, wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout,
+ ATA_DELAY / 1000 * hz, wdctimeout, xfer);
} else if (ata_bio->nblks > 1) {
/* The number of blocks in the last stretch may be smaller. */
nblks = xfer->c_bcount / drvp->lp->d_secsize;
@@ -1429,7 +1429,7 @@ mvsata_bio_done(struct ata_channel *chp,
device_xname(MVSATA_DEV2(mvport)), chp->ch_channel, xfer->c_drive,
(u_int)xfer->c_flags));
- callout_stop(&chp->ch_callout);
+ callout_stop(&xfer->c_timo_callout);
/* EDMA restart, if enabled */
if (!(xfer->c_flags & C_DMA) && mvport->port_edmamode != nodma) {
@@ -1605,8 +1605,8 @@ mvsata_wdc_cmd_start(struct ata_channel
if ((ata_c->flags & AT_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, ata_c->timeout / 1000 * hz,
- wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz,
+ wdctimeout, xfer);
return;
}
/*
@@ -1707,8 +1707,8 @@ again:
ata_c->flags |= AT_XFDONE;
if ((ata_c->flags & AT_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for intr */
- callout_reset(&chp->ch_callout,
- mstohz(ata_c->timeout), wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout,
+ mstohz(ata_c->timeout), wdctimeout, xfer);
return 1;
} else
goto again;
@@ -1946,8 +1946,8 @@ ready:
}
/* start timeout machinery */
if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)
- callout_reset(&chp->ch_callout, mstohz(sc_xfer->timeout),
- wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
+ wdctimeout, xfer);
MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM);
switch (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags) < 0) {
@@ -2315,7 +2315,7 @@ mvsata_atapi_phase_complete(struct ata_x
mvsata_atapi_reset(chp, xfer);
return;
} else
- callout_reset(&chp->ch_callout, 1,
+ callout_reset(&xfer->c_timo_callout, 1,
mvsata_atapi_polldsc, xfer);
return;
}
Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30.4.4 src/sys/dev/ic/siisata.c:1.30.4.5
--- src/sys/dev/ic/siisata.c:1.30.4.4 Sat Apr 15 17:14:11 2017
+++ src/sys/dev/ic/siisata.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.4 2017/04/15 17:14:11 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.5 2017/04/19 20:49:17 jdolecek Exp $ */
/* from ahcisata_core.c */
@@ -79,7 +79,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.4 2017/04/15 17:14:11 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.5 2017/04/19 20:49:17 jdolecek Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -865,8 +865,8 @@ siisata_cmd_start(struct ata_channel *ch
if ((ata_c->flags & AT_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, mstohz(ata_c->timeout),
- siisata_timeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),
+ siisata_timeout, xfer);
goto out;
}
@@ -881,7 +881,7 @@ siisata_cmd_start(struct ata_channel *ch
}
if ((ata_c->flags & AT_DONE) == 0) {
- siisata_timeout(chp);
+ siisata_timeout(xfer);
}
/* reenable interrupts */
@@ -928,7 +928,7 @@ siisata_cmd_complete(struct ata_channel
if (xfer->c_flags & C_TIMEOU)
ata_c->flags |= AT_TIMEOU;
else
- callout_stop(&chp->ch_callout);
+ callout_stop(&xfer->c_timo_callout);
if (chp->ch_status & WDCS_BSY) {
ata_c->flags |= AT_TIMEOU;
@@ -1067,8 +1067,8 @@ siisata_bio_start(struct ata_channel *ch
if ((ata_bio->flags & ATA_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, mstohz(ATA_DELAY),
- siisata_timeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),
+ siisata_timeout, xfer);
goto out;
}
@@ -1133,7 +1133,7 @@ siisata_bio_complete(struct ata_channel
if (xfer->c_flags & C_TIMEOU) {
ata_bio->error = TIMEOUT;
} else {
- callout_stop(&chp->ch_callout);
+ callout_stop(&xfer->c_timo_callout);
ata_bio->error = NOERROR;
}
@@ -1178,8 +1178,8 @@ siisata_bio_complete(struct ata_channel
void
siisata_timeout(void *v)
{
- struct ata_channel *chp = (struct ata_channel *)v;
- struct ata_xfer *xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0); /* XXX slot */
+ struct ata_xfer *xfer = v;
+ struct ata_channel *chp = xfer->c_chp;
int slot = SIISATA_NON_NCQ_SLOT;
int s = splbio();
SIISATA_DEBUG_PRINT(("%s: %p\n", __func__, xfer), DEBUG_INTR);
@@ -1612,8 +1612,8 @@ siisata_atapi_start(struct ata_channel *
if ((xfer->c_flags & C_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, mstohz(sc_xfer->timeout),
- siisata_timeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
+ siisata_timeout, xfer);
goto out;
}
@@ -1627,7 +1627,7 @@ siisata_atapi_start(struct ata_channel *
DELAY(1000);
}
if ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
- siisata_timeout(chp);
+ siisata_timeout(xfer);
}
/* reenable interrupts */
siisata_enable_port_interrupt(chp);
@@ -1654,7 +1654,7 @@ siisata_atapi_complete(struct ata_channe
if (xfer->c_flags & C_TIMEOU) {
sc_xfer->error = XS_TIMEOUT;
} else {
- callout_stop(&chp->ch_callout);
+ callout_stop(&xfer->c_timo_callout);
sc_xfer->error = XS_NOERROR;
}
Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.283.2.3 src/sys/dev/ic/wdc.c:1.283.2.4
--- src/sys/dev/ic/wdc.c:1.283.2.3 Sat Apr 15 17:14:11 2017
+++ src/sys/dev/ic/wdc.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wdc.c,v 1.283.2.3 2017/04/15 17:14:11 jdolecek Exp $ */
+/* $NetBSD: wdc.c,v 1.283.2.4 2017/04/19 20:49:17 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.3 2017/04/15 17:14:11 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.4 2017/04/19 20:49:17 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -1323,7 +1323,8 @@ wdc_dmawait(struct ata_channel *chp, str
void
wdctimeout(void *arg)
{
- struct ata_channel *chp = (struct ata_channel *)arg;
+ struct ata_xfer *xfer = arg;
+ struct ata_channel *chp = xfer->c_chp;
#if NATA_DMA || NATA_PIOBM
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
#endif
@@ -1332,7 +1333,6 @@ wdctimeout(void *arg)
ATADEBUG_PRINT(("wdctimeout\n"), DEBUG_FUNCS);
s = splbio();
- struct ata_xfer *xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
KASSERT(xfer != NULL);
if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) {
__wdcerror(chp, "lost interrupt");
@@ -1355,7 +1355,7 @@ wdctimeout(void *arg)
* in case it will miss another irq while in this transfer
* We arbitray chose it to be 1s
*/
- callout_reset(&chp->ch_callout, hz, wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout, hz, wdctimeout, xfer);
xfer->c_flags |= C_TIMEOU;
chp->ch_flags &= ~ATACH_IRQ_WAIT;
KASSERT(xfer->c_intr != NULL);
@@ -1464,8 +1464,8 @@ __wdccommand_start(struct ata_channel *c
if ((ata_c->flags & AT_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout, ata_c->timeout / 1000 * hz,
- wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz,
+ wdctimeout, xfer);
return;
}
/*
@@ -1574,8 +1574,8 @@ __wdccommand_intr(struct ata_channel *ch
ata_c->flags |= AT_XFDONE;
if ((ata_c->flags & AT_POLL) == 0) {
chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
- callout_reset(&chp->ch_callout,
- mstohz(ata_c->timeout), wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout,
+ mstohz(ata_c->timeout), wdctimeout, xfer);
return 1;
} else {
goto again;
Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.3 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.4
--- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.3 Sat Apr 15 17:14:11 2017
+++ src/sys/dev/scsipi/atapi_wdc.c Wed Apr 19 20:49:17 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atapi_wdc.c,v 1.123.4.3 2017/04/15 17:14:11 jdolecek Exp $ */
+/* $NetBSD: atapi_wdc.c,v 1.123.4.4 2017/04/19 20:49:17 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.3 2017/04/15 17:14:11 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.4 2017/04/19 20:49:17 jdolecek Exp $");
#ifndef ATADEBUG
#define ATADEBUG
@@ -197,8 +197,10 @@ wdc_atapi_get_params(struct scsipi_chann
struct wdc_regs *wdr = &wdc->regs[chan->chan_channel];
struct ata_channel *chp = atac->atac_channels[chan->chan_channel];
struct ata_xfer xfer;
+ int rv;
+
+ ata_xfer_init(&xfer, true);
- memset(&xfer, 0, sizeof(xfer));
xfer.c_ata_c.r_command = ATAPI_SOFT_RESET;
xfer.c_ata_c.r_st_bmask = 0;
xfer.c_ata_c.r_st_pmask = 0;
@@ -215,7 +217,8 @@ wdc_atapi_get_params(struct scsipi_chann
"failed for drive %s:%d:%d: error 0x%x\n",
device_xname(atac->atac_dev), chp->ch_channel, drive,
xfer.c_ata_c.r_error), DEBUG_PROBE);
- return -1;
+ rv = -1;
+ goto out;
}
chp->ch_drive[drive].state = 0;
@@ -228,9 +231,14 @@ wdc_atapi_get_params(struct scsipi_chann
"failed for drive %s:%d:%d: error 0x%x\n",
device_xname(atac->atac_dev), chp->ch_channel, drive,
xfer.c_ata_c.r_error), DEBUG_PROBE);
- return -1;
+ rv = -1;
+ goto out;
}
- return 0;
+ rv = 0;
+
+out:
+ ata_xfer_destroy(&xfer);
+ return rv;
}
static void
@@ -564,8 +572,8 @@ ready:
}
/* start timeout machinery */
if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)
- callout_reset(&chp->ch_callout, mstohz(sc_xfer->timeout),
- wdctimeout, chp);
+ callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
+ wdctimeout, xfer);
if (wdc->select)
wdc->select(chp, xfer->c_drive);
@@ -1020,7 +1028,7 @@ wdc_atapi_phase_complete(struct ata_xfer
wdc_atapi_reset(chp, xfer);
return;
} else
- callout_reset(&chp->ch_callout, 1,
+ callout_reset(&xfer->c_timo_callout, 1,
wdc_atapi_polldsc, xfer);
return;
}