NT4/private/ntos/miniport/trantor/source/mv101.c
2020-09-30 17:12:29 +02:00

618 lines
15 KiB
C

//----------------------------------------------------------------------
//
// 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;
}