📄 adviopci.c
字号:
ADP->fr1 = fr;
ADP->sc1 = sc;
ADP->sn1 = sect;
ADP->cl1 = cyl & 0x00ff;
ADP->ch1 = ( cyl & 0xff00 ) >> 8;
ADP->dh1 = ADP->devBit | ( head & 0x0f );
// ADP->dc1 = 0x00; // nIEN=0 required for DMA, see sub_setup_command()
ADP->ns = numSect;
ADP->lbaSize = LBACHS;
// Execute the command.
return exec_pci_ata_cmd( seg, off, numSect );
}
//***********************************************************
//
// dma_pci_lba28() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************
int dma_pci_lba28( int cmd,
unsigned int fr, unsigned int sc,
unsigned long lba,
unsigned int seg, unsigned int off,
long numSect )
{
// Setup current command information.
sub_zero_return_data();
ADP->flg = TRC_FLAG_ATA;
ADP->ct = TRC_TYPE_ADMAI;
if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
ADP->ct = TRC_TYPE_ADMAO;
ADP->cmd = cmd;
ADP->fr1 = fr;
ADP->sc1 = sc;
ADP->dh1 = CB_DH_LBA | ADP->devBit;
// ADP->dc1 = 0x00; // nIEN=0 required for DMA, see sub_setup_command()
ADP->ns = numSect;
ADP->lbaSize = LBA28;
ADP->lbaHigh1 = 0L;
ADP->lbaLow1 = lba;
// Execute the command.
return exec_pci_ata_cmd( seg, off, numSect );
}
//***********************************************************
//
// dma_pci_lba48() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************
int dma_pci_lba48( int cmd,
unsigned int fr, unsigned int sc,
unsigned long lbahi, unsigned long lbalo,
unsigned int seg, unsigned int off,
long numSect )
{
// Setup current command information.
sub_zero_return_data();
ADP->flg = TRC_FLAG_ATA;
ADP->ct = TRC_TYPE_ADMAI;
if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
ADP->ct = TRC_TYPE_ADMAO;
ADP->cmd = cmd;
ADP->fr1 = fr;
ADP->sc1 = sc;
ADP->dh1 = CB_DH_LBA | ADP->devBit;
// ADP->dc1 = 0x00; // nIEN=0 required for DMA, see sub_setup_command()
ADP->ns = numSect;
ADP->lbaSize = LBA48;
ADP->lbaHigh1 = lbahi;
ADP->lbaLow1 = lbalo;
// Execute the command.
return exec_pci_ata_cmd( seg, off, numSect );
}
#if ADVIO_INCL_ATAPI_DMA
//***********************************************************
//
// dma_pci_packet() - PCI Bus Master for ATAPI Packet command
//
//***********************************************************
int dma_pci_packet( unsigned int cpbc,
unsigned int cpseg, unsigned int cpoff,
int dir,
long dpbc,
unsigned int dpseg, unsigned int dpoff,
unsigned long lba )
{
unsigned char status;
unsigned char reason;
unsigned char lowCyl;
unsigned char highCyl;
unsigned int cntr;
int ndx;
unsigned char far * cfp;
// mark start of a PI DMA cmd in low level trace
trc_llt( 0, 0, TRC_LLT_S_PID );
// Make sure the command packet size is either 12 or 16
// and save the command packet size and data.
cpbc = cpbc < 12 ? 12 : cpbc;
cpbc = cpbc > 12 ? 16 : cpbc;
// Setup current command information.
sub_zero_return_data();
ADP->flg = TRC_FLAG_ATAPI;
ADP->ct = dir ? TRC_TYPE_PDMAO : TRC_TYPE_PDMAI;
ADP->cmd = CMD_PACKET;
ADP->fr1 = ADP->reg_atapi_reg_fr | 0x01; // packet DMA mode !
ADP->sc1 = ADP->reg_atapi_reg_sc;
ADP->sn1 = ADP->reg_atapi_reg_sn;
ADP->cl1 = 0; // no Byte Count Limit in DMA !
ADP->ch1 = 0; // no Byte Count Limit in DMA !
ADP->dh1 = ADP->devBit;
// ADP->dc1 = 0x00; // nIEN=0 required for DMA, see sub_setup_command()
ADP->lbaSize = LBA32;
ADP->lbaLow1 = lba;
ADP->lbaHigh1 = 0L;
ADP->reg_atapi_cp_size = cpbc;
cfp = MK_FP( cpseg, cpoff );
for ( ndx = 0; ndx < cpbc; ndx ++ )
{
ADP->reg_atapi_cp_data[ndx] = * cfp;
cfp ++ ;
}
// Zero the alternate ATAPI register data.
ADP->reg_atapi_reg_fr = 0;
ADP->reg_atapi_reg_sc = 0;
ADP->reg_atapi_reg_sn = 0;
ADP->reg_atapi_reg_dh = 0;
// Quit now if no dma channel set up
if ( ! ADP->bmcrBase )
{
ADP->ec = 70;
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_PID );
return 1;
}
// the data packet byte count must be even
// and must not be zero
if ( dpbc & 1L )
dpbc ++ ;
if ( dpbc < 2L )
dpbc = 2L;
// Quit now if 1) I/O buffer overrun possible
// or 2) DMA can't handle the transfer size.
if ( ( dpbc > 262144L ) || ( dpbc > ADP->reg_buffer_size ) )
{
ADP->ec = 61;
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_PID );
return 1;
}
// set up the dma transfer(s)
set_up_xfer( dir, dpbc, dpseg, dpoff );
// Set command time out.
tmr_set_timeout();
// Select the drive - call the reg_select function.
// Quit now if this fails.
if ( sub_select() )
{
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_PID );
return 1;
}
// Set up all the registers except the command register.
sub_setup_command();
// Start the command by setting the Command register. The drive
// should immediately set BUSY status.
// Zero the interrupt flag.
int_on();
pio_outbyte( CB_CMD, CMD_PACKET );
// Waste some time by reading the alternate status a few times.
// This gives the drive time to set BUSY in the status register on
// really fast systems. If we don't do this, a slow drive on a fast
// system may not set BUSY fast enough and we would think it had
// completed the command when it really had not even started the
// command yet.
DELAY400NS;
// Command packet transfer...
// Check for protocol failures,
// the device should have BSY=1 or
// if BSY=0 then either DRQ=1 or CHK=1.
status = pio_inbyte( CB_ASTAT );
if ( status & CB_STAT_BSY )
{
// BSY=1 is OK
}
else
{
if ( status & ( CB_STAT_DRQ | CB_STAT_ERR ) )
{
// BSY=0 and DRQ=1 is OK
// BSY=0 and ERR=1 is OK
}
else
{
ADP->failbits |= FAILBIT0; // not OK
}
}
// Command packet transfer...
// Poll Alternate Status for BSY=0.
trc_llt( 0, 0, TRC_LLT_PNBSY );
while ( 1 )
{
status = pio_inbyte( CB_ASTAT ); // poll for not busy
if ( ( status & CB_STAT_BSY ) == 0 )
break;
if ( tmr_chk_timeout() ) // time out yet ?
{
trc_llt( 0, 0, TRC_LLT_TOUT ); // yes
ADP->to = 1;
ADP->ec = 75;
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
break;
}
}
// Command packet transfer...
// If no error, transfer the command packet.
if ( ADP->ec == 0 )
{
// Command packet transfer...
// Read the primary status register and the other ATAPI registers.
status = pio_inbyte( CB_STAT );
reason = pio_inbyte( CB_SC );
lowCyl = pio_inbyte( CB_CL );
highCyl = pio_inbyte( CB_CH );
// Command packet transfer...
// check status: must have BSY=0, DRQ=1 now
if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ | CB_STAT_ERR ) )
!= CB_STAT_DRQ
)
{
ADP->ec = 76;
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
}
else
{
// Command packet transfer...
// Check for protocol failures...
// check: C/nD=1, IO=0.
if ( ( reason & ( CB_SC_P_TAG | CB_SC_P_REL | CB_SC_P_IO ) )
|| ( ! ( reason & CB_SC_P_CD ) )
)
ADP->failbits |= FAILBIT2;
if ( ( lowCyl != ADP->cl1 )
|| ( highCyl != ADP->ch1 ) )
ADP->failbits |= FAILBIT3;
// Command packet transfer...
// trace cdb byte 0,
// xfer the command packet (the cdb)
trc_llt( 0, * (unsigned char far *) MK_FP( cpseg, cpoff ), TRC_LLT_P_CMD );
pio_drq_block_out( CB_DATA, cpseg, cpoff, cpbc >> 1 );
}
}
// The drive should start executing the command
// including any data transfer.
// Data transfer...
// The drive should start executing the command
// including any data transfer.
// If no error, set up and start the DMA,
// and wait for the DMA to complete.
if ( ADP->ec == 0 )
{
// Data transfer...
// read the BMIDE regs
// enable/start the dma channel.
// read the BMIDE regs again
sub_readBusMstrCmd();
sub_readBusMstrStatus();
sub_writeBusMstrCmd( ADP->rwControl | BM_CR_MASK_START );
sub_readBusMstrCmd();
sub_readBusMstrStatus();
// Data transfer...
// the device and dma channel transfer the data here while we start
// checking for command completion...
// wait for the PCI BM Active=0 and Interrupt=1 or PCI BM Error=1...
trc_llt( 0, 0, TRC_LLT_WINT );
cntr = 0;
while ( 1 )
{
cntr ++ ;
if ( ! ( cntr & 0x1fff ) )
{
sub_readBusMstrStatus(); // read BM status (for trace)
if ( ! ( ADP->incompat_flags & REG_INCOMPAT_DMA_POLL ) )
pio_inbyte( CB_ASTAT ); // poll Alt Status
}
if ( int_check() ) // interrupt yet?
{
trc_llt( 0, 0, TRC_LLT_INTRQ ); // yes
trc_llt( 0, ADP->bmStatus, TRC_LLT_R_BM_SR );
trc_llt( CB_STAT, ADP->ataStatus, TRC_LLT_INB );
trc_llt( 0, 0x04, TRC_LLT_W_BM_SR );
break;
}
if ( tmr_chk_timeout() ) // time out ?
{
trc_llt( 0, 0, TRC_LLT_TOUT ); // yes
ADP->to = 1;
ADP->ec = 73;
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
break;
}
#if ADVIO_INCL_MULTI_THREAD
// in a multi-thread application
// yield to other threads here,
// maybe one of them can do something
// on a different ATA channel?
ADVIO_CALL_YIELD; // BM DMA not done yet, yield
#endif
}
if ( ADP->incompat_flags & REG_INCOMPAT_DMA_DELAY )
delay( 1 ); // delay for buggy controllers
// End of command...
// disable/stop the dma channel
status = ADP->bmStatus; // read BM status
status &= ~ BM_SR_MASK_ACT; // ignore Active bit
sub_writeBusMstrCmd( BM_CR_MASK_STOP ); // shutdowm DMA
sub_readBusMstrCmd(); // read BM cmd (just for trace)
status |= sub_readBusMstrStatus(); // read BM status again
if ( ADP->incompat_flags & REG_INCOMPAT_DMA_DELAY )
delay( 1 ); // delay for buggy controllers
}
if ( ADP->ec == 0 )
{
if ( status & ( BM_SR_MASK_ERR ) ) // bus master error?
{
ADP->ec = 78; // yes
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
}
if ( status & BM_SR_MASK_ACT ) // end of PRD list?
{
ADP->ec = 71; // yes
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
}
}
#if DEBUG_PCI & 0x01
trc_llt( 0, int_check(), TRC_LLT_DEBUG ); // for debugging
#endif
// End of command...
// If no error use the Status register value that was read
// by the interrupt handler. If there was an error
// read the Status register because it may not have been
// read by the interrupt handler.
if ( ADP->ec )
status = pio_inbyte( CB_STAT );
else
status = ADP->ataStatus;
int_off();
// Final status check...
// if no error, check final status...
// Error if BUSY, DRQ or ERROR status now.
if ( ADP->ec == 0 )
{
if ( status & ( CB_STAT_BSY | CB_STAT_DRQ | CB_STAT_ERR ) )
{
ADP->ec = 74;
trc_llt( 0, ADP->ec, TRC_LLT_ERROR );
}
}
// Final status check...
// Check for protocol failures...
// check: C/nD=1, IO=1.
reason = pio_inbyte( CB_SC );
if ( ( reason & ( CB_SC_P_TAG | CB_SC_P_REL ) )
|| ( ! ( reason & CB_SC_P_IO ) )
|| ( ! ( reason & CB_SC_P_CD ) )
)
ADP->failbits |= FAILBIT8;
// Final status check...
// if any error, update total bytes transferred.
if ( ADP->ec == 0 )
ADP->totalBytesXfer = dpbc;
else
ADP->totalBytesXfer = 0L;
// Done...
// Read the output registers and trace the command.
sub_trace_command();
// Done...
// mark end of isa dma PI cmd in low level trace
trc_llt( 0, 0, TRC_LLT_E_PID );
// All done. The return values of this function are described in
// ADVIO.H.
if ( ADP->ec )
return 1;
return 0;
}
#endif
// end adviopci.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -