Module Name: src
Committed By: jdolecek
Date: Sat Apr 15 12:01:24 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
src/sys/dev/usb [jdolecek-ncq]: umass_isdata.c
Log Message:
make ata_xfer's allocated as part of ata_queue and make it include ata_bio;
they are pre-allocated on attach and ata_get_xfer() now never sleep, drop the
pool
modify wd(4) to file the bio requests using the xfers and hence
make it possible to have more than one active I/O request in flight;
ata_bio callback doesn't need to allocate any memory any more,
require it to never return ATACMD_TRY_AGAIN
move lp, badsect, multi from ata_bio to ata_drive_datas, as they are per-drive,
not per transfer
drop unused drv atac_claim_hw/atac_free_hw hooks, and also drop again ata_bio
c_hwslot
To generate a diff of this commit:
cvs rdiff -u -r1.132.8.2 -r1.132.8.3 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.105.6.1 -r1.105.6.2 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.92.8.2 -r1.92.8.3 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.7 -r1.7.28.1 src/sys/dev/ata/satafis_subr.c
cvs rdiff -u -r1.428.2.2 -r1.428.2.3 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.43.4.1 -r1.43.4.2 src/sys/dev/ata/wdvar.h
cvs rdiff -u -r1.57.6.2 -r1.57.6.3 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35.6.3 -r1.35.6.4 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30.4.2 -r1.30.4.3 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283.2.1 -r1.283.2.2 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.123.4.1 -r1.123.4.2 src/sys/dev/scsipi/atapi_wdc.c
cvs rdiff -u -r1.33 -r1.33.4.1 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/ata.c
diff -u src/sys/dev/ata/ata.c:1.132.8.2 src/sys/dev/ata/ata.c:1.132.8.3
--- src/sys/dev/ata/ata.c:1.132.8.2 Tue Apr 11 18:15:03 2017
+++ src/sys/dev/ata/ata.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata.c,v 1.132.8.2 2017/04/11 18:15:03 jdolecek Exp $ */
+/* $NetBSD: ata.c,v 1.132.8.3 2017/04/15 12:01:23 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.2 2017/04/11 18:15:03 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.3 2017/04/15 12:01:23 jdolecek Exp $");
#include "opt_ata.h"
@@ -37,7 +37,6 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.13
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
-#include <sys/pool.h>
#include <sys/kthread.h>
#include <sys/errno.h>
#include <sys/ataio.h>
@@ -45,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.13
#include <sys/intr.h>
#include <sys/bus.h>
#include <sys/once.h>
+#include <sys/bitops.h>
#define ATABUS_PRIVATE
@@ -84,7 +84,6 @@ int atadebug_mask = ATADEBUG_MASK;
#endif
static ONCE_DECL(ata_init_ctrl);
-static struct pool ata_xfer_pool;
/*
* A queue of atabus instances, used to ensure the same bus probe order
@@ -139,8 +138,6 @@ static int
atabus_init(void)
{
- pool_init(&ata_xfer_pool, sizeof(struct ata_xfer), 0, 0, 0,
- "ataspl", NULL, IPL_BIO);
TAILQ_INIT(&atabus_initq_head);
mutex_init(&atabus_qlock, MUTEX_DEFAULT, IPL_NONE);
cv_init(&atabus_qcv, "atainitq");
@@ -187,29 +184,18 @@ ata_queue_reset(struct ata_queue *chq)
{
/* make sure that we can use polled commands */
TAILQ_INIT(&chq->queue_xfer);
+ TAILQ_INIT(&chq->active_xfers);
chq->queue_freeze = 0;
chq->queue_active = 0;
- for (u_int i = 0; i < chq->queue_openings; i++) {
- chq->active_xfers[0] = NULL;
- }
}
struct ata_xfer *
ata_queue_hwslot_to_xfer(struct ata_queue *chq, int hwslot)
{
KASSERT(hwslot < chq->queue_openings);
- if (chq->queue_openings == 1) {
- struct ata_xfer *xfer = chq->active_xfers[0];
- KASSERT(xfer == NULL || xfer->c_hwslot == hwslot);
- return xfer;
- }
- for (u_int i = 0; i < chq->queue_openings; i++) {
- struct ata_xfer *xfer = chq->active_xfers[i];
- if (xfer != NULL && xfer->c_hwslot == hwslot) {
- return xfer;
- }
- }
- return NULL;
+ KASSERT((chq->queue_xfers_avail & __BIT(hwslot)) == 0);
+
+ return &chq->queue_xfers[hwslot];
}
struct ata_queue *
@@ -217,10 +203,11 @@ ata_queue_alloc(int openings)
{
if (openings == 0)
openings = 1;
- struct ata_queue *chq = malloc(offsetof(struct ata_queue, active_xfers[openings]),
+ struct ata_queue *chq = malloc(offsetof(struct ata_queue, queue_xfers[openings]),
M_DEVBUF, M_WAITOK);
if (chq != NULL) {
chq->queue_openings = openings;
+ chq->queue_xfers_avail = (1 << openings) - 1;
ata_queue_reset(chq);
}
return chq;
@@ -520,11 +507,9 @@ atabus_thread(void *arg)
*/
chq->queue_freeze--;
u_int active __diagused = 0;
- for (i = 0; i < chq->queue_openings; i++) {
- if ((xfer = chq->active_xfers[i]) != NULL) {
- (*xfer->c_start)(xfer->c_chp, xfer);
- active++;
- }
+ TAILQ_FOREACH(xfer, &chq->active_xfers, c_activechain) {
+ (*xfer->c_start)(xfer->c_chp, xfer);
+ active++;
}
KASSERT(active == chq->queue_active);
} else if (chq->queue_freeze > 1)
@@ -961,7 +946,6 @@ ata_exec_xfer(struct ata_channel *chp, s
/* complete xfer setup */
xfer->c_chp = chp;
- xfer->c_slot = 0;
/* insert at the end of command list */
TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
@@ -1053,11 +1037,6 @@ atastart(struct ata_channel *chp)
if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0)
panic("atastart: channel waiting for irq");
#endif
- if (atac->atac_claim_hw) {
- if (!(*atac->atac_claim_hw)(chp, 0))
- return;
- }
-
ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d\n", xfer,
chp->ch_channel, xfer->c_drive), DEBUG_XFERS);
if (drvp->drive_flags & ATA_DRIVE_RESET) {
@@ -1065,18 +1044,6 @@ atastart(struct ata_channel *chp)
drvp->state = 0;
}
- if (chq->queue_openings == 1) {
- xfer->c_slot = 0;
- xfer->c_hwslot = 0;
- } else {
- for (u_int slot = 0; slot < chq->queue_openings; slot++) {
- if (chq->active_xfers[slot] == NULL) {
- xfer->c_slot = slot;
- xfer->c_hwslot = slot;
- break;
- }
- }
- }
ata_activate_xfer(chp, xfer);
if (atac->atac_cap & ATAC_CAP_NOIRQ)
@@ -1086,26 +1053,34 @@ atastart(struct ata_channel *chp)
}
struct ata_xfer *
-ata_get_xfer(int flags)
+ata_get_xfer(struct ata_channel *chp)
{
- struct ata_xfer *xfer;
+ struct ata_queue *chq = chp->ch_queue;
+ struct ata_xfer *xfer = NULL;
int s;
+ uint32_t avail, slot;
s = splbio();
- xfer = pool_get(&ata_xfer_pool,
- ((flags & ATAXF_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
+ avail = ffs32(chq->queue_xfers_avail);
+ if (avail == 0)
+ goto out;
+
+ slot = avail - 1;
+ xfer = &chq->queue_xfers[slot];
+ chq->queue_xfers_avail &= ~__BIT(slot);
+
+ memset(xfer, 0, sizeof(struct ata_xfer));
+ xfer->c_slot = slot;
+
+out:
splx(s);
- if (xfer != NULL) {
- memset(xfer, 0, sizeof(struct ata_xfer));
- }
- xfer->c_slot = -1;
return xfer;
}
void
ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
{
- struct atac_softc *atac = chp->ch_atac;
+ struct ata_queue *chq = chp->ch_queue;
int s;
if (xfer->c_flags & C_WAITACT) {
@@ -1126,10 +1101,9 @@ ata_free_xfer(struct ata_channel *chp, s
}
#endif
- if (atac->atac_free_hw)
- (*atac->atac_free_hw)(chp);
s = splbio();
- pool_put(&ata_xfer_pool, xfer);
+ KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
+ chq->queue_xfers_avail |= __BIT(xfer->c_slot);
splx(s);
}
@@ -1138,13 +1112,12 @@ ata_activate_xfer(struct ata_channel *ch
{
struct ata_queue * const chq = chp->ch_queue;
- KASSERT(xfer->c_slot >= 0);
KASSERT(chq->queue_active < chq->queue_openings);
- KASSERT(chq->active_xfers[xfer->c_slot] == NULL);
+ KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
TAILQ_REMOVE(&chq->queue_xfer, xfer, c_xferchain);
+ TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain);
- chq->active_xfers[xfer->c_slot] = xfer;
chq->queue_active++;
}
@@ -1153,17 +1126,14 @@ ata_deactivate_xfer(struct ata_channel *
{
struct ata_queue * const chq = chp->ch_queue;
- KASSERT(xfer->c_slot >= 0);
KASSERT(chq->queue_active > 0);
- KASSERT(chq->active_xfers[xfer->c_slot] == xfer);
+ KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
//if ((xfer->c_flags & C_TIMEOU) == 0)
callout_stop(&chp->ch_callout);
- chq->active_xfers[xfer->c_slot] = NULL;
+ TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
chq->queue_active--;
-
- xfer->c_slot = -1;
}
@@ -1172,7 +1142,7 @@ ata_waitdrain_check(struct ata_channel *
{
if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
- wakeup(chp->ch_queue->active_xfers);
+ wakeup(&chp->ch_queue->active_xfers);
return true;
}
return false;
@@ -1185,7 +1155,7 @@ ata_waitdrain_xfer_check(struct ata_chan
if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
(*xfer->c_kill_xfer)(chp, xfer, KILL_GONE);
chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
- wakeup(chp->ch_queue->active_xfers);
+ wakeup(&chp->ch_queue->active_xfers);
return true;
}
return false;
@@ -1200,12 +1170,10 @@ void
ata_kill_active(struct ata_channel *chp, int reason)
{
struct ata_queue * const chq = chp->ch_queue;
- for (u_int i = 0;
- chq->queue_active > 0 && i < chq->queue_openings; i++) {
- struct ata_xfer *xfer = chq->active_xfers[i];
- if (xfer != NULL) {
- (*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
- }
+ struct ata_xfer *xfer, *xfernext;
+
+ TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) {
+ (*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
}
}
@@ -1233,12 +1201,13 @@ ata_kill_pending(struct ata_drive_datas
while (chq->queue_active > 0) {
if (chq->queue_openings == 1 && chp->ch_ndrives > 1) {
- xfer = chq->active_xfers[0];
+ xfer = TAILQ_FIRST(&chq->active_xfers);
+ KASSERT(xfer != NULL);
if (xfer->c_chp != chp || xfer->c_drive != drvp->drive)
break;
}
drvp->drive_flags |= ATA_DRIVE_WAITDRAIN;
- (void) tsleep(&chq->active_xfers[0], PRIBIO, "atdrn", 0);
+ (void) tsleep(&chq->active_xfers, PRIBIO, "atdrn", 0);
}
splx(s);
}
Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.105.6.1 src/sys/dev/ata/ata_wdc.c:1.105.6.2
--- src/sys/dev/ata/ata_wdc.c:1.105.6.1 Mon Apr 10 22:57:02 2017
+++ src/sys/dev/ata/ata_wdc.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ata_wdc.c,v 1.105.6.1 2017/04/10 22:57:02 jdolecek Exp $ */
+/* $NetBSD: ata_wdc.c,v 1.105.6.2 2017/04/15 12:01:23 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.1 2017/04/10 22:57:02 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.2 2017/04/15 12:01:23 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -103,7 +103,7 @@ extern int wdcdebug_wd_mask; /* inited i
#define ATA_DELAY 10000 /* 10s for a drive I/O */
-static int wdc_ata_bio(struct ata_drive_datas*, struct ata_bio*);
+static int wdc_ata_bio(struct ata_drive_datas*, struct ata_xfer *);
static void wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
static void _wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
static int wdc_ata_bio_intr(struct ata_channel *, struct ata_xfer *,
@@ -135,15 +135,12 @@ const struct ata_bustype wdc_ata_bustype
* ATACMD_TRY_AGAIN. Must be called at splbio().
*/
static int
-wdc_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+wdc_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
{
- struct ata_xfer *xfer;
struct ata_channel *chp = drvp->chnl_softc;
struct atac_softc *atac = chp->ch_atac;
+ struct ata_bio *ata_bio = &xfer->c_bio;
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
- if (xfer == NULL)
- return ATACMD_TRY_AGAIN;
if (atac->atac_cap & ATAC_CAP_NOIRQ)
ata_bio->flags |= ATA_POLL;
if (ata_bio->flags & ATA_POLL)
@@ -161,7 +158,6 @@ wdc_ata_bio(struct ata_drive_datas *drvp
xfer->c_flags |= C_PIOBM;
#endif
xfer->c_drive = drvp->drive;
- xfer->c_cmd = ata_bio;
xfer->c_databuf = ata_bio->databuf;
xfer->c_bcount = ata_bio->bcount;
xfer->c_start = wdc_ata_bio_start;
@@ -177,7 +173,7 @@ wdc_ata_bio_start(struct ata_channel *ch
struct atac_softc *atac = chp->ch_atac;
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
int wait_flags;
const char *errstring;
@@ -266,20 +262,20 @@ geometry:
if (ata_bio->flags & ATA_LBA)
goto multimode;
wdccommand(chp, xfer->c_drive, WDCC_IDP,
- ata_bio->lp->d_ncylinders,
- ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
- (ata_bio->lp->d_type == DKTYPE_ST506) ?
- ata_bio->lp->d_precompcyl / 4 : 0);
+ drvp->lp->d_ncylinders,
+ drvp->lp->d_ntracks - 1, 0, drvp->lp->d_nsectors,
+ (drvp->lp->d_type == DKTYPE_ST506) ?
+ drvp->lp->d_precompcyl / 4 : 0);
errstring = "geometry";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
goto ctrltimeout;
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto ctrlerror;
multimode:
- if (ata_bio->multi == 1)
+ if (drvp->multi == 1)
goto ready;
wdccommand(chp, xfer->c_drive, WDCC_SETMULTI, 0, 0, 0,
- ata_bio->multi, 0);
+ drvp->multi, 0);
errstring = "setmulti";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
goto ctrltimeout;
@@ -332,7 +328,7 @@ _wdc_ata_bio_start(struct ata_channel *c
struct atac_softc *atac = chp->ch_atac;
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
int wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0;
uint16_t cyl;
@@ -367,12 +363,12 @@ again:
if (ata_bio->flags & ATA_SINGLE)
nblks = 1;
else
- nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+ nblks = xfer->c_bcount / drvp->lp->d_secsize;
/* Check for bad sectors and adjust transfer, if necessary. */
- if ((ata_bio->lp->d_flags & D_BADSECT) != 0) {
+ if ((drvp->lp->d_flags & D_BADSECT) != 0) {
long blkdiff;
int i;
- for (i = 0; (blkdiff = ata_bio->badsect[i]) != -1;
+ for (i = 0; (blkdiff = drvp->badsect[i]) != -1;
i++) {
blkdiff -= ata_bio->blkno;
if (blkdiff < 0)
@@ -380,8 +376,8 @@ again:
if (blkdiff == 0) {
/* Replace current block of transfer. */
ata_bio->blkno =
- ata_bio->lp->d_secperunit -
- ata_bio->lp->d_nsectors - i - 1;
+ drvp->lp->d_secperunit -
+ drvp->lp->d_nsectors - i - 1;
}
if (blkdiff < nblks) {
/* Bad block inside transfer. */
@@ -403,11 +399,11 @@ again:
head |= WDSD_LBA;
} else {
int blkno = ata_bio->blkno;
- sect = blkno % ata_bio->lp->d_nsectors;
+ sect = blkno % drvp->lp->d_nsectors;
sect++; /* Sectors begin with 1, not 0. */
- blkno /= ata_bio->lp->d_nsectors;
- head = blkno % ata_bio->lp->d_ntracks;
- blkno /= ata_bio->lp->d_ntracks;
+ blkno /= drvp->lp->d_nsectors;
+ head = blkno % drvp->lp->d_ntracks;
+ blkno /= drvp->lp->d_ntracks;
cyl = blkno;
head |= WDSD_CHS;
}
@@ -502,8 +498,8 @@ again:
}
}
#endif
- ata_bio->nblks = min(nblks, ata_bio->multi);
- ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize;
+ ata_bio->nblks = min(nblks, drvp->multi);
+ ata_bio->nbytes = ata_bio->nblks * drvp->lp->d_secsize;
KASSERT(nblks == 1 || (ata_bio->flags & ATA_SINGLE) == 0);
if (ata_bio->nblks > 1) {
cmd = (ata_bio->flags & ATA_READ) ?
@@ -531,8 +527,8 @@ again:
} else {
wdccommand(chp, xfer->c_drive, cmd, cyl,
head, sect, nblks,
- (ata_bio->lp->d_type == DKTYPE_ST506) ?
- ata_bio->lp->d_precompcyl / 4 : 0);
+ (drvp->lp->d_type == DKTYPE_ST506) ?
+ drvp->lp->d_precompcyl / 4 : 0);
}
/* start timeout machinery */
if ((xfer->c_flags & C_POLL) == 0)
@@ -540,7 +536,7 @@ again:
ATA_DELAY / 1000 * hz, wdctimeout, chp);
} else if (ata_bio->nblks > 1) {
/* The number of blocks in the last stretch may be smaller. */
- nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+ nblks = xfer->c_bcount / drvp->lp->d_secsize;
if (ata_bio->nblks > nblks) {
ata_bio->nblks = nblks;
ata_bio->nbytes = xfer->c_bcount;
@@ -615,7 +611,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
{
struct atac_softc *atac = chp->ch_atac;
struct wdc_softc *wdc = CHAN_TO_WDC(chp);
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
int drv_err;
@@ -768,11 +764,9 @@ static void
wdc_ata_bio_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer,
int reason)
{
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
int drive = xfer->c_drive;
- ata_free_xfer(chp, xfer);
-
ata_bio->flags |= ATA_ITSDONE;
switch (reason) {
case KILL_GONE:
@@ -788,13 +782,13 @@ wdc_ata_bio_kill_xfer(struct ata_channel
}
ata_bio->r_error = WDCE_ABRT;
ATADEBUG_PRINT(("wdc_ata_bio_kill_xfer: drv_done\n"), DEBUG_XFERS);
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
}
static void
wdc_ata_bio_done(struct ata_channel *chp, struct ata_xfer *xfer)
{
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
int drive = xfer->c_drive;
ATADEBUG_PRINT(("wdc_ata_bio_done %s:%d:%d: flags 0x%x\n",
@@ -809,14 +803,13 @@ wdc_ata_bio_done(struct ata_channel *chp
/* mark controller inactive and free xfer */
ata_deactivate_xfer(chp, xfer);
- ata_free_xfer(chp, xfer);
if (ata_waitdrain_check(chp, drive)) {
ata_bio->error = ERR_NODEV;
}
ata_bio->flags |= ATA_ITSDONE;
ATADEBUG_PRINT(("wdc_ata_done: drv_done\n"), DEBUG_XFERS);
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
ATADEBUG_PRINT(("atastart from wdc_ata_done, flags 0x%x\n",
chp->ch_flags), DEBUG_XFERS);
atastart(chp);
Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92.8.2 src/sys/dev/ata/atavar.h:1.92.8.3
--- src/sys/dev/ata/atavar.h:1.92.8.2 Tue Apr 11 18:15:03 2017
+++ src/sys/dev/ata/atavar.h Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.92.8.2 2017/04/11 18:15:03 jdolecek Exp $ */
+/* $NetBSD: atavar.h,v 1.92.8.3 2017/04/15 12:01:23 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -37,6 +37,38 @@
#include <dev/scsipi/atapiconf.h>
/*
+ * Parameters/state needed by the controller to perform an ATA bio.
+ */
+struct ata_bio {
+ volatile uint16_t flags;/* cmd flags */
+/* 0x0001 free, was ATA_NOSLEEP */
+#define ATA_POLL 0x0002 /* poll for completion */
+#define ATA_ITSDONE 0x0004 /* the transfer is as done as it gets */
+#define ATA_SINGLE 0x0008 /* transfer must be done in singlesector mode */
+#define ATA_LBA 0x0010 /* transfer uses LBA addressing */
+#define ATA_READ 0x0020 /* transfer is a read (otherwise a write) */
+#define ATA_CORR 0x0040 /* transfer had a corrected error */
+#define ATA_LBA48 0x0080 /* transfer uses 48-bit LBA addressing */
+ daddr_t blkno; /* block addr */
+ daddr_t blkdone;/* number of blks transferred */
+ daddr_t nblks; /* number of block currently transferring */
+ int nbytes; /* number of bytes currently transferring */
+ long bcount; /* total number of bytes */
+ char *databuf;/* data buffer address */
+ volatile int error;
+#define NOERROR 0 /* There was no error (r_error invalid) */
+#define ERROR 1 /* check r_error */
+#define ERR_DF 2 /* Drive fault */
+#define ERR_DMA 3 /* DMA error */
+#define TIMEOUT 4 /* device timed out */
+#define ERR_NODEV 5 /* device has been gone */
+#define ERR_RESET 6 /* command was terminated by channel reset */
+ uint8_t r_error;/* copy of error register */
+ int retries;/* number of xfer retry */
+ struct buf *bp;
+};
+
+/*
* Description of a command to be handled by an ATA controller. These
* commands are queued in a list.
*/
@@ -47,7 +79,6 @@ struct ata_xfer {
struct ata_channel *c_chp;
uint16_t c_drive;
int8_t c_slot; /* queue slot # */
- uint8_t c_hwslot; /* hardware slot # */
void *c_cmd; /* private request structure pointer */
void *c_databuf; /* pointer to data buffer */
@@ -56,8 +87,15 @@ struct ata_xfer {
int c_dscpoll; /* counter for dsc polling (ATAPI) */
int c_lenoff; /* offset to c_bcount (ATAPI) */
+ union {
+ struct ata_bio c_bio; /* block I/O context */
+ } u;
+#define c_bio u.c_bio
+
/* Link on the command queue. */
TAILQ_ENTRY(ata_xfer) c_xferchain;
+ TAILQ_ENTRY(ata_xfer) c_activechain;
+ STAILQ_ENTRY(ata_xfer) c_restartchain;
/* Low-level protocol handlers. */
void (*c_start)(struct ata_channel *, struct ata_xfer *);
@@ -79,17 +117,18 @@ struct ata_xfer {
#define KILL_GONE 1 /* device is gone */
#define KILL_RESET 2 /* xfer was reset */
-/* Per-channel queue of ata_xfers. May be shared by multiple channels. */
+/* 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 is wants the controller idle */
-#define QF_SHARED 0x02 /* this queue is shared */
+#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 */
#ifdef ATABUS_PRIVATE
- struct ata_xfer *active_xfers[1]; /* active command */
+ TAILQ_HEAD(, ata_xfer) active_xfers; /* active commands */
+ uint32_t queue_xfers_avail; /* available xfers mask */
+ struct ata_xfer queue_xfers[0]; /* xfers */
#endif
};
@@ -176,10 +215,15 @@ struct ata_drive_datas {
#endif
/* Callbacks into the drive's driver. */
- void (*drv_done)(void *); /* transfer is done */
+ void (*drv_done)(void *, struct ata_xfer *); /* transfer is done */
- device_t drv_softc; /* ATA drives softc, if any */
+ device_t drv_softc; /* ATA drives softc, if any */
void *chnl_softc; /* channel softc */
+
+ /* Context used for I/O */
+ struct disklabel *lp; /* pointer to drive's label info */
+ uint8_t multi; /* # of blocks to transfer in multi-mode */
+ daddr_t badsect[127]; /* 126 plus trailing -1 marker */
};
/* User config flags that force (or disable) the use of a mode */
@@ -196,39 +240,6 @@ struct ata_drive_datas {
#define ATA_CONFIG_UDMA_OFF 8
/*
- * Parameters/state needed by the controller to perform an ATA bio.
- */
-struct ata_bio {
- volatile uint16_t flags;/* cmd flags */
-/* 0x0001 free, was ATA_NOSLEEP */
-#define ATA_POLL 0x0002 /* poll for completion */
-#define ATA_ITSDONE 0x0004 /* the transfer is as done as it gets */
-#define ATA_SINGLE 0x0008 /* transfer must be done in singlesector mode */
-#define ATA_LBA 0x0010 /* transfer uses LBA addressing */
-#define ATA_READ 0x0020 /* transfer is a read (otherwise a write) */
-#define ATA_CORR 0x0040 /* transfer had a corrected error */
-#define ATA_LBA48 0x0080 /* transfer uses 48-bit LBA addressing */
- int multi; /* # of blocks to transfer in multi-mode */
- struct disklabel *lp; /* pointer to drive's label info */
- daddr_t blkno; /* block addr */
- daddr_t blkdone;/* number of blks transferred */
- daddr_t nblks; /* number of block currently transferring */
- int nbytes; /* number of bytes currently transferring */
- long bcount; /* total number of bytes */
- char *databuf;/* data buffer address */
- volatile int error;
-#define NOERROR 0 /* There was no error (r_error invalid) */
-#define ERROR 1 /* check r_error */
-#define ERR_DF 2 /* Drive fault */
-#define ERR_DMA 3 /* DMA error */
-#define TIMEOUT 4 /* device timed out */
-#define ERR_NODEV 5 /* device has been gone */
-#define ERR_RESET 6 /* command was terminated by channel reset */
- uint8_t r_error;/* copy of error register */
- daddr_t badsect[127];/* 126 plus trailing -1 marker */
-};
-
-/*
* ATA/ATAPI commands description
*
* This structure defines the interface between the ATA/ATAPI device driver
@@ -289,7 +300,7 @@ struct ata_command {
*/
struct ata_bustype {
int bustype_type; /* symbolic name of type */
- int (*ata_bio)(struct ata_drive_datas *, struct ata_bio *);
+ int (*ata_bio)(struct ata_drive_datas *, struct ata_xfer *);
void (*ata_reset_drive)(struct ata_drive_datas *, int, uint32_t *);
void (*ata_reset_channel)(struct ata_channel *, int);
/* extra flags for ata_reset_*(), in addition to AT_* */
@@ -422,10 +433,6 @@ struct atac_softc {
/* Driver callback to probe for drives. */
void (*atac_probe)(struct ata_channel *);
- /* Optional callbacks to lock/unlock hardware. */
- int (*atac_claim_hw)(struct ata_channel *, int);
- void (*atac_free_hw)(struct ata_channel *);
-
/*
* Optional callbacks to set drive mode. Required for anything
* but basic PIO operation.
@@ -449,7 +456,7 @@ int ata_set_mode(struct ata_drive_datas
#define CMD_ERR 1
#define CMD_AGAIN 2
-struct ata_xfer *ata_get_xfer(int);
+struct ata_xfer *ata_get_xfer(struct ata_channel *);
void ata_free_xfer(struct ata_channel *, struct ata_xfer *);
#define ATAXF_CANSLEEP 0x00
#define ATAXF_NOSLEEP 0x01
Index: src/sys/dev/ata/satafis_subr.c
diff -u src/sys/dev/ata/satafis_subr.c:1.7 src/sys/dev/ata/satafis_subr.c:1.7.28.1
--- src/sys/dev/ata/satafis_subr.c:1.7 Sun Jul 22 17:57:57 2012
+++ src/sys/dev/ata/satafis_subr.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: satafis_subr.c,v 1.7 2012/07/22 17:57:57 jakllsch Exp $ */
+/* $NetBSD: satafis_subr.c,v 1.7.28.1 2017/04/15 12:01:23 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 2012/07/22 17:57:57 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: satafis_subr.c,v 1.7.28.1 2017/04/15 12:01:23 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -100,10 +100,11 @@ satafis_rhd_construct_cmd(struct ata_com
void
satafis_rhd_construct_bio(struct ata_xfer *xfer, uint8_t *fis)
{
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
+ struct ata_drive_datas *drvp = &xfer->c_chp->ch_drive[xfer->c_drive];
int nblks;
- nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+ nblks = xfer->c_bcount / drvp->lp->d_secsize;
memset(fis, 0, RHD_FISLEN);
Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.428.2.2 src/sys/dev/ata/wd.c:1.428.2.3
--- src/sys/dev/ata/wd.c:1.428.2.2 Wed Apr 12 22:28:20 2017
+++ src/sys/dev/ata/wd.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wd.c,v 1.428.2.2 2017/04/12 22:28:20 jdolecek Exp $ */
+/* $NetBSD: wd.c,v 1.428.2.3 2017/04/15 12:01:23 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.2 2017/04/12 22:28:20 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.3 2017/04/15 12:01:23 jdolecek Exp $");
#include "opt_ata.h"
@@ -90,7 +90,7 @@ __KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428
#include <prop/proplib.h>
-#define WDIORETRIES_SINGLE 4 /* number of retries before single-sector */
+#define WDIORETRIES_SINGLE 4 /* number of retries for single-sector */
#define WDIORETRIES 5 /* number of retries before giving up */
#define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */
@@ -119,7 +119,7 @@ int wdprobe(device_t, cfdata_t, void *);
void wdattach(device_t, device_t, void *);
int wddetach(device_t, int);
int wdprint(void *, char *);
-void wdperror(const struct wd_softc *);
+void wdperror(const struct wd_softc *, struct ata_xfer *);
static void wdminphys(struct buf *);
@@ -186,12 +186,17 @@ void wi_free(struct wd_ioctl *);
struct wd_ioctl *wi_get(struct wd_softc *);
void wdioctlstrategy(struct buf *);
+struct wd_split_mod15_private {
+ struct buf *bp;
+ struct ata_xfer *xfer;
+};
+
void wdgetdefaultlabel(struct wd_softc *, struct disklabel *);
void wdgetdisklabel(struct wd_softc *);
-void wdstart(void *);
-void wdstart1(struct wd_softc*, struct buf *);
+void wdstart(struct wd_softc *);
+void wdstart1(struct wd_softc *, struct buf *, struct ata_xfer *);
void wdrestart(void *);
-void wddone(void *);
+void wddone(void *, struct ata_xfer *);
static void wd_params_to_properties(struct wd_softc *);
int wd_get_params(struct wd_softc *, uint8_t, struct ataparams *);
int wd_flushcache(struct wd_softc *, int);
@@ -295,14 +300,15 @@ wdattach(device_t parent, device_t self,
ATADEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE);
callout_init(&wd->sc_restart_ch, CALLOUT_MPSAFE);
+ callout_setfunc(&wd->sc_restart_ch, wdrestart, wd);
mutex_init(&wd->sc_lock, MUTEX_DEFAULT, IPL_BIO);
bufq_alloc(&wd->sc_q, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);
#ifdef WD_SOFTBADSECT
SLIST_INIT(&wd->sc_bslist);
#endif
LIST_INIT(&wd->wi_head);
+ STAILQ_INIT(&wd->xfer_restart);
wd->atabus = adev->adev_bustype;
- wd->openings = adev->adev_openings;
wd->drvp = adev->adev_drv_data;
wd->drvp->drv_done = wddone;
@@ -347,13 +353,13 @@ wdattach(device_t parent, device_t self,
}
if ((wd->sc_params.atap_multi & 0xff) > 1) {
- wd->sc_multi = wd->sc_params.atap_multi & 0xff;
+ wd->drvp->multi = wd->sc_params.atap_multi & 0xff;
} else {
- wd->sc_multi = 1;
+ wd->drvp->multi = 1;
}
aprint_verbose_dev(self, "drive supports %d-sector PIO transfers,",
- wd->sc_multi);
+ wd->drvp->multi);
/* 48-bit LBA addressing */
if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0)
@@ -426,7 +432,7 @@ out:
/* we fill in dk_info later */
disk_init(&wd->sc_dk, device_xname(wd->sc_dev), &wddkdriver);
disk_attach(&wd->sc_dk);
- wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;
+ wd->drvp->lp = wd->sc_dk.dk_label;
wd_params_to_properties(wd);
rnd_attach_source(&wd->rnd_source, device_xname(wd->sc_dev),
RND_TYPE_DISK, RND_FLAG_DEFAULT);
@@ -588,18 +594,20 @@ wdstrategy(struct buf *bp)
* even attempting to start a transfer up under the premis that we
* will just end up doing more retries for a transfer that will end
* up failing again.
- * XXX:SMP - mutex required to protect with DIOCBSFLUSH
*/
if (__predict_false(!SLIST_EMPTY(&wd->sc_bslist))) {
struct disk_badsectors *dbs;
daddr_t maxblk = blkno + (bp->b_bcount / wd->sc_blksize) - 1;
+ mutex_enter(&wd->sc_lock);
SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next)
if ((dbs->dbs_min <= blkno && blkno <= dbs->dbs_max) ||
(dbs->dbs_min <= maxblk && maxblk <= dbs->dbs_max)){
bp->b_error = EIO;
+ mutex_exit(&wd->sc_lock);
goto done;
}
+ mutex_exit(&wd->sc_lock);
}
#endif
@@ -607,8 +615,9 @@ wdstrategy(struct buf *bp)
mutex_enter(&wd->sc_lock);
disk_wait(&wd->sc_dk);
bufq_put(wd->sc_q, bp);
- wdstart(wd);
mutex_exit(&wd->sc_lock);
+
+ wdstart(wd);
return;
done:
/* Toss transfer; we're done early. */
@@ -620,10 +629,10 @@ done:
* Queue a drive for I/O.
*/
void
-wdstart(void *arg)
+wdstart(struct wd_softc *wd)
{
- struct wd_softc *wd = arg;
- struct buf *bp = NULL;
+ struct buf *bp;
+ struct ata_xfer *xfer;
ATADEBUG_PRINT(("wdstart %s\n", device_xname(wd->sc_dev)),
DEBUG_XFERS);
@@ -631,29 +640,36 @@ wdstart(void *arg)
if (!device_is_active(wd->sc_dev))
return;
- while (wd->openings > 0) {
+ mutex_enter(&wd->sc_lock);
- /* Is there a buf for us ? */
- if ((bp = bufq_get(wd->sc_q)) == NULL)
- return;
+ while (bufq_peek(wd->sc_q) != NULL) {
+ /* First try to get command */
+ xfer = ata_get_xfer(wd->drvp->chnl_softc);
+ if (!xfer)
+ break;
- /*
- * Make the command. First lock the device
- */
- wd->openings--;
+ /* There is got to be a buf for us */
+ bp = bufq_get(wd->sc_q);
+ KASSERT(bp != NULL);
- wd->retries = 0;
- wdstart1(wd, bp);
+ wdstart1(wd, bp, xfer);
}
+
+ mutex_exit(&wd->sc_lock);
}
static void
wd_split_mod15_write(struct buf *bp)
{
- struct buf *obp = bp->b_private;
+ struct wd_split_mod15_private *m = bp->b_private;
+ struct buf *obp = m->bp;
+ struct ata_xfer *xfer = m->xfer;
struct wd_softc *wd =
device_lookup_private(&wd_cd, DISKUNIT(obp->b_dev));
+ free(m, sizeof *m);
+
+ mutex_enter(&wd->sc_lock);
if (__predict_false(bp->b_error != 0)) {
/*
* Propagate the error. If this was the first half of
@@ -673,7 +689,7 @@ wd_split_mod15_write(struct buf *bp)
/*
* Advance the pointer to the second half and issue that command
- * using the same opening.
+ * using the same xfer.
*/
bp->b_flags = obp->b_flags;
bp->b_oflags = obp->b_oflags;
@@ -681,26 +697,25 @@ wd_split_mod15_write(struct buf *bp)
bp->b_data = (char *)bp->b_data + bp->b_bcount;
bp->b_blkno += (bp->b_bcount / DEV_BSIZE);
bp->b_rawblkno += (bp->b_bcount / wd->sc_blksize);
- mutex_enter(&wd->sc_lock);
- wdstart1(wd, bp);
+ memset(xfer, 0, sizeof(*xfer));
+ wdstart1(wd, bp, xfer);
mutex_exit(&wd->sc_lock);
return;
done:
obp->b_error = bp->b_error;
obp->b_resid = bp->b_resid;
- mutex_enter(&wd->sc_lock);
+ mutex_exit(&wd->sc_lock);
+
putiobuf(bp);
biodone(obp);
- wd->openings++;
- mutex_exit(&wd->sc_lock);
/* wddone() will call wdstart() */
}
void
-wdstart1(struct wd_softc *wd, struct buf *bp)
+wdstart1(struct wd_softc *wd, struct buf *bp, struct ata_xfer *xfer)
{
- /* already locked */
+ /* must be locked on entry */
KASSERT(mutex_owned(&wd->sc_lock));
/*
@@ -716,14 +731,21 @@ wdstart1(struct wd_softc *wd, struct buf
bp->b_bcount > 512 &&
((bp->b_bcount / 512) % 15) == 1)) {
struct buf *nbp;
+ struct wd_split_mod15_private *m;
+
+ m = malloc(sizeof *m, M_TEMP, M_NOWAIT);
+ if (m == NULL)
+ goto fail;
nbp = getiobuf(NULL, false);
if (__predict_false(nbp == NULL)) {
+ free(m, sizeof *m);
+fail:
/* No memory -- fail the iop. */
bp->b_error = ENOMEM;
bp->b_resid = bp->b_bcount;
biodone(bp);
- wd->openings++;
+ ata_free_xfer(wd->drvp->chnl_softc, xfer);
return;
}
@@ -744,43 +766,46 @@ wdstart1(struct wd_softc *wd, struct buf
nbp->b_iodone = wd_split_mod15_write;
/* Put ptr to orig buf in b_private and use new buf */
- nbp->b_private = bp;
+ m->bp = bp;
+ m->xfer = xfer;
+ nbp->b_private = m;
BIO_COPYPRIO(nbp, bp);
bp = nbp;
}
- wd->sc_wdc_bio.blkno = bp->b_rawblkno;
- wd->sc_wdc_bio.bcount = bp->b_bcount;
- wd->sc_wdc_bio.databuf = bp->b_data;
- wd->sc_wdc_bio.blkdone =0;
- KASSERT(bp == wd->sc_bp || wd->sc_bp == NULL);
- wd->sc_bp = bp;
+ xfer->c_bio.blkno = bp->b_rawblkno;
+ xfer->c_bio.bcount = bp->b_bcount;
+ xfer->c_bio.databuf = bp->b_data;
+ xfer->c_bio.blkdone = 0;
+ KASSERT(bp == xfer->c_bio.bp || xfer->c_bio.bp == NULL);
+ xfer->c_bio.bp = bp;
/*
* If we're retrying, retry in single-sector mode. This will give us
* the sector number of the problem, and will eventually allow the
* transfer to succeed.
*/
- if (wd->retries >= WDIORETRIES_SINGLE)
- wd->sc_wdc_bio.flags = ATA_SINGLE;
+ if (xfer->c_bio.retries >= WDIORETRIES_SINGLE)
+ xfer->c_bio.flags = ATA_SINGLE;
else
- wd->sc_wdc_bio.flags = 0;
+ xfer->c_bio.flags = 0;
if (wd->sc_flags & WDF_LBA48 &&
- (wd->sc_wdc_bio.blkno +
- wd->sc_wdc_bio.bcount / wd->sc_dk.dk_label->d_secsize) >
+ (xfer->c_bio.blkno +
+ xfer->c_bio.bcount / wd->sc_dk.dk_label->d_secsize) >
wd->sc_capacity28)
- wd->sc_wdc_bio.flags |= ATA_LBA48;
+ xfer->c_bio.flags |= ATA_LBA48;
if (wd->sc_flags & WDF_LBA)
- wd->sc_wdc_bio.flags |= ATA_LBA;
+ xfer->c_bio.flags |= ATA_LBA;
if (bp->b_flags & B_READ)
- wd->sc_wdc_bio.flags |= ATA_READ;
+ xfer->c_bio.flags |= ATA_READ;
+
/* Instrumentation. */
disk_busy(&wd->sc_dk);
- switch (wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
+ switch (wd->atabus->ata_bio(wd->drvp, xfer)) {
case ATACMD_TRY_AGAIN:
- callout_reset(&wd->sc_restart_ch, hz, wdrestart, wd);
+ panic("wdstart1: try again");
break;
case ATACMD_QUEUED:
case ATACMD_COMPLETE:
@@ -791,22 +816,23 @@ wdstart1(struct wd_softc *wd, struct buf
}
void
-wddone(void *v)
+wddone(void *v, struct ata_xfer *xfer)
{
struct wd_softc *wd = device_private(v);
- struct buf *bp;
const char *errmsg;
- int do_perror = 0;
+ int do_perror = 0, finish;
+ struct buf *bp;
ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)),
DEBUG_XFERS);
mutex_enter(&wd->sc_lock);
- if ((bp = wd->sc_bp) == NULL)
- goto out;
- bp->b_resid = wd->sc_wdc_bio.bcount;
- switch (wd->sc_wdc_bio.error) {
+ bp = xfer->c_bio.bp;
+ KASSERT(bp != NULL);
+
+ bp->b_resid = xfer->c_bio.bcount;
+ switch (xfer->c_bio.error) {
case ERR_DMA:
errmsg = "DMA error";
goto retry;
@@ -821,8 +847,8 @@ wddone(void *v)
goto retry2;
case ERROR:
/* Don't care about media change bits */
- if (wd->sc_wdc_bio.r_error != 0 &&
- (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)
+ if (xfer->c_bio.r_error != 0 &&
+ (xfer->c_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)
goto noerror;
errmsg = "error";
do_perror = 1;
@@ -830,17 +856,28 @@ retry: /* Just reset and retry. Can we
(*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD, NULL);
retry2:
diskerr(bp, "wd", errmsg, LOG_PRINTF,
- wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
- if (wd->retries < WDIORETRIES)
+ xfer->c_bio.blkdone, wd->sc_dk.dk_label);
+ if (xfer->c_bio.retries < WDIORETRIES)
printf(", retrying");
printf("\n");
if (do_perror)
- wdperror(wd);
- if (wd->retries < WDIORETRIES) {
- wd->retries++;
- callout_reset(&wd->sc_restart_ch, RECOVERYTIME,
- wdrestart, wd);
- goto out;
+ wdperror(wd, xfer);
+ if (xfer->c_bio.retries < WDIORETRIES) {
+ xfer->c_bio.retries++;
+ STAILQ_INSERT_TAIL(&wd->xfer_restart, xfer,
+ c_restartchain);
+
+ /*
+ * Only restart the timer if it's not already pending,
+ * so that we wouldn't postpone processing beyond
+ * original schedule.
+ */
+ if (!callout_pending(&wd->sc_restart_ch)) {
+ callout_schedule(&wd->sc_restart_ch,
+ RECOVERYTIME);
+ }
+ mutex_exit(&wd->sc_lock);
+ return;
}
#ifdef WD_SOFTBADSECT
@@ -851,8 +888,8 @@ retry2:
* itself, according to Manuel.
*/
if ((bp->b_flags & B_READ) &&
- ((wd->drvp->ata_vers >= 4 && wd->sc_wdc_bio.r_error & 64) ||
- (wd->drvp->ata_vers < 4 && wd->sc_wdc_bio.r_error & 192))) {
+ ((wd->drvp->ata_vers >= 4 && xfer->c_bio.r_error & 64) ||
+ (wd->drvp->ata_vers < 4 && xfer->c_bio.r_error & 192))) {
struct disk_badsectors *dbs;
dbs = malloc(sizeof *dbs, M_TEMP, M_WAITOK);
@@ -867,7 +904,7 @@ retry2:
bp->b_error = EIO;
break;
case NOERROR:
-noerror: if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0)
+noerror: if ((xfer->c_bio.flags & ATA_CORR) || xfer->c_bio.retries > 0)
aprint_error_dev(wd->sc_dev,
"soft error (corrected)\n");
break;
@@ -886,31 +923,44 @@ noerror: if ((wd->sc_wdc_bio.flags & ATA
disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid),
(bp->b_flags & B_READ));
rnd_add_uint32(&wd->rnd_source, bp->b_blkno);
- /* XXX Yuck, but we don't want to increment openings in this case */
- if (__predict_false(bp->b_iodone == wd_split_mod15_write))
- biodone(bp);
- else {
- biodone(bp);
- wd->openings++;
- }
- KASSERT(wd->sc_bp != NULL);
- wd->sc_bp = NULL;
- wdstart(wd);
-out:
+ /*
+ * XXX Yuck, but we don't want to free the xfer in this case.
+ * See wd_split_mod15_write() for details.
+ */
+ finish = (bp->b_iodone != wd_split_mod15_write);
+
mutex_exit(&wd->sc_lock);
+
+ biodone(bp);
+
+ if (__predict_true(finish)) {
+ ata_free_xfer(wd->drvp->chnl_softc, xfer);
+ wdstart(wd);
+ }
}
void
wdrestart(void *v)
{
struct wd_softc *wd = v;
- struct buf *bp = wd->sc_bp;
+ struct ata_xfer *xfer;
ATADEBUG_PRINT(("wdrestart %s\n", device_xname(wd->sc_dev)),
DEBUG_XFERS);
+
+ /*
+ * Resend all failed xfers out immediatelly regardless of original
+ * schedule, so that we error out reasonably fast in case of massive
+ * permanent errors.
+ */
mutex_enter(&wd->sc_lock);
- wdstart1(v, bp);
+ while (!STAILQ_EMPTY(&wd->xfer_restart)) {
+ xfer = STAILQ_FIRST(&wd->xfer_restart);
+ STAILQ_REMOVE_HEAD(&wd->xfer_restart, c_restartchain);
+
+ wdstart1(v, xfer->c_bio.bp, xfer);
+ }
mutex_exit(&wd->sc_lock);
}
@@ -1138,7 +1188,7 @@ wdgetdisklabel(struct wd_softc *wd)
wdgetdefaultlabel(wd, lp);
- wd->sc_badsect[0] = -1;
+ wd->drvp->badsect[0] = -1;
if (wd->drvp->state > RESET) {
mutex_enter(&wd->sc_lock);
@@ -1180,7 +1230,7 @@ wdgetdisklabel(struct wd_softc *wd)
}
void
-wdperror(const struct wd_softc *wd)
+wdperror(const struct wd_softc *wd, struct ata_xfer *xfer)
{
static const char *const errstr0_3[] = {"address mark not found",
"track 0 not found", "aborted command", "media change requested",
@@ -1197,7 +1247,7 @@ wdperror(const struct wd_softc *wd)
const char *devname = device_xname(wd->sc_dev);
struct ata_drive_datas *drvp = wd->drvp;
- int errno = wd->sc_wdc_bio.r_error;
+ int errno = xfer->c_bio.r_error;
if (drvp->ata_vers >= 4)
errstr = errstr4_5;
@@ -1630,6 +1680,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
struct disklabel *lp; /* disk's disklabel */
int part, err;
int nblks; /* total number of sectors left to write */
+ struct ata_xfer *xfer;
/* Check if recursive dump; if so, punt. */
if (wddoingadump)
@@ -1664,18 +1715,21 @@ wddump(dev_t dev, daddr_t blkno, void *v
wd->drvp->state = RESET;
}
- wd->sc_bp = NULL;
- wd->sc_wdc_bio.blkno = blkno;
- wd->sc_wdc_bio.flags = ATA_POLL;
+ xfer = ata_get_xfer(wd->drvp->chnl_softc);
+ if (xfer == NULL)
+ return EAGAIN;
+
+ xfer->c_bio.blkno = blkno;
+ xfer->c_bio.flags = ATA_POLL;
if (wd->sc_flags & WDF_LBA48 &&
- (wd->sc_wdc_bio.blkno + nblks) > wd->sc_capacity28)
- wd->sc_wdc_bio.flags |= ATA_LBA48;
+ (xfer->c_bio.blkno + nblks) > wd->sc_capacity28)
+ xfer->c_bio.flags |= ATA_LBA48;
if (wd->sc_flags & WDF_LBA)
- wd->sc_wdc_bio.flags |= ATA_LBA;
- wd->sc_wdc_bio.bcount = nblks * lp->d_secsize;
- wd->sc_wdc_bio.databuf = va;
+ xfer->c_bio.flags |= ATA_LBA;
+ xfer->c_bio.bcount = nblks * lp->d_secsize;
+ xfer->c_bio.databuf = va;
#ifndef WD_DUMP_NOT_TRUSTED
- switch (err = wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
+ switch (err = wd->atabus->ata_bio(wd->drvp, xfer)) {
case ATACMD_TRY_AGAIN:
panic("wddump: try again");
break;
@@ -1687,7 +1741,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
default:
panic("wddump: unknown atacmd code %d", err);
}
- switch(err = wd->sc_wdc_bio.error) {
+ switch(err = xfer->c_bio.error) {
case TIMEOUT:
printf("wddump: device timed out");
err = EIO;
@@ -1702,7 +1756,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
break;
case ERROR:
printf("wddump: ");
- wdperror(wd);
+ wdperror(wd, xfer);
err = EIO;
break;
case NOERROR:
@@ -1711,6 +1765,9 @@ wddump(dev_t dev, daddr_t blkno, void *v
default:
panic("wddump: unknown error type %d", err);
}
+
+ ata_free_xfer(wd->drvp->chnl_softc, xfer);
+
if (err != 0) {
printf("\n");
return err;
@@ -1742,13 +1799,13 @@ bad144intern(struct wd_softc *wd)
for (; i < NBT_BAD; i++) {
if (bt->bt_bad[i].bt_cyl == 0xffff)
break;
- wd->sc_badsect[i] =
+ wd->drvp->badsect[i] =
bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
(bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
(bt->bt_bad[i].bt_trksec & 0xff);
}
for (; i < NBT_BAD+1; i++)
- wd->sc_badsect[i] = -1;
+ wd->drvp->badsect[i] = -1;
}
#endif
Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.43.4.1 src/sys/dev/ata/wdvar.h:1.43.4.2
--- src/sys/dev/ata/wdvar.h:1.43.4.1 Wed Apr 12 21:59:14 2017
+++ src/sys/dev/ata/wdvar.h Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wdvar.h,v 1.43.4.1 2017/04/12 21:59:14 jdolecek Exp $ */
+/* $NetBSD: wdvar.h,v 1.43.4.2 2017/04/15 12:01:23 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -43,11 +43,8 @@ struct wd_softc {
int sc_quirks; /* any quirks drive might have */
/* IDE disk soft states */
- struct ata_bio sc_wdc_bio; /* current transfer */
- struct buf *sc_bp; /* buf being transfered */
struct ata_drive_datas *drvp; /* Our controller's infos */
const struct ata_bustype *atabus;
- int openings;
struct ataparams sc_params;/* drive characteristics found */
int sc_flags;
#define WDF_WLABEL 0x004 /* label is writable */
@@ -66,8 +63,6 @@ struct wd_softc {
uint32_t sc_capacity28; /* capacity accessible with LBA28 commands */
uint32_t sc_blksize; /* logical block size, in bytes */
- int retries; /* number of xfer retry */
-
#ifdef WD_SOFTBADSECT
SLIST_HEAD(, disk_badsectors) sc_bslist;
u_int sc_bscount;
@@ -75,11 +70,8 @@ struct wd_softc {
krndsource_t rnd_source;
LIST_HEAD(, wd_ioctl) wi_head;
-};
-#define sc_drive sc_wdc_bio.drive
-#define sc_mode sc_wdc_bio.mode
-#define sc_multi sc_wdc_bio.multi
-#define sc_badsect sc_wdc_bio.badsect
+ STAILQ_HEAD(, ata_xfer) xfer_restart;
+};
#endif /* _DEV_ATA_WDVAR_H_ */
Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.2 src/sys/dev/ic/ahcisata_core.c:1.57.6.3
--- src/sys/dev/ic/ahcisata_core.c:1.57.6.2 Tue Apr 11 18:13:17 2017
+++ src/sys/dev/ic/ahcisata_core.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ahcisata_core.c,v 1.57.6.2 2017/04/11 18:13:17 jdolecek Exp $ */
+/* $NetBSD: ahcisata_core.c,v 1.57.6.3 2017/04/15 12:01:23 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.2 2017/04/11 18:13:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.3 2017/04/15 12:01:23 jdolecek Exp $");
#include <sys/types.h>
#include <sys/malloc.h>
@@ -57,7 +57,7 @@ int ahcidebug_mask = 0;
static void ahci_probe_drive(struct ata_channel *);
static void ahci_setup_channel(struct ata_channel *);
-static int ahci_ata_bio(struct ata_drive_datas *, struct ata_bio *);
+static int ahci_ata_bio(struct ata_drive_datas *, struct ata_xfer *);
static int ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *);
static void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *);
static void ahci_reset_channel(struct ata_channel *, int);
@@ -930,8 +930,7 @@ ahci_exec_command(struct ata_drive_datas
AHCIDEBUG_PRINT(("ahci_exec_command port %d CI 0x%x\n",
chp->ch_channel, AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
DEBUG_XFERS);
- xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
- ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(chp);
if (xfer == NULL) {
return ATACMD_TRY_AGAIN;
}
@@ -1164,23 +1163,18 @@ ahci_cmd_done(struct ata_channel *chp, s
}
static int
-ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
{
struct ata_channel *chp = drvp->chnl_softc;
- struct ata_xfer *xfer;
+ struct ata_bio *ata_bio = &xfer->c_bio;
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
AHCIDEBUG_PRINT(("ahci_ata_bio port %d CI 0x%x\n",
chp->ch_channel, AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
DEBUG_XFERS);
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
- if (xfer == NULL) {
- return ATACMD_TRY_AGAIN;
- }
if (ata_bio->flags & ATA_POLL)
xfer->c_flags |= C_POLL;
xfer->c_drive = drvp->drive;
- xfer->c_cmd = ata_bio;
xfer->c_databuf = ata_bio->databuf;
xfer->c_bcount = ata_bio->bcount;
xfer->c_start = ahci_bio_start;
@@ -1195,7 +1189,7 @@ ahci_bio_start(struct ata_channel *chp,
{
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
struct ahci_channel *achp = (struct ahci_channel *)chp;
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
int slot = 0 /* XXX slot */;
struct ahci_cmd_tbl *cmd_tbl;
struct ahci_cmd_header *cmd_h;
@@ -1275,13 +1269,12 @@ ahci_bio_kill_xfer(struct ata_channel *c
{
int slot = 0; /* XXX slot */
int drive = xfer->c_drive;
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
struct ahci_channel *achp = (struct ahci_channel *)chp;
AHCIDEBUG_PRINT(("ahci_bio_kill_xfer channel %d\n", chp->ch_channel),
DEBUG_FUNCS);
achp->ahcic_cmds_active &= ~(1 << slot);
- ata_free_xfer(chp, xfer);
ata_bio->flags |= ATA_ITSDONE;
switch (reason) {
case KILL_GONE:
@@ -1295,14 +1288,14 @@ ahci_bio_kill_xfer(struct ata_channel *c
panic("ahci_bio_kill_xfer");
}
ata_bio->r_error = WDCE_ABRT;
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
}
static int
ahci_bio_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
{
int slot = 0; /* XXX slot */
- struct ata_bio *ata_bio = xfer->c_cmd;
+ struct ata_bio *ata_bio = &xfer->c_bio;
int drive = xfer->c_drive;
struct ahci_channel *achp = (struct ahci_channel *)chp;
struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -1329,7 +1322,6 @@ ahci_bio_complete(struct ata_channel *ch
if (ata_waitdrain_xfer_check(chp, xfer)) {
return 0;
}
- ata_free_xfer(chp, xfer);
ata_bio->flags |= ATA_ITSDONE;
if (chp->ch_status & WDCS_DWF) {
ata_bio->error = ERR_DF;
@@ -1352,7 +1344,7 @@ ahci_bio_complete(struct ata_channel *ch
if ((ata_bio->flags & ATA_READ) || ata_bio->error == NOERROR)
ata_bio->bcount -= le32toh(achp->ahcic_cmdh[slot].cmdh_prdbc);
AHCIDEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS);
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
atastart(chp);
return 0;
}
@@ -1569,7 +1561,7 @@ ahci_atapi_scsipi_request(struct scsipi_
scsipi_done(sc_xfer);
return;
}
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(atac->atac_channels[channel]);
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.3 src/sys/dev/ic/mvsata.c:1.35.6.4
--- src/sys/dev/ic/mvsata.c:1.35.6.3 Tue Apr 11 18:14:47 2017
+++ src/sys/dev/ic/mvsata.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsata.c,v 1.35.6.3 2017/04/11 18:14:47 jdolecek Exp $ */
+/* $NetBSD: mvsata.c,v 1.35.6.4 2017/04/15 12:01:23 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.3 2017/04/11 18:14:47 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.4 2017/04/15 12:01:23 jdolecek Exp $");
#include "opt_mvsata.h"
@@ -108,7 +108,7 @@ int mvsata_debug = 2;
static void mvsata_probe_drive(struct ata_channel *);
#ifndef MVSATA_WITHOUTDMA
-static int mvsata_bio(struct ata_drive_datas *, struct ata_bio *);
+static int mvsata_bio(struct ata_drive_datas *, struct ata_xfer *);
static void mvsata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
static void mvsata_reset_channel(struct ata_channel *, int);
static int mvsata_exec_command(struct ata_drive_datas *, struct ata_command *);
@@ -530,17 +530,16 @@ mvsata_probe_drive(struct ata_channel *c
#ifndef MVSATA_WITHOUTDMA
static int
-mvsata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+mvsata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
{
struct ata_channel *chp = drvp->chnl_softc;
struct atac_softc *atac = chp->ch_atac;
- struct ata_xfer *xfer;
+ struct ata_bio *ata_bio = &xfer->c_bio;
DPRINTFN(1, ("%s:%d: mvsata_bio: drive=%d, blkno=%" PRId64
", bcount=%ld\n", device_xname(atac->atac_dev), chp->ch_channel,
drvp->drive, ata_bio->blkno, ata_bio->bcount));
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
if (xfer == NULL)
return ATACMD_TRY_AGAIN;
if (atac->atac_cap & ATAC_CAP_NOIRQ)
@@ -661,8 +660,7 @@ 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));
- xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
- ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(chp);
if (xfer == NULL)
return ATACMD_TRY_AGAIN;
if (ata_c->flags & AT_POLL)
@@ -777,7 +775,7 @@ mvsata_atapi_scsipi_request(struct scsip
scsipi_done(sc_xfer);
return;
}
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(atac->atac_channels[channel]);
if (xfer == NULL) {
sc_xfer->error = XS_RESOURCE_SHORTAGE;
scsipi_done(sc_xfer);
@@ -1084,13 +1082,13 @@ again:
if (ata_bio->flags & ATA_SINGLE)
nblks = 1;
else
- nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+ nblks = xfer->c_bcount / drvp->lp->d_secsize;
/* Check for bad sectors and adjust transfer, if necessary. */
- if ((ata_bio->lp->d_flags & D_BADSECT) != 0) {
+ if ((drvp->lp->d_flags & D_BADSECT) != 0) {
long blkdiff;
int i;
- for (i = 0; (blkdiff = ata_bio->badsect[i]) != -1;
+ for (i = 0; (blkdiff = drvp->badsect[i]) != -1;
i++) {
blkdiff -= ata_bio->blkno;
if (blkdiff < 0)
@@ -1098,8 +1096,8 @@ again:
if (blkdiff == 0)
/* Replace current block of transfer. */
ata_bio->blkno =
- ata_bio->lp->d_secperunit -
- ata_bio->lp->d_nsectors - i - 1;
+ drvp->lp->d_secperunit -
+ drvp->lp->d_nsectors - i - 1;
if (blkdiff < nblks) {
/* Bad block inside transfer. */
ata_bio->flags |= ATA_SINGLE;
@@ -1164,16 +1162,16 @@ do_pio:
head |= WDSD_LBA;
} else {
int blkno = ata_bio->blkno;
- sect = blkno % ata_bio->lp->d_nsectors;
+ sect = blkno % drvp->lp->d_nsectors;
sect++; /* Sectors begin with 1, not 0. */
- blkno /= ata_bio->lp->d_nsectors;
- head = blkno % ata_bio->lp->d_ntracks;
- blkno /= ata_bio->lp->d_ntracks;
+ blkno /= drvp->lp->d_nsectors;
+ head = blkno % drvp->lp->d_ntracks;
+ blkno /= drvp->lp->d_ntracks;
cyl = blkno;
head |= WDSD_CHS;
}
- ata_bio->nblks = min(nblks, ata_bio->multi);
- ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize;
+ ata_bio->nblks = min(nblks, drvp->multi);
+ ata_bio->nbytes = ata_bio->nblks * drvp->lp->d_secsize;
KASSERT(nblks == 1 || (ata_bio->flags & ATA_SINGLE) == 0);
if (ata_bio->nblks > 1)
cmd = (ata_bio->flags & ATA_READ) ?
@@ -1228,8 +1226,8 @@ do_pio:
else
wdccommand(chp, 0, cmd, cyl,
head, sect, nblks,
- (ata_bio->lp->d_type == DKTYPE_ST506) ?
- ata_bio->lp->d_precompcyl / 4 : 0);
+ (drvp->lp->d_type == DKTYPE_ST506) ?
+ drvp->lp->d_precompcyl / 4 : 0);
/* start timeout machinery */
if ((xfer->c_flags & C_POLL) == 0)
@@ -1237,7 +1235,7 @@ do_pio:
ATA_DELAY / 1000 * hz, wdctimeout, chp);
} else if (ata_bio->nblks > 1) {
/* The number of blocks in the last stretch may be smaller. */
- nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+ nblks = xfer->c_bcount / drvp->lp->d_secsize;
if (ata_bio->nblks > nblks) {
ata_bio->nblks = nblks;
ata_bio->nbytes = xfer->c_bcount;
@@ -1408,8 +1406,6 @@ mvsata_bio_kill_xfer(struct ata_channel
mvsata_edma_enable(mvport);
}
- ata_free_xfer(chp, xfer);
-
ata_bio->flags |= ATA_ITSDONE;
switch (reason) {
case KILL_GONE:
@@ -1424,7 +1420,7 @@ mvsata_bio_kill_xfer(struct ata_channel
panic("mvsata_bio_kill_xfer");
}
ata_bio->r_error = WDCE_ABRT;
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
}
static void
@@ -1451,12 +1447,11 @@ mvsata_bio_done(struct ata_channel *chp,
/* mark controller inactive and free xfer */
ata_deactivate_xfer(chp, xfer);
- ata_free_xfer(chp, xfer);
if (ata_waitdrain_check(chp, drive))
ata_bio->error = ERR_NODEV;
ata_bio->flags |= ATA_ITSDONE;
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
atastart(chp);
}
@@ -1518,19 +1513,19 @@ mvsata_bio_ready(struct mvsata_port *mvp
geometry:
if (ata_bio->flags & ATA_LBA)
goto multimode;
- wdccommand(chp, 0, WDCC_IDP, ata_bio->lp->d_ncylinders,
- ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
- (ata_bio->lp->d_type == DKTYPE_ST506) ?
- ata_bio->lp->d_precompcyl / 4 : 0);
+ wdccommand(chp, 0, WDCC_IDP, drvp->lp->d_ncylinders,
+ drvp->lp->d_ntracks - 1, 0, drvp->lp->d_nsectors,
+ (drvp->lp->d_type == DKTYPE_ST506) ?
+ drvp->lp->d_precompcyl / 4 : 0);
errstring = "geometry";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
goto ctrltimeout;
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto ctrlerror;
multimode:
- if (ata_bio->multi == 1)
+ if (drvp->multi == 1)
goto ready;
- wdccommand(chp, 0, WDCC_SETMULTI, 0, 0, 0, ata_bio->multi, 0);
+ wdccommand(chp, 0, WDCC_SETMULTI, 0, 0, 0, drvp->multi, 0);
errstring = "setmulti";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
goto ctrltimeout;
Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30.4.2 src/sys/dev/ic/siisata.c:1.30.4.3
--- src/sys/dev/ic/siisata.c:1.30.4.2 Tue Apr 11 18:13:17 2017
+++ src/sys/dev/ic/siisata.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.2 2017/04/11 18:13:17 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.3 2017/04/15 12:01:23 jdolecek Exp $ */
/* from ahcisata_core.c */
@@ -79,7 +79,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.2 2017/04/11 18:13:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.3 2017/04/15 12:01:23 jdolecek Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -138,7 +138,7 @@ static void siisata_intr_port(struct sii
void siisata_probe_drive(struct ata_channel *);
void siisata_setup_channel(struct ata_channel *);
-int siisata_ata_bio(struct ata_drive_datas *, struct ata_bio *);
+int siisata_ata_bio(struct ata_drive_datas *, struct ata_xfer *);
void siisata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
void siisata_reset_channel(struct ata_channel *, int);
int siisata_ata_addref(struct ata_drive_datas *);
@@ -773,8 +773,7 @@ siisata_exec_command(struct ata_drive_da
SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__),
DEBUG_FUNCS);
- xfer = ata_get_xfer(ata_c->flags & AT_WAIT ?
- ATAXF_CANSLEEP : ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(chp);
if (xfer == NULL)
return ATACMD_TRY_AGAIN;
if (ata_c->flags & AT_POLL)
@@ -1006,16 +1005,15 @@ siisata_cmd_done(struct ata_channel *chp
}
int
-siisata_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+siisata_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
{
struct ata_channel *chp = drvp->chnl_softc;
- struct ata_xfer *xfer;
+ struct ata_bio *ata_bio = &xfer->c_bio;
SIISATA_DEBUG_PRINT( ("%s: %s.\n",
SIISATANAME((struct siisata_softc *)chp->ch_atac),
__func__), DEBUG_FUNCS);
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
if (xfer == NULL)
return ATACMD_TRY_AGAIN;
if (ata_bio->flags & ATA_POLL)
@@ -1113,7 +1111,6 @@ siisata_bio_kill_xfer(struct ata_channel
siisata_deactivate_prb(schp, slot);
- ata_free_xfer(chp, xfer);
ata_bio->flags |= ATA_ITSDONE;
switch (reason) {
case KILL_GONE:
@@ -1127,7 +1124,7 @@ siisata_bio_kill_xfer(struct ata_channel
__func__, chp->ch_channel, reason);
}
ata_bio->r_error = WDCE_ABRT;
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
}
int
@@ -1159,8 +1156,6 @@ siisata_bio_complete(struct ata_channel
return 0;
}
- ata_free_xfer(chp, xfer);
-
ata_bio->flags |= ATA_ITSDONE;
if (chp->ch_status & WDCS_DWF) {
ata_bio->error = ERR_DF;
@@ -1182,7 +1177,7 @@ siisata_bio_complete(struct ata_channel
SIISATA_DEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS);
if (ata_bio->flags & ATA_POLL)
return 1;
- (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+ (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
atastart(chp);
return 0;
}
@@ -1535,7 +1530,7 @@ siisata_atapi_scsipi_request(struct scsi
scsipi_done(sc_xfer);
return;
}
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(atac->atac_channels[channel]);
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.1 src/sys/dev/ic/wdc.c:1.283.2.2
--- src/sys/dev/ic/wdc.c:1.283.2.1 Mon Apr 10 22:57:02 2017
+++ src/sys/dev/ic/wdc.c Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: wdc.c,v 1.283.2.1 2017/04/10 22:57:02 jdolecek Exp $ */
+/* $NetBSD: wdc.c,v 1.283.2.2 2017/04/15 12:01:23 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.1 2017/04/10 22:57:02 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.2 2017/04/15 12:01:23 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wdc.h"
@@ -1377,8 +1377,7 @@ wdc_exec_command(struct ata_drive_datas
drvp->drive), DEBUG_FUNCS);
/* set up an xfer and queue. Wait for completion */
- xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
- ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(chp);
if (xfer == NULL) {
return ATACMD_TRY_AGAIN;
}
Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.1 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.2
--- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.1 Mon Apr 10 22:57:03 2017
+++ src/sys/dev/scsipi/atapi_wdc.c Sat Apr 15 12:01:24 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: atapi_wdc.c,v 1.123.4.1 2017/04/10 22:57:03 jdolecek Exp $ */
+/* $NetBSD: atapi_wdc.c,v 1.123.4.2 2017/04/15 12:01:24 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.1 2017/04/10 22:57:03 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.2 2017/04/15 12:01:24 jdolecek Exp $");
#ifndef ATADEBUG
#define ATADEBUG
@@ -362,7 +362,7 @@ wdc_atapi_scsipi_request(struct scsipi_c
return;
}
- xfer = ata_get_xfer(ATAXF_NOSLEEP);
+ xfer = ata_get_xfer(atac->atac_channels[channel]);
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 src/sys/dev/usb/umass_isdata.c:1.33.4.1
--- src/sys/dev/usb/umass_isdata.c:1.33 Fri Nov 25 12:56:29 2016
+++ src/sys/dev/usb/umass_isdata.c Sat Apr 15 12:01:24 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: umass_isdata.c,v 1.33 2016/11/25 12:56:29 skrll Exp $ */
+/* $NetBSD: umass_isdata.c,v 1.33.4.1 2017/04/15 12:01:24 jdolecek Exp $ */
/*
* TODO:
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33 2016/11/25 12:56:29 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33.4.1 2017/04/15 12:01:24 jdolecek Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -93,7 +93,7 @@ struct uisdata_softc {
struct ata_drive_datas sc_drv_data;
struct isd200_config sc_isd_config;
- void *sc_ata_bio;
+ struct ata_xfer *sc_ata_xfer;
u_long sc_skip;
};
@@ -108,8 +108,8 @@ int uisdatadebug = 0;
#define DPRINTFN(n,x)
#endif
-int uisdata_bio(struct ata_drive_datas *, struct ata_bio *);
-int uisdata_bio1(struct ata_drive_datas *, struct ata_bio *);
+int uisdata_bio(struct ata_drive_datas *, struct ata_xfer *);
+int uisdata_bio1(struct ata_drive_datas *, struct ata_xfer *);
void uisdata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
void uisdata_reset_channel(struct ata_channel *, int);
int uisdata_exec_command(struct ata_drive_datas *, struct ata_command *);
@@ -220,6 +220,7 @@ umass_isdata_attach(struct umass_softc *
adev.adev_drv_data = &scbus->sc_drv_data;
scbus->sc_drv_data.drive_type = ATA_DRIVET_ATA;
scbus->sc_drv_data.chnl_softc = sc;
+#error chnl_softc is used by ata_get_xfer() as ata_channel
scbus->base.sc_child = config_found(sc->sc_dev, &adev, uwdprint);
return 0;
@@ -230,13 +231,14 @@ void
uisdata_bio_cb(struct umass_softc *sc, void *priv, int residue, int status)
{
struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
- struct ata_bio *ata_bio = priv;
+ struct ata_xfer *xfer = priv;
+ struct ata_bio *ata_bio = &xfer->c_bio;
int s;
DPRINTF(("%s: residue=%d status=%d\n", __func__, residue, status));
s = splbio();
- scbus->sc_ata_bio = NULL;
+ scbus->sc_ata_xfer = NULL;
if (status != STATUS_CMD_OK)
ata_bio->error = ERR_DF; /* ??? */
else
@@ -251,7 +253,7 @@ uisdata_bio_cb(struct umass_softc *sc, v
ata_bio->bcount += residue;
} else if (ata_bio->bcount > 0) {
DPRINTF(("%s: continue\n", __func__));
- (void)uisdata_bio1(&scbus->sc_drv_data, ata_bio); /*XXX save drv*/
+ (void)uisdata_bio1(&scbus->sc_drv_data, xfer); /*XXX save drv*/
splx(s);
return;
}
@@ -260,27 +262,29 @@ uisdata_bio_cb(struct umass_softc *sc, v
DPRINTF(("%s: wakeup %p\n", __func__, ata_bio));
wakeup(ata_bio);
} else {
- (*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc);
+ (*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc,
+ xfer);
}
splx(s);
}
int
-uisdata_bio(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
+uisdata_bio(struct ata_drive_datas *drv, struct ata_xfer *xfer)
{
struct umass_softc *sc = drv->chnl_softc;
struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
scbus->sc_skip = 0;
- return uisdata_bio1(drv, ata_bio);
+ return uisdata_bio1(drv, xfer);
}
int
-uisdata_bio1(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
+uisdata_bio1(struct ata_drive_datas *drv, struct ata_xfer *xfer)
{
struct umass_softc *sc = drv->chnl_softc;
struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
struct isd200_config *cf = &scbus->sc_isd_config;
+ struct ata_bio *ata_bio = &xfer->c_bio;
struct ata_cmd ata;
uint16_t cyl;
uint8_t head, sect;
@@ -298,11 +302,11 @@ uisdata_bio1(struct ata_drive_datas *drv
return ATACMD_COMPLETE;
}
- if (scbus->sc_ata_bio != NULL) {
+ if (scbus->sc_ata_xfer != NULL) {
printf("%s: multiple uisdata_bio\n", __func__);
return ATACMD_TRY_AGAIN;
} else
- scbus->sc_ata_bio = ata_bio;
+ scbus->sc_ata_xfer = xfer;
if (ata_bio->flags & ATA_LBA) {
sect = (ata_bio->blkno >> 0) & 0xff;
@@ -311,11 +315,11 @@ uisdata_bio1(struct ata_drive_datas *drv
head |= WDSD_LBA;
} else {
int blkno = ata_bio->blkno;
- sect = blkno % ata_bio->lp->d_nsectors;
+ sect = blkno % drv->lp->d_nsectors;
sect++; /* Sectors begin with 1, not 0. */
- blkno /= ata_bio->lp->d_nsectors;
- head = blkno % ata_bio->lp->d_ntracks;
- blkno /= ata_bio->lp->d_ntracks;
+ blkno /= drv->lp->d_nsectors;
+ head = blkno % drv->lp->d_ntracks;
+ blkno /= drv->lp->d_ntracks;
cyl = blkno;
head |= WDSD_CHS;
}
@@ -324,8 +328,8 @@ uisdata_bio1(struct ata_drive_datas *drv
if (ata_bio->flags & ATA_SINGLE)
nblks = 1;
else
- nblks = min(ata_bio->multi, nbytes / ata_bio->lp->d_secsize);
- nbytes = nblks * ata_bio->lp->d_secsize;
+ nblks = min(drv->multi, nbytes / drv->lp->d_secsize);
+ nbytes = nblks * drv->lp->d_secsize;
ata_bio->nblks = nblks;
ata_bio->nbytes = nbytes;
@@ -364,7 +368,7 @@ uisdata_bio1(struct ata_drive_datas *drv
ata_bio->bcount, drv->drive));
sc->sc_methods->wire_xfer(sc, drv->drive, &ata, sizeof(ata),
ata_bio->databuf + scbus->sc_skip, nbytes,
- dir, ATA_DELAY, 0, uisdata_bio_cb, ata_bio);
+ dir, ATA_DELAY, 0, uisdata_bio_cb, xfer);
while (ata_bio->flags & ATA_POLL) {
DPRINTF(("%s: tsleep %p\n", __func__, ata_bio));
@@ -496,17 +500,19 @@ uisdata_kill_pending(struct ata_drive_da
{
struct umass_softc *sc = drv->chnl_softc;
struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
- struct ata_bio *ata_bio = scbus->sc_ata_bio;
+ struct ata_xfer *xfer = scbus->sc_ata_xfer;
+ struct ata_bio *ata_bio = &xfer->c_bio;
DPRINTFN(-1,("%s\n", __func__));
- if (ata_bio == NULL)
+ if (xfer == NULL)
return;
- scbus->sc_ata_bio = NULL;
+
+ scbus->sc_ata_xfer = NULL;
ata_bio->flags |= ATA_ITSDONE;
ata_bio->error = ERR_NODEV;
ata_bio->r_error = WDCE_ABRT;
- (*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc);
+ (*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc, xfer);
}
int