Module Name: src Committed By: jdolecek Date: Mon Jun 19 21:00:00 UTC 2017
Modified Files: src/sys/dev/ata [jdolecek-ncq]: TODO.ncq ata.c atavar.h satapmp_subr.c wd.c src/sys/dev/ic [jdolecek-ncq]: ahcisata_core.c mvsata.c siisata.c wdc.c src/sys/dev/scsipi [jdolecek-ncq]: atapi_wdc.c src/sys/dev/usb [jdolecek-ncq]: umass_isdata.c Log Message: add ata_channel lock, use it to protect queue manipulation (only that for now); add ata_channel_detach() to destroy the locks change ata_get_xfer() so that it can wait for xfer, convert all on-stack xfer code to use the blocking variant fix siisata_reset_drive() to use polled reset and not try ata_activate_xfer(), convert drive probe code also over from slot0 XXX to ata_get_xfer() drive reset and PMP now works on siisata(4) too; changes tested also on piixide(4), ahci(4), mvsata(4) To generate a diff of this commit: cvs rdiff -u -r1.1.2.17 -r1.1.2.18 src/sys/dev/ata/TODO.ncq cvs rdiff -u -r1.132.8.10 -r1.132.8.11 src/sys/dev/ata/ata.c cvs rdiff -u -r1.92.8.9 -r1.92.8.10 src/sys/dev/ata/atavar.h cvs rdiff -u -r1.12.24.2 -r1.12.24.3 src/sys/dev/ata/satapmp_subr.c cvs rdiff -u -r1.428.2.17 -r1.428.2.18 src/sys/dev/ata/wd.c cvs rdiff -u -r1.57.6.13 -r1.57.6.14 src/sys/dev/ic/ahcisata_core.c cvs rdiff -u -r1.35.6.11 -r1.35.6.12 src/sys/dev/ic/mvsata.c cvs rdiff -u -r1.30.4.16 -r1.30.4.17 src/sys/dev/ic/siisata.c cvs rdiff -u -r1.283.2.5 -r1.283.2.6 src/sys/dev/ic/wdc.c cvs rdiff -u -r1.123.4.5 -r1.123.4.6 src/sys/dev/scsipi/atapi_wdc.c cvs rdiff -u -r1.33.4.2 -r1.33.4.3 src/sys/dev/usb/umass_isdata.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.17 src/sys/dev/ata/TODO.ncq:1.1.2.18 --- src/sys/dev/ata/TODO.ncq:1.1.2.17 Sat Jun 17 19:24:26 2017 +++ src/sys/dev/ata/TODO.ncq Mon Jun 19 21:00:00 2017 @@ -6,11 +6,11 @@ fix crashdump for mvsata - request times siisata - fix all new XXX and unmergable bits, fix PMP test crashdump with siisata - -reset channel and PMP doesn't work with siisata - siisata_reset_drive() -uses ata_get_xfer() and this can clash on slot 0 with on-stack xfers +- fails with recursive panic via pmap_kremove_local() regardless if + drive connected via PMP or direct test wd* at umass?, confirm the ata_channel kludge works ++ add detach code (channel detach, free queue) is ata_exec_xfer() + POLL safe wrt. more outstanding I/Os? why is it waiting until xfer is head of queue? also layer violation with the ata_xfer_free() call @@ -30,6 +30,10 @@ drive rescaned after detach of non-NCQ d to have active or pending transfers (e.g. when non-NCQ device is attached while there is already NCQ device present) +add mechanics to re-check queue when xfer is finished - needed on PMP +and for IDE disks, when one drive uses up all available xfers nothing +ever restarts queue for the other drives + Other random notes (do outside the NCQ branch): ----------------------------------------------------- change wd(4) to use dk_open() Index: src/sys/dev/ata/ata.c diff -u src/sys/dev/ata/ata.c:1.132.8.10 src/sys/dev/ata/ata.c:1.132.8.11 --- src/sys/dev/ata/ata.c:1.132.8.10 Sat Jun 17 14:01:36 2017 +++ src/sys/dev/ata/ata.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ata.c,v 1.132.8.10 2017/06/17 14:01:36 jdolecek Exp $ */ +/* $NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.10 2017/06/17 14:01:36 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 jdolecek Exp $"); #include "opt_ata.h" @@ -129,6 +129,9 @@ static bool atabus_resume(device_t, cons static bool atabus_suspend(device_t, const pmf_qual_t *); static void atabusconfig_thread(void *); +static void ata_xfer_init(struct ata_xfer *, bool); +static void ata_xfer_destroy(struct ata_xfer *); + /* * atabus_init: * @@ -221,7 +224,7 @@ ata_queue_active_xfer_peek(struct ata_qu return TAILQ_FIRST(&chq->active_xfers); } -void +static void ata_xfer_init(struct ata_xfer *xfer, bool zero) { if (zero) @@ -230,7 +233,7 @@ ata_xfer_init(struct ata_xfer *xfer, boo callout_init(&xfer->c_timo_callout, 0); /* XXX MPSAFE */ } -void +static void ata_xfer_destroy(struct ata_xfer *xfer) { callout_halt(&xfer->c_timo_callout, NULL); /* XXX MPSAFE */ @@ -257,6 +260,8 @@ ata_queue_alloc(uint8_t openings) chq->queue_openings = openings; ata_queue_reset(chq); + cv_init(&chq->queue_busy, "ataqbusy"); + for (uint8_t i = 0; i < openings; i++) ata_xfer_init(&chq->queue_xfers[i], false); @@ -283,6 +288,12 @@ ata_queue_free(struct ata_queue *chq) free(chq, M_DEVBUF); } +void +ata_channel_init(struct ata_channel *chp) +{ + mutex_init(&chp->ch_lock, MUTEX_DEFAULT, IPL_BIO); +} + /* * ata_channel_attach: * @@ -291,17 +302,37 @@ ata_queue_free(struct ata_queue *chq) void ata_channel_attach(struct ata_channel *chp) { - struct ata_queue * const chq = chp->ch_queue; - if (chp->ch_flags & ATACH_DISABLED) return; - ata_queue_reset(chq); + KASSERT(chp->ch_queue != NULL); + + ata_channel_init(chp); chp->atabus = config_found_ia(chp->ch_atac->atac_dev, "ata", chp, atabusprint); } +void +ata_channel_destroy(struct ata_channel *chp) +{ + mutex_destroy(&chp->ch_lock); +} + +/* + * ata_channel_detach: + * + * Common parts of detaching an atabus to an ATA controller channel. + */ +void +ata_channel_detach(struct ata_channel *chp) +{ + if (chp->ch_flags & ATACH_DISABLED) + return; + + ata_channel_destroy(chp); +} + static void atabusconfig(struct atabus_softc *atabus_sc) { @@ -1130,17 +1161,27 @@ atastart(struct ata_channel *chp) } struct ata_xfer * -ata_get_xfer(struct ata_channel *chp) +ata_get_xfer(struct ata_channel *chp, bool wait) { struct ata_queue *chq = chp->ch_queue; struct ata_xfer *xfer = NULL; - int s; uint32_t avail, slot; + int error; - s = splbio(); + mutex_enter(&chp->ch_lock); + +retry: avail = ffs32(chq->queue_xfers_avail); - if (avail == 0) + if (avail == 0) { + if (wait) { + chq->queue_flags |= QF_NEED_XFER; + error = cv_wait_sig(&chq->queue_busy, &chp->ch_lock); + if (error == 0) + goto retry; + } + goto out; + } slot = avail - 1; xfer = &chq->queue_xfers[slot]; @@ -1154,7 +1195,7 @@ ata_get_xfer(struct ata_channel *chp) xfer->c_slot = slot; out: - splx(s); + mutex_exit(&chp->ch_lock); return xfer; } @@ -1165,13 +1206,14 @@ void ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer) { struct ata_queue *chq = chp->ch_queue; - int s; + + mutex_enter(&chp->ch_lock); if (xfer->c_flags & C_WAITACT) { /* Someone is waiting for this xfer, so we can't free now */ xfer->c_flags |= C_FREE; wakeup(xfer); - return; + goto out; } #if NATA_PIOBM /* XXX wdc dependent code */ @@ -1185,11 +1227,17 @@ ata_free_xfer(struct ata_channel *chp, s } #endif - s = splbio(); KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0); KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0); chq->queue_xfers_avail |= __BIT(xfer->c_slot); - splx(s); + +out: + if (chq->queue_flags & QF_NEED_XFER) { + chq->queue_flags &= ~QF_NEED_XFER; + cv_broadcast(&chq->queue_busy); + } + + mutex_exit(&chp->ch_lock); } void @@ -1197,6 +1245,8 @@ ata_activate_xfer(struct ata_channel *ch { struct ata_queue * const chq = chp->ch_queue; + mutex_enter(&chp->ch_lock); + KASSERT(chq->queue_active < chq->queue_openings); KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0); @@ -1204,6 +1254,8 @@ ata_activate_xfer(struct ata_channel *ch TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain); chq->active_xfers_used |= __BIT(xfer->c_slot); chq->queue_active++; + + mutex_exit(&chp->ch_lock); } void @@ -1211,6 +1263,8 @@ ata_deactivate_xfer(struct ata_channel * { struct ata_queue * const chq = chp->ch_queue; + mutex_enter(&chp->ch_lock); + KASSERT(chq->queue_active > 0); KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0); @@ -1219,6 +1273,8 @@ ata_deactivate_xfer(struct ata_channel * TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain); chq->active_xfers_used &= ~__BIT(xfer->c_slot); chq->queue_active--; + + mutex_exit(&chp->ch_lock); } Index: src/sys/dev/ata/atavar.h diff -u src/sys/dev/ata/atavar.h:1.92.8.9 src/sys/dev/ata/atavar.h:1.92.8.10 --- src/sys/dev/ata/atavar.h:1.92.8.9 Fri Jun 16 20:40:49 2017 +++ src/sys/dev/ata/atavar.h Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: atavar.h,v 1.92.8.9 2017/06/16 20:40:49 jdolecek Exp $ */ +/* $NetBSD: atavar.h,v 1.92.8.10 2017/06/19 21:00:00 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -186,12 +186,14 @@ struct ata_xfer { /* Per-channel queue of ata_xfers */ struct ata_queue { TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */ - int queue_freeze; /* freeze count for the queue */ - int queue_flags; /* flags for this queue */ -#define QF_IDLE_WAIT 0x01 /* someone wants the controller idle */ - int queue_active; /* number of active transfers */ - int queue_openings; /* max number of active transfers */ + int queue_freeze; /* freeze count for the queue */ + int8_t queue_flags; /* flags for this queue */ +#define QF_IDLE_WAIT 0x01 /* someone wants the controller idle */ +#define QF_NEED_XFER 0x02 /* someone wants xfer */ + int8_t queue_active; /* number of active transfers */ + int8_t queue_openings; /* max number of active transfers */ #ifdef ATABUS_PRIVATE + kcondvar_t queue_busy; /* c: waiting of xfer */ TAILQ_HEAD(, ata_xfer) active_xfers; /* active commands */ uint32_t active_xfers_used; /* mask of active commands */ uint32_t queue_xfers_avail; /* available xfers mask */ @@ -358,6 +360,7 @@ struct ata_device { struct ata_channel { int ch_channel; /* location */ struct atac_softc *ch_atac; /* ATA controller softc */ + kmutex_t ch_lock; /* channel lock - queue */ /* Our state */ volatile int ch_flags; @@ -457,6 +460,9 @@ struct atac_softc { #ifdef _KERNEL void ata_channel_attach(struct ata_channel *); +void ata_channel_init(struct ata_channel *); +void ata_channel_detach(struct ata_channel *); +void ata_channel_destroy(struct ata_channel *); int atabusprint(void *aux, const char *); int ataprint(void *aux, const char *); @@ -471,7 +477,7 @@ int ata_set_mode(struct ata_drive_datas #define CMD_ERR 1 #define CMD_AGAIN 2 -struct ata_xfer *ata_get_xfer(struct ata_channel *); +struct ata_xfer *ata_get_xfer(struct ata_channel *, bool); void ata_free_xfer(struct ata_channel *, struct ata_xfer *); #define ATAXF_CANSLEEP 0x00 #define ATAXF_NOSLEEP 0x01 @@ -497,8 +503,6 @@ 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(uint8_t openings); void ata_queue_free(struct ata_queue *); Index: src/sys/dev/ata/satapmp_subr.c diff -u src/sys/dev/ata/satapmp_subr.c:1.12.24.2 src/sys/dev/ata/satapmp_subr.c:1.12.24.3 --- src/sys/dev/ata/satapmp_subr.c:1.12.24.2 Sat Jun 17 14:01:36 2017 +++ src/sys/dev/ata/satapmp_subr.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: satapmp_subr.c,v 1.12.24.2 2017/06/17 14:01:36 jdolecek Exp $ */ +/* $NetBSD: satapmp_subr.c,v 1.12.24.3 2017/06/19 21:00:00 jdolecek Exp $ */ /* * Copyright (c) 2012 Manuel Bouyer. All rights reserved. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.12.24.2 2017/06/17 14:01:36 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.12.24.3 2017/06/19 21:00:00 jdolecek Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -50,7 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: satapmp_subr static int satapmp_read_8(struct ata_channel *chp, int port, int reg, uint64_t *value) { - struct ata_xfer xfer; + struct ata_xfer *xfer; struct atac_softc *atac = chp->ch_atac; struct ata_drive_datas *drvp; int error = 0; @@ -61,45 +61,47 @@ satapmp_read_8(struct ata_channel *chp, drvp = &chp->ch_drive[PMP_PORT_CTL]; KASSERT(drvp->drive == PMP_PORT_CTL); - ata_xfer_init(&xfer, true); - - xfer.c_ata_c.r_command = PMPC_READ_PORT; - xfer.c_ata_c.r_features = reg; - xfer.c_ata_c.r_device = port; - xfer.c_ata_c.timeout = 3000; /* 3s */ - xfer.c_ata_c.r_st_bmask = 0; - xfer.c_ata_c.r_st_pmask = WDCS_DRDY; - xfer.c_ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT; + xfer = ata_get_xfer(chp, true); + if (xfer == NULL) + return EINTR; + + xfer->c_ata_c.r_command = PMPC_READ_PORT; + xfer->c_ata_c.r_features = reg; + xfer->c_ata_c.r_device = port; + xfer->c_ata_c.timeout = 3000; /* 3s */ + xfer->c_ata_c.r_st_bmask = 0; + xfer->c_ata_c.r_st_pmask = WDCS_DRDY; + xfer->c_ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT; if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, - &xfer) != ATACMD_COMPLETE) { + xfer) != ATACMD_COMPLETE) { aprint_error_dev(chp->atabus, "PMP port %d register %d read failed\n", port, reg); error = EIO; goto out; } - if (xfer.c_ata_c.flags & (AT_TIMEOU | AT_DF)) { + if (xfer->c_ata_c.flags & (AT_TIMEOU | AT_DF)) { aprint_error_dev(chp->atabus, "PMP port %d register %d read failed, flags 0x%x\n", - port, reg, xfer.c_ata_c.flags); + port, reg, xfer->c_ata_c.flags); error = EIO; goto out; } - if (xfer.c_ata_c.flags & AT_ERROR) { + if (xfer->c_ata_c.flags & AT_ERROR) { aprint_verbose_dev(chp->atabus, "PMP port %d register %d read failed, error 0x%x\n", - port, reg, xfer.c_ata_c.r_error); + port, reg, xfer->c_ata_c.r_error); error = EIO; goto out; } - *value = ((uint64_t)((xfer.c_ata_c.r_lba >> 24) & 0xffffff) << 40) | - ((uint64_t)((xfer.c_ata_c.r_count >> 8) & 0xff) << 32) | - ((uint64_t)((xfer.c_ata_c.r_lba >> 0) & 0xffffff) << 8) | - ((uint64_t)((xfer.c_ata_c.r_count >> 0) & 0xff) << 0); + *value = ((uint64_t)((xfer->c_ata_c.r_lba >> 24) & 0xffffff) << 40) | + ((uint64_t)((xfer->c_ata_c.r_count >> 8) & 0xff) << 32) | + ((uint64_t)((xfer->c_ata_c.r_lba >> 0) & 0xffffff) << 8) | + ((uint64_t)((xfer->c_ata_c.r_count >> 0) & 0xff) << 0); out: - ata_xfer_destroy(&xfer); + ata_free_xfer(chp, xfer); return error; } @@ -120,7 +122,7 @@ satapmp_read(struct ata_channel *chp, in static int satapmp_write_8(struct ata_channel *chp, int port, int reg, uint64_t value) { - struct ata_xfer xfer; + struct ata_xfer *xfer; struct atac_softc *atac = chp->ch_atac; struct ata_drive_datas *drvp; int error = 0; @@ -131,44 +133,46 @@ satapmp_write_8(struct ata_channel *chp, drvp = &chp->ch_drive[PMP_PORT_CTL]; KASSERT(drvp->drive == PMP_PORT_CTL); - ata_xfer_init(&xfer, true); - - xfer.c_ata_c.r_command = PMPC_WRITE_PORT; - xfer.c_ata_c.r_features = reg; - xfer.c_ata_c.r_device = port; - xfer.c_ata_c.r_lba = (((value >> 40) & 0xffffff) << 24) | + xfer = ata_get_xfer(chp, true); + if (xfer == NULL) + return EINTR; + + xfer->c_ata_c.r_command = PMPC_WRITE_PORT; + xfer->c_ata_c.r_features = reg; + xfer->c_ata_c.r_device = port; + xfer->c_ata_c.r_lba = (((value >> 40) & 0xffffff) << 24) | (((value >> 8) & 0xffffff) << 0); - xfer.c_ata_c.r_count = (((value >> 32) & 0xff) << 8) | + xfer->c_ata_c.r_count = (((value >> 32) & 0xff) << 8) | (((value >> 0) & 0xff) << 0); - xfer.c_ata_c.timeout = 3000; /* 3s */ - xfer.c_ata_c.r_st_bmask = 0; - xfer.c_ata_c.r_st_pmask = WDCS_DRDY; - xfer.c_ata_c.flags = AT_LBA48 | AT_WAIT; + xfer->c_ata_c.timeout = 3000; /* 3s */ + xfer->c_ata_c.r_st_bmask = 0; + xfer->c_ata_c.r_st_pmask = WDCS_DRDY; + xfer->c_ata_c.flags = AT_LBA48 | AT_WAIT; if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, - &xfer) != ATACMD_COMPLETE) { + xfer) != ATACMD_COMPLETE) { aprint_error_dev(chp->atabus, "PMP port %d register %d write failed\n", port, reg); error = EIO; goto out; } - if (xfer.c_ata_c.flags & (AT_TIMEOU | AT_DF)) { + if (xfer->c_ata_c.flags & (AT_TIMEOU | AT_DF)) { aprint_error_dev(chp->atabus, "PMP port %d register %d write failed, flags 0x%x\n", - port, reg, xfer.c_ata_c.flags); + port, reg, xfer->c_ata_c.flags); error = EIO; goto out; } - if (xfer.c_ata_c.flags & AT_ERROR) { + if (xfer->c_ata_c.flags & AT_ERROR) { aprint_verbose_dev(chp->atabus, "PMP port %d register %d write failed, error 0x%x\n", - port, reg, xfer.c_ata_c.r_error); + port, reg, xfer->c_ata_c.r_error); error = EIO; goto out; } out: - ata_xfer_destroy(&xfer); + ata_free_xfer(chp, xfer); return error; } Index: src/sys/dev/ata/wd.c diff -u src/sys/dev/ata/wd.c:1.428.2.17 src/sys/dev/ata/wd.c:1.428.2.18 --- src/sys/dev/ata/wd.c:1.428.2.17 Mon Jun 19 17:11:24 2017 +++ src/sys/dev/ata/wd.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: wd.c,v 1.428.2.17 2017/06/19 17:11:24 jdolecek Exp $ */ +/* $NetBSD: wd.c,v 1.428.2.18 2017/06/19 21:00:00 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.17 2017/06/19 17:11:24 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.18 2017/06/19 21:00:00 jdolecek Exp $"); #include "opt_ata.h" @@ -646,8 +646,8 @@ wdstart(struct wd_softc *wd) while (bufq_peek(wd->sc_q) != NULL) { /* First try to get command */ - xfer = ata_get_xfer(wd->drvp->chnl_softc); - if (!xfer) + xfer = ata_get_xfer(wd->drvp->chnl_softc, false); + if (xfer == NULL) break; /* There is got to be a buf for us */ @@ -1637,7 +1637,7 @@ wddump(dev_t dev, daddr_t blkno, void *v wd->drvp->state = RESET; } - xfer = ata_get_xfer(wd->drvp->chnl_softc); + xfer = ata_get_xfer(wd->drvp->chnl_softc, false); if (xfer == NULL) return EAGAIN; @@ -1812,7 +1812,7 @@ int wd_setcache(struct wd_softc *wd, int bits) { struct ataparams params; - struct ata_xfer xfer; + struct ata_xfer *xfer; int error; if (wd_get_params(wd, AT_WAIT, ¶ms) != 0) @@ -1827,26 +1827,29 @@ wd_setcache(struct wd_softc *wd, int bit (bits & DKCACHE_SAVE) != 0) return EOPNOTSUPP; - 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; - xfer.c_ata_c.timeout = 30000; /* 30s timeout */ - xfer.c_ata_c.flags = AT_WAIT; + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); + if (xfer == NULL) + return EINTR; + + xfer->c_ata_c.r_command = SET_FEATURES; + xfer->c_ata_c.r_st_bmask = 0; + xfer->c_ata_c.r_st_pmask = 0; + xfer->c_ata_c.timeout = 30000; /* 30s timeout */ + xfer->c_ata_c.flags = AT_WAIT; if (bits & DKCACHE_WRITE) - xfer.c_ata_c.r_features = WDSF_WRITE_CACHE_EN; + xfer->c_ata_c.r_features = WDSF_WRITE_CACHE_EN; else - xfer.c_ata_c.r_features = WDSF_WRITE_CACHE_DS; - if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) { + xfer->c_ata_c.r_features = WDSF_WRITE_CACHE_DS; + if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { aprint_error_dev(wd->sc_dev, "wd_setcache command not complete\n"); error = EIO; goto out; } - if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { + 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); + snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags); aprint_error_dev(wd->sc_dev, "wd_setcache: status=%s\n", sbuf); error = EIO; goto out; @@ -1855,38 +1858,41 @@ wd_setcache(struct wd_softc *wd, int bit error = 0; out: - ata_xfer_destroy(&xfer); + ata_free_xfer(wd->drvp->chnl_softc, xfer); return error; } static int wd_standby(struct wd_softc *wd, int flags) { - struct ata_xfer xfer; + struct ata_xfer *xfer; int error; - 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; - xfer.c_ata_c.flags = flags; - xfer.c_ata_c.timeout = 30000; /* 30s timeout */ - if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) { + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); + if (xfer == NULL) + return EINTR; + + 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; + xfer->c_ata_c.flags = flags; + xfer->c_ata_c.timeout = 30000; /* 30s timeout */ + if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { aprint_error_dev(wd->sc_dev, "standby immediate command didn't complete\n"); error = EIO; goto out; } - if (xfer.c_ata_c.flags & AT_ERROR) { - if (xfer.c_ata_c.r_error == WDCE_ABRT) { + if (xfer->c_ata_c.flags & AT_ERROR) { + if (xfer->c_ata_c.r_error == WDCE_ABRT) { /* command not supported */ error = ENODEV; goto out; } } - if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { + 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); + snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags); aprint_error_dev(wd->sc_dev, "wd_standby: status=%s\n", sbuf); error = EIO; goto out; @@ -1894,14 +1900,14 @@ wd_standby(struct wd_softc *wd, int flag error = 0; out: - ata_xfer_destroy(&xfer); + ata_free_xfer(wd->drvp->chnl_softc, xfer); return error; } int wd_flushcache(struct wd_softc *wd, int flags) { - struct ata_xfer xfer; + struct ata_xfer *xfer; int error; /* @@ -1913,33 +1919,36 @@ wd_flushcache(struct wd_softc *wd, int f wd->sc_params.atap_cmd_set2 == 0xffff)) return ENODEV; - ata_xfer_init(&xfer, true); + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); + if (xfer == NULL) + return EINTR; + 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; + xfer->c_ata_c.r_command = WDCC_FLUSHCACHE_EXT; flags |= AT_LBA48; } else - xfer.c_ata_c.r_command = WDCC_FLUSHCACHE; - xfer.c_ata_c.r_st_bmask = WDCS_DRDY; - xfer.c_ata_c.r_st_pmask = WDCS_DRDY; - xfer.c_ata_c.flags = flags | AT_READREG; - xfer.c_ata_c.timeout = 300000; /* 5m timeout */ - if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) { + xfer->c_ata_c.r_command = WDCC_FLUSHCACHE; + xfer->c_ata_c.r_st_bmask = WDCS_DRDY; + xfer->c_ata_c.r_st_pmask = WDCS_DRDY; + xfer->c_ata_c.flags = flags | AT_READREG; + xfer->c_ata_c.timeout = 300000; /* 5m timeout */ + if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { aprint_error_dev(wd->sc_dev, "flush cache command didn't complete\n"); error = EIO; goto out; } - if (xfer.c_ata_c.flags & AT_ERROR) { - if (xfer.c_ata_c.r_error == WDCE_ABRT) { + if (xfer->c_ata_c.flags & AT_ERROR) { + if (xfer->c_ata_c.r_error == WDCE_ABRT) { /* command not supported */ error = ENODEV; goto out; } } - if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { + 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); + snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags); aprint_error_dev(wd->sc_dev, "wd_flushcache: status=%s\n", sbuf); error = EIO; @@ -1948,20 +1957,24 @@ wd_flushcache(struct wd_softc *wd, int f error = 0; out: - ata_xfer_destroy(&xfer); + ata_free_xfer(wd->drvp->chnl_softc, xfer); return error; } int wd_trim(struct wd_softc *wd, int part, daddr_t bno, long size) { - struct ata_xfer xfer; + struct ata_xfer *xfer; int error; unsigned char *req; if (part != RAW_PART) bno += wd->sc_dk.dk_label->d_partitions[part].p_offset;; + xfer = ata_get_xfer(wd->drvp->chnl_softc, true); + if (xfer == NULL) + return EINTR; + req = kmem_zalloc(512, KM_SLEEP); req[0] = bno & 0xff; req[1] = (bno >> 8) & 0xff; @@ -1972,17 +1985,16 @@ wd_trim(struct wd_softc *wd, int part, d req[6] = size & 0xff; req[7] = (size >> 8) & 0xff; - 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; - xfer.c_ata_c.r_st_bmask = WDCS_DRDY; - xfer.c_ata_c.r_st_pmask = WDCS_DRDY; - xfer.c_ata_c.timeout = 30000; /* 30s timeout */ - xfer.c_ata_c.data = req; - xfer.c_ata_c.bcount = 512; - xfer.c_ata_c.flags |= AT_WRITE | AT_WAIT; - if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) { + 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; + xfer->c_ata_c.r_st_bmask = WDCS_DRDY; + xfer->c_ata_c.r_st_pmask = WDCS_DRDY; + xfer->c_ata_c.timeout = 30000; /* 30s timeout */ + xfer->c_ata_c.data = req; + xfer->c_ata_c.bcount = 512; + xfer->c_ata_c.flags |= AT_WRITE | AT_WAIT; + if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { aprint_error_dev(wd->sc_dev, "trim command didn't complete\n"); kmem_free(req, 512); @@ -1990,16 +2002,16 @@ wd_trim(struct wd_softc *wd, int part, d goto out; } kmem_free(req, 512); - if (xfer.c_ata_c.flags & AT_ERROR) { - if (xfer.c_ata_c.r_error == WDCE_ABRT) { + if (xfer->c_ata_c.flags & AT_ERROR) { + if (xfer->c_ata_c.r_error == WDCE_ABRT) { /* command not supported */ error = ENODEV; goto out; } } - if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { + 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); + snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags); aprint_error_dev(wd->sc_dev, "wd_trim: status=%s\n", sbuf); error = EIO; @@ -2008,7 +2020,7 @@ wd_trim(struct wd_softc *wd, int part, d error = 0; out: - ata_xfer_destroy(&xfer); + ata_free_xfer(wd->drvp->chnl_softc, xfer); return error; } @@ -2114,7 +2126,7 @@ void wdioctlstrategy(struct buf *bp) { struct wd_ioctl *wi; - struct ata_xfer xfer; + struct ata_xfer *xfer; int error = 0; wi = wi_find(bp); @@ -2125,7 +2137,11 @@ wdioctlstrategy(struct buf *bp) goto out2; } - ata_xfer_init(&xfer, true); + xfer = ata_get_xfer(wi->wi_softc->drvp->chnl_softc, true); + if (xfer == NULL) { + error = EINTR; + goto out2; + } /* * Abort if physio broke up the transfer @@ -2159,62 +2175,62 @@ wdioctlstrategy(struct buf *bp) } if (wi->wi_atareq.flags & ATACMD_READ) - xfer.c_ata_c.flags |= AT_READ; + xfer->c_ata_c.flags |= AT_READ; else if (wi->wi_atareq.flags & ATACMD_WRITE) - xfer.c_ata_c.flags |= AT_WRITE; + xfer->c_ata_c.flags |= AT_WRITE; if (wi->wi_atareq.flags & ATACMD_READREG) - xfer.c_ata_c.flags |= AT_READREG; + xfer->c_ata_c.flags |= AT_READREG; if ((wi->wi_atareq.flags & ATACMD_LBA) != 0) - xfer.c_ata_c.flags |= AT_LBA; + xfer->c_ata_c.flags |= AT_LBA; - xfer.c_ata_c.flags |= AT_WAIT; + xfer->c_ata_c.flags |= AT_WAIT; - xfer.c_ata_c.timeout = wi->wi_atareq.timeout; - xfer.c_ata_c.r_command = wi->wi_atareq.command; - xfer.c_ata_c.r_lba = ((wi->wi_atareq.head & 0x0f) << 24) | + xfer->c_ata_c.timeout = wi->wi_atareq.timeout; + xfer->c_ata_c.r_command = wi->wi_atareq.command; + xfer->c_ata_c.r_lba = ((wi->wi_atareq.head & 0x0f) << 24) | (wi->wi_atareq.cylinder << 8) | wi->wi_atareq.sec_num; - xfer.c_ata_c.r_count = wi->wi_atareq.sec_count; - xfer.c_ata_c.r_features = wi->wi_atareq.features; - xfer.c_ata_c.r_st_bmask = WDCS_DRDY; - xfer.c_ata_c.r_st_pmask = WDCS_DRDY; - xfer.c_ata_c.data = wi->wi_bp.b_data; - xfer.c_ata_c.bcount = wi->wi_bp.b_bcount; + xfer->c_ata_c.r_count = wi->wi_atareq.sec_count; + xfer->c_ata_c.r_features = wi->wi_atareq.features; + xfer->c_ata_c.r_st_bmask = WDCS_DRDY; + xfer->c_ata_c.r_st_pmask = WDCS_DRDY; + xfer->c_ata_c.data = wi->wi_bp.b_data; + xfer->c_ata_c.bcount = wi->wi_bp.b_bcount; - if (wi->wi_softc->atabus->ata_exec_command(wi->wi_softc->drvp, &xfer) + if (wi->wi_softc->atabus->ata_exec_command(wi->wi_softc->drvp, xfer) != ATACMD_COMPLETE) { wi->wi_atareq.retsts = ATACMD_ERROR; error = EIO; goto out; } - if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { - if (xfer.c_ata_c.flags & AT_ERROR) { + if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { + if (xfer->c_ata_c.flags & AT_ERROR) { wi->wi_atareq.retsts = ATACMD_ERROR; - wi->wi_atareq.error = xfer.c_ata_c.r_error; - } else if (xfer.c_ata_c.flags & AT_DF) + wi->wi_atareq.error = xfer->c_ata_c.r_error; + } else if (xfer->c_ata_c.flags & AT_DF) wi->wi_atareq.retsts = ATACMD_DF; else wi->wi_atareq.retsts = ATACMD_TIMEOUT; } else { wi->wi_atareq.retsts = ATACMD_OK; if (wi->wi_atareq.flags & ATACMD_READREG) { - wi->wi_atareq.command = xfer.c_ata_c.r_status; - wi->wi_atareq.features = xfer.c_ata_c.r_error; - wi->wi_atareq.sec_count = xfer.c_ata_c.r_count; - wi->wi_atareq.sec_num = xfer.c_ata_c.r_lba & 0xff; - wi->wi_atareq.head = (xfer.c_ata_c.r_device & 0xf0) | - ((xfer.c_ata_c.r_lba >> 24) & 0x0f); + wi->wi_atareq.command = xfer->c_ata_c.r_status; + wi->wi_atareq.features = xfer->c_ata_c.r_error; + wi->wi_atareq.sec_count = xfer->c_ata_c.r_count; + wi->wi_atareq.sec_num = xfer->c_ata_c.r_lba & 0xff; + wi->wi_atareq.head = (xfer->c_ata_c.r_device & 0xf0) | + ((xfer->c_ata_c.r_lba >> 24) & 0x0f); wi->wi_atareq.cylinder = - (xfer.c_ata_c.r_lba >> 8) & 0xffff; - wi->wi_atareq.error = xfer.c_ata_c.r_error; + (xfer->c_ata_c.r_lba >> 8) & 0xffff; + wi->wi_atareq.error = xfer->c_ata_c.r_error; } } out: - ata_xfer_destroy(&xfer); + ata_free_xfer(wi->wi_softc->drvp->chnl_softc, xfer); out2: bp->b_error = error; if (error) Index: src/sys/dev/ic/ahcisata_core.c diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.13 src/sys/dev/ic/ahcisata_core.c:1.57.6.14 --- src/sys/dev/ic/ahcisata_core.c:1.57.6.13 Fri Jun 16 20:40:49 2017 +++ src/sys/dev/ic/ahcisata_core.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ahcisata_core.c,v 1.57.6.13 2017/06/16 20:40:49 jdolecek Exp $ */ +/* $NetBSD: ahcisata_core.c,v 1.57.6.14 2017/06/19 21:00:00 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.13 2017/06/16 20:40:49 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.14 2017/06/19 21:00:00 jdolecek Exp $"); #include <sys/types.h> #include <sys/malloc.h> @@ -511,6 +511,8 @@ ahci_detach(struct ahci_softc *sc, int f ata_queue_free(chp->ch_queue); chp->ch_queue = NULL; chp->atabus = NULL; + + ata_channel_detach(chp); } bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_hdrd); @@ -1567,7 +1569,7 @@ ahci_atapi_scsipi_request(struct scsipi_ scsipi_done(sc_xfer); return; } - xfer = ata_get_xfer(atac->atac_channels[channel]); + xfer = ata_get_xfer(atac->atac_channels[channel], false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/ic/mvsata.c diff -u src/sys/dev/ic/mvsata.c:1.35.6.11 src/sys/dev/ic/mvsata.c:1.35.6.12 --- src/sys/dev/ic/mvsata.c:1.35.6.11 Fri Jun 16 20:40:49 2017 +++ src/sys/dev/ic/mvsata.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsata.c,v 1.35.6.11 2017/06/16 20:40:49 jdolecek Exp $ */ +/* $NetBSD: mvsata.c,v 1.35.6.12 2017/06/19 21:00:00 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.11 2017/06/16 20:40:49 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.12 2017/06/19 21:00:00 jdolecek Exp $"); #include "opt_mvsata.h" @@ -791,7 +791,7 @@ mvsata_atapi_scsipi_request(struct scsip scsipi_done(sc_xfer); return; } - xfer = ata_get_xfer(chp); + xfer = ata_get_xfer(chp, false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/ic/siisata.c diff -u src/sys/dev/ic/siisata.c:1.30.4.16 src/sys/dev/ic/siisata.c:1.30.4.17 --- src/sys/dev/ic/siisata.c:1.30.4.16 Fri Jun 16 20:40:49 2017 +++ src/sys/dev/ic/siisata.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: siisata.c,v 1.30.4.16 2017/06/16 20:40:49 jdolecek Exp $ */ +/* $NetBSD: siisata.c,v 1.30.4.17 2017/06/19 21:00:00 jdolecek Exp $ */ /* from ahcisata_core.c */ @@ -79,7 +79,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.16 2017/06/16 20:40:49 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.17 2017/06/19 21:00:00 jdolecek Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -425,6 +425,8 @@ siisata_detach(struct siisata_softc *sc, free(chp->ch_queue, M_DEVBUF); chp->atabus = NULL; + + ata_channel_detach(chp); } if (adapt->adapt_refcnt != 0) @@ -582,22 +584,29 @@ siisata_reset_drive(struct ata_drive_dat while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY)) DELAY(10); - xfer = ata_get_xfer(chp); /* Is this right? What if the slots are full? */ - if (xfer == NULL) + /* + * Try to get available slot. If there is none available, must + * do full channel reset. + */ + xfer = ata_get_xfer(chp, false); + if (xfer == NULL) { + siisata_reset_channel(chp, flags); return; + } prb = schp->sch_prb[xfer->c_slot]; memset(prb, 0, SIISATA_CMD_SIZE); prb->prb_control = - htole16(PRB_CF_SOFT_RESET /* | PRB_CF_INTERRUPT_MASK */); + htole16(PRB_CF_SOFT_RESET | PRB_CF_INTERRUPT_MASK); KASSERT(drvp->drive <= PMP_PORT_CTL); prb->prb_fis[rhd_c] = drvp->drive; - ata_activate_xfer(chp, xfer); + siisata_disable_port_interrupt(chp); + siisata_activate_prb(schp, xfer->c_slot); for(i = 0; i < 3100; i++) { -#if 0 /* XXX-jak-jd-ncq this block needs re-work... XXX */ +#if 1 /* XXX-jak-jd-ncq this block needs re-work... XXX */ PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_INCOR); pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)); PRWRITE(sc, PRX(chp->ch_channel, PRO_PCC), PR_PC_INCOR); @@ -626,6 +635,8 @@ siisata_reset_drive(struct ata_drive_dat PR_PIS_CMDERRR); } + siisata_enable_port_interrupt(chp); + if (i == 3100) { /* timeout */ siisata_device_reset(chp); /* XXX is this right? */ @@ -642,7 +653,6 @@ siisata_reset_drive(struct ata_drive_dat } } - ata_deactivate_xfer(chp, xfer); ata_free_xfer(chp, xfer); #if 1 @@ -723,11 +733,19 @@ siisata_probe_drive(struct ata_channel * uint32_t sig; struct siisata_prb *prb; bool timed_out; - const u_int slot0 = 0; /* XXX this is a problem */ + struct ata_xfer *xfer; SIISATA_DEBUG_PRINT(("%s: %s: port %d start\n", SIISATANAME(sc), __func__, chp->ch_channel), DEBUG_FUNCS); + xfer = ata_get_xfer(chp, true); + if (xfer == NULL) { + aprint_error_dev(sc->sc_atac.atac_dev, + "failed to get xfer port %d\n", + chp->ch_channel); + return; + } + /* * disable port interrupt as we're polling for PHY up and * prb completion @@ -747,17 +765,17 @@ siisata_probe_drive(struct ata_channel * while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY)) DELAY(10); - prb = schp->sch_prb[slot0]; + prb = schp->sch_prb[xfer->c_slot]; memset(prb, 0, SIISATA_CMD_SIZE); prb->prb_control = htole16(PRB_CF_SOFT_RESET); prb->prb_fis[rhd_c] = PMP_PORT_CTL; - siisata_activate_prb(schp, slot0); + siisata_activate_prb(schp, xfer->c_slot); timed_out = 1; for(i = 0; i < 3100; i++) { if ((PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) & - PR_PXSS(slot0)) == 0) { + PR_PXSS(xfer->c_slot)) == 0) { /* prb completed */ timed_out = 0; break; @@ -771,7 +789,8 @@ siisata_probe_drive(struct ata_channel * tsleep(schp, PRIBIO, "siiprb", mstohz(10)); } - siisata_deactivate_prb(schp, slot0); + siisata_deactivate_prb(schp, xfer->c_slot); + if (timed_out) { aprint_error_dev(sc->sc_atac.atac_dev, "SOFT_RESET failed on port %d (error %d PSS 0x%x), " @@ -784,9 +803,9 @@ siisata_probe_drive(struct ata_channel * /* read the signature out of the FIS */ sig = 0; - sig |= (PRREAD(sc, PRSX(chp->ch_channel, slot0, + sig |= (PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot, PRSO_FIS+0x4)) & 0x00ffffff) << 8; - sig |= PRREAD(sc, PRSX(chp->ch_channel, slot0, + sig |= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot, PRSO_FIS+0xc)) & 0xff; SIISATA_DEBUG_PRINT(("%s: %s: sig=0x%08x\n", SIISATANAME(sc), @@ -1578,7 +1597,7 @@ siisata_atapi_scsipi_request(struct scsi scsipi_done(sc_xfer); return; } - xfer = ata_get_xfer(atac->atac_channels[channel]); + xfer = ata_get_xfer(atac->atac_channels[channel], false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/ic/wdc.c diff -u src/sys/dev/ic/wdc.c:1.283.2.5 src/sys/dev/ic/wdc.c:1.283.2.6 --- src/sys/dev/ic/wdc.c:1.283.2.5 Fri Jun 16 20:40:49 2017 +++ src/sys/dev/ic/wdc.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: wdc.c,v 1.283.2.5 2017/06/16 20:40:49 jdolecek Exp $ */ +/* $NetBSD: wdc.c,v 1.283.2.6 2017/06/19 21:00:00 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.5 2017/06/16 20:40:49 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.6 2017/06/19 21:00:00 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wdc.h" @@ -823,6 +823,7 @@ wdcdetach(device_t self, int flags) DEBUG_DETACH); if ((error = config_detach(chp->atabus, flags)) != 0) return error; + ata_channel_detach(chp); } if (adapt->adapt_refcnt != 0) return EBUSY; Index: src/sys/dev/scsipi/atapi_wdc.c diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.5 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.6 --- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.5 Fri Jun 16 20:40:49 2017 +++ src/sys/dev/scsipi/atapi_wdc.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: atapi_wdc.c,v 1.123.4.5 2017/06/16 20:40:49 jdolecek Exp $ */ +/* $NetBSD: atapi_wdc.c,v 1.123.4.6 2017/06/19 21:00:00 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.5 2017/06/16 20:40:49 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.6 2017/06/19 21:00:00 jdolecek Exp $"); #ifndef ATADEBUG #define ATADEBUG @@ -198,27 +198,31 @@ wdc_atapi_get_params(struct scsipi_chann struct atac_softc *atac = &wdc->sc_atac; struct wdc_regs *wdr = &wdc->regs[chan->chan_channel]; struct ata_channel *chp = atac->atac_channels[chan->chan_channel]; - struct ata_xfer xfer; + struct ata_xfer *xfer; int rv; - ata_xfer_init(&xfer, true); + xfer = ata_get_xfer(chp, true); + if (xfer == NULL) { + printf("wdc_atapi_get_params: no xfer\n"); + return EBUSY; + } - 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; - xfer.c_ata_c.flags = AT_WAIT | AT_POLL; - xfer.c_ata_c.timeout = WDC_RESET_WAIT; - if (wdc_exec_command(&chp->ch_drive[drive], &xfer) != ATACMD_COMPLETE) { + 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; + xfer->c_ata_c.flags = AT_WAIT | AT_POLL; + xfer->c_ata_c.timeout = WDC_RESET_WAIT; + if (wdc_exec_command(&chp->ch_drive[drive], xfer) != ATACMD_COMPLETE) { printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for" " drive %s:%d:%d: driver failed\n", device_xname(atac->atac_dev), chp->ch_channel, drive); panic("wdc_atapi_get_params"); } - if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { + if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_SOFT_RESET " "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); + xfer->c_ata_c.r_error), DEBUG_PROBE); rv = -1; goto out; } @@ -232,14 +236,14 @@ wdc_atapi_get_params(struct scsipi_chann ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE " "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); + xfer->c_ata_c.r_error), DEBUG_PROBE); rv = -1; goto out; } rv = 0; out: - ata_xfer_destroy(&xfer); + ata_free_xfer(chp, xfer); return rv; } @@ -372,7 +376,7 @@ wdc_atapi_scsipi_request(struct scsipi_c return; } - xfer = ata_get_xfer(atac->atac_channels[channel]); + xfer = ata_get_xfer(atac->atac_channels[channel], false); if (xfer == NULL) { sc_xfer->error = XS_RESOURCE_SHORTAGE; scsipi_done(sc_xfer); Index: src/sys/dev/usb/umass_isdata.c diff -u src/sys/dev/usb/umass_isdata.c:1.33.4.2 src/sys/dev/usb/umass_isdata.c:1.33.4.3 --- src/sys/dev/usb/umass_isdata.c:1.33.4.2 Thu Apr 20 20:14:42 2017 +++ src/sys/dev/usb/umass_isdata.c Mon Jun 19 21:00:00 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: umass_isdata.c,v 1.33.4.2 2017/04/20 20:14:42 jdolecek Exp $ */ +/* $NetBSD: umass_isdata.c,v 1.33.4.3 2017/06/19 21:00:00 jdolecek Exp $ */ /* * TODO: @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33.4.2 2017/04/20 20:14:42 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33.4.3 2017/06/19 21:00:00 jdolecek Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -221,6 +221,7 @@ umass_isdata_attach(struct umass_softc * adev.adev_drv_data = &scbus->sc_drv_data; /* Fake ATA channel so wd(4) ata_{get,free}_xfer() work */ + ata_channel_init(&scbus->sc_channel); scbus->sc_channel.atabus = (device_t)scbus; scbus->sc_channel.ch_queue = ata_queue_alloc(1); @@ -520,7 +521,7 @@ uisdata_get_params(struct ata_drive_data struct ataparams *prms) { char tb[DEV_BSIZE]; - struct ata_xfer xfer; + struct ata_xfer *xfer; int rv; #if BYTE_ORDER == LITTLE_ENDIAN @@ -533,19 +534,23 @@ uisdata_get_params(struct ata_drive_data memset(tb, 0, DEV_BSIZE); memset(prms, 0, sizeof(struct ataparams)); - ata_xfer_init(&xfer, true); + xfer = ata_get_xfer(drvp->chnl_softc, true); + if (!xfer) { + rv = CMD_AGAIN; + goto out; + } - xfer.c_ata_c.r_command = WDCC_IDENTIFY; - xfer.c_ata_c.timeout = 1000; /* 1s */ - xfer.c_ata_c.flags = AT_READ | flags; - xfer.c_ata_c.data = tb; - xfer.c_ata_c.bcount = DEV_BSIZE; - if (uisdata_exec_command(drvp, &xfer) != ATACMD_COMPLETE) { + xfer->c_ata_c.r_command = WDCC_IDENTIFY; + xfer->c_ata_c.timeout = 1000; /* 1s */ + xfer->c_ata_c.flags = AT_READ | flags; + xfer->c_ata_c.data = tb; + xfer->c_ata_c.bcount = DEV_BSIZE; + if (uisdata_exec_command(drvp, xfer) != ATACMD_COMPLETE) { DPRINTF(("uisdata_get_parms: wdc_exec_command failed\n")); rv = CMD_AGAIN; goto out; } - if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { + if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { DPRINTF(("uisdata_get_parms: ata_c.flags=0x%x\n", ata_c.flags)); rv = CMD_ERR; @@ -585,7 +590,7 @@ uisdata_get_params(struct ata_drive_data rv = CMD_OK; out: - ata_xfer_destroy(&xfer); + ata_free_xfer(drvp->chnl_softc, xfer); return rv; }