version 1.20, 1999/04/01 21:46:30 |
version 1.20.2.6, 2000/07/07 17:33:51 |
Line 234 wdc_atapi_start(chp, xfer) |
|
Line 234 wdc_atapi_start(chp, xfer) |
|
sc_xfer->flags), DEBUG_XFERS); |
sc_xfer->flags), DEBUG_XFERS); |
/* Adjust C_DMA, it may have changed if we are requesting sense */ |
/* Adjust C_DMA, it may have changed if we are requesting sense */ |
if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) && |
if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) && |
(sc_xfer->datalen > 0 || (xfer->c_flags & C_SENSE))) |
(sc_xfer->datalen > 0 || (xfer->c_flags & C_SENSE))) { |
|
if (drvp->n_xfers <= NXFER) |
|
drvp->n_xfers++; |
xfer->c_flags |= C_DMA; |
xfer->c_flags |= C_DMA; |
else |
} else { |
xfer->c_flags &= ~C_DMA; |
xfer->c_flags &= ~C_DMA; |
|
} |
|
/* start timeout machinery */ |
|
if ((sc_xfer->flags & SCSI_POLL) == 0) |
|
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); |
/* Do control operations specially. */ |
/* Do control operations specially. */ |
if (drvp->state < READY) { |
if (drvp->state < READY) { |
if (drvp->state != PIOMODE) { |
if (drvp->state != RESET) { |
printf("%s:%d:%d: bad state %d in wdc_atapi_start\n", |
printf("%s:%d:%d: bad state %d in wdc_atapi_start\n", |
chp->wdc->sc_dev.dv_xname, chp->channel, |
chp->wdc->sc_dev.dv_xname, chp->channel, |
xfer->drive, drvp->state); |
xfer->drive, drvp->state); |
panic("wdc_atapi_start: bad state"); |
panic("wdc_atapi_start: bad state"); |
} |
} |
|
drvp->state = PIOMODE; |
wdc_atapi_ctrl(chp, xfer, 0); |
wdc_atapi_ctrl(chp, xfer, 0); |
return; |
return; |
} |
} |
Line 278 wdc_atapi_start(chp, xfer) |
|
Line 285 wdc_atapi_start(chp, xfer) |
|
* the interrupt routine. If it is a polled command, call the interrupt |
* the interrupt routine. If it is a polled command, call the interrupt |
* routine until command is done. |
* routine until command is done. |
*/ |
*/ |
if ((sc_xfer->sc_link->scsipi_atapi.cap & 0x0300) != ACAP_DRQ_INTR || |
if ((sc_xfer->sc_link->scsipi_atapi.cap & ATAPI_CFG_DRQ_MASK) != |
sc_xfer->flags & SCSI_POLL) { |
ATAPI_CFG_IRQ_DRQ || (sc_xfer->flags & SCSI_POLL)) { |
/* Wait for at last 400ns for status bit to be valid */ |
/* Wait for at last 400ns for status bit to be valid */ |
DELAY(1); |
DELAY(1); |
wdc_atapi_intr(chp, xfer, 0); |
wdc_atapi_intr(chp, xfer, 0); |
|
} else { |
|
chp->ch_flags |= WDCF_IRQ_WAIT; |
} |
} |
if (sc_xfer->flags & SCSI_POLL) { |
if (sc_xfer->flags & SCSI_POLL) { |
while ((sc_xfer->flags & ITSDONE) == 0) { |
while ((sc_xfer->flags & ITSDONE) == 0) { |
/* Wait for at last 400ns for status bit to be valid */ |
/* Wait for at last 400ns for status bit to be valid */ |
DELAY(1); |
DELAY(1); |
|
if (chp->ch_flags & WDCF_DMA_WAIT) { |
|
wdc_dmawait(chp, xfer, sc_xfer->timeout); |
|
chp->ch_flags &= ~WDCF_DMA_WAIT; |
|
} |
wdc_atapi_intr(chp, xfer, 0); |
wdc_atapi_intr(chp, xfer, 0); |
} |
} |
} |
} |
Line 302 wdc_atapi_intr(chp, xfer, irq) |
|
Line 315 wdc_atapi_intr(chp, xfer, irq) |
|
struct scsipi_xfer *sc_xfer = xfer->cmd; |
struct scsipi_xfer *sc_xfer = xfer->cmd; |
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; |
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; |
int len, phase, i, retries=0; |
int len, phase, i, retries=0; |
int ire, dma_err = 0; |
int ire; |
int dma_flags = 0; |
int dma_flags = 0; |
struct scsipi_generic _cmd_reqsense; |
struct scsipi_generic _cmd_reqsense; |
struct scsipi_sense *cmd_reqsense = |
struct scsipi_sense *cmd_reqsense = |
Line 319 wdc_atapi_intr(chp, xfer, irq) |
|
Line 332 wdc_atapi_intr(chp, xfer, irq) |
|
drvp->state); |
drvp->state); |
panic("wdc_atapi_intr: bad state\n"); |
panic("wdc_atapi_intr: bad state\n"); |
} |
} |
|
/* |
|
* 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) { |
|
sc_xfer->error = XS_TIMEOUT; |
|
wdc_atapi_reset(chp, xfer); |
|
return 1; |
|
} |
|
|
/* Ack interrupt done in wait_for_unbusy */ |
/* Ack interrupt done in wait_for_unbusy */ |
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, |
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, |
WDSD_IBM | (xfer->drive << 4)); |
WDSD_IBM | (xfer->drive << 4)); |
Line 330 wdc_atapi_intr(chp, xfer, irq) |
|
Line 353 wdc_atapi_intr(chp, xfer, irq) |
|
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
xfer->c_bcount, xfer->c_skip); |
xfer->c_bcount, xfer->c_skip); |
if (xfer->c_flags & C_DMA) |
if (xfer->c_flags & C_DMA) |
drvp->n_dmaerrs++; |
ata_dmaerr(drvp); |
sc_xfer->error = XS_TIMEOUT; |
sc_xfer->error = XS_TIMEOUT; |
wdc_atapi_reset(chp, xfer); |
wdc_atapi_reset(chp, xfer); |
return 1; |
return 1; |
} |
} |
|
if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) |
|
chp->wdc->irqack(chp); |
|
|
/* If we missed an IRQ and were using DMA, flag it as a DMA error */ |
/* 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)) |
if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) |
drvp->n_dmaerrs++; |
ata_dmaerr(drvp); |
/* |
/* |
* if the request sense command was aborted, report the short sense |
* if the request sense command was aborted, report the short sense |
* previously recorded, else continue normal processing |
* previously recorded, else continue normal processing |
Line 356 wdc_atapi_intr(chp, xfer, irq) |
|
Line 382 wdc_atapi_intr(chp, xfer, irq) |
|
if (xfer->c_flags & C_DMA) { |
if (xfer->c_flags & C_DMA) { |
dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) || |
dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) || |
(xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0; |
(xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0; |
dma_flags |= sc_xfer->flags & SCSI_POLL ? WDC_DMA_POLL : 0; |
|
} |
} |
again: |
again: |
len = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo) + |
len = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo) + |
|
|
/* Start the DMA channel if necessary */ |
/* Start the DMA channel if necessary */ |
if (xfer->c_flags & C_DMA) { |
if (xfer->c_flags & C_DMA) { |
(*chp->wdc->dma_start)(chp->wdc->dma_arg, |
(*chp->wdc->dma_start)(chp->wdc->dma_arg, |
chp->channel, xfer->drive, dma_flags); |
chp->channel, xfer->drive); |
|
chp->ch_flags |= WDCF_DMA_WAIT; |
} |
} |
|
|
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
chp->ch_flags |= WDCF_IRQ_WAIT; |
chp->ch_flags |= WDCF_IRQ_WAIT; |
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); |
|
} |
} |
return 1; |
return 1; |
|
|
|
|
(xfer->c_flags & C_DMA) != 0) { |
(xfer->c_flags & C_DMA) != 0) { |
printf("wdc_atapi_intr: bad data phase DATAOUT\n"); |
printf("wdc_atapi_intr: bad data phase DATAOUT\n"); |
if (xfer->c_flags & C_DMA) { |
if (xfer->c_flags & C_DMA) { |
(*chp->wdc->dma_finish)(chp->wdc->dma_arg, |
ata_dmaerr(drvp); |
chp->channel, xfer->drive, dma_flags); |
|
drvp->n_dmaerrs++; |
|
} |
} |
sc_xfer->error = XS_TIMEOUT; |
sc_xfer->error = XS_TIMEOUT; |
wdc_atapi_reset(chp, xfer); |
wdc_atapi_reset(chp, xfer); |
|
|
} |
} |
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
chp->ch_flags |= WDCF_IRQ_WAIT; |
chp->ch_flags |= WDCF_IRQ_WAIT; |
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); |
|
} |
} |
return 1; |
return 1; |
|
|
|
|
(xfer->c_flags & C_DMA) != 0) { |
(xfer->c_flags & C_DMA) != 0) { |
printf("wdc_atapi_intr: bad data phase DATAIN\n"); |
printf("wdc_atapi_intr: bad data phase DATAIN\n"); |
if (xfer->c_flags & C_DMA) { |
if (xfer->c_flags & C_DMA) { |
(*chp->wdc->dma_finish)(chp->wdc->dma_arg, |
ata_dmaerr(drvp); |
chp->channel, xfer->drive, dma_flags); |
|
drvp->n_dmaerrs++; |
|
} |
} |
sc_xfer->error = XS_TIMEOUT; |
sc_xfer->error = XS_TIMEOUT; |
wdc_atapi_reset(chp, xfer); |
wdc_atapi_reset(chp, xfer); |
|
|
} |
} |
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
chp->ch_flags |= WDCF_IRQ_WAIT; |
chp->ch_flags |= WDCF_IRQ_WAIT; |
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); |
|
} |
} |
return 1; |
return 1; |
|
|
|
|
WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR); |
WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR); |
/* turn off DMA channel */ |
/* turn off DMA channel */ |
if (xfer->c_flags & C_DMA) { |
if (xfer->c_flags & C_DMA) { |
dma_err = (*chp->wdc->dma_finish)(chp->wdc->dma_arg, |
|
chp->channel, xfer->drive, dma_flags); |
|
if (xfer->c_flags & C_SENSE) |
if (xfer->c_flags & C_SENSE) |
xfer->c_bcount -= |
xfer->c_bcount -= |
sizeof(sc_xfer->sense.scsi_sense); |
sizeof(sc_xfer->sense.scsi_sense); |
|
|
xfer->c_bcount -= sc_xfer->datalen; |
xfer->c_bcount -= sc_xfer->datalen; |
} |
} |
if (xfer->c_flags & C_SENSE) { |
if (xfer->c_flags & C_SENSE) { |
if ((chp->ch_status & WDCS_ERR) || dma_err < 0) { |
if ((chp->ch_status & WDCS_ERR) || |
|
(chp->wdc->dma_status & |
|
(WDC_DMAST_NOIRQ | WDC_DMAST_ERR))) { |
/* |
/* |
* request sense failed ! it's not suppossed |
* request sense failed ! it's not suppossed |
* to be possible |
* to be possible |
*/ |
*/ |
if (dma_err < 0) |
if (xfer->c_flags & C_DMA) |
drvp->n_dmaerrs++; |
ata_dmaerr(drvp); |
sc_xfer->error = XS_RESET; |
sc_xfer->error = XS_RESET; |
wdc_atapi_reset(chp, xfer); |
wdc_atapi_reset(chp, xfer); |
return (1); |
return (1); |
|
|
sc_xfer->error = XS_SHORTSENSE; |
sc_xfer->error = XS_SHORTSENSE; |
} |
} |
} else { |
} else { |
|
sc_xfer->resid = xfer->c_bcount; |
if (chp->ch_status & WDCS_ERR) { |
if (chp->ch_status & WDCS_ERR) { |
/* save the short sense */ |
/* save the short sense */ |
sc_xfer->error = XS_SHORTSENSE; |
sc_xfer->error = XS_SHORTSENSE; |
|
|
xfer->databuf = &sc_xfer->sense; |
xfer->databuf = &sc_xfer->sense; |
xfer->c_bcount = |
xfer->c_bcount = |
sizeof(sc_xfer->sense.scsi_sense); |
sizeof(sc_xfer->sense.scsi_sense); |
|
xfer->c_skip = 0; |
xfer->c_flags |= C_SENSE; |
xfer->c_flags |= C_SENSE; |
|
untimeout(wdctimeout, chp); |
wdc_atapi_start(chp, xfer); |
wdc_atapi_start(chp, xfer); |
return 1; |
return 1; |
} |
} |
} else if (dma_err < 0) { |
} else if (chp->wdc->dma_status & |
drvp->n_dmaerrs++; |
(WDC_DMAST_NOIRQ | WDC_DMAST_ERR)) { |
|
ata_dmaerr(drvp); |
sc_xfer->error = XS_RESET; |
sc_xfer->error = XS_RESET; |
wdc_atapi_reset(chp, xfer); |
wdc_atapi_reset(chp, xfer); |
return (1); |
return (1); |
|
|
sc_xfer->error = XS_SHORTSENSE; |
sc_xfer->error = XS_SHORTSENSE; |
sc_xfer->sense.atapi_sense = chp->ch_error; |
sc_xfer->sense.atapi_sense = chp->ch_error; |
} else { |
} else { |
|
if (xfer->c_flags & C_DMA) |
|
ata_dmaerr(drvp); |
sc_xfer->error = XS_RESET; |
sc_xfer->error = XS_RESET; |
wdc_atapi_reset(chp, xfer); |
wdc_atapi_reset(chp, xfer); |
return (1); |
return (1); |
|
|
WDSD_IBM | (xfer->drive << 4)); |
WDSD_IBM | (xfer->drive << 4)); |
switch (drvp->state) { |
switch (drvp->state) { |
case PIOMODE: |
case PIOMODE: |
|
piomode: |
/* Don't try to set mode if controller can't be adjusted */ |
/* Don't try to set mode if controller can't be adjusted */ |
if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0) |
if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0) |
goto ready; |
goto ready; |
|
|
errstring = "piomode"; |
errstring = "piomode"; |
if (wait_for_unbusy(chp, delay)) |
if (wait_for_unbusy(chp, delay)) |
goto timeout; |
goto timeout; |
if (chp->ch_status & WDCS_ERR) |
if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) |
goto error; |
chp->wdc->irqack(chp); |
|
if (chp->ch_status & WDCS_ERR) { |
|
if (drvp->PIO_mode < 3) { |
|
drvp->PIO_mode = 3; |
|
goto piomode; |
|
} else { |
|
goto error; |
|
} |
|
} |
/* fall through */ |
/* fall through */ |
|
|
case DMAMODE: |
case DMAMODE: |
|
|
errstring = "dmamode"; |
errstring = "dmamode"; |
if (wait_for_unbusy(chp, delay)) |
if (wait_for_unbusy(chp, delay)) |
goto timeout; |
goto timeout; |
|
if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) |
|
chp->wdc->irqack(chp); |
if (chp->ch_status & WDCS_ERR) |
if (chp->ch_status & WDCS_ERR) |
goto error; |
goto error; |
/* fall through */ |
/* fall through */ |
|
|
ready: |
ready: |
drvp->state = READY; |
drvp->state = READY; |
xfer->c_intr = wdc_atapi_intr; |
xfer->c_intr = wdc_atapi_intr; |
|
untimeout(wdctimeout, chp); |
wdc_atapi_start(chp, xfer); |
wdc_atapi_start(chp, xfer); |
return 1; |
return 1; |
} |
} |
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
if ((sc_xfer->flags & SCSI_POLL) == 0) { |
chp->ch_flags |= WDCF_IRQ_WAIT; |
chp->ch_flags |= WDCF_IRQ_WAIT; |
xfer->c_intr = wdc_atapi_ctrl; |
xfer->c_intr = wdc_atapi_ctrl; |
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); |
|
} else { |
} else { |
goto again; |
goto again; |
} |
} |
Line 779 wdc_atapi_done(chp, xfer) |
|
Line 815 wdc_atapi_done(chp, xfer) |
|
struct wdc_xfer *xfer; |
struct wdc_xfer *xfer; |
{ |
{ |
struct scsipi_xfer *sc_xfer = xfer->cmd; |
struct scsipi_xfer *sc_xfer = xfer->cmd; |
int need_done = xfer->c_flags & C_NEEDDONE; |
|
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; |
|
|
|
WDCDEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x\n", |
WDCDEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x\n", |
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, |
(u_int)xfer->c_flags), DEBUG_XFERS); |
(u_int)xfer->c_flags), DEBUG_XFERS); |
sc_xfer->resid = xfer->c_bcount; |
untimeout(wdctimeout, chp); |
/* remove this command from xfer queue */ |
/* remove this command from xfer queue */ |
xfer->c_skip = 0; |
|
wdc_free_xfer(chp, xfer); |
wdc_free_xfer(chp, xfer); |
sc_xfer->flags |= ITSDONE; |
sc_xfer->flags |= ITSDONE; |
if (drvp->n_dmaerrs || |
|
(sc_xfer->error != XS_NOERROR && sc_xfer->error != XS_SENSE && |
|
sc_xfer->error != XS_SHORTSENSE)) { |
|
drvp->n_dmaerrs = 0; |
|
wdc_downgrade_mode(drvp); |
|
} |
|
|
|
if (need_done) { |
WDCDEBUG_PRINT(("wdc_atapi_done: scsipi_done\n"), DEBUG_XFERS); |
WDCDEBUG_PRINT(("wdc_atapi_done: scsipi_done\n"), DEBUG_XFERS); |
scsipi_done(sc_xfer); |
scsipi_done(sc_xfer); |
|
} |
|
WDCDEBUG_PRINT(("wdcstart from wdc_atapi_done, flags 0x%x\n", |
WDCDEBUG_PRINT(("wdcstart from wdc_atapi_done, flags 0x%x\n", |
chp->ch_flags), DEBUG_XFERS); |
chp->ch_flags), DEBUG_XFERS); |
wdcstart(chp); |
wdcstart(chp); |