Allow polled commands to be queued, if ata_exec_xfer() is called in thread
context. For this introduce 3 new xfer tags: - C_WAIT, equivalent of AT_WAIT - C_WAITACT, when there is a thread waiting on this xfer to become the active one (that is, to be at the head of the queue) - C_FREE, set by ata_free_xfer() when it can't free the xfer because it's still in use. The holder should then free the xfer ASAP. If ata_exec_xfer() is called with (C_POLL | C_WAIT), and there is already xfers to be processed, assert C_WAITACT and sleep. atastart() checks for C_WAITACT, and wakeup the thread waiting for this xfer to become active if set. atastart() won't process this xfer, it's the responsability of the thread waked up to handle it. Fix (the right way) kern/27421 by Martin Husemann.
This commit is contained in:
parent
58d3abc94f
commit
c31b572a47
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: ata.c,v 1.61 2004/10/28 20:11:41 bouyer Exp $ */
|
/* $NetBSD: ata.c,v 1.62 2004/10/30 23:10:37 bouyer Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
|
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.61 2004/10/28 20:11:41 bouyer Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.62 2004/10/30 23:10:37 bouyer Exp $");
|
||||||
|
|
||||||
#ifndef ATADEBUG
|
#ifndef ATADEBUG
|
||||||
#define ATADEBUG
|
#define ATADEBUG
|
||||||
|
@ -702,6 +702,21 @@ ata_exec_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
|
||||||
TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
|
TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
|
||||||
ATADEBUG_PRINT(("atastart from ata_exec_xfer, flags 0x%x\n",
|
ATADEBUG_PRINT(("atastart from ata_exec_xfer, flags 0x%x\n",
|
||||||
chp->ch_flags), DEBUG_XFERS);
|
chp->ch_flags), DEBUG_XFERS);
|
||||||
|
/*
|
||||||
|
* if polling and can sleep, wait for the xfer to be at head of queue
|
||||||
|
*/
|
||||||
|
if ((xfer->c_flags & (C_POLL | C_WAIT)) == (C_POLL | C_WAIT)) {
|
||||||
|
while (chp->ch_queue->active_xfer != NULL ||
|
||||||
|
TAILQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) {
|
||||||
|
xfer->c_flags |= C_WAITACT;
|
||||||
|
tsleep(xfer, PRIBIO, "ataact", 0);
|
||||||
|
xfer->c_flags &= ~C_WAITACT;
|
||||||
|
if (xfer->c_flags & C_FREE) {
|
||||||
|
ata_free_xfer(chp, xfer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
atastart(chp);
|
atastart(chp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,6 +759,17 @@ atastart(struct ata_channel *chp)
|
||||||
if (__predict_false(chp->ch_queue->queue_freeze > 0)) {
|
if (__predict_false(chp->ch_queue->queue_freeze > 0)) {
|
||||||
return; /* queue froozen */
|
return; /* queue froozen */
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* if someone is waiting for the command to be active, wake it up
|
||||||
|
* and let it process the command
|
||||||
|
*/
|
||||||
|
if (xfer->c_flags & C_WAITACT) {
|
||||||
|
ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d "
|
||||||
|
"wait active\n", xfer, chp->ch_channel, xfer->c_drive),
|
||||||
|
DEBUG_XFERS);
|
||||||
|
wakeup(xfer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
#ifdef DIAGNOSTIC
|
#ifdef DIAGNOSTIC
|
||||||
if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0)
|
if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0)
|
||||||
panic("atastart: channel waiting for irq");
|
panic("atastart: channel waiting for irq");
|
||||||
|
@ -763,6 +789,7 @@ atastart(struct ata_channel *chp)
|
||||||
|
|
||||||
if (atac->atac_cap & ATAC_CAP_NOIRQ)
|
if (atac->atac_cap & ATAC_CAP_NOIRQ)
|
||||||
KASSERT(xfer->c_flags & C_POLL);
|
KASSERT(xfer->c_flags & C_POLL);
|
||||||
|
|
||||||
xfer->c_start(chp, xfer);
|
xfer->c_start(chp, xfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,6 +815,13 @@ ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
|
||||||
struct atac_softc *atac = chp->ch_atac;
|
struct atac_softc *atac = chp->ch_atac;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (atac->atac_free_hw)
|
if (atac->atac_free_hw)
|
||||||
(*atac->atac_free_hw)(chp);
|
(*atac->atac_free_hw)(chp);
|
||||||
s = splbio();
|
s = splbio();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: atavar.h,v 1.64 2004/08/20 23:26:54 thorpej Exp $ */
|
/* $NetBSD: atavar.h,v 1.65 2004/10/30 23:10:37 bouyer Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2001 Manuel Bouyer.
|
* Copyright (c) 1998, 2001 Manuel Bouyer.
|
||||||
|
@ -70,11 +70,14 @@ struct ata_xfer {
|
||||||
void (*c_kill_xfer)(struct ata_channel *, struct ata_xfer *, int);
|
void (*c_kill_xfer)(struct ata_channel *, struct ata_xfer *, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* vlags in c_flags */
|
/* flags in c_flags */
|
||||||
#define C_ATAPI 0x0001 /* xfer is ATAPI request */
|
#define C_ATAPI 0x0001 /* xfer is ATAPI request */
|
||||||
#define C_TIMEOU 0x0002 /* xfer processing timed out */
|
#define C_TIMEOU 0x0002 /* xfer processing timed out */
|
||||||
#define C_POLL 0x0004 /* command is polled */
|
#define C_POLL 0x0004 /* command is polled */
|
||||||
#define C_DMA 0x0008 /* command uses DMA */
|
#define C_DMA 0x0008 /* command uses DMA */
|
||||||
|
#define C_WAIT 0x0010 /* can use tsleep */
|
||||||
|
#define C_WAITACT 0x0020 /* wakeup when active */
|
||||||
|
#define C_FREE 0x0040 /* call ata_free_xfer() asap */
|
||||||
|
|
||||||
/* reasons for c_kill_xfer() */
|
/* reasons for c_kill_xfer() */
|
||||||
#define KILL_GONE 1 /* device is gone */
|
#define KILL_GONE 1 /* device is gone */
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: wdc.c,v 1.216 2004/10/30 17:17:21 bouyer Exp $ */
|
/* $NetBSD: wdc.c,v 1.217 2004/10/30 23:10:37 bouyer Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved.
|
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved.
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.216 2004/10/30 17:17:21 bouyer Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.217 2004/10/30 23:10:37 bouyer Exp $");
|
||||||
|
|
||||||
#ifndef ATADEBUG
|
#ifndef ATADEBUG
|
||||||
#define ATADEBUG
|
#define ATADEBUG
|
||||||
|
@ -1274,6 +1274,8 @@ wdc_exec_command(struct ata_drive_datas *drvp, struct ata_command *ata_c)
|
||||||
ata_c->flags |= AT_POLL;
|
ata_c->flags |= AT_POLL;
|
||||||
if (ata_c->flags & AT_POLL)
|
if (ata_c->flags & AT_POLL)
|
||||||
xfer->c_flags |= C_POLL;
|
xfer->c_flags |= C_POLL;
|
||||||
|
if (ata_c->flags & AT_WAIT)
|
||||||
|
xfer->c_flags |= C_WAIT;
|
||||||
xfer->c_drive = drvp->drive;
|
xfer->c_drive = drvp->drive;
|
||||||
xfer->c_databuf = ata_c->data;
|
xfer->c_databuf = ata_c->data;
|
||||||
xfer->c_bcount = ata_c->bcount;
|
xfer->c_bcount = ata_c->bcount;
|
||||||
|
@ -1657,7 +1659,7 @@ static void
|
||||||
__wdcerror(struct ata_channel *chp, char *msg)
|
__wdcerror(struct ata_channel *chp, char *msg)
|
||||||
{
|
{
|
||||||
struct atac_softc *atac = chp->ch_atac;
|
struct atac_softc *atac = chp->ch_atac;
|
||||||
struct ata_xfer *xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer);
|
struct ata_xfer *xfer = chp->ch_queue->active_xfer;
|
||||||
|
|
||||||
if (xfer == NULL)
|
if (xfer == NULL)
|
||||||
printf("%s:%d: %s\n", atac->atac_dev.dv_xname, chp->ch_channel,
|
printf("%s:%d: %s\n", atac->atac_dev.dv_xname, chp->ch_channel,
|
||||||
|
|
Loading…
Reference in New Issue