summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1999-07-22 03:10:48 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1999-07-22 03:10:48 +0000
commit08cef83f8688a6261687608372fc7e52698e475f (patch)
tree9fed62ff3f9a989c0834ca9b30a087f971efc32f
parentf237139cfc1d3ae4925187db3ef95410975c2718 (diff)
Use wdc_select_drive if we're starting in the IDLE bus state.
Modify the ATAPI reset state machine. Added two states, IDENTIFY and IDENTIFY_WAIT. These will revive ATAPI drives after a hard ATA reset. I don't think ATAPI devices have LUNs, so flag SDEV_NOLUNS as quirk of the SCSI adapter. The SCSI devices will "inherit" this setting from the parent. Correctly deal with 16-byte command packet devices (not that any exists, AFAIK). Optimization - don't poll devices that assert an interrupt on after sending PACKET cmd.
-rw-r--r--sys/dev/atapiscsi/atapiconf.h14
-rw-r--r--sys/dev/atapiscsi/atapiscsi.c114
2 files changed, 95 insertions, 33 deletions
diff --git a/sys/dev/atapiscsi/atapiconf.h b/sys/dev/atapiscsi/atapiconf.h
index 6a2995b7ed9..41d6bbc36e8 100644
--- a/sys/dev/atapiscsi/atapiconf.h
+++ b/sys/dev/atapiscsi/atapiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: atapiconf.h,v 1.1 1999/07/18 21:25:18 csapuntz Exp $ */
+/* $OpenBSD: atapiconf.h,v 1.2 1999/07/22 03:10:47 csapuntz Exp $ */
/* $NetBSD: atapiconf.h,v 1.7 1998/10/12 16:09:24 bouyer Exp $ */
/*
@@ -33,11 +33,13 @@
#include <scsi/scsiconf.h>
/* drive states stored in ata_drive_datas */
-#define PIOMODE 0
-#define PIOMODE_WAIT 1
-#define DMAMODE 2
-#define DMAMODE_WAIT 3
-#define READY 4
+#define IDENTIFY 0
+#define IDENTIFY_WAIT 1
+#define PIOMODE 2
+#define PIOMODE_WAIT 3
+#define DMAMODE 4
+#define DMAMODE_WAIT 5
+#define READY 6
struct atapi_mode_header;
struct ataparams;
diff --git a/sys/dev/atapiscsi/atapiscsi.c b/sys/dev/atapiscsi/atapiscsi.c
index ab34d658bb1..b9a6de0ac10 100644
--- a/sys/dev/atapiscsi/atapiscsi.c
+++ b/sys/dev/atapiscsi/atapiscsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atapiscsi.c,v 1.3 1999/07/20 06:21:58 csapuntz Exp $ */
+/* $OpenBSD: atapiscsi.c,v 1.4 1999/07/22 03:10:47 csapuntz Exp $ */
/*
* This code is derived from code with the copyright below.
@@ -119,11 +119,9 @@ struct atapiscsi_softc {
struct device sc_dev;
struct scsi_link sc_adapterlink;
struct wdc_softc *sc_wdc;
-
- u_int8_t sc_channel; /* Channel we represent */
- struct scsi_link sc_link[2];
+ u_int8_t sc_channel;
int valid[2];
- struct ata_drive_datas *sc_drvs; /* array supplied by adapter */
+ struct ata_drive_datas *sc_drvs;
};
static struct scsi_adapter atapiscsi_switch =
@@ -198,6 +196,7 @@ atapiscsi_attach(parent, self, aux)
as->sc_adapterlink.device = &atapiscsi_dev;
as->sc_adapterlink.openings = 1;
as->sc_adapterlink.flags = SDEV_ATAPI;
+ as->sc_adapterlink.quirks = SDEV_NOLUNS;
as->sc_wdc->channels[as->sc_channel]->ch_as = as;
for (drive = 0; drive < 2 ; drive++ ) {
@@ -211,13 +210,15 @@ atapiscsi_attach(parent, self, aux)
will be called atapibus by the IDE side of the
driver. */
drvp->drv_softc = (struct device *)as;
- wdc_probe_caps(drvp);
+ wdc_probe_caps(drvp);
+
+ if ((id->atap_config & ATAPI_CFG_CMD_MASK)
+ == ATAPI_CFG_CMD_16)
+ drvp->atapi_cap |= ACAP_LEN;
+
+ drvp->atapi_cap |= (id->atap_config & ATAPI_CFG_DRQ_MASK);
}
}
-
-#if 0
- config_found(self, &as->sc_adapterlink, scsiprint);
-#endif
}
@@ -387,7 +388,7 @@ wdc_atapi_start(chp, xfer)
xfer->c_flags &= ~C_DMA;
/* Do control operations specially. */
if (drvp->state < READY) {
- if (drvp->state != PIOMODE) {
+ if (drvp->state != IDENTIFY) {
printf("%s:%d:%d: bad state %d in wdc_atapi_start\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive, drvp->state);
@@ -396,9 +397,8 @@ wdc_atapi_start(chp, xfer)
wdc_atapi_ctrl(chp, xfer, 0);
return;
}
- bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
- WDSD_IBM | (xfer->drive << 4));
- if (wait_for_unbusy(chp, ATAPI_DELAY) < 0) {
+
+ if (wdc_select_drive(chp, xfer->drive, ATAPI_DELAY) < 0) {
printf("wdc_atapi_start: not ready, st = %02x\n",
chp->ch_status);
sc_xfer->error = XS_TIMEOUT;
@@ -419,20 +419,14 @@ wdc_atapi_start(chp, xfer)
sc_xfer->datalen <= 0xffff ? sc_xfer->datalen : 0xffff,
0, 0, 0,
(xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 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 (
-#ifndef __OpenBSD__
- (sc_xfer->sc_link->scsi_atapi.cap & ATAPI_CFG_DRQ_MASK) !=
- ATAPI_CFG_IRQ_DRQ || (sc_xfer->flags & SCSI_POLL)
-#else
- 1
-#endif
- ) {
+ if (((drvp->atapi_cap & ATAPI_CFG_DRQ_MASK) != ATAPI_CFG_IRQ_DRQ)
+ || (sc_xfer->flags & SCSI_POLL)) {
/* Wait for at last 400ns for status bit to be valid */
DELAY(1);
wdc_atapi_intr(chp, xfer, 0);
@@ -465,7 +459,7 @@ wdc_atapi_intr(chp, xfer, irq)
struct scsi_sense *cmd_reqsense =
(struct scsi_sense *)&_cmd_reqsense;
u_int32_t cmd[4];
- int cmdlen =12; /* XXX - Not true for all ATAPI devices */
+ int cmdlen = (drvp->atapi_cap & ACAP_LEN) ? 16 : 12;
memset (cmd, 0, sizeof(cmd));
@@ -479,9 +473,13 @@ wdc_atapi_intr(chp, xfer, irq)
drvp->state);
panic("wdc_atapi_intr: bad state\n");
}
- /* Ack interrupt done in wait_for_unbusy */
+
+ /* We should really wait_for_unbusy here too before
+ switching drives. */
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
+
+ /* 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)
@@ -547,6 +545,7 @@ again:
break;
}
}
+
/* send packet command */
/* Commands are 12 or 16 bytes long. It's 32-bit aligned */
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM)) {
@@ -658,6 +657,7 @@ again:
xfer->c_bcount -= len;
}
}
+
if ((sc_xfer->flags & SCSI_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
@@ -735,6 +735,7 @@ again:
xfer->c_bcount -=len;
}
}
+
if ((sc_xfer->flags & SCSI_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
@@ -857,9 +858,52 @@ again:
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);
- bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
- WDSD_IBM | (xfer->drive << 4));
+
+ /* 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);
+
switch (drvp->state) {
+ /* You need to send an ATAPI drive an ATAPI-specific
+ command to revive it after a hard reset. Identify
+ is about the most innocuous thing you can do
+ that's guaranteed to be there */
+ case IDENTIFY:
+ wdccommandshort(chp, drvp->drive, ATAPI_IDENTIFY_DEVICE);
+ drvp->state = IDENTIFY_WAIT;
+ break;
+
+ case IDENTIFY_WAIT:
+ errstring = "IDENTIFY";
+
+ if (wdcwait(chp, 0, 0, delay))
+ goto timeout;
+
+ if (chp->ch_status & WDCS_ERR) {
+ chp->ch_error = bus_space_read_1(chp->cmd_iot,
+ chp->cmd_ioh,
+ wd_error);
+ goto error;
+ }
+
+ if (wdcwait(chp, WDCS_DRQ, WDCS_DRQ, 1000))
+ goto timeout;
+
+ if (chp->ch_status & WDCS_ERR) {
+ chp->ch_error = bus_space_read_1(chp->cmd_iot,
+ chp->cmd_ioh,
+ wd_error);
+ goto error;
+ }
+
+ wdcbit_bucket(chp, 512);
+
+ drvp->state = PIOMODE;
+ break;
+
case PIOMODE:
piomode:
/* Don't try to set mode if controller can't be adjusted */
@@ -981,7 +1025,22 @@ wdc_atapi_reset(chp, xfer)
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
struct scsi_xfer *sc_xfer = xfer->cmd;
+ chp->ch_status = bus_space_read_1(chp->cmd_iot,
+ chp->cmd_ioh,
+ wd_status);
+
+ if (chp->ch_status & WDCS_DRQ) {
+ printf ("wdc_atapi_reset: DRQ is asserted. We've really messed up\n");
+ wdc_reset_channel(drvp);
+ }
+
wdccommandshort(chp, xfer->drive, ATAPI_SOFT_RESET);
+
+ /* Some ATAPI devices need extra time to find their
+ brains after a reset
+ */
+ delay(5000);
+
drvp->state = 0;
if (wait_for_unbusy(chp, WDC_RESET_WAIT) != 0) {
printf("%s:%d:%d: reset failed\n",
@@ -989,6 +1048,7 @@ wdc_atapi_reset(chp, xfer)
xfer->drive);
sc_xfer->error = XS_SELTIMEOUT;
}
+
wdc_atapi_done(chp, xfer);
return;
}