mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
525 lines
14 KiB
525 lines
14 KiB
//-----------------------------------------------------------------------
|
|
//
|
|
// File: N53C400.C
|
|
//
|
|
// N53C400 access file.
|
|
//
|
|
// These routines are independent of the card the N53C400 is on. The
|
|
// cardxxxx.h file must define the following routines:
|
|
//
|
|
// N53C400PortPut
|
|
// N53C400PortGet
|
|
// N53C400PortSet
|
|
// N53C400PortClear
|
|
// N53C400PortTest
|
|
// N53C400PortGetBuffer
|
|
// N53C400PortPutBuffer
|
|
//
|
|
// These routines could be defined by some other include file instead of
|
|
// cardxxxx.h, as the pc9010 defines the needed n5380xxxxxxxx routines.
|
|
//
|
|
//
|
|
// Revisions:
|
|
// 09-01-92 KJB First.
|
|
// 02-19-93 KJB Added support for data underrun read & write.
|
|
// transfer only 2 128 bytes fifos at a time
|
|
// might want to change this back if dataunderrun ok.
|
|
// 03-01-93 KJB Added N53C400CheckAdapter to check specifically for
|
|
// N53C400 and perform a chip reset on the 53C400 before
|
|
// checking.
|
|
// 03-02-93 KJB/JAP Phase checking for data phase moved to scsifnc.c.
|
|
// Wait for last byte sent in write bytes.
|
|
// 03-02-93 JAP Cleaned comments.
|
|
// 03-02-93 KJB Fixed Names-- baseIoAddress back.
|
|
// 03-03-93 JAP Cleaned comments again, reverting func declarations.
|
|
// 03-05-93 JAP Changed N53C400DisableInterrupt() and N53C400EnableInterrupt
|
|
// to mirror what is done in ASM code.
|
|
// 03-07-93 KJB WriteBytesFast now returns the correct error code
|
|
// when error occurs during slow write.
|
|
// 03-11-93 JAP Changed retcode equates to reflect new names.
|
|
// 03-11-93 KJB Changes code to reflect new 5380 names.
|
|
// 03-17-93 JAP Removed unreference lablellings.
|
|
// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
|
|
// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
|
|
// 05-14-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 a PINIT and a PWORKSPACE parameters.
|
|
// 05-17-93 KJB Added ErrorLogging capabilities (used by WINNT).
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
#include CARDTXXX_H
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// Local prototypes
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
USHORT N53C400Wait5380Access (PADAPTER_INFO g, ULONG usec);
|
|
USHORT N53C400WaitHostBufferReady (PADAPTER_INFO g, ULONG usec);
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// Routines
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400CheckAdapter
|
|
//
|
|
// This routine checks for the presense of a 53C400.
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
BOOLEAN N53C400CheckAdapter (PADAPTER_INFO g)
|
|
{
|
|
USHORT rval;
|
|
|
|
// Reset the N53C400 chip.
|
|
// WARNING -- Could be destructive to other cards @ this port
|
|
|
|
N53C400PortPut (g, N53C400_CONTROL, CR_RST);
|
|
|
|
// check by testing the 5380
|
|
|
|
rval = N5380CheckAdapter (g);
|
|
|
|
return (BOOLEAN) rval;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400WaitHostBufferReady
|
|
//
|
|
// This routine waits until the 53c400's 128 byte queue is ready with
|
|
// or for data.
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
USHORT N53C400WaitHostBufferReady (PADAPTER_INFO g, ULONG usec)
|
|
{
|
|
ULONG i;
|
|
USHORT rval;
|
|
|
|
// see if the flag comes back quickly
|
|
|
|
for (i = 0; i < TIMEOUT_QUICK; i++) {
|
|
if (!N53C400PortTest (g, N53C400_STATUS, SR_HBFR_RDY)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// ok, it did not come back quickly, we will yield to other processes
|
|
|
|
for (i = 0; i < usec; i++) {
|
|
if (!N53C400PortTest (g, N53C400_STATUS, SR_HBFR_RDY)) {
|
|
return 0;
|
|
}
|
|
|
|
// if we suddenly have access, then phase mismatch and over/underrun
|
|
|
|
if (N53C400PortTest (g, N53C400_STATUS, SR_ACCESS)) {
|
|
rval = RET_STATUS_DATA_OVERRUN;
|
|
DebugPrint((DEBUG_LEVEL,"Error - 0 - ScsiWaitHostBufferReady\n"));
|
|
goto error;
|
|
}
|
|
|
|
ScsiPortStallExecution(1);
|
|
}
|
|
|
|
// reset the n53c400 in the case of a timeout
|
|
|
|
N53C400PortPut (g, N53C400_CONTROL, CR_RST);
|
|
|
|
TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 30);
|
|
|
|
rval = RET_STATUS_TIMEOUT;
|
|
|
|
error:
|
|
DebugPrint((DEBUG_LEVEL,"Error - 1 - ScsiWaitHostBufferReady\n"));
|
|
|
|
// return with an error, non-zero indicates timeout
|
|
|
|
return rval;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400Wait5380Access
|
|
//
|
|
// Waits until 5380 access is allowed.
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
USHORT N53C400Wait5380Access (PADAPTER_INFO g, ULONG usec)
|
|
{
|
|
ULONG i;
|
|
|
|
// see if the flag comes back quickly
|
|
|
|
for (i = 0; i < TIMEOUT_QUICK; i++) {
|
|
if (N53C400PortTest (g, N53C400_STATUS, SR_ACCESS)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// ok, it did not come back quickly, we will yield to other processes
|
|
|
|
for (i = 0; i < usec; i++) {
|
|
if (N53C400PortTest (g, N53C400_STATUS, SR_ACCESS)) {
|
|
return 0;
|
|
}
|
|
ScsiPortStallExecution(1);
|
|
}
|
|
|
|
DebugPrint((DEBUG_LEVEL,"Error - ScsiWait5380Access\n"));
|
|
|
|
TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 31);
|
|
|
|
// return with an error, non-zero indicates timeout
|
|
|
|
return RET_STATUS_TIMEOUT;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400WriteyBytesFast
|
|
//
|
|
// Write the bytes from a n53c400 as fast as possible.
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
USHORT N53C400WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
|
|
ULONG len, PULONG pActualLen, UCHAR phase)
|
|
{
|
|
ULONG i;
|
|
USHORT rval = 0;
|
|
ULONG remainder;
|
|
ULONG cnt;
|
|
ULONG blocks;
|
|
ULONG total_blocks;
|
|
UCHAR tmp;
|
|
|
|
remainder = len % 128;
|
|
total_blocks = cnt = len / 128;
|
|
|
|
// are there any 128 byte blocks to be received
|
|
|
|
while (cnt) {
|
|
|
|
// send up to 256 128 bytes blocks at a time
|
|
|
|
blocks = (cnt > 256) ? 256 : cnt;
|
|
cnt -= blocks;
|
|
|
|
// clear any interrupt condition on the 5380
|
|
|
|
N5380PortGet (g, N5380_RESET_INTERRUPT, &tmp);
|
|
|
|
// Clear the 53c400 dir bit.
|
|
// Don't preserve any bits in this register.
|
|
|
|
N53C400PortPut (g, N53C400_CONTROL, 0);
|
|
|
|
// set the dma bit of 5380, and enable end of dma int
|
|
|
|
N5380PortSet (g, N5380_MODE, MR_DMA_MODE |
|
|
MR_ENABLE_EODMA_INTERRUPT);
|
|
|
|
// start the dma on the 5380
|
|
|
|
N5380PortPut (g, N5380_START_DMA_SEND, 1);
|
|
|
|
// write the count of 128 byte blocks
|
|
|
|
N53C400PortPut (g, N53C400_COUNTER, (UCHAR)blocks);
|
|
|
|
for (i = 0; i < blocks; i++) {
|
|
|
|
// wait for host buffer ready
|
|
|
|
if (rval = N53C400WaitHostBufferReady (g, TIMEOUT_REQUEST)) {
|
|
|
|
DebugPrint((DEBUG_LEVEL,"Error - 0 - N53C400WriteBytesFast\n"));
|
|
|
|
// calculate # of bytes transferred
|
|
// not including this one
|
|
|
|
*pActualLen = (total_blocks - (cnt+blocks-i)) * 128;
|
|
|
|
goto error_clear_dma;
|
|
}
|
|
|
|
N53C400PortPutBuffer (g, N53C400_HOST_BFR, pbytes, 128);
|
|
pbytes += 128;
|
|
}
|
|
|
|
// wait for access to 5380
|
|
|
|
if (rval = N53C400Wait5380Access (g, TIMEOUT_REQUEST)) {
|
|
|
|
// if timeout, do reset
|
|
|
|
N53C400PortPut (g, N53C400_CONTROL, CR_RST);
|
|
}
|
|
|
|
// wait for last byte to be sent
|
|
|
|
if (rval = N5380WaitLastByteSent (g, TIMEOUT_REQUEST)) {
|
|
goto error_clear_dma;
|
|
}
|
|
|
|
// clear dma mode
|
|
|
|
N5380PortClear (g, N5380_MODE, MR_DMA_MODE |
|
|
MR_ENABLE_EODMA_INTERRUPT);
|
|
N5380DisableInterrupt (g);
|
|
}
|
|
|
|
// calculate # of bytes transferred
|
|
|
|
*pActualLen = (total_blocks - cnt) * 128;
|
|
|
|
// If xfr count was not a multiple of 128, write remainder slowly.
|
|
|
|
if (remainder) {
|
|
|
|
ULONG bytes_xferred;
|
|
|
|
rval = ScsiWriteBytesSlow (g, pbytes, remainder, &bytes_xferred,
|
|
phase);
|
|
|
|
*pActualLen += bytes_xferred;
|
|
}
|
|
|
|
done:
|
|
return rval;
|
|
|
|
error_clear_dma:
|
|
|
|
// clear dma mode
|
|
|
|
N5380PortClear(g,N5380_MODE, MR_DMA_MODE |
|
|
MR_ENABLE_EODMA_INTERRUPT);
|
|
N5380DisableInterrupt(g);
|
|
|
|
goto done;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400ReadyBytesFast
|
|
//
|
|
// Read the bytes from a n53c400 as fast as possible.
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
USHORT N53C400ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
|
|
ULONG len, PULONG pActualLen, UCHAR phase)
|
|
{
|
|
ULONG i;
|
|
USHORT rval = 0;
|
|
ULONG remainder;
|
|
ULONG cnt;
|
|
ULONG blocks;
|
|
ULONG total_blocks;
|
|
UCHAR tmp;
|
|
|
|
// For uneven transfers (here not a multiple of 256),
|
|
// assume we could have an underrun. Read bytes slow to prevent it...
|
|
|
|
if ((len % 256)) {
|
|
rval = ScsiReadBytesSlow (g, pbytes, len, pActualLen, phase);
|
|
goto done;
|
|
}
|
|
|
|
remainder = len % 128;
|
|
total_blocks = cnt = len / 128;
|
|
|
|
// are there any 128 byte blocks to be received
|
|
|
|
while (cnt) {
|
|
|
|
blocks = (cnt > 256) ? 256 : cnt;
|
|
cnt -= blocks;
|
|
|
|
// clear any interrupt condition on the 5380
|
|
|
|
N5380PortGet (g, N5380_RESET_INTERRUPT, &tmp);
|
|
|
|
// set the 53c400 dir bit
|
|
// don't preserve any bits in this register...
|
|
|
|
N53C400PortPut (g, N53C400_CONTROL, CR_DIR);
|
|
|
|
// set the dma bit of 5380, enable end of dma int
|
|
|
|
N5380PortSet (g, N5380_MODE, MR_DMA_MODE |
|
|
MR_ENABLE_EODMA_INTERRUPT);
|
|
|
|
// start the dma on the 5380
|
|
|
|
N5380PortPut (g, N5380_START_INITIATOR_RECEIVE, 1);
|
|
|
|
// write the count of 128 byte blocks
|
|
|
|
N53C400PortPut (g, N53C400_COUNTER, (UCHAR)blocks);
|
|
|
|
for (i = 0; i < blocks; i++) {
|
|
|
|
// wait for host buffer ready
|
|
|
|
if (rval = N53C400WaitHostBufferReady (g, TIMEOUT_REQUEST)) {
|
|
|
|
// WHAT DO YOU DO when the transfer ends early and the n5380
|
|
// has some of the bytes in its buffers? HELP!!!
|
|
|
|
DebugPrint((DEBUG_LEVEL,"Error - 0 - N53C400ReadBytesFast\n"));
|
|
|
|
N53C400PortGetBuffer (g, N53C400_HOST_BFR, pbytes, 128);
|
|
|
|
// clear dma mode
|
|
|
|
N5380PortClear (g, N5380_MODE, MR_DMA_MODE |
|
|
MR_ENABLE_EODMA_INTERRUPT);
|
|
N5380DisableInterrupt (g);
|
|
|
|
// calculate # of bytes transferred, not including this one
|
|
|
|
*pActualLen = (total_blocks - (cnt+blocks-i)) * 128;
|
|
|
|
goto done;
|
|
}
|
|
|
|
N53C400PortGetBuffer (g, N53C400_HOST_BFR, pbytes, 128);
|
|
pbytes += 128;
|
|
}
|
|
|
|
// wait for access to 5380
|
|
|
|
if (rval = N53C400Wait5380Access (g, TIMEOUT_REQUEST)) {
|
|
|
|
// if timeout, do reset
|
|
|
|
N53C400PortPut (g, N53C400_CONTROL, CR_RST);
|
|
}
|
|
|
|
// clear dma mode
|
|
|
|
N5380PortClear (g, N5380_MODE, MR_DMA_MODE |
|
|
MR_ENABLE_EODMA_INTERRUPT);
|
|
N5380DisableInterrupt (g);
|
|
}
|
|
|
|
// calculate # of bytes transferred
|
|
|
|
*pActualLen = (total_blocks - cnt) * 128;
|
|
|
|
// If xfr count was not a multiple of 128, read remainder slowly
|
|
|
|
if (remainder) {
|
|
|
|
ULONG bytes_xferred;
|
|
|
|
ScsiReadBytesSlow (g,pbytes, remainder, &bytes_xferred,
|
|
phase);
|
|
|
|
*pActualLen += bytes_xferred;
|
|
}
|
|
|
|
done:
|
|
|
|
return rval;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400DisableInterrupt
|
|
//
|
|
// Disable interrupts on the N53C400
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
VOID N53C400DisableInterrupt (PADAPTER_INFO g)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// disable interrupt in the 53c400 for 5380 ints
|
|
|
|
N53C400PortGet (g, N53C400_CONTROL, &tmp);
|
|
tmp &= (CR_DIR | CR_BFR_INT | CR_SH_INT);
|
|
N53C400PortPut (g, N53C400_CONTROL, tmp);
|
|
|
|
// disable the interrupt on the 5380
|
|
|
|
N5380DisableInterrupt (g);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400EnableInterrupt
|
|
//
|
|
// Enable interrupts on the N53C400
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
VOID N53C400EnableInterrupt (PADAPTER_INFO g)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// set the dma bit of 5380 so we can get phase mismatch ints
|
|
|
|
N5380EnableInterrupt (g);
|
|
|
|
// enable interrupt in the 53c400 for 5380 interrupts
|
|
|
|
N53C400PortGet (g, N53C400_CONTROL, &tmp);
|
|
tmp &= (CR_DIR | CR_BFR_INT | CR_5380_INT | CR_SH_INT);
|
|
tmp |= CR_5380_INT;
|
|
N53C400PortPut (g, N53C400_CONTROL, tmp);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// N53C400ResetBus
|
|
//
|
|
// Reset the SCSI bus
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
VOID N53C400ResetBus (PADAPTER_INFO g)
|
|
{
|
|
// reset the 53c400
|
|
|
|
N53C400PortPut (g, N53C400_CONTROL, CR_RST);
|
|
|
|
// disable interrupts
|
|
|
|
N53C400DisableInterrupt (g);
|
|
|
|
// reset the scsi bus
|
|
|
|
N5380ResetBus (g);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
// End Of File.
|
|
//-----------------------------------------------------------------------
|
|
|