FreeBSD/sys/dev/ata/ata-lowlevel.c
/* must be called with ATA channel locked and state_mtx held */
must be called with ATA channel locked and state_mtx held
must be called with ATA channel locked and state_mtx held
int
ata_begin_transaction(struct ata_request *request)
{
    struct ata_channel *ch = device_get_softc(request->parent);
    int dummy, error;
    ATA_DEBUG_RQ(request, "begin transaction");
    if ((ch->flags & ATA_NO_ATAPI_DMA) &&
	(request->flags & ATA_R_ATAPI) == ATA_R_ATAPI)
	    request->flags &= ~ATA_R_DMA;
    if ((ch->flags & ATA_ATAPI_DMA_RO) &&
	((request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)) ==
	 (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)))
	request->flags &= ~ATA_R_DMA;
    switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) {
    default:
	{
	int write = (request->flags & ATA_R_WRITE);
	    if (ch->hw.command(request)) {
		device_printf(request->parent, "error issuing %s command\n",
			   ata_cmd2str(request));
		request->result = EIO;
		goto begin_finished;
	    }
	    if (request->u.ata.command == ATA_DEVICE_RESET) {
		int timeout = 1000000;
		do {
		    DELAY(10);
		    request->status = ATA_IDX_INB(ch, ATA_STATUS);
		} while (request->status & ATA_S_BUSY && timeout--);
		if (request->status & ATA_S_ERROR)
		    request->error = ATA_IDX_INB(ch, ATA_ERROR);
		ch->hw.tf_read(request);
		goto begin_finished;
	    }
	    if (write) {
		if (ata_wait(ch, request->unit, (ATA_S_READY | ATA_S_DRQ)) < 0) {
		    device_printf(request->parent,
				  "timeout waiting for write DRQ\n");
		    request->result = EIO;
		    goto begin_finished;
		}
		ata_pio_write(request, request->transfersize);
	    }
	}
	goto begin_continue;
    case ATA_R_DMA:
	if ((error = ch->dma.load(request, NULL, &dummy))) {
	    device_printf(request->parent, "setting up DMA failed\n");
	    request->result = error;
	    goto begin_finished;
	}
	if ((ch->flags & ATA_DMA_BEFORE_CMD) &&
	   ch->dma.start && ch->dma.start(request)) {
	    device_printf(request->parent, "error starting DMA\n");
	    request->result = EIO;
	    goto begin_finished;
	}
	if (ch->hw.command(request)) {
	    device_printf(request->parent, "error issuing %s command\n",
		       ata_cmd2str(request));
	    request->result = EIO;
	    goto begin_finished;
	}
	if (!(ch->flags & ATA_DMA_BEFORE_CMD) &&
	   ch->dma.start && ch->dma.start(request)) {
	    device_printf(request->parent, "error starting DMA\n");
	    request->result = EIO;
	    goto begin_finished;
	}
	goto begin_continue;
    case ATA_R_ATAPI:
	if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit));
	    DELAY(10);
	    if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC))
		request->result = EBUSY;
	    goto begin_finished;
	}
	if (ch->hw.command(request)) {
	    device_printf(request->parent, "error issuing ATA PACKET command\n");
	    request->result = EIO;
	    goto begin_finished;
	}
	goto begin_continue;
    case ATA_R_ATAPI|ATA_R_DMA:
	if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit));
	    DELAY(10);
	    if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC))
		request->result = EBUSY;
	    goto begin_finished;
	}
	if ((error = ch->dma.load(request, NULL, &dummy))) {
	    device_printf(request->parent, "setting up DMA failed\n");
	    request->result = error;
	    goto begin_finished;
	}
	if (ch->hw.command(request)) {
	    device_printf(request->parent, "error issuing ATA PACKET command\n");
	    request->result = EIO;
	    goto begin_finished;
	}
	if (ch->dma.start && ch->dma.start(request)) {
	    request->result = EIO;
	    goto begin_finished;
	}
	goto begin_continue;
    }
    printf("ata_begin_transaction OOPS!!!\n");
begin_finished:
    if (ch->dma.unload) {
        ch->dma.unload(request);
    }
    return ATA_OP_FINISHED;
