/* $NetBSD: atapi_wdc.c,v 1.141 2021/10/05 08:01:05 rin Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
if (bp->b_bcount > MAX_SIZE)
bp->b_bcount = MAX_SIZE;
minphys(bp);
}
/*
* Kill off all pending xfers for a periph.
*
* Must be called with adapter lock held
*/
static void
wdc_atapi_kill_pending(struct scsipi_periph *periph)
{
struct atac_softc *atac =
device_private(periph->periph_channel->chan_adapter->adapt_dev);
struct ata_channel *chp =
atac->atac_channels[periph->periph_channel->chan_channel];
/* Some ATAPI devices need a bit more time after software reset. */
delay(5000);
if (ata_get_params(&chp->ch_drive[drive], AT_WAIT, id) != 0) {
ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE "
"failed for drive %s:%d:%d\n",
device_xname(atac->atac_dev), chp->ch_channel, drive),
DEBUG_PROBE);
rv = -1;
goto out;
}
rv = 0;
out:
return rv;
/* skip if already attached */
if (scsipi_lookup_periph(chan, target, 0) != NULL)
return;
/* if no ATAPI device detected at wdc attach time, skip */
if (drvp->drive_type != ATA_DRIVET_ATAPI) {
ATADEBUG_PRINT(("wdc_atapi_probe_device: "
"drive %d not present\n", target), DEBUG_PROBE);
return;
}
if (sc_xfer->xs_control & XS_CTL_POLL)
xfer->c_flags |= C_POLL;
#if NATA_DMA
if ((atac->atac_channels[channel]->ch_drive[drive].drive_flags &
(ATA_DRIVE_DMA | ATA_DRIVE_UDMA)) && sc_xfer->datalen > 0)
xfer->c_flags |= C_DMA;
#endif
#if NATA_DMA && NATA_PIOBM
else
#endif
#if NATA_PIOBM
if ((atac->atac_cap & ATAC_CAP_PIOBM) &&
sc_xfer->datalen > 0)
xfer->c_flags |= C_PIOBM;
#endif
xfer->c_drive = drive;
xfer->c_flags |= C_ATAPI;
#if NATA_DMA
if (sc_xfer->cmd->opcode == GPCMD_REPORT_KEY ||
sc_xfer->cmd->opcode == GPCMD_SEND_KEY ||
sc_xfer->cmd->opcode == GPCMD_READ_DVD_STRUCTURE) {
/*
* DVD authentication commands must always be done in
* PIO mode.
*/
xfer->c_flags &= ~C_DMA;
}
/*
* DMA normally can't deal with transfers which are not a
* multiple of its databus width. It's a bug to request odd
* length transfers for ATAPI.
*
* Some devices also can't cope with unaligned DMA xfers
* either. Also some devices seem to not handle DMA xfers of
* less than 4 bytes.
*
* By enforcing at least 4 byte aligned offset and length for
* DMA, we might use PIO where DMA could be allowed but better
* safe than sorry as recent problems proved.
*
* Offending structures that are thus done by PIO instead of
* DMA are normally small structures since all bulkdata is
* aligned. But as the request may come from userland, we have
* to protect against it anyway.
*
* XXX check for the 32 bit wide flag?
*/
#if NATA_DMA
if ((xfer->c_flags & C_DMA) && (drvp->n_xfers <= NXFER))
drvp->n_xfers++;
#endif
/* Do control operations specially. */
if (__predict_false(drvp->state < READY)) {
/* If it's not a polled command, we need the kernel thread */
if ((sc_xfer->xs_control & XS_CTL_POLL) == 0
&& !ata_is_thread_run(chp))
return ATASTART_TH;
/*
* disable interrupts, all commands here should be quick
* enough to be able to poll, and we don't go here that often
*/
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
WDCTL_4BIT | WDCTL_IDS);
if (wdc->select)
wdc->select(chp, xfer->c_drive);
bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0,
WDSD_IBM | (xfer->c_drive << 4));
/* Don't try to set mode if controller can't be adjusted */
if (atac->atac_set_modes == NULL)
goto ready;
/* Also don't try if the drive didn't report its mode */
if ((drvp->drive_flags & ATA_DRIVE_MODE) == 0)
goto ready;
errstring = "unbusy";
if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd))
goto timeout;
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x08 | drvp->PIO_mode, WDSF_SET_MODE);
errstring = "piomode";
if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags,
&tfd))
goto timeout;
if (ATACH_ST(tfd) & WDCS_ERR) {
if (ATACH_ST(tfd) == WDCE_ABRT) {
/*
* Some ATAPI drives reject PIO settings.
* Fall back to PIO mode 3 since that's the
* minimum for ATAPI.
*/
printf("%s:%d:%d: PIO mode %d rejected, "
"falling back to PIO mode 3\n",
device_xname(atac->atac_dev),
chp->ch_channel, xfer->c_drive,
drvp->PIO_mode);
if (drvp->PIO_mode > 3)
drvp->PIO_mode = 3;
} else
goto error;
}
#if NATA_DMA
#if NATA_UDMA
if (drvp->drive_flags & ATA_DRIVE_UDMA) {
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
} else
#endif
if (drvp->drive_flags & ATA_DRIVE_DMA) {
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x20 | drvp->DMA_mode, WDSF_SET_MODE);
} else {
goto ready;
}
errstring = "dmamode";
if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags,
&tfd))
goto timeout;
if (ATACH_ST(tfd) & WDCS_ERR) {
if (ATACH_ERR(tfd) == WDCE_ABRT) {
#if NATA_UDMA
if (drvp->drive_flags & ATA_DRIVE_UDMA)
goto error;
else
#endif
{
/*
* The drive rejected our DMA setting.
* Fall back to mode 1.
*/
printf("%s:%d:%d: DMA mode %d rejected, "
"falling back to DMA mode 0\n",
device_xname(atac->atac_dev),
chp->ch_channel, xfer->c_drive,
drvp->DMA_mode);
if (drvp->DMA_mode > 0)
drvp->DMA_mode = 0;
}
} else
goto error;
}
#endif /* NATA_DMA */
ready:
drvp->state = READY;
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
WDCTL_4BIT);
delay(10); /* some drives need a little delay here */
}
/* start timeout machinery */
if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)
callout_reset(&chp->c_timo_callout, mstohz(sc_xfer->timeout),
wdctimeout, chp);
if (wdc->select)
wdc->select(chp, xfer->c_drive);
bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0,
WDSD_IBM | (xfer->c_drive << 4));
switch (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd)) {
case WDCWAIT_OK:
break;
case WDCWAIT_TOUT:
printf("wdc_atapi_start: not ready, st = %02x\n",
ATACH_ST(tfd));
sc_xfer->error = XS_TIMEOUT;
return ATASTART_ABORT;
case WDCWAIT_THR:
return ATASTART_TH;
}
/*
* Even with WDCS_ERR, the device should accept a command packet
* Limit length to what can be stuffed into the cylinder register
* (16 bits). Some CD-ROMs seem to interpret '0' as 65536,
* but not all devices do that and it's not obvious from the
* ATAPI spec that that behaviour should be expected. If more
* data is necessary, multiple data transfer phases will be done.
*/
#if NATA_PIOBM
if (xfer->c_flags & C_PIOBM) {
int error;
int dma_flags = (sc_xfer->xs_control & XS_CTL_DATA_IN)
? WDC_DMA_READ : 0;
if (xfer->c_flags & C_POLL) {
/* XXX not supported yet --- fall back to PIO */
xfer->c_flags &= ~C_PIOBM;
} else {
/* Init the DMA channel. */
error = (*wdc->dma_init)(wdc->dma_arg,
chp->ch_channel, xfer->c_drive,
(char *)xfer->c_databuf,
xfer->c_bcount,
dma_flags | WDC_DMA_PIOBM_ATAPI);
if (error) {
if (error == EINVAL) {
/*
* We can't do DMA on this transfer
* for some reason. Fall back to
* PIO.
*/
xfer->c_flags &= ~C_PIOBM;
error = 0;
} else {
sc_xfer->error = XS_DRIVER_STUFFUP;
errstring = "piobm";
goto error;
}
}
}
}
#endif
/*
* If there is no interrupt for CMD input, busy-wait for it (done in
* the interrupt routine. Poll routine will exit early in this case.
*/
if ((sc_xfer->xs_periph->periph_cap & ATAPI_CFG_DRQ_MASK) !=
ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL))
return ATASTART_POLL;
else {
chp->ch_flags |= ATACH_IRQ_WAIT;
return ATASTART_STARTED;
}
timeout:
printf("%s:%d:%d: %s timed out\n",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
errstring);
sc_xfer->error = XS_TIMEOUT;
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
delay(10); /* some drives need a little delay here */
return ATASTART_ABORT;
error:
printf("%s:%d:%d: %s ",
device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
errstring);
printf("error (0x%x)\n", ATACH_ERR(tfd));
sc_xfer->error = XS_SHORTSENSE;
sc_xfer->sense.atapi_sense = ATACH_ERR(tfd);
bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
delay(10); /* some drives need a little delay here */
return ATASTART_ABORT;
}
static int
wdc_atapi_poll(struct ata_channel *chp, struct ata_xfer *xfer)
{
/*
* 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.
*/
const bool poll = ((xfer->c_scsipi->xs_control & XS_CTL_POLL) != 0);
/* Wait for at last 400ns for status bit to be valid */
DELAY(1);
wdc_atapi_intr(chp, xfer, 0);
if (!poll)
return ATAPOLL_DONE;
#if NATA_DMA
if (chp->ch_flags & ATACH_DMA_WAIT) {
wdc_dmawait(chp, xfer, xfer->c_scsipi->timeout);
chp->ch_flags &= ~ATACH_DMA_WAIT;
}
#endif
while ((xfer->c_scsipi->xs_status & XS_STS_DONE) == 0) {
/* Wait for at last 400ns for status bit to be valid */
DELAY(1);
wdc_atapi_intr(chp, xfer, 0);
}
return ATAPOLL_DONE;
}
static int
wdc_atapi_intr(struct ata_channel *chp, struct ata_xfer *xfer, int irq)
{
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 scsipi_xfer *sc_xfer = xfer->c_scsipi;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
int len, phase, i, retries=0;
int ire, tfd;
#if NATA_DMA
int error;
#endif
#if NATA_DMA || NATA_PIOBM
int dma_flags = 0;
#endif
void *cmd;
/* 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",
device_xname(atac->atac_dev), chp->ch_channel,
xfer->c_drive, drvp->state);
panic("wdc_atapi_intr: bad state");
}
/*
* If we missed an interrupt in a PIO transfer, reset and restart.
* Don't try to continue transfer, we may have missed cycles.
*/
if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) {
ata_channel_unlock(chp);
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_reset(chp, xfer);
return 1;
}
#if NATA_PIOBM
/* Transfer-done interrupt for busmastering PIO operation */
if ((xfer->c_flags & C_PIOBM) && (chp->ch_flags & ATACH_PIOBM_WAIT)) {
chp->ch_flags &= ~ATACH_PIOBM_WAIT;
/* restore transfer length */
len = xfer->c_bcount;
if (xfer->c_atapi.c_lenoff < 0)
len += xfer->c_atapi.c_lenoff;
/* Ack interrupt done in wdc_wait_for_unbusy */
if (wdc->select)
wdc->select(chp, xfer->c_drive);
bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0,
WDSD_IBM | (xfer->c_drive << 4));
if (wdc_wait_for_unbusy(chp,
(irq == 0) ? sc_xfer->timeout : 0, AT_POLL, &tfd) == WDCWAIT_TOUT) {
if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
ata_channel_unlock(chp);
return 0; /* IRQ was not for us */
}
printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",
device_xname(atac->atac_dev), chp->ch_channel,
xfer->c_drive, xfer->c_bcount, xfer->c_skip);
#if NATA_DMA
if (xfer->c_flags & C_DMA) {
ata_dmaerr(drvp,
(xfer->c_flags & C_POLL) ? AT_POLL : 0);
}
#endif
sc_xfer->error = XS_TIMEOUT;
ata_channel_unlock(chp);
wdc_atapi_reset(chp, xfer);
return 1;
}
if (wdc->irqack)
wdc->irqack(chp);
#if NATA_DMA
/*
* If we missed an IRQ and were using DMA, flag it as a DMA error
* and reset device.
*/
if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) {
ata_dmaerr(drvp, (xfer->c_flags & C_POLL) ? AT_POLL : 0);
sc_xfer->error = XS_RESET;
ata_channel_unlock(chp);
wdc_atapi_reset(chp, xfer);
return (1);
}
#endif
/*
* if the request sense command was aborted, report the short sense
* previously recorded, else continue normal processing
*/
switch (phase) {
case PHASE_CMDOUT:
cmd = sc_xfer->cmd;
ATADEBUG_PRINT(("PHASE_CMDOUT\n"), DEBUG_INTR);
#if NATA_DMA
/* Init the DMA channel if necessary */
if (xfer->c_flags & C_DMA) {
error = (*wdc->dma_init)(wdc->dma_arg,
chp->ch_channel, xfer->c_drive,
xfer->c_databuf, xfer->c_bcount, dma_flags);
if (error) {
if (error == EINVAL) {
/*
* We can't do DMA on this transfer
* for some reason. Fall back to
* PIO.
*/
xfer->c_flags &= ~C_DMA;
error = 0;
} else {
sc_xfer->error = XS_DRIVER_STUFFUP;
break;
}
}
}
#endif
#if NATA_PIOBM
end_piobm_dataout:
#endif
for (i = xfer->c_atapi.c_lenoff; i > 0; i -= 2)
bus_space_write_2(wdr->cmd_iot,
wdr->cmd_iohs[wd_data], 0, 0);