summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/atapiscsi/atapiscsi.c910
-rw-r--r--sys/dev/ic/wdcvar.h17
2 files changed, 559 insertions, 368 deletions
diff --git a/sys/dev/atapiscsi/atapiscsi.c b/sys/dev/atapiscsi/atapiscsi.c
index 5938166e8ee..98d2816ce1e 100644
--- a/sys/dev/atapiscsi/atapiscsi.c
+++ b/sys/dev/atapiscsi/atapiscsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atapiscsi.c,v 1.19 1999/11/17 01:22:55 csapuntz Exp $ */
+/* $OpenBSD: atapiscsi.c,v 1.20 1999/12/11 10:15:02 csapuntz Exp $ */
/*
* This code is derived from code with the copyright below.
@@ -77,6 +77,7 @@
#define DEBUG_POLL 0x40
#define DEBUG_ERRORS 0x80 /* Debug error handling code */
+#define WDCDEBUG
#ifdef WDCDEBUG
int wdcdebug_atapi_mask = 0;
#define WDCDEBUG_PRINT(args, level) \
@@ -89,18 +90,46 @@ int wdcdebug_atapi_mask = 0;
/* 10 ms, this is used only before sending a cmd. */
#define ATAPI_DELAY 10
#define ATAPI_RESET_WAIT 2000
+#define ATAPI_CTRL_WAIT 4000
/* When polling, let the exponential backoff max out at 1 second's interval. */
#define ATAPI_POLL_MAXTIC (hz)
void wdc_atapi_minphys __P((struct buf *bp));
void wdc_atapi_start __P((struct channel_softc *,struct wdc_xfer *));
-int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *, int));
+
+void timer_handler __P((void *));
+
+int wdc_atapi_real_start __P((struct channel_softc *, struct wdc_xfer *,
+ int));
+int wdc_atapi_real_start_2 __P((struct channel_softc *, struct wdc_xfer *,
+ int));
+int wdc_atapi_intr_command __P((struct channel_softc *, struct wdc_xfer *,
+ int));
+
+int wdc_atapi_intr_data __P((struct channel_softc *, struct wdc_xfer *,
+ int));
+int wdc_atapi_intr_complete __P((struct channel_softc *, struct wdc_xfer *,
+ int));
+
+int wdc_atapi_intr_for_us __P((struct channel_softc *, struct wdc_xfer *,
+ int));
+
+int wdc_atapi_send_packet __P((struct channel_softc *, struct wdc_xfer *,
+ int));
+int wdc_atapi_dma_flags __P((struct wdc_xfer *));
+
int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *, int));
-void wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *));
-void wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *));
+int wdc_atapi_in_data_phase __P((struct wdc_xfer *, int, int));
+
+int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *, int));
+
+int wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *, int));
+int wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *, int));
+int wdc_atapi_reset_2 __P((struct channel_softc *, struct wdc_xfer *, int));
int wdc_atapi_send_cmd __P((struct scsi_xfer *sc_xfer));
+int wdc_atapi_tape_done __P((struct channel_softc *, struct wdc_xfer *, int));
#define MAX_SIZE MAXPHYS
struct atapiscsi_softc;
@@ -113,6 +142,7 @@ int wdc_atapi_get_params __P((struct channel_softc *, u_int8_t, struct ataparams
int atapi_dsc_wait __P((struct ata_drive_datas *, int));
int atapi_dsc_ready __P((void *));
+void atapi_dsc_check __P((void *));
int atapi_dsc_semiready __P((void *));
int atapi_poll_wait __P((int (*) __P((void *)), void *, int, int, char *));
void atapi_to_scsi_sense __P((struct scsi_xfer *, u_int8_t));
@@ -359,11 +389,7 @@ wdc_atapi_send_cmd(sc_xfer)
struct ata_drive_datas *drvp = &chp->ch_drive[drive];
struct wdc_xfer *xfer;
int flags = sc_xfer->flags;
- int s, ret, saved_datalen;
- char saved_len_bytes[3];
-
-restart:
- saved_datalen = 0;
+ int s, ret;
WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drive), DEBUG_XFERS);
@@ -392,31 +418,32 @@ restart:
if (drvp->atapi_cap & ACAP_DSC) {
WDCDEBUG_PRINT(("about to send cmd %x ", sc_xfer->cmd->opcode),
DEBUG_DSC);
- xfer->c_flags |= C_NEEDDONE;
switch (sc_xfer->cmd->opcode) {
case READ:
case WRITE:
+ xfer->c_flags |= C_MEDIA_ACCESS;
+
/* If we are not in buffer availability mode,
we limit the first request to 0 bytes, which
gets us into buffer availability mode without
holding the bus. */
if (!(drvp->drive_flags & DRIVE_DSCBA)) {
- saved_datalen = sc_xfer->datalen;
- xfer->c_flags &= ~C_NEEDDONE;
- sc_xfer->datalen = xfer->c_bcount = 0;
- bcopy(
- ((struct scsi_rw_tape *)sc_xfer->cmd)->len,
- saved_len_bytes, 3);
+ xfer->c_bcount = 0;
+ xfer->transfer_len =
+ _3btol(((struct scsi_rw_tape *)
+ sc_xfer->cmd)->len);
_lto3b(0,
((struct scsi_rw_tape *)
sc_xfer->cmd)->len);
+ xfer->c_done = wdc_atapi_tape_done;
WDCDEBUG_PRINT(
("R/W in completion mode, do 0 blocks\n"),
DEBUG_DSC);
} else
WDCDEBUG_PRINT(("R/W %d blocks %d bytes\n",
- _3btol(((struct scsi_rw_tape *)
- sc_xfer->cmd)->len), sc_xfer->datalen),
+ _3btol(((struct scsi_rw_tape *)
+ sc_xfer->cmd)->len),
+ sc_xfer->datalen),
DEBUG_DSC);
/* DSC will change to buffer availability mode.
@@ -427,15 +454,13 @@ restart:
case LOAD:
case REWIND:
case SPACE:
+ case WRITE_FILEMARKS:
#if 0
case LOCATE:
case READ_POSITION:
- case WRITE_FILEMARK:
#endif
- /* DSC will change to command completion mode.
- We can reflect this early. */
- drvp->drive_flags &= ~DRIVE_DSCBA;
- WDCDEBUG_PRINT(("clear DCSBA\n"), DEBUG_DSC);
+
+ xfer->c_flags |= C_MEDIA_ACCESS;
break;
default:
@@ -445,19 +470,10 @@ restart:
wdc_exec_xfer(chp, xfer);
#ifdef DIAGNOSTIC
- if (((sc_xfer->flags & SCSI_POLL) != 0 ||
- (drvp->atapi_cap & ACAP_DSC) != 0) &&
+ if ((xfer->c_flags & C_POLL) != 0 &&
(sc_xfer->flags & ITSDONE) == 0)
panic("wdc_atapi_send_cmd: polled command not done");
#endif
- if ((drvp->atapi_cap & ACAP_DSC) && saved_datalen != 0) {
- sc_xfer->datalen = saved_datalen;
- bcopy(saved_len_bytes,
- ((struct scsi_rw_tape *)sc_xfer->cmd)->len, 3);
- sc_xfer->flags &= ~ITSDONE;
- splx(s);
- goto restart;
- }
ret = (sc_xfer->flags & ITSDONE) ? COMPLETE : SUCCESSFULLY_QUEUED;
splx(s);
return (ret);
@@ -500,14 +516,215 @@ atapi_to_scsi_sense(xfer, flags)
}
+enum atapi_context {
+ ctxt_process = 0,
+ ctxt_timer = 1,
+ ctxt_interrupt = 2
+};
+
+int wdc_atapi_the_machine __P((struct channel_softc *, struct wdc_xfer *,
+ enum atapi_context));
+
+int wdc_atapi_the_poll_machine __P((struct channel_softc *, struct wdc_xfer *));
+
void
wdc_atapi_start(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
+ xfer->next = wdc_atapi_real_start;
+
+ wdc_atapi_the_machine(chp, xfer, ctxt_process);
+}
+
+
+void
+timer_handler(arg)
+ void *arg;
+{
+ struct wdc_xfer *xfer = arg;
+ struct channel_softc *chp = xfer->chp;
+ int s;
+
+ xfer->c_flags &= ~C_POLL_MACHINE;
+
+ /* There is a race here between us and the interrupt */
+ s = splbio();
+ wdc_atapi_the_machine(chp, xfer, ctxt_timer);
+ splx(s);
+}
+
+
+int
+wdc_atapi_intr(chp, xfer, irq)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ int irq;
+{
+ /* XXX we should consider an alternate signaling regime here */
+ if (xfer->c_flags & C_TIMEOU) {
+ xfer->c_flags &= ~C_TIMEOU;
+ return (wdc_atapi_the_machine(chp, xfer, ctxt_timer));
+ }
+
+ return (wdc_atapi_the_machine(chp, xfer, ctxt_interrupt));
+}
+
+#define CONTINUE_POLL 0
+#define GOTO_NEXT 1
+#define DONE 2
+
+int
+wdc_atapi_the_poll_machine(chp, xfer)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+{
+ int idx = 0, ret;
+ int current_timeout;
+
+ xfer->timeout = -1;
+
+ while (1) {
+ idx++;
+
+ xfer->timeout = -1;
+ xfer->delay = 0;
+ xfer->expect_irq = 0;
+
+ ret = (xfer->next)(chp, xfer, (current_timeout * 1000 <= idx));
+
+ if (xfer->timeout != -1) {
+ current_timeout = xfer->timeout;
+ idx = 0;
+ }
+
+ if (xfer->delay != 0) {
+ while (xfer->delay--)
+ delay(1000);
+ }
+
+ switch (ret) {
+ case GOTO_NEXT:
+ break;
+
+ case CONTINUE_POLL:
+ DELAY(1);
+
+ break;
+
+ case DONE:
+ wdc_free_xfer(chp, xfer);
+ wdcstart(chp);
+ return (0);
+ }
+ }
+}
+
+int
+wdc_atapi_the_machine(chp, xfer, ctxt)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ enum atapi_context ctxt;
+{
+ int idx = 0, ret;
+ int claim_irq = 0;
+ u_int64_t now = (u_int64_t)time.tv_sec * 1000 + time.tv_usec / 1000;
+ int timeout_delay = hz / 10;
+
+ if (xfer->c_flags & C_POLL) {
+ if (ctxt != ctxt_process)
+ return (0);
+
+ wdc_atapi_the_poll_machine(chp, xfer);
+ return (0);
+ }
+
+ do_op:
+ idx++;
+
+ xfer->timeout = -1;
+ xfer->claim_irq = 0;
+ xfer->delay = 0;
+
+ ret = (xfer->next)(chp, xfer, now >= xfer->endtime);
+
+ if (xfer->timeout != -1) {
+ now = (u_int64_t)time.tv_sec * 1000 +
+ time.tv_usec / 1000;
+
+ xfer->endtime = (u_int64_t)xfer->timeout + now;
+
+ }
+
+ if (xfer->claim_irq) claim_irq = xfer->claim_irq;
+
+ if (xfer->delay) timeout_delay = max(xfer->delay * hz / 1000, 1);
+
+ switch (ret) {
+ case GOTO_NEXT:
+ if (xfer->expect_irq) {
+ chp->ch_flags |= WDCF_IRQ_WAIT;
+ xfer->expect_irq = 0;
+ timeout(wdctimeout, chp,
+ (xfer->endtime - now) * hz / 1000);
+
+ return (claim_irq);
+ }
+
+ if (xfer->delay)
+ break;
+
+ goto do_op;
+
+ case CONTINUE_POLL:
+ if (xfer->delay) break;
+ if (idx >= 50) break;
+
+ DELAY(1);
+ goto do_op;
+
+ case DONE:
+ if (xfer->c_flags & C_POLL_MACHINE)
+ untimeout (timer_handler, xfer);
+
+ wdc_free_xfer(chp, xfer);
+ wdcstart(chp);
+
+ return (claim_irq);
+ }
+
+ timeout(timer_handler, xfer, timeout_delay);
+ xfer->c_flags |= C_POLL_MACHINE;
+ return (claim_irq);
+}
+
+
+void wdc_atapi_update_status __P((struct channel_softc *));
+
+void
+wdc_atapi_update_status(chp)
+ struct channel_softc *chp;
+{
+ chp->ch_status = CHP_READ_REG(chp, wdr_status);
+
+ if (chp->ch_status == 0xff && (chp->ch_flags & WDCF_ONESLAVE)) {
+ CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | 0x10);
+
+ chp->ch_status = CHP_READ_REG(chp, wdr_status);
+ }
+
+ if ((chp->ch_status & (WDCS_BSY | WDCS_ERR)) == WDCS_ERR)
+ chp->ch_error = CHP_READ_REG(chp, wdr_error);
+}
+
+int
+wdc_atapi_real_start(chp, xfer, timeout)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ int timeout;
+{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
- struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive,
@@ -515,17 +732,44 @@ wdc_atapi_start(chp, xfer)
/* Adjust C_DMA, it may have changed if we are requesting sense */
if (!(xfer->c_flags & C_POLL) &&
(drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
- (sc_xfer->datalen > 0 || (xfer->c_flags & C_SENSE)))
+ (xfer->c_bcount > 0 || (xfer->c_flags & C_SENSE)))
xfer->c_flags |= C_DMA;
else
xfer->c_flags &= ~C_DMA;
- if (wdc_select_drive(chp, xfer->drive, ATAPI_DELAY) < 0) {
+
+ CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4));
+
+ DELAY(1);
+
+ xfer->next = wdc_atapi_real_start_2;
+ xfer->timeout = ATAPI_DELAY;
+
+ return (GOTO_NEXT);
+}
+
+
+int
+wdc_atapi_real_start_2(chp, xfer, timeout)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ int timeout;
+{
+ struct scsi_xfer *sc_xfer = xfer->cmd;
+ struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
+
+ if (timeout) {
printf("wdc_atapi_start: not ready, st = %02x\n",
chp->ch_status);
+
sc_xfer->error = XS_TIMEOUT;
- wdc_atapi_reset(chp, xfer);
- return;
+ xfer->next = wdc_atapi_reset;
+ return (GOTO_NEXT);
+ } else {
+ wdc_atapi_update_status(chp);
+
+ if (chp->ch_status & WDCS_BSY)
+ return (CONTINUE_POLL);
}
/* Do control operations specially. */
@@ -536,22 +780,26 @@ wdc_atapi_start(chp, xfer)
xfer->drive, drvp->state);
panic("wdc_atapi_start: bad state");
}
- wdc_atapi_ctrl(chp, xfer, 0);
- return;
- }
-
- if (drvp->atapi_cap & ACAP_DSC) {
- if (atapi_dsc_wait(drvp, sc_xfer->timeout)) {
- sc_xfer->error = XS_TIMEOUT;
- wdc_atapi_reset(chp, xfer);
- return;
- }
- WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, DSC asserted\n",
- chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),
- DEBUG_DSC);
- drvp->drive_flags &= ~DRIVE_DSCWAIT;
+
+ xfer->next = wdc_atapi_ctrl;
+ return (GOTO_NEXT);
}
+ xfer->next = wdc_atapi_send_packet;
+ return (GOTO_NEXT);
+}
+
+
+int
+wdc_atapi_send_packet(chp, xfer, timeout)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ int timeout;
+{
+ struct scsi_xfer *sc_xfer = xfer->cmd;
+ struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
+ struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
+
/*
* Even with WDCS_ERR, the device should accept a command packet
* Limit length to what can be stuffed into the cylinder register
@@ -569,69 +817,37 @@ wdc_atapi_start(chp, xfer)
as->protocol_phase = as_cmdout;
as->retries = 0;
- /*
- * If there is no interrupt for CMD input, busy-wait for it (done in
- * the interrupt routine. If it is a polled command, call the interrupt
- * routine until command is done.
- */
- if (((drvp->atapi_cap & ATAPI_CFG_DRQ_MASK) != ATAPI_CFG_IRQ_DRQ) ||
- (sc_xfer->flags & SCSI_POLL) || (drvp->atapi_cap & ACAP_DSC)) {
- /* Wait for at last 400ns for status bit to be valid */
- DELAY(1);
- wdc_atapi_intr(chp, xfer, 0);
- } else {
- chp->ch_flags |= WDCF_IRQ_WAIT;
- timeout(wdctimeout, chp, hz);
- return;
- }
+ DELAY(1);
- if ((sc_xfer->flags & SCSI_POLL) || (drvp->atapi_cap & ACAP_DSC)) {
- while ((sc_xfer->flags & ITSDONE) == 0) {
- if (drvp->atapi_cap & ACAP_DSC) {
- if (atapi_poll_wait(
- (drvp->drive_flags & DRIVE_DSCWAIT) ?
- atapi_dsc_ready : atapi_dsc_semiready,
- drvp, sc_xfer->timeout, PZERO + PCATCH,
- "atapist")) {
- sc_xfer->error = XS_TIMEOUT;
- wdc_atapi_reset(chp, xfer);
- return;
- }
- } else
- /* Wait for at last 400ns for status bit to
- be valid */
- DELAY(1);
+ xfer->next = wdc_atapi_intr_for_us;
+ xfer->timeout = sc_xfer->timeout;
- wdc_atapi_intr(chp, xfer, 0);
- }
+ if ((drvp->atapi_cap & ATAPI_CFG_DRQ_MASK) == ATAPI_CFG_IRQ_DRQ) {
+ /* We expect an IRQ to tell us of the next state */
+ xfer->expect_irq = 1;
}
+ return (GOTO_NEXT);
}
int
-atapi_dsc_semiready(arg)
- void *arg;
+wdc_atapi_dma_flags(xfer)
+ struct wdc_xfer *xfer;
{
- struct ata_drive_datas *drvp = arg;
- struct channel_softc *chp = drvp->chnl_softc;
+ struct scsi_xfer *sc_xfer = xfer->cmd;
+ int dma_flags;
- /* We should really wait_for_unbusy here too before
- switching drives. */
- CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drvp->drive << 4));
+ dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) ||
+ (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0;
+ dma_flags |= (xfer->c_flags & C_POLL) ? WDC_DMA_POLL : 0;
- return (wait_for_unbusy(chp, 0) == 0);
+ return (dma_flags);
}
-
-int wdc_atapi_intr_command __P((struct channel_softc *, struct wdc_xfer *, int));
-int wdc_atapi_intr_data __P((struct channel_softc *, struct wdc_xfer *, int));
-int wdc_atapi_intr_complete __P((struct channel_softc *, struct wdc_xfer *, int));
-
-
int
-wdc_atapi_intr_command(chp, xfer, dma_flags)
+wdc_atapi_intr_command(chp, xfer, timeout)
struct channel_softc *chp;
struct wdc_xfer *xfer;
- int dma_flags;
+ int timeout;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
@@ -640,6 +856,10 @@ wdc_atapi_intr_command(chp, xfer, dma_flags)
u_int8_t cmd[16];
struct scsi_sense *cmd_reqsense;
int cmdlen = (drvp->atapi_cap & ACAP_LEN) ? 16 : 12;
+ int dma_flags;
+
+ xfer->claim_irq = 1;
+ dma_flags = wdc_atapi_dma_flags(xfer);
bzero(cmd, sizeof(cmd));
@@ -660,8 +880,9 @@ wdc_atapi_intr_command(chp, xfer, dma_flags)
chp->channel, xfer->drive, xfer->databuf,
xfer->c_bcount, dma_flags) != 0) {
sc_xfer->error = XS_DRIVER_STUFFUP;
- wdc_atapi_done(chp, xfer);
- return (1);
+
+ xfer->next = wdc_atapi_done;
+ return (GOTO_NEXT);
}
}
@@ -676,57 +897,38 @@ wdc_atapi_intr_command(chp, xfer, dma_flags)
dma_flags);
}
- if ((sc_xfer->flags & SCSI_POLL) == 0 &&
- (drvp->atapi_cap & ACAP_DSC) == 0) {
- chp->ch_flags |= WDCF_IRQ_WAIT;
- timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
- }
+ xfer->expect_irq = 1;
/* If we read/write to a tape we will get into buffer
availability mode. */
if (drvp->atapi_cap & ACAP_DSC) {
- if (!(drvp->drive_flags & DRIVE_DSCBA) &&
- (sc_xfer->cmd->opcode == READ ||
- sc_xfer->cmd->opcode == WRITE)) {
+ if ((sc_xfer->cmd->opcode == READ ||
+ sc_xfer->cmd->opcode == WRITE)) {
drvp->drive_flags |= DRIVE_DSCBA;
WDCDEBUG_PRINT(("set DSCBA\n"), DEBUG_DSC);
+ } else if ((xfer->c_flags & C_MEDIA_ACCESS) &&
+ (drvp->drive_flags & DRIVE_DSCBA)) {
+ /* Clause 3.2.4 of QIC-157 D.
+
+ Any media access command other than read or
+ write will switch DSC back to completion
+ mode */
+ drvp->drive_flags &= ~DRIVE_DSCBA;
+ WDCDEBUG_PRINT(("clear DCSBA\n"), DEBUG_DSC);
}
- if (sc_xfer->cmd->opcode == READ)
- drvp->drive_flags |= DRIVE_DSCWAIT;
}
- return (1);
+ return (GOTO_NEXT);
}
+
int
-wdc_atapi_intr_data(chp, xfer, dma_flags)
- struct channel_softc *chp;
+wdc_atapi_in_data_phase(xfer, len, ire)
struct wdc_xfer *xfer;
- int dma_flags;
-
+ int len, ire;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
- struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
- struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
- int len, ire;
- char *message = 0;
-
- len = (CHP_READ_REG(chp, wdr_cyl_hi) << 8) |
- CHP_READ_REG(chp, wdr_cyl_lo);
- ire = CHP_READ_REG(chp, wdr_ireason);
-
- WDCDEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x "
- "ire 0x%x :", xfer->c_bcount,
- len, chp->ch_status, chp->ch_error, ire), DEBUG_INTR);
-
- /* Possibility to explore; what if we get an interrupt
- during DMA ? */
- if ((xfer->c_flags & C_DMA) != 0) {
- if ((xfer->c_flags & C_TIMEOU) == 0)
- message = "unexpected interrupt during DMA mode";
-
- goto unexpected_state;
- }
+ char *message;
if (ire & WDCI_CMD) {
message = "unexpectedly in command phase";
@@ -738,7 +940,7 @@ wdc_atapi_intr_data(chp, xfer, dma_flags)
message = "data phase where none expected";
goto unexpected_state;
}
-
+
/* Make sure polarities match */
if (((ire & WDCI_IN) == WDCI_IN) ==
((sc_xfer->flags & SCSI_DATA_OUT) == SCSI_DATA_OUT)) {
@@ -757,7 +959,36 @@ wdc_atapi_intr_data(chp, xfer, dma_flags)
goto unexpected_state;
}
+
+ return (1);
+
+ unexpected_state:
+
+ return (0);
+}
+
+int
+wdc_atapi_intr_data(chp, xfer, timeout)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ int timeout;
+{
+ struct scsi_xfer *sc_xfer = xfer->cmd;
+ struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
+ int len, ire;
+
+ len = (CHP_READ_REG(chp, wdr_cyl_hi) << 8) |
+ CHP_READ_REG(chp, wdr_cyl_lo);
+ ire = CHP_READ_REG(chp, wdr_ireason);
+
+ if (!wdc_atapi_in_data_phase(xfer, len, ire))
+ return (CONTINUE_POLL);
+
if (xfer->c_bcount >= len) {
+ WDCDEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x "
+ "ire 0x%x\n", xfer->c_bcount,
+ len, chp->ch_status, chp->ch_error, ire), DEBUG_INTR);
+
/* Common case */
if (sc_xfer->flags & SCSI_DATA_OUT)
wdc_output_bytes(drvp, (u_int8_t *)xfer->databuf +
@@ -793,60 +1024,25 @@ wdc_atapi_intr_data(chp, xfer, dma_flags)
xfer->c_bcount = 0;
}
- if ((sc_xfer->flags & SCSI_POLL) == 0 &&
- (drvp->atapi_cap & ACAP_DSC) == 0) {
- chp->ch_flags |= WDCF_IRQ_WAIT;
- timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
- } else if (drvp->atapi_cap & ACAP_DSC)
- drvp->drive_flags |= DRIVE_DSCWAIT;
- return (1);
-
- unexpected_state:
+ xfer->expect_irq = 1;
+ xfer->next = wdc_atapi_intr_for_us;
- /* If we're in polling mode, then it's possible we caught
- a drive in some awkward, intermediate state. Of course,
- the drive should have BSY set while it's transitioning
- through awkward states, but this may not always
- be the case. */
-
- /* Spurious interrupts can cause us pain too and we don't deal
- with those nearly as well. We assume the spurious
- interrupts are random and won't affect us on retry */
- if (xfer->c_flags & C_POLL) {
- DELAY(1000);
- as->retries++;
- /* Give the drive up to 2 seconds to fix itself */
- if (as->retries <= 2000)
- return (1);
- }
-
- if (message)
- printf ("wdc_atapi_intr_drq: %s\n", message);
-
- if (xfer->c_flags & C_DMA) {
- (*chp->wdc->dma_finish)(chp->wdc->dma_arg,
- chp->channel, xfer->drive, dma_flags);
- drvp->n_dmaerrs++;
- }
-
- sc_xfer->error = XS_RESET;
- wdc_atapi_reset(chp, xfer);
-
- return (1);
+ return (GOTO_NEXT);
}
int
-wdc_atapi_intr_complete(chp, xfer, dma_flags)
+wdc_atapi_intr_complete(chp, xfer, timeout)
struct channel_softc *chp;
struct wdc_xfer *xfer;
- int dma_flags;
+ int timeout;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
int dma_err = 0;
+ int dma_flags = wdc_atapi_dma_flags(xfer);
WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR);
@@ -856,12 +1052,8 @@ wdc_atapi_intr_complete(chp, xfer, dma_flags)
dma_err = (*chp->wdc->dma_finish)(chp->wdc->dma_arg,
chp->channel, xfer->drive, dma_flags);
- /* Assume everything was transferred
- XXX - maybe we want to check the error register here */
- if (xfer->c_flags & C_SENSE)
- xfer->c_bcount -= sizeof(sc_xfer->sense);
- else
- xfer->c_bcount -= sc_xfer->datalen;
+ /* Assume everything was transferred */
+ xfer->c_bcount = 0;
}
as->protocol_phase = as_none;
@@ -872,8 +1064,8 @@ wdc_atapi_intr_complete(chp, xfer, dma_flags)
WDCDEBUG_PRINT(("wdc_atapi_intr: request_sense aborted, "
"calling wdc_atapi_done()"
), DEBUG_INTR);
- wdc_atapi_done(chp, xfer);
- return (1);
+ xfer->next = wdc_atapi_done;
+ return (GOTO_NEXT);
}
/*
@@ -882,8 +1074,9 @@ wdc_atapi_intr_complete(chp, xfer, dma_flags)
*/
sc_xfer->error = XS_RESET;
- wdc_atapi_reset(chp, xfer);
- return (1);
+ xfer->next = wdc_atapi_reset;
+ return (GOTO_NEXT);
+
} else if (xfer->c_bcount < sizeof(sc_xfer->sense)) {
/* use the sense we just read */
sc_xfer->error = XS_SENSE;
@@ -907,21 +1100,22 @@ wdc_atapi_intr_complete(chp, xfer, dma_flags)
* 'request sense'
*/
xfer->databuf = &sc_xfer->sense;
- xfer->c_bcount =
- sizeof(sc_xfer->sense);
+ xfer->c_bcount = sizeof(sc_xfer->sense);
xfer->c_skip = 0;
+ xfer->c_done = NULL;
xfer->c_flags |= C_SENSE;
- wdc_atapi_start(chp, xfer);
- return (1);
+ xfer->next = wdc_atapi_real_start;
+ return (GOTO_NEXT);
}
- }
+ }
}
if (dma_err < 0) {
drvp->n_dmaerrs++;
sc_xfer->error = XS_RESET;
- wdc_atapi_reset(chp, xfer);
- return (1);
+
+ xfer->next = wdc_atapi_reset;
+ return (GOTO_NEXT);
}
@@ -939,98 +1133,113 @@ wdc_atapi_intr_complete(chp, xfer, dma_flags)
WDCDEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done() (end), error 0x%x "
"\n", sc_xfer->error),
DEBUG_INTR);
- wdc_atapi_done(chp, xfer);
- return (1);
+
+
+ if (xfer->c_done)
+ xfer->next = xfer->c_done;
+ else
+ xfer->next = wdc_atapi_done;
+
+ return (GOTO_NEXT);
}
int
-wdc_atapi_intr(chp, xfer, irq)
+wdc_atapi_intr_for_us(chp, xfer, timeout)
struct channel_softc *chp;
struct wdc_xfer *xfer;
- int irq;
+ int timeout;
+
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc;
- int dma_flags = 0;
- WDCDEBUG_PRINT(("wdc_atapi_intr %s:%d:%d\n",
- chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),
- DEBUG_INTR);
+ WDCDEBUG_PRINT(("ATAPI_INTR\n"), DEBUG_INTR);
- /* Is it not a transfer, but a control operation? */
- if (drvp->state < READY) {
- printf("%s:%d:%d: bad state %d in wdc_atapi_intr\n",
- chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
- drvp->state);
- panic("wdc_atapi_intr: bad state\n");
- }
+ /* If we missed an IRQ and were using DMA, flag it as a DMA error */
/* We should really wait_for_unbusy here too before
switching drives. */
CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4));
+ DELAY (1);
- /* Ack interrupt done in wait_for_unbusy */
- if (wait_for_unbusy(chp,
- (irq == 0) ? sc_xfer->timeout : 0) != 0) {
- if (irq && (xfer->c_flags & C_TIMEOU) == 0)
- return (0); /* IRQ was not for us */
- printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",
- chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
- xfer->c_bcount, xfer->c_skip);
- if (xfer->c_flags & C_DMA)
- drvp->n_dmaerrs++;
- sc_xfer->error = XS_TIMEOUT;
- wdc_atapi_reset(chp, xfer);
- return (1);
+ wdc_atapi_update_status(chp);
+
+ if (chp->ch_status & WDCS_BSY) {
+ if (timeout) {
+ printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",
+ chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
+ xfer->c_bcount, xfer->c_skip);
+
+ if (xfer->c_flags & C_DMA)
+ drvp->n_dmaerrs++;
+
+ sc_xfer->error = XS_TIMEOUT;
+ xfer->next = wdc_atapi_reset;
+ return (GOTO_NEXT);
+ } else {
+ return (CONTINUE_POLL);
+ }
}
- /* If we missed an IRQ and were using DMA, flag it as a DMA error */
- if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA))
- drvp->n_dmaerrs++;
- /* DRQ was dropped. This means the command is over.
- Do cleanup, check for errors, etc. */
- if (xfer->c_flags & C_DMA) {
- dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) ||
- (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0;
- dma_flags |= ((sc_xfer->flags & SCSI_POLL) ||
- (drvp->atapi_cap & ACAP_DSC)) ? WDC_DMA_POLL : 0;
+ if (as->protocol_phase != as_cmdout &&
+ (xfer->c_flags & C_MEDIA_ACCESS) &&
+ !(chp->ch_status & WDCS_DSC)) {
+ xfer->delay = 100;
+ return (CONTINUE_POLL);
}
+ xfer->claim_irq = 1;
+
+ if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA))
+ drvp->n_dmaerrs++;
+
if (chp->ch_status & WDCS_DRQ) {
if (as->protocol_phase == as_cmdout)
- return (wdc_atapi_intr_command(chp, xfer, dma_flags));
+ return (wdc_atapi_intr_command(chp, xfer, timeout));
+
+ if (!(xfer->c_flags & C_DMA))
+ return (wdc_atapi_intr_data(chp, xfer, timeout));
else
- return (wdc_atapi_intr_data(chp, xfer, dma_flags));
- } else
- return (wdc_atapi_intr_complete(chp, xfer, dma_flags));
+ return (CONTINUE_POLL);
+ }
+
+ return (wdc_atapi_intr_complete(chp, xfer, timeout));
}
int
-wdc_atapi_ctrl(chp, xfer, irq)
+wdc_atapi_ctrl(chp, xfer, timeout)
struct channel_softc *chp;
struct wdc_xfer *xfer;
- int irq;
+ int timeout;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
char *errstring = NULL;
- int delay;
/* Ack interrupt done in wait_for_unbusy */
-again:
- delay = (xfer->c_flags & C_POLL) ? 4000 : ((irq == 0) ? ATAPI_DELAY : 1);
+ CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4));
+ delay (1);
+
+ if (timeout) {
+ if (drvp->state == IDENTIFY_WAIT ||
+ drvp->state == PIOMODE ||
+ drvp->state == PIOMODE_WAIT ||
+ drvp->state == DMAMODE_WAIT)
+ goto timeout;
+ } else {
+ wdc_atapi_update_status(chp);
+
+ if (chp->ch_status & WDCS_BSY)
+ return (CONTINUE_POLL);
+ }
+
+ xfer->claim_irq = 1;
+
WDCDEBUG_PRINT(("wdc_atapi_ctrl %s:%d:%d state %d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, drvp->state),
DEBUG_INTR | DEBUG_FUNCS);
- /* We shouldn't have to select the drive in these states.
- If we do, there are other, more serious problems */
- if (drvp->state != IDENTIFY_WAIT &&
- drvp->state != PIOMODE_WAIT &&
- drvp->state != DMAMODE_WAIT)
- wdc_select_drive(chp, xfer->drive, delay);
-
/* Don't timeout during configuration */
xfer->c_flags &= ~C_TIMEOU;
@@ -1042,17 +1251,13 @@ again:
case IDENTIFY:
wdccommandshort(chp, drvp->drive, ATAPI_IDENTIFY_DEVICE);
drvp->state = IDENTIFY_WAIT;
+ xfer->timeout = ATAPI_CTRL_WAIT;
+ xfer->expect_irq = 1;
break;
case IDENTIFY_WAIT:
errstring = "IDENTIFY";
- /* Some ATAPI devices need to try to read the media
- before responding. Well, let's hope resets while
- polling are few and far between */
- if (wdcwait(chp, 0, 0, delay))
- goto timeout;
-
/* We don't really care if this operation failed.
It's just there to wake the drive from its stupor. */
if (!(chp->ch_status & WDCS_ERR)) {
@@ -1060,11 +1265,13 @@ again:
errstring = "Post IDENTIFY";
- if (wdcwait(chp, WDCS_DRQ, 0, 100))
- goto timeout;
+ xfer->timeout = 100;
+ drvp->state = PIOMODE;
+ break;
}
drvp->state = PIOMODE;
+
case PIOMODE:
piomode:
/* Don't try to set mode if controller can't be adjusted */
@@ -1076,11 +1283,11 @@ piomode:
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x08 | drvp->PIO_mode, WDSF_SET_MODE);
drvp->state = PIOMODE_WAIT;
+ xfer->timeout = ATAPI_CTRL_WAIT;
+ xfer->expect_irq = 1;
break;
case PIOMODE_WAIT:
errstring = "piomode";
- if (wait_for_unbusy(chp, delay))
- goto timeout;
if (chp->ch_status & WDCS_ERR) {
if (drvp->PIO_mode < 3) {
drvp->PIO_mode = 3;
@@ -1102,11 +1309,13 @@ piomode:
goto ready;
}
drvp->state = DMAMODE_WAIT;
+
+ xfer->timeout = ATAPI_CTRL_WAIT;
+ xfer->expect_irq = 1;
break;
+
case DMAMODE_WAIT:
errstring = "dmamode";
- if (wait_for_unbusy(chp, delay))
- goto timeout;
if (chp->ch_status & WDCS_ERR)
goto error;
/* fall through */
@@ -1114,29 +1323,18 @@ piomode:
case READY:
ready:
drvp->state = READY;
- xfer->c_intr = wdc_atapi_intr;
- wdc_atapi_start(chp, xfer);
- return (1);
- }
- if ((sc_xfer->flags & SCSI_POLL) == 0 &&
- (drvp->atapi_cap & ACAP_DSC) == 0) {
- chp->ch_flags |= WDCF_IRQ_WAIT;
- xfer->c_intr = wdc_atapi_ctrl;
- timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
- } else {
- goto again;
+ xfer->next = wdc_atapi_real_start;
+ break;
}
- return (1);
+ return (GOTO_NEXT);
timeout:
- if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
- return (0); /* IRQ was not for us */
- }
printf("%s:%d:%d: %s timed out\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
sc_xfer->error = XS_TIMEOUT;
- wdc_atapi_reset(chp, xfer);
- return (1);
+ xfer->next = wdc_atapi_reset;
+ return (GOTO_NEXT);
+
error:
printf("%s:%d:%d: %s ",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
@@ -1144,14 +1342,41 @@ error:
printf("error (0x%x)\n", chp->ch_error);
sc_xfer->error = XS_SHORTSENSE;
atapi_to_scsi_sense(sc_xfer, chp->ch_error);
- wdc_atapi_reset(chp, xfer);
- return (1);
+ xfer->next = wdc_atapi_reset;
+ return (GOTO_NEXT);
}
-void
-wdc_atapi_done(chp, xfer)
+int
+wdc_atapi_tape_done(chp, xfer, timeout)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ int timeout;
+{
+ struct scsi_xfer *sc_xfer = xfer->cmd;
+
+ if (sc_xfer->error != XS_NOERROR) {
+ xfer->next = wdc_atapi_done;
+ return (GOTO_NEXT);
+ }
+
+ _lto3b(xfer->transfer_len,
+ ((struct scsi_rw_tape *)
+ sc_xfer->cmd)->len);
+
+ xfer->c_bcount = sc_xfer->datalen;
+ xfer->c_done = NULL;
+ xfer->c_skip = 0;
+
+ xfer->next = wdc_atapi_real_start;
+ return (GOTO_NEXT);
+}
+
+
+int
+wdc_atapi_done(chp, xfer, timeout)
struct channel_softc *chp;
struct wdc_xfer *xfer;
+ int timeout;
{
struct scsi_xfer *sc_xfer = xfer->cmd;
int need_done = xfer->c_flags & C_NEEDDONE;
@@ -1161,8 +1386,7 @@ wdc_atapi_done(chp, xfer)
WDCDEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
(u_int)xfer->c_flags), DEBUG_XFERS);
- /* remove this command from xfer queue */
- wdc_free_xfer(chp, xfer);
+
sc_xfer->flags |= ITSDONE;
if (drvp->n_dmaerrs ||
(sc_xfer->error != XS_NOERROR && sc_xfer->error != XS_SENSE &&
@@ -1174,111 +1398,63 @@ wdc_atapi_done(chp, xfer)
if (doing_dma)
wdc_downgrade_mode(drvp);
}
-
+
if (need_done) {
WDCDEBUG_PRINT(("wdc_atapi_done: scsi_done\n"), DEBUG_XFERS);
scsi_done(sc_xfer);
}
- WDCDEBUG_PRINT(("wdcstart from wdc_atapi_done, flags 0x%x\n",
- chp->ch_flags), DEBUG_XFERS);
- wdcstart(chp);
-}
-
-/* Wait until DSC gets asserted. */
-int
-atapi_dsc_wait(drvp, timo)
- struct ata_drive_datas *drvp;
- int timo;
-{
- struct channel_softc *chp = drvp->chnl_softc;
- chp->ch_flags &= ~WDCF_ACTIVE;
-#if 0
- /* XXX Something like this may be needed I have not investigated
- close enough yet. If so we may need to put it back after
- the poll wait. */
- TAILQ_REMOVE(&chp->ch_queue->sc_xfer, xfer, c_xferchain);
-#endif
- return (atapi_poll_wait(atapi_dsc_ready, drvp, timo, PZERO + PCATCH,
- "atapidsc"));
+ return (DONE);
}
-int
-atapi_dsc_ready(arg)
- void *arg;
-{
- struct ata_drive_datas *drvp = arg;
- struct channel_softc *chp = drvp->chnl_softc;
-
- if (chp->ch_flags & WDCF_ACTIVE)
- return (0);
- wdc_select_drive(chp, drvp->drive, 0);
- chp->ch_status = CHP_READ_REG(chp, wdr_status);
- return ((chp->ch_status & (WDCS_BSY | WDCS_DSC)) == WDCS_DSC);
-}
int
-atapi_poll_wait(ready, arg, timo, pri, msg)
- int (*ready) __P((void *));
- void *arg;
- int timo;
- int pri;
- char *msg;
-{
- int maxtic, tic = 0, error;
- u_int64_t starttime = time.tv_sec * 1000 + time.tv_usec / 1000;
- u_int64_t endtime = starttime + timo;
-
- while (1) {
- WDCDEBUG_PRINT(("atapi_poll_wait: msg=%s tic=%d\n", msg, tic),
- DEBUG_POLL);
- if (ready(arg))
- return (0);
-
-#if 0
- /* Exponential backoff. */
- tic = tic + tic + 1;
-#else
- tic = min(hz / 100, 1);
-#endif
- maxtic = (int)
- (endtime - (time.tv_sec * 1000 + time.tv_usec / 1000));
- if (maxtic <= 0)
- return (EWOULDBLOCK);
- if (tic > maxtic)
- tic = maxtic;
- if (tic > ATAPI_POLL_MAXTIC)
- tic = ATAPI_POLL_MAXTIC;
- error = tsleep(arg, pri, msg, tic);
- if (error != EWOULDBLOCK)
- return (error);
- }
-}
-
-void
-wdc_atapi_reset(chp, xfer)
+wdc_atapi_reset(chp, xfer, timeout)
struct channel_softc *chp;
struct wdc_xfer *xfer;
+ int timeout;
{
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
- struct scsi_xfer *sc_xfer = xfer->cmd;
wdccommandshort(chp, xfer->drive, ATAPI_SOFT_RESET);
+ drvp->state = 0;
/* Some ATAPI devices need extra time to find their
brains after a reset
*/
- delay(5000);
+ xfer->next = wdc_atapi_reset_2;
+ xfer->delay = 10;
+ xfer->timeout = ATAPI_RESET_WAIT;
+ return (GOTO_NEXT);
+}
- drvp->state = 0;
- if (wdcwait(chp, WDCS_DRQ, 0, ATAPI_RESET_WAIT) != 0) {
+int
+wdc_atapi_reset_2(chp, xfer, timeout)
+ struct channel_softc *chp;
+ struct wdc_xfer *xfer;
+ int timeout;
+{
+ struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
+ struct scsi_xfer *sc_xfer = xfer->cmd;
+
+ if (timeout) {
printf("%s:%d:%d: reset failed\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive);
sc_xfer->error = XS_SELTIMEOUT;
wdc_reset_channel(drvp);
+
+ xfer->next = wdc_atapi_done;
+ return (GOTO_NEXT);
}
- wdc_atapi_done(chp, xfer);
- return;
+ wdc_atapi_update_status(chp);
+
+ if (chp->ch_status & (WDCS_BSY | WDCS_DRQ)) {
+ return (CONTINUE_POLL);
+ }
+
+ xfer->next = wdc_atapi_done;
+ return (GOTO_NEXT);
}
+
diff --git a/sys/dev/ic/wdcvar.h b/sys/dev/ic/wdcvar.h
index cfe869793ea..c0b18b6574b 100644
--- a/sys/dev/ic/wdcvar.h
+++ b/sys/dev/ic/wdcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdcvar.h,v 1.5 1999/11/17 01:22:56 csapuntz Exp $ */
+/* $OpenBSD: wdcvar.h,v 1.6 1999/12/11 10:15:03 csapuntz Exp $ */
/* $NetBSD: wdcvar.h,v 1.17 1999/04/11 20:50:29 bouyer Exp $ */
/*-
@@ -188,6 +188,8 @@ struct wdc_xfer {
#define C_POLL 0x0020 /* cmd is polled */
#define C_DMA 0x0040 /* cmd uses DMA */
#define C_SENSE 0x0080 /* cmd is a internal command */
+#define C_MEDIA_ACCESS 0x0100 /* is a media access command */
+#define C_POLL_MACHINE 0x0200 /* machine has a poll hander */
/* Informations about our location */
struct channel_softc *chp;
@@ -202,6 +204,19 @@ struct wdc_xfer {
LIST_ENTRY(wdc_xfer) free_list;
void (*c_start) __P((struct channel_softc *, struct wdc_xfer *));
int (*c_intr) __P((struct channel_softc *, struct wdc_xfer *, int));
+ int (*c_done) __P((struct channel_softc *, struct wdc_xfer *, int));
+
+ /* Used by ATAPISCSI */
+ int timeout;
+ u_int64_t endtime;
+ int delay;
+ unsigned int expect_irq:1;
+ unsigned int claim_irq:1;
+
+ int (*next) __P((struct channel_softc *, struct wdc_xfer *, int));
+
+ /* Used for tape devices */
+ int transfer_len;
};
/*