begin_continue:
    callout_reset(&request->callout, request->timeout * hz,
		  (timeout_t*)ata_timeout, request);
    return ATA_OP_CONTINUES;
}
int ata_begin_transaction ( struct ata_request * request ) { struct ata_channel * ch = device_get_softc ( request -> parent ) ; int dummy , error ; ATA_DEBUG_RQ ( request , " " ) ; if ( ( ch -> flags & ATA_NO_ATAPI_DMA ) && ( request -> flags & ATA_R_ATAPI ) == ATA_R_ATAPI ) request -> flags &= ~ ATA_R_DMA ; if ( ( ch -> flags & ATA_ATAPI_DMA_RO ) && ( ( request -> flags & ( ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE ) ) == ( ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE ) ) ) request -> flags &= ~ ATA_R_DMA ; switch ( request -> flags & ( ATA_R_ATAPI | ATA_R_DMA ) ) { default : { int write = ( request -> flags & ATA_R_WRITE ) ; if ( ch -> hw . command ( request ) ) { device_printf ( request -> parent , " \n " , ata_cmd2str ( request ) ) ; request -> result = EIO ; goto begin_finished ; } if ( request -> u . ata . command == ATA_DEVICE_RESET ) { int timeout = 1000000 ; do { DELAY ( 10 ) ; request -> status = ATA_IDX_INB ( ch , ATA_STATUS ) ; } while ( request -> status & ATA_S_BUSY && timeout -- ) ; if ( request -> status & ATA_S_ERROR ) request -> error = ATA_IDX_INB ( ch , ATA_ERROR ) ; ch -> hw . tf_read ( request ) ; goto begin_finished ; } if ( write ) { if ( ata_wait ( ch , request -> unit , ( ATA_S_READY | ATA_S_DRQ ) ) < 0 ) { device_printf ( request -> parent , " \n " ) ; request -> result = EIO ; goto begin_finished ; } ata_pio_write ( request , request -> transfersize ) ; } } goto begin_continue ; case ATA_R_DMA : if ( ( error = ch -> dma . load ( request , NULL , & dummy ) ) ) { device_printf ( request -> parent , " \n " ) ; request -> result = error ; goto begin_finished ; } if ( ( ch -> flags & ATA_DMA_BEFORE_CMD ) && ch -> dma . start && ch -> dma . start ( request ) ) { device_printf ( request -> parent , " \n " ) ; request -> result = EIO ; goto begin_finished ; } if ( ch -> hw . command ( request ) ) { device_printf ( request -> parent , " \n " , ata_cmd2str ( request ) ) ; request -> result = EIO ; goto begin_finished ; } if ( ! ( ch -> flags & ATA_DMA_BEFORE_CMD ) && ch -> dma . start && ch -> dma . start ( request ) ) { device_printf ( request -> parent , " \n " ) ; request -> result = EIO ; goto begin_finished ; } goto begin_continue ; case ATA_R_ATAPI : if ( request -> u . atapi . ccb [ 0 ] == ATAPI_POLL_DSC ) { ATA_IDX_OUTB ( ch , ATA_DRIVE , ATA_D_IBM | ATA_DEV ( request -> unit ) ) ; DELAY ( 10 ) ; if ( ! ( ATA_IDX_INB ( ch , ATA_ALTSTAT ) & ATA_S_DSC ) ) request -> result = EBUSY ; goto begin_finished ; } if ( ch -> hw . command ( request ) ) { device_printf ( request -> parent , " \n " ) ; request -> result = EIO ; goto begin_finished ; } goto begin_continue ; case ATA_R_ATAPI | ATA_R_DMA : if ( request -> u . atapi . ccb [ 0 ] == ATAPI_POLL_DSC ) { ATA_IDX_OUTB ( ch , ATA_DRIVE , ATA_D_IBM | ATA_DEV ( request -> unit ) ) ; DELAY ( 10 ) ; if ( ! ( ATA_IDX_INB ( ch , ATA_ALTSTAT ) & ATA_S_DSC ) ) request -> result = EBUSY ; goto begin_finished ; } if ( ( error = ch -> dma . load ( request , NULL , & dummy ) ) ) { device_printf ( request -> parent , " \n " ) ; request -> result = error ; goto begin_finished ; } if ( ch -> hw . command ( request ) ) { device_printf ( request -> parent , " \n " ) ; request -> result = EIO ; goto begin_finished ; } if ( ch -> dma . start && ch -> dma . start ( request ) ) { request -> result = EIO ; goto begin_finished ; } goto begin_continue ; } printf ( " \n " ) ; begin_finished : if ( ch -> dma . unload ) { ch -> dma . unload ( request ) ; } return ATA_OP_FINISHED ; begin_continue : callout_reset ( & request -> callout , request -> timeout * hz , ( timeout_t * ) ata_timeout , request ) ; return ATA_OP_CONTINUES ; }
must be called with ATA channel locked and state_mtx held
must be called with ATA channel locked and state_mtx held
/* disable ATAPI DMA writes if HW doesn't support it */ /* ATA PIO data transfer and control commands */ /* record command direction here as our request might be gone later */ /* issue command */ /* device reset doesn't interrupt */ /* if write command output the data */ /* ATA DMA data transfer commands */ /* check sanity, setup SG list and DMA engine */ /* start DMA engine if necessary */ /* issue command */ /* start DMA engine */ /* ATAPI PIO commands */ /* is this just a POLL DSC command ? */ /* start ATAPI operation */ /* ATAPI DMA commands */ /* is this just a POLL DSC command ? */ /* check sanity, setup SG list and DMA engine */ /* start ATAPI operation */ /* start DMA engine */ /* NOT REACHED */