|
|
//----------------------------------------------------------------------
//
// MV101.C
//
// Trantor MV101 access file.
//
// These routines are independent of the card the MV101 logic is on. The
// cardxxxx.h file must define the following routines:
//
// MV101PortPut
// MV101PortGet
// MV101PortSet
// MV101PortClear
// MV101PortTest
//
// These routines could be defined by some other include file instead of
// cardxxxx.h, as the pc9010 defines the needed n5380xxxxxxxx routines.
//
// Revisions:
// 02-25-93 KJB First.
// 03-05-93 KJB Added call to N5380DisableDmaWrite.
// 03-11-93 JAP Changed retcode equates to reflect new names.
// 03-11-93 KJB Changed to use new N5380.H names.
// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
// 05-13-93 KJB Added CardParseCommandString for card specific
// standard string parsing across platforms.
// Changed CardCheckAdapter to accept an
// Initialization info from command line, ie
// force bi-directional ports, etc.
// All functions that used to take an PBASE_REGISTER
// parameter now take PWORKSPACE. CardCheckAdapter
// takes the both the PBASE_REGISTER and the
// PWORKSPACE parameters. Auto Request Sense is
// now supported.
// 05-13-93 KJB Merged Microsoft Bug fixes to card detection.
// 05-14-93 KJB Remove all WINNT specific #ifdef i386 references.
// 05-17-93 KJB Added ErrorLogging capabilities (used by WINNT).
//
//----------------------------------------------------------------------
#include CARDTXXX_H
#include "findpas.h"
//
// local functions
//
VOID MV101ResetDmaTimeout (PADAPTER_INFO g); VOID MV101EnableDmaWrite (PADAPTER_INFO g); VOID MV101EnableDmaRead (PADAPTER_INFO g); USHORT MV101WaitXfrReady (PADAPTER_INFO g, ULONG usec);
//
// local redefines
//
#define MV101DisableDmaRead N5380DisableDmaRead
#define MV101DisableDmaWrite N5380DisableDmaWrite
//
// N5380PortPut
//
// This routine is used by the N5380.C module to write byte to a 5380
// controller. This allows the module to be card independent. Other
// modules that assume a N5380 may also use this function.
//
VOID N5380PortPut (PADAPTER_INFO g, UCHAR reg, UCHAR byte) { if (reg<4) { PortIOPut((PUCHAR)g->BaseIoAddress+MV101_5380_1+reg,byte); } else { PortIOPut((PUCHAR)g->BaseIoAddress+MV101_5380_2+reg-4,byte); } }
//
// N5380PortGet
//
// This routine is used by the N5380.C module to get a byte from a 5380
// controller. This allows the module to be card independent. Other
// modules that assume a N5380 may also use this function.
//
VOID N5380PortGet (PADAPTER_INFO g, UCHAR reg, PUCHAR byte) { if (reg<4) { PortIOGet ((PUCHAR)g->BaseIoAddress+MV101_5380_1+reg, byte); } else { PortIOGet ((PUCHAR)g->BaseIoAddress+MV101_5380_2+reg-4,byte); } }
//
// MV101CheckAdapter
//
// This routine sees if there is an adapter at this address. If so,
// then this adapter is initialized.
//
BOOLEAN MV101CheckAdapter (PADAPTER_INFO g) { FOUNDINFO fi;
//
// FindPasHardware does it's own mapping of port bases.
// Set the base to zero and indicate which port is currently being
// polled.
//
fi.PROBase = 0; fi.ProPort = (ULONG) g->BaseIoAddress; if (!FindPasHardware(&fi)) { return FALSE; } // for old boards, we use bit 1 for drq mask during dma xfers
if (fi.wBoardRev == PAS_VERSION_1) { g->DRQMask = 0x01; } else { g->DRQMask = 0x80; }
// is there an adapter here?
if (N5380CheckAdapter (g)) { // found a 5380, initialize special dma hardware for
// dma fast read and writes.
MV101PortPut (g,MV101_SYSTEM_CONFIG4,0x49); MV101PortPut (g,MV101_TIMEOUT_COUNTER,0x30); MV101PortPut (g,MV101_TIMEOUT_STATUS,0x01); MV101PortPut (g,MV101_WAIT_STATE,0x01); return TRUE; } else { return FALSE; } }
//
// MV101WaitXfrReady
//
// This routine waits till the DRQ flag goes up.
//
USHORT MV101WaitXfrReady (PADAPTER_INFO g, ULONG usec) { ULONG i;
// see if the flag comes back quickly
for (i=0;i<TIMEOUT_QUICK;i++) {
// wait for card to be ready
if (MV101PortTest(g, MV101_DRQ_PORT, g->DRQMask)) { return 0; } }
// ok, it did not come back quickly, we will yield to other processes
for (i=0; i < usec; i++) {
// wait for card to be ready
if (MV101PortTest (g, MV101_DRQ_PORT, g->DRQMask)) { return 0; }
// see if bus free
if (!N5380PortTest (g, N5380_CURRENT_STATUS, CS_BSY)) {
TrantorLogError (g->BaseIoAddress, RET_STATUS_UNEXPECTED_BUS_FREE, 100);
return RET_STATUS_UNEXPECTED_BUS_FREE; }
// since we have taken some time... check for phase change
if (!N5380PortTest (g, N5380_DMA_STATUS, DS_PHASE_MATCH)) { return RET_STATUS_DATA_OVERRUN; }
// wait for card to be ready
ScsiPortStallExecution(1); }
DebugPrint ((DEBUG_LEVEL,"Error - MV101WaitXfrReady\n"));
// return with an error, non-zero indicates timeout
TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 102);
return RET_STATUS_TIMEOUT; }
//
// MV101ResetDmaTimeout
//
// Resets the dma timout bit.
//
VOID MV101ResetDmaTimeout (PADAPTER_INFO g) { MV101PortPut (g, MV101_TIMEOUT_STATUS, 0x01); }
//
// MV101EnableDmaRead
//
// Enables the DMA read operation for the T128.
//
VOID MV101EnableDmaRead (PADAPTER_INFO g) { // start dma on the 5380
N5380EnableDmaRead(g);
// toggle the t120 timeout bit to clear any timeout
MV101ResetDmaTimeout(g); }
//
// MV101EnableDmaWrite
//
// Enables the DMA write operation for the T128.
//
VOID MV101EnableDmaWrite (PADAPTER_INFO g) { // start dma on the 5380
N5380EnableDmaWrite (g);
// toggle the t120 timeout bit to clear any timeout
MV101ResetDmaTimeout (g); }
//
// MV101SetInterruptLevel
//
// The Media Vision MV101s need to be programmed for interrupts.
// In particular, one needs to set the interrupt level into a register.
//
VOID MV101SetInterruptLevel (PADAPTER_INFO g, UCHAR level) { // int from drive active high
MV101PortSet (g, MV101_SYSTEM_CONFIG4, 0x04);
// enable interrupts for the card
MV101PortSet (g, MV101_SYSTEM_CONFIG4, 0x20);
// set the interrupt level in IO port config register 3
MV101PortClear(g,MV101_IO_PORT_CONFIG3,0xf0);
if (level < 8) { MV101PortSet (g, MV101_IO_PORT_CONFIG3, (UCHAR)((level-1)<<4)); } else { MV101PortSet (g, MV101_IO_PORT_CONFIG3, (UCHAR)((7+level-10)<<4)); } }
//
// MV101EnableInterrupt
//
// Enables the interrupt on the card and on the 5380.
//
VOID MV101EnableInterrupt (PADAPTER_INFO g) { // interrupt reset for tmv1 card
MV101PortSet (g, MV101_TIMEOUT_STATUS, 0x01);
// enable interrupts on the 5380
N5380EnableInterrupt (g); }
//
// MV101DisableInterrupt
//
// Disables the interrupt on the card and on the 5380.
//
VOID MV101DisableInterrupt (PADAPTER_INFO g) { // interrupt reset for tmv1 card
MV101PortSet (g, MV101_TIMEOUT_STATUS, 0x01);
// disable the signal from the 5380
N5380DisableInterrupt (g); }
//
// MV101ReadBytesFast
//
// This routine is used by the ScsiFnc routines to read bytes to the scsi
// bus quickly. The ScsiFnc routines don't know how to do this quickly for
// a particular card, so they call this. This routine can be mapped to the
// slower ScsiReadBytesSlow routine for small transferrs or if this routine
// is not supported.
//
USHORT MV101ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes, ULONG len, PULONG pActualLen, UCHAR phase) { USHORT rval = 0;
// for small transfers, use slow loop (inquiry and other stuff)
if (len < 512) { rval = ScsiReadBytesSlow (g, pbytes, len, pActualLen, phase); return rval; }
// start dma for this card
MV101EnableDmaRead (g);
// wait for buffer to be ready
if (rval = MV101WaitXfrReady (g,TIMEOUT_REQUEST)) { goto done; }
// due to the speed of i/o instructions in 486 protected mode,
// we can afford to do all the drq checking. There is no need for
// the 'blind mode' rep insb transfers. These have been tried and
// the result is "20 FF FF FF 20 FF FF 41", indicating that we are
// two to three times faster than the card, hence we can afford to
// poll the card.
{ PUCHAR dma_port = (PUCHAR)g->BaseIoAddress + MV101_DMA_PORT; PUCHAR drq_port = (PUCHAR)g->BaseIoAddress + MV101_DRQ_PORT; ULONG xfer_count = len; UCHAR drq_mask = g->DRQMask;
_asm { pushf push esi push edi push es cld mov ah,drq_mask #ifdef MODE_32BIT
mov edx,dma_port mov esi,drq_port mov edi,pbytes mov ecx,len #else
mov edx,word ptr dma_port mov esi,word ptr drq_port mov edi,word ptr pbytes mov ecx,word ptr len mov es,word ptr pbytes+2 #endif
loop1: xchg edx,esi // dx drq_port
in al,dx test al,ah jnz ready in al,dx test al,ah jnz ready in al,dx test al,ah jnz ready push ecx mov ecx,TIMEOUT_READWRITE_LOOP loop3: mov ebx,0x10000 loop2: in al,dx test al,ah jnz ready1 in al,dx test al,ah jnz ready1 // check for phase mismatch
sub dx, MV101_DRQ_PORT - MV101_5380_2 // dx = N5380_CURRENT_STATUS
in al,dx test al,CS_REQ jz no_req add dx, (N5380_DMA_STATUS - N5380_CURRENT_STATUS) // dx = N5380_DMA_STATUS
in al,dx test al,DS_PHASE_MATCH jz phase_error sub dx, N5380_DMA_STATUS - N5380_CURRENT_STATUS // dx = N5380_CURRENT_STATUS
no_req: add dx, MV101_DRQ_PORT - MV101_5380_2 // dx = MV101_DRQ
dec ebx jnz loop2 dec ecx jnz loop3 pop ecx mov rval,RET_STATUS_TIMEOUT jmp short timeout phase_error: pop ecx mov rval,RET_STATUS_DATA_OVERRUN jmp short timeout ready1: pop ecx // jmp ready
ready: xchg edx,esi // dx dma_port
insb dec ecx jnz loop1 timeout: pop es #ifdef MODE_32BIT
mov xfer_count,ecx #else
mov word ptr xfer_count,ecx #endif
pop edi pop esi popf }
// compute actual xfer len
*pActualLen = len - xfer_count; }
done: // disable dma
MV101DisableDmaRead (g);
// check for errors...
if (rval == RET_STATUS_TIMEOUT) { TrantorLogError (g->BaseIoAddress, rval, 103); }
return rval; }
//
// MV101WriteBytesFast
//
// This routine is used by the ScsiFnc routines to write bytes to the scsi
// bus quickly. The ScsiFnc routines don't know how to do this quickly for
// a particular card, so they call this. This routine can be mapped to the
// slower ScsiReadBytesSlow routine for small transferrs or if this routine
// is not supported.
//
USHORT MV101WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes, ULONG len, PULONG pActualLen, UCHAR phase) { USHORT rval = 0;
// for small transfers, use slow loop (inquiry and other stuff)
if (len < 512) { rval = ScsiWriteBytesSlow (g, pbytes, len, pActualLen, phase); return rval; }
// start dma for this card
MV101EnableDmaWrite (g);
// wait for buffer to be ready
if (rval = MV101WaitXfrReady (g, TIMEOUT_REQUEST)) { goto done; }
// due to the speed of i/o instructions in 486 protected mode,
// we can afford to do all the drq checking. There is no need for
// the 'blind mode' rep insb transfers. These have been tried and
// the result is "20 FF FF FF 20 FF FF 41", indicating that we are
// two to three times faster than the card, hence we can afford to
// poll the card.
{ PUCHAR dma_port = (PUCHAR)g->BaseIoAddress + MV101_DMA_PORT; PUCHAR drq_port = (PUCHAR)g->BaseIoAddress + MV101_DRQ_PORT; ULONG xfer_count = len; UCHAR drq_mask = g->DRQMask; _asm { pushf push esi push edi push ds cld mov ah,drq_mask #ifdef MODE_32BIT
mov edx,dma_port mov edi,drq_port mov esi,pbytes mov ecx,len #else
mov edx,word ptr dma_port mov edi,word ptr drq_port mov esi,word ptr pbytes mov ecx,word ptr len mov ds, word ptr pbytes+2 #endif
loop1: xchg edx,edi // edx drq_port
in al,dx test al,ah jnz ready in al,dx test al,ah jnz ready in al,dx test al,ah jnz ready push ecx mov ecx,TIMEOUT_READWRITE_LOOP loop3: mov ebx,0x10000 loop2: in al,dx test al,ah jnz ready1 in al,dx test al,ah jnz ready1 // check for phase mismatch
sub dx, MV101_DRQ_PORT - MV101_5380_2 // dx = N5380_CURRENT_STATUS
in al,dx test al,CS_REQ jz no_req add dx, N5380_DMA_STATUS - N5380_CURRENT_STATUS // dx = N5380_DMA_STATUS
in al,dx test al,DS_PHASE_MATCH jz phase_error sub dx, N5380_DMA_STATUS - N5380_CURRENT_STATUS // dx = N5380_CURRENT_STATUS
no_req: add dx, MV101_DRQ_PORT - MV101_5380_2 // dx = MV101_DRQ_PORT
dec ebx jnz loop2 dec ecx jnz loop3 pop ecx mov rval,RET_STATUS_TIMEOUT jmp short timeout phase_error: pop ecx mov rval,RET_STATUS_DATA_OVERRUN jmp short timeout ready1: pop ecx // jmp ready
ready: xchg edx,edi // edx dma_port
outsb dec ecx jnz loop1 timeout: pop ds #ifdef MODE_32BIT
mov xfer_count,ecx #else
mov word ptr xfer_count,ecx #endif
pop edi pop esi popf }
// compute actual xfer len
*pActualLen = len - xfer_count; }
done: // disable dma
MV101DisableDmaWrite (g);
// check for errors...
if (rval == RET_STATUS_TIMEOUT) { TrantorLogError (g->BaseIoAddress, rval, 104); }
return rval; }
|