/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Finite State Machines for ATA controller and ATAPI devices */ #include #include "ata_common.h" #include "atapi.h" /* * Local functions */ static int atapi_start_cmd(ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp); static void atapi_send_cdb(ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp); static void atapi_start_dma(ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp); static void atapi_pio_data_in(ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp); static void atapi_pio_data_out(ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp); static void atapi_status(ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp, uchar_t status, int dma_complete); static void atapi_fsm_error(ata_ctl_t *ata_ctlp, uchar_t state, uchar_t event); static void atapi_fsm_error( ata_ctl_t *ata_ctlp, uchar_t state, uchar_t event) { ADBG_ERROR(("atapi protocol error: 0x%p 0x%x 0x%x\n", (void *)ata_ctlp->ac_data, state, event)); } /* * * IO CoD DRQ * -- --- --- * 0 0 0 == 0 invalid * 0 0 1 == 1 Data to device * 0 1 0 == 2 Idle * 0 1 1 == 3 Send ATAPI CDB to device * 1 0 0 == 4 invalid * 1 0 1 == 5 Data from device * 1 1 0 == 6 Status ready * 1 1 1 == 7 Future use * */ /* * Given the current state and the current event this * table determines what action to take. Note, in the actual * table I've left room for the invalid event codes: 0, 2, and 7. * * +----------------------------------------------------- * | Current Event * | * State | dataout idle cdb datain status * | 1 2 3 5 6 * |----------------------------------------------------- * idle | sendcmd sendcmd sendcmd sendcmd sendcmd * cmd | * * sendcdb * read-err-code * cdb | xfer-out nada nada xfer-in read-err-code * datain | * * * xfer-in read-err-code * dataout | xfer-out * * * read-err-code * DMA | * * * * read-err-code * */ uchar_t atapi_PioAction[ATAPI_NSTATES][ATAPI_NEVENTS] = { /* invalid dataout idle cdb invalid datain status future */ { A_NADA, A_NADA, A_NADA, A_NADA, A_NADA, A_NADA, A_NADA, A_NADA }, /* Idle */ { A_NADA, A_NADA, A_NADA, A_CDB, A_NADA, A_NADA, A_RE, A_NADA }, /* Cmd */ { A_REX, A_OUT, A_NADA, A_NADA, A_IDLE, A_IN, A_RE, A_UNK }, /* Cdb */ { A_REX, A_UNK, A_IDLE, A_UNK, A_IDLE, A_IN, A_RE, A_UNK }, /* DtaIn */ { A_REX, A_OUT, A_IDLE, A_UNK, A_IDLE, A_UNK, A_RE, A_UNK }, /* DtaOut */ { A_REX, A_UNK, A_UNK, A_UNK, A_UNK, A_UNK, A_RE, A_UNK } /* DmaAct */ }; /* * * Give the current state and the current event this table * determines the new state of the device. * * +---------------------------------------------- * | Current Event * | * State | dataout idle cdb datain status * |---------------------------------------------- * idle | cmd cmd cmd cmd cmd * cmd | * * cdb * * * cdb | dataout cdb cdb datain (idle) * datain | * * * datain (idle) * dataout | dataout * * * (idle) * DMA | DMA DMA DMA DMA (idle) * * * Note: the states enclosed in parens "(state)", are the accept states * for this FSM. A separate table is used to encode the done * states rather than extra state codes. * */ uchar_t atapi_PioNextState[ATAPI_NSTATES][ATAPI_NEVENTS] = { /* invalid dataout idle cdb invalid datain status future */ { S_IDLE, S_IDLE, S_IDLE, S_IDLE, S_IDLE, S_IDLE, S_IDLE, S_IDLE}, /* idle */ { S_CDB, S_CDB, S_CDB, S_CDB, S_CDB, S_CDB, S_IDLE, S_X }, /* cmd */ { S_IDLE, S_OUT, S_CDB, S_CDB, S_CDB, S_IN, S_IDLE, S_X }, /* cdb */ { S_IDLE, S_X, S_IN, S_X, S_IN, S_IN, S_IDLE, S_X }, /* datain */ { S_IDLE, S_OUT, S_OUT, S_X, S_OUT, S_X, S_IDLE, S_X }, /* dataout */ { S_IDLE, S_DMA, S_DMA, S_DMA, S_DMA, S_DMA, S_IDLE, S_DMA } /* dmaActv */ }; static int atapi_start_cmd( ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp) { ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; ddi_acc_handle_t io_hdl2 = ata_ctlp->ac_iohandle2; /* * Bug 1256489: * * If AC_BSY_WAIT is set, wait for controller to be not busy, * before issuing a command. If AC_BSY_WAIT is not set, * skip the wait. This is important for laptops that do * suspend/resume but do not correctly wait for the busy bit to * drop after a resume. */ if (ata_ctlp->ac_timing_flags & AC_BSY_WAIT) { if (!ata_wait(io_hdl2, ata_ctlp->ac_ioaddr2, 0, ATS_BSY, 5000000)) { ADBG_WARN(("atapi_start: BSY too long!\n")); ata_pktp->ap_flags |= AP_ERROR; return (ATA_FSM_RC_BUSY); } } /* * Select the drive */ ddi_put8(io_hdl1, ata_ctlp->ac_drvhd, ata_pktp->ap_hd); ata_nsecwait(400); /* * make certain the drive selected */ if (!ata_wait(io_hdl2, ata_ctlp->ac_ioaddr2, 0, ATS_BSY, 5000000)) { ADBG_ERROR(("atapi_start_cmd: drive select failed\n")); return (ATA_FSM_RC_BUSY); } /* * Always make certain interrupts are enabled. It's been reported * (but not confirmed) that some notebook computers don't * clear the interrupt disable bit after being resumed. The * easiest way to fix this is to always clear the disable bit * before every command. */ ddi_put8(io_hdl2, ata_ctlp->ac_devctl, ATDC_D3); ddi_put8(io_hdl1, ata_ctlp->ac_lcyl, ata_pktp->ap_lwcyl); ddi_put8(io_hdl1, ata_ctlp->ac_hcyl, ata_pktp->ap_hicyl); ddi_put8(io_hdl1, ata_ctlp->ac_sect, ata_pktp->ap_sec); ddi_put8(io_hdl1, ata_ctlp->ac_count, ata_pktp->ap_count); if (ata_pktp->ap_pciide_dma) { ASSERT((ata_pktp->ap_flags & (AP_READ | AP_WRITE)) != 0); /* * DMA but no Overlap */ ddi_put8(io_hdl1, ata_ctlp->ac_feature, ATF_ATAPI_DMA); /* * copy the Scatter/Gather list to the controller's * Physical Region Descriptor Table */ ata_pciide_dma_setup(ata_ctlp, ata_pktp->ap_sg_list, ata_pktp->ap_sg_cnt); } else { /* * no DMA and no Overlap */ ddi_put8(io_hdl1, ata_ctlp->ac_feature, 0); } /* * This next one sets the device in motion */ ddi_put8(io_hdl1, ata_ctlp->ac_cmd, ata_pktp->ap_cmd); /* wait for the busy bit to settle */ ata_nsecwait(400); if (!(ata_drvp->ad_flags & AD_NO_CDB_INTR)) { /* * the device will send me an interrupt when it's * ready for the packet */ return (ATA_FSM_RC_OKAY); } /* else */ /* * If we don't receive an interrupt requesting the scsi CDB, * we must poll for DRQ, and then send out the CDB. */ /* * Wait for DRQ before sending the CDB. Bailout early * if an error occurs. * * I'm not certain what the correct timeout should be. */ if (ata_wait3(io_hdl2, ata_ctlp->ac_ioaddr2, ATS_DRQ, ATS_BSY, /* okay */ ATS_ERR, ATS_BSY, /* cmd failed */ ATS_DF, ATS_BSY, /* cmd failed */ 4000000)) { /* got good status */ return (ATA_FSM_RC_INTR); } ADBG_WARN(("atapi_start_cmd: 0x%x status 0x%x error 0x%x\n", ata_pktp->ap_cmd, ddi_get8(io_hdl2, ata_ctlp->ac_altstatus), ddi_get8(io_hdl1, ata_ctlp->ac_error))); return (ATA_FSM_RC_INTR); } /* * * Send the SCSI CDB to the ATAPI device * */ static void atapi_send_cdb( ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp) { ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; int padding; ADBG_TRACE(("atapi_send_cdb entered\n")); /* * send the CDB to the drive */ ddi_rep_put16(io_hdl1, (ushort_t *)ata_pktp->ap_cdbp, ata_ctlp->ac_data, ata_pktp->ap_cdb_len >> 1, DDI_DEV_NO_AUTOINCR); /* * pad to ad_cdb_len bytes */ padding = ata_pktp->ap_cdb_pad; while (padding) { ddi_put16(io_hdl1, ata_ctlp->ac_data, 0); padding--; } /* wait for the busy bit to settle */ ata_nsecwait(400); #ifdef ATA_DEBUG_XXX { uchar_t *cp = ata_pktp->ap_cdbp; ADBG_TRANSPORT(("\tatapi scsi cmd (%d bytes):\n ", ata_pktp->ap_cdb_len)); ADBG_TRANSPORT(("\t\t 0x%x 0x%x 0x%x 0x%x\n", cp[0], cp[1], cp[2], cp[3])); ADBG_TRANSPORT(("\t\t 0x%x 0x%x 0x%x 0x%x\n", cp[4], cp[5], cp[6], cp[7])); ADBG_TRANSPORT(("\t\t 0x%x 0x%x 0x%x 0x%x\n", cp[8], cp[9], cp[10], cp[11])); } #endif ata_pktp->ap_flags |= AP_SENT_CMD; } /* * Start the DMA engine */ /* ARGSUSED */ static void atapi_start_dma( ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp) { uchar_t rd_wr; /* * Determine the direction. This may look backwards * but the command bit programmed into the DMA engine * specifies the type of operation the engine performs * on the PCI bus (not the ATA bus). Therefore when * transferring data from the device to system memory, the * DMA engine performs PCI Write operations. */ if (ata_pktp->ap_flags & AP_READ) rd_wr = PCIIDE_BMICX_RWCON_WRITE_TO_MEMORY; else rd_wr = PCIIDE_BMICX_RWCON_READ_FROM_MEMORY; /* * Start the DMA engine */ ata_pciide_dma_start(ata_ctlp, rd_wr); } /* * Transfer the data from the device * * Note: the atapi_pio_data_in() and atapi_pio_data_out() functions * are complicated a lot by the requirement to handle an odd byte count. * The only device we've seen which does this is the Hitachi CDR-7730. * See bug ID 1214595. It's my understanding that Dell stopped shipping * that drive after discovering all the problems it caused, so it may * be impossible to find one for any sort of regression test. * * In the future, ATAPI tape drives will also probably support odd byte * counts so this code will be excersized more often. * */ static void atapi_pio_data_in( ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp) { ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; int drive_bytes; int xfer_bytes; int xfer_words; ata_pktp->ap_flags |= AP_XFERRED_DATA; /* * Get the device's byte count for this transfer */ drive_bytes = ((int)ddi_get8(io_hdl1, ata_ctlp->ac_hcyl) << 8) + ddi_get8(io_hdl1, ata_ctlp->ac_lcyl); /* * Determine actual number I'm going to transfer. My * buffer might have fewer bytes than what the device * expects or handles on each interrupt. */ xfer_bytes = min(ata_pktp->ap_resid, drive_bytes); ASSERT(xfer_bytes >= 0); /* * Round down my transfer count to whole words so that * if the transfer count is odd it's still handled correctly. */ xfer_words = xfer_bytes / 2; if (xfer_words) { int byte_count = xfer_words * 2; ddi_rep_get16(io_hdl1, (ushort_t *)ata_pktp->ap_v_addr, ata_ctlp->ac_data, xfer_words, DDI_DEV_NO_AUTOINCR); ata_pktp->ap_v_addr += byte_count; drive_bytes -= byte_count; } /* * Handle possible odd byte at end. Read a 16-bit * word but discard the high-order byte. */ if (xfer_bytes & 1) { ushort_t tmp_word; tmp_word = ddi_get16(io_hdl1, ata_ctlp->ac_data); *ata_pktp->ap_v_addr++ = tmp_word & 0xff; drive_bytes -= 2; } ata_pktp->ap_resid -= xfer_bytes; ADBG_TRANSPORT(("atapi_pio_data_in: read 0x%x bytes\n", xfer_bytes)); /* * Discard any unwanted data. */ if (drive_bytes > 0) { ADBG_TRANSPORT(("atapi_pio_data_in: dump 0x%x bytes\n", drive_bytes)); /* rounded up if the drive_bytes count is odd */ for (; drive_bytes > 0; drive_bytes -= 2) (void) ddi_get16(io_hdl1, ata_ctlp->ac_data); } /* wait for the busy bit to settle */ ata_nsecwait(400); } /* * Transfer the data to the device */ static void atapi_pio_data_out( ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp) { ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; int drive_bytes; int xfer_bytes; int xfer_words; ata_pktp->ap_flags |= AP_XFERRED_DATA; /* * Get the device's byte count for this transfer */ drive_bytes = ((int)ddi_get8(io_hdl1, ata_ctlp->ac_hcyl) << 8) + ddi_get8(io_hdl1, ata_ctlp->ac_lcyl); /* * Determine actual number I'm going to transfer. My * buffer might have fewer bytes than what the device * expects or handles on each interrupt. */ xfer_bytes = min(ata_pktp->ap_resid, drive_bytes); /* * Round down my transfer count to whole words so that * if the transfer count is odd it's handled correctly. */ xfer_words = xfer_bytes / 2; if (xfer_words) { int byte_count = xfer_words * 2; ddi_rep_put16(io_hdl1, (ushort_t *)ata_pktp->ap_v_addr, ata_ctlp->ac_data, xfer_words, DDI_DEV_NO_AUTOINCR); ata_pktp->ap_v_addr += byte_count; } /* * If odd byte count, transfer the last * byte. Use a tmp so that I don't run off * the end off the buffer and possibly page * fault. */ if (xfer_bytes & 1) { ushort_t tmp_word; /* grab the last unsigned byte and widen it to 16-bits */ tmp_word = *ata_pktp->ap_v_addr++; ddi_put16(io_hdl1, ata_ctlp->ac_data, tmp_word); } ata_pktp->ap_resid -= xfer_bytes; ADBG_TRANSPORT(("atapi_pio_data_out: wrote 0x%x bytes\n", xfer_bytes)); /* wait for the busy bit to settle */ ata_nsecwait(400); } /* * * check status of completed command * */ static void atapi_status( ata_ctl_t *ata_ctlp, ata_pkt_t *ata_pktp, uchar_t status, int dma_completion) { ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; ata_pktp->ap_flags |= AP_GOT_STATUS; if (status & (ATS_DF | ATS_ERR)) { ata_pktp->ap_flags |= AP_ERROR; } if (ata_pktp->ap_flags & AP_ERROR) { ata_pktp->ap_status = status; ata_pktp->ap_error = ddi_get8(io_hdl1, ata_ctlp->ac_error); } /* * If the DMA transfer failed leave the resid set to * the original byte count. The target driver has * to do a REQUEST SENSE to get the true residual * byte count. Otherwise, it all transferred so update * the flags and residual byte count. */ if (dma_completion && !(ata_pktp->ap_flags & AP_TRAN_ERROR)) { ata_pktp->ap_flags |= AP_XFERRED_DATA; ata_pktp->ap_resid = 0; } } static void atapi_device_reset( ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp) { ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; ddi_acc_handle_t io_hdl2 = ata_ctlp->ac_iohandle2; /* select the drive */ ddi_put8(io_hdl1, ata_ctlp->ac_drvhd, ata_drvp->ad_drive_bits); ata_nsecwait(400); /* issue atapi DEVICE RESET */ ddi_put8(io_hdl1, ata_ctlp->ac_cmd, ATC_DEVICE_RESET); /* wait for the busy bit to settle */ ata_nsecwait(400); /* * Re-select the drive (this is probably only necessary * when resetting drive 1). */ ddi_put8(io_hdl1, ata_ctlp->ac_drvhd, ata_drvp->ad_drive_bits); ata_nsecwait(400); /* allow the drive the full 6 seconds to respond */ /* LINTED */ if (!ata_wait(io_hdl2, ata_ctlp->ac_ioaddr2, 0, ATS_BSY, 6 * 1000000)) { ADBG_WARN(("atapi_device_reset: still busy\n")); /* * It's not clear to me what to do at this point, * the drive might be dead or might eventually * recover. For now just ignore it and continue * to attempt to use the drive. */ } } void atapi_fsm_reset(ata_ctl_t *ata_ctlp) { ata_drv_t *ata_drvp; int drive; /* * reset drive drive 0 and the drive 1 */ for (drive = 0; drive <= 1; drive++) { ata_drvp = CTL2DRV(ata_ctlp, drive, 0); if (ata_drvp && ATAPIDRV(ata_drvp)) { ata_drvp->ad_state = S_IDLE; atapi_device_reset(ata_ctlp, ata_drvp); } } } int atapi_fsm_start( ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp) { int rc; ADBG_TRACE(("atapi_start entered\n")); ADBG_TRANSPORT(("atapi_start: pkt = 0x%p\n", ata_pktp)); /* * check for valid state */ if (ata_drvp->ad_state != S_IDLE) { ADBG_ERROR(("atapi_fsm_start not idle 0x%x\n", ata_drvp->ad_state)); return (ATA_FSM_RC_BUSY); } else { ata_drvp->ad_state = S_CMD; } rc = atapi_start_cmd(ata_ctlp, ata_drvp, ata_pktp); switch (rc) { case ATA_FSM_RC_OKAY: /* * The command started okay. Just return. */ break; case ATA_FSM_RC_INTR: /* * Got Command Phase. The upper layer will send * the cdb by faking an interrupt. */ break; case ATA_FSM_RC_FINI: /* * command completed immediately, stick on done q */ break; case ATA_FSM_RC_BUSY: /* * The command wouldn't start, tell the upper layer to * stick this request on the done queue. */ ata_drvp->ad_state = S_IDLE; return (ATA_FSM_RC_BUSY); } return (rc); } /* * * All interrupts on an ATAPI device come through here. * This function determines what to do next, based on * the current state of the request and the drive's current * status bits. See the FSM tables at the top of this file. * */ int atapi_fsm_intr( ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp) { ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; uchar_t status; uchar_t intr_reason; uchar_t state; uchar_t event; uchar_t action; /* * get the prior state */ state = ata_drvp->ad_state; /* * If doing DMA, then: * * 1. halt the DMA engine * 2. reset the interrupt and error latches * 3. reset the drive's IRQ. * * I think the order of these operations must be * exactly as listed. Otherwise we the PCI-IDE * controller can hang or we can miss the next interrupt * edge. * */ switch (state) { case S_DMA: ASSERT(ata_pktp->ap_pciide_dma == TRUE); /* * Halt the DMA engine. When we reach this point * we already know for certain that the device has * an interrupt pending since the ata_get_status() * function already checked the PCI-IDE interrupt * status bit. */ ata_pciide_dma_stop(ata_ctlp); /*FALLTHRU*/ case S_IDLE: case S_CMD: case S_CDB: case S_IN: case S_OUT: break; } /* * Clear the PCI-IDE latches and the drive's IRQ */ status = ata_get_status_clear_intr(ata_ctlp, ata_pktp); /* * some non-compliant (i.e., NEC) drives don't * set ATS_BSY within 400 nsec. and/or don't keep * it asserted until they're actually non-busy. * There's a small window between reading the alt_status * and status registers where the drive might "bounce" * the ATS_BSY bit. */ if (status & ATS_BSY) return (ATA_FSM_RC_BUSY); /* * get the interrupt reason code */ intr_reason = ddi_get8(io_hdl1, ata_ctlp->ac_count); /* * encode the status and interrupt reason bits * into an event code which is used to index the * FSM tables */ event = ATAPI_EVENT(status, intr_reason); /* * determine the action for this event */ action = atapi_PioAction[state][event]; /* * determine the new state */ ata_drvp->ad_state = atapi_PioNextState[state][event]; switch (action) { default: case A_UNK: /* * invalid state */ /* * ??? this shouldn't happen. ??? * if there's an active command on * this device, the pkt timer should eventually clear the * device. I might try sending a DEVICE-RESET here to speed * up the error recovery except that DEVICE-RESET is kind of * complicated to implement correctly because if I send a * DEVICE-RESET to drive 1 it deselects itself. */ ADBG_WARN(("atapi_fsm_intr: Unsupported intr\n")); break; case A_NADA: drv_usecwait(100); break; case A_CDB: /* * send out atapi pkt */ atapi_send_cdb(ata_ctlp, ata_pktp); /* * start the DMA engine if necessary and change * the state variable to reflect not doing PIO */ if (ata_pktp->ap_pciide_dma) { atapi_start_dma(ata_ctlp, ata_drvp, ata_pktp); ata_drvp->ad_state = S_DMA; } break; case A_IN: if (!(ata_pktp->ap_flags & AP_READ)) { /* * maybe this was a spurious interrupt, just * spin for a bit and see if the drive * recovers */ atapi_fsm_error(ata_ctlp, state, event); drv_usecwait(100); break; } /* * read in the data */ if (!ata_pktp->ap_pciide_dma) { atapi_pio_data_in(ata_ctlp, ata_pktp); } break; case A_OUT: if (!(ata_pktp->ap_flags & AP_WRITE)) { /* spin for a bit and see if the drive recovers */ atapi_fsm_error(ata_ctlp, state, event); drv_usecwait(100); break; } /* * send out data */ if (!ata_pktp->ap_pciide_dma) { atapi_pio_data_out(ata_ctlp, ata_pktp); } break; case A_IDLE: /* * The DRQ bit deasserted before or between the data * transfer phases. */ if (!ata_drvp->ad_bogus_drq) { ata_drvp->ad_bogus_drq = TRUE; atapi_fsm_error(ata_ctlp, state, event); } drv_usecwait(100); break; case A_RE: /* * If we get here, a command has completed! * * check status of completed command */ atapi_status(ata_ctlp, ata_pktp, status, (state == S_DMA) ? TRUE : FALSE); return (ATA_FSM_RC_FINI); case A_REX: /* * some NEC drives don't report the right interrupt * reason code for the status phase */ if (!ata_drvp->ad_nec_bad_status) { ata_drvp->ad_nec_bad_status = TRUE; atapi_fsm_error(ata_ctlp, state, event); drv_usecwait(100); } atapi_status(ata_ctlp, ata_pktp, status, (state == S_DMA) ? TRUE : FALSE); return (ATA_FSM_RC_FINI); } return (ATA_FSM_RC_OKAY); }