📄 ataiopci.c
字号:
bufStart = bufStart << 4;
bufStart = bufStart + (unsigned long) off;
bufStart = bufStart & 0xfffffffeL;
// move up to dword boundary
bufStart = ( bufStart + 15L ) & 0xfffffff0;
// compute end
bufEnd = bufStart + bufSize;
// compute start/end of 64K area (pma)
// that will be the I/O buffer
pmaStart = ( bufStart + 0x00010000L ) & 0xffff0000;
pmaEnd = pmaStart + 0x00010000L;
// if pma is in buffer then...
if ( ( pmaStart < bufEnd ) && ( pmaEnd <= bufEnd ) )
{
// ...find location for PRD list
if ( ( pmaStart - bufStart ) >= 4096L )
{
// PRD buffer first (I/O buffer second)
dma_pci_largePrdBufPtr = MK_FP( (unsigned int) ( bufStart >> 4 ), 0 );
}
else
if ( ( bufEnd - pmaEnd ) >= 4096L )
{
// PRD buffer second (I/O buffer first)
dma_pci_largePrdBufPtr = MK_FP( (unsigned int) ( pmaEnd >> 4 ), 0 );
}
if ( dma_pci_largePrdBufPtr )
{
dma_pci_largeIoBufPtr = MK_FP( (unsigned int) ( pmaStart >> 4 ), 0 );
dma_pci_largeMaxB = 65536L * 512L;
dma_pci_largeMaxS = 65536L;
}
}
#if DEBUG_PCI & 0x02
pstr( "=>[dma] dma_pci_set_max_xfer()..." );
sprintf( LFB, "=>[dma] seg %04x off %04x bufSize %lx", seg, off, bufSize );
prt();
sprintf( LFB, "=>[dma] bufStart %lx bufEnd %lx", bufStart, bufEnd );
prt();
sprintf( LFB, "=>[dma] pmaStart %lx pmaEnd %lx", pmaStart, pmaEnd );
prt();
sprintf( LFB, "=>[dma] largePrdBufPtr %Fp largeIoBufPtr %Fp",
dma_pci_largePrdBufPtr, dma_pci_largeIoBufPtr );
prt();
sprintf( LFB, "=>[dma] dma_pci_largeMaxB %ld dma_pci_largeMaxS %ld",
dma_pci_largeMaxB, dma_pci_largeMaxS );
prt();
#endif
}
//***********************************************************
//
// exec_pci_ata_cmd() - PCI Bus Master for ATA R/W DMA commands
//
//***********************************************************
static int exec_pci_ata_cmd( int dev,
unsigned int seg, unsigned int off,
long numSect );
static int exec_pci_ata_cmd( int dev,
unsigned int seg, unsigned int off,
long numSect )
{
unsigned int cntr;
unsigned char status;
long lw;
// mark start of a R/W DMA command in low level trace
trc_llt( 0, 0, TRC_LLT_S_RWD );
// Quit now if the command is incorrect.
if ( ( reg_cmd_info.cmd != CMD_READ_DMA )
&& ( reg_cmd_info.cmd != CMD_READ_DMA_EXT )
&& ( reg_cmd_info.cmd != CMD_WRITE_DMA )
&& ( reg_cmd_info.cmd != CMD_WRITE_DMA_EXT ) )
{
reg_cmd_info.ec = 77;
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_RWD );
return 1;
}
// Quit now if no dma channel set up
// or interrupts are not enabled.
if ( ( ! pio_bmcr_base_addr ) || ( ! int_use_intr_flag ) )
{
reg_cmd_info.ec = 70;
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_RWD );
return 1;
}
// Quit now if 1) I/O buffer overrun possible.
// or 2) DMA can't handle the transfer size.
lw = numSect * 512L;
if ( ( ( dma_pci_prd_type != PRD_TYPE_LARGE )
&& ( ( lw > MAX_TRANSFER_SIZE ) || ( lw > reg_buffer_size ) ) )
||
( ( dma_pci_prd_type == PRD_TYPE_LARGE )
&& ( lw > dma_pci_largeMaxB ) )
)
{
reg_cmd_info.ec = 61;
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_PID );
return 1;
}
// Set up the dma transfer
if ( set_up_xfer( ( reg_cmd_info.cmd == CMD_WRITE_DMA )
||
( reg_cmd_info.cmd == CMD_WRITE_DMA_EXT ),
numSect * 512L, seg, off ) )
{
reg_cmd_info.ec = 61;
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_PID );
return 1;
}
// Set command time out.
tmr_set_timeout();
// Select the drive - call the sub_select function.
// Quit now if this fails.
if ( sub_select( dev ) )
{
sub_trace_command();
trc_llt( 0, 0, TRC_LLT_E_RWD );
return 1;
}
// Set up all the registers except the command register.
sub_setup_command();
// For interrupt mode, install interrupt handler.
int_save_int_vect();
// Start the command by setting the Command register. The drive
// should immediately set BUSY status.
pio_outbyte( CB_CMD, reg_cmd_info.cmd );
// The drive should start executing the command including any
// data transfer.
// Data transfer...
// read the BMIDE regs
// enable/start the dma channel.
// read the BMIDE regs again
sub_readBusMstrCmd();
sub_readBusMstrStatus();
sub_writeBusMstrCmd( 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 Interrupt=1 (see ATAIOINT.C)...
trc_llt( 0, 0, TRC_LLT_WINT );
cntr = 0;
while ( 1 )
{
cntr ++ ;
if ( ! ( cntr & 0x1fff ) )
{
sub_readBusMstrStatus(); // read BM status (for trace)
if ( ! ( reg_incompat_flags & REG_INCOMPAT_DMA_POLL ) )
pio_inbyte( CB_ASTAT ); // poll Alt Status
}
if ( int_intr_flag ) // interrupt ?
{
trc_llt( 0, 0, TRC_LLT_INTRQ ); // yes
trc_llt( 0, int_bm_status, TRC_LLT_R_BM_SR );
trc_llt( CB_STAT, int_ata_status, 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
reg_cmd_info.to = 1;
reg_cmd_info.ec = 73;
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
break;
}
}
if ( reg_incompat_flags & REG_INCOMPAT_DMA_DELAY )
delay( 1 ); // delay for buggy controllers
// End of command...
// disable/stop the dma channel
status = int_bm_status; // read BM status
status &= ~ BM_SR_MASK_ACT; // ignore Active bit
sub_writeBusMstrCmd( BM_CR_MASK_STOP ); // shutdown DMA
sub_readBusMstrCmd(); // read BM cmd (just for trace)
status |= sub_readBusMstrStatus(); // read BM status again
if ( reg_incompat_flags & REG_INCOMPAT_DMA_DELAY )
delay( 1 ); // delay for buggy controlers
if ( reg_cmd_info.ec == 0 )
{
if ( status & BM_SR_MASK_ERR ) // bus master error?
{
reg_cmd_info.ec = 78; // yes
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
}
}
if ( reg_cmd_info.ec == 0 )
{
if ( status & BM_SR_MASK_ACT ) // end of PRD list?
{
reg_cmd_info.ec = 71; // no
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
}
}
#if DEBUG_PCI & 0x01
trc_llt( 0, int_intr_cntr, 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 ( reg_cmd_info.ec )
status = pio_inbyte( CB_STAT );
else
status = int_ata_status;
// Final status check...
// if no error, check final status...
// Error if BUSY, DEVICE FAULT, DRQ or ERROR status now.
if ( reg_cmd_info.ec == 0 )
{
if ( status & ( CB_STAT_BSY | CB_STAT_DF | CB_STAT_DRQ | CB_STAT_ERR ) )
{
reg_cmd_info.ec = 74;
trc_llt( 0, reg_cmd_info.ec, TRC_LLT_ERROR );
}
}
// Final status check...
// if any error, update total bytes transferred.
if ( reg_cmd_info.ec == 0 )
reg_cmd_info.totalBytesXfer = numSect * 512L;
else
reg_cmd_info.totalBytesXfer = 0L;
// Done...
// Read the output registers and trace the command.
sub_trace_command();
// Done...
// For interrupt mode, remove interrupt handler.
int_restore_int_vect();
// Done...
// mark end of a R/W DMA command in low level trace
trc_llt( 0, 0, TRC_LLT_E_RWD );
// All done. The return values of this function are described in
// ATAIO.H.
if ( reg_cmd_info.ec )
return 1;
return 0;
}
//***********************************************************
//
// dma_pci_chs() - PCI Bus Master for ATA R/W DMA commands
//
//***********************************************************
int dma_pci_chs( int dev, int cmd,
unsigned int fr, unsigned int sc,
unsigned int cyl, unsigned int head, unsigned int sect,
unsigned int seg, unsigned int off,
long numSect )
{
// Setup current command information.
sub_zero_return_data();
reg_cmd_info.flg = TRC_FLAG_ATA;
reg_cmd_info.ct = TRC_TYPE_ADMAI;
if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
reg_cmd_info.ct = TRC_TYPE_ADMAO;
reg_cmd_info.cmd = cmd;
reg_cmd_info.fr1 = fr;
reg_cmd_info.sc1 = sc;
reg_cmd_info.sn1 = sect;
reg_cmd_info.cl1 = cyl & 0x00ff;
reg_cmd_info.ch1 = ( cyl & 0xff00 ) >> 8;
reg_cmd_info.dh1 = ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) | ( head & 0x0f );
reg_cmd_info.dc1 = 0x00; // nIEN=0 required on PCI !
reg_cmd_info.ns = numSect;
reg_cmd_info.lbaSize = LBACHS;
// Execute the command.
return exec_pci_ata_cmd( dev, seg, off, numSect );
}
//***********************************************************
//
// dma_pci_lba28() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************
int dma_pci_lba28( int dev, 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();
reg_cmd_info.flg = TRC_FLAG_ATA;
reg_cmd_info.ct = TRC_TYPE_ADMAI;
if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
reg_cmd_info.ct = TRC_TYPE_ADMAO;
reg_cmd_info.cmd = cmd;
reg_cmd_info.fr1 = fr;
reg_cmd_info.sc1 = sc;
reg_cmd_info.dh1 = CB_DH_LBA | (dev ? CB_DH_DEV1 : CB_DH_DEV0 );
reg_cmd_info.dc1 = 0x00; // nIEN=0 required on PCI !
reg_cmd_info.ns = numSect;
reg_cmd_info.lbaSize = LBA28;
reg_cmd_info.lbaHigh1 = 0L;
reg_cmd_info.lbaLow1 = lba;
// Execute the command.
return exec_pci_ata_cmd( dev, seg, off, numSect );
}
//***********************************************************
//
// dma_pci_lba48() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************
int dma_pci_lba48( int dev, 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();
reg_cmd_info.flg = TRC_FLAG_ATA;
reg_cmd_info.ct = TRC_TYPE_ADMAI;
if ( ( cmd == CMD_WRITE_DMA ) || ( cmd == CMD_WRITE_DMA_EXT ) )
reg_cmd_info.ct = TRC_TYPE_ADMAO;
reg_cmd_info.cmd = cmd;
reg_cmd_info.fr1 = fr;
reg_cmd_info.sc1 = sc;
reg_cmd_info.dh1 = CB_DH_LBA | (dev ? CB_DH_DEV1 : CB_DH_DEV0 );
reg_cmd_info.dc1 = 0x00; // nIEN=0 required on PCI !
reg_cmd_info.ns = numSect;
reg_cmd_info.lbaSize = LBA48;
reg_cmd_info.lbaHigh1 = lbahi;
reg_cmd_info.lbaLow1 = lbalo;
// Execute the command.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -