Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1924 lines
50 KiB

//**********************************************************************
//**********************************************************************
//
// File Name: RESET.C
//
// Program Name: NetFlex NDIS 3.0 Miniport Driver
//
// Companion Files: None
//
// Function: This module contains the NetFlex Miniport Driver
// interface routines called by the Wrapper and the
// configuration manager.
//
// (c) Compaq Computer Corporation, 1992,1993,1994
//
// This file is licensed by Compaq Computer Corporation to Microsoft
// Corporation pursuant to the letter of August 20, 1992 from
// Gary Stimac to Mark Baber.
//
// History:
//
// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
//
//**********************************************************************
//**********************************************************************
//-------------------------------------
// Include all general companion files
//-------------------------------------
#include <ndis.h>
#include "tmsstrct.h"
#include "macstrct.h"
#include "adapter.h"
#include "protos.h"
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexResetDispatch
//
// Description:
// Kick off a reset!
//
// Input:
// MiniportAdapterContext - really our acb.
//
// Output:
// Returns NDIS_STATUS_PENDING unless we are already handling a reset,
// in which case we return NDIS_STATUS_RESET_IN_PROGRESS.
//
// Called By:
// Miniport Wrapper
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NDIS_STATUS
NetFlexResetDispatch(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext
)
{
PACB acb = (PACB) MiniportAdapterContext;
BOOLEAN ReceiveResult = FALSE;
DebugPrint(1,("NF(%d): Reset Called!\n",acb->anum));
if ( acb->ResetState && (acb->ResetState != RESET_HALTED))
{
return NDIS_STATUS_RESET_IN_PROGRESS;
}
acb->acb_lastringstate = NdisRingStateClosed;
acb->acb_state = AS_RESETTING;
acb->ResetState = RESET_STAGE_1;
//
// Cancel the DPC Timer!
//
NdisMCancelTimer(&acb->DpcTimer,&ReceiveResult);
//
// Set the timer for the NetFlexResetHandler DPC.
//
NdisMSetTimer(&acb->ResetTimer,500 );
return NDIS_STATUS_PENDING;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexResetHandler
//
// Description:
// Performs that operations to put the adatper
// through a reset and back into operation.
//
//
// Input:
//
// SystemSpecific1 - Not used.
// acb - The Adapter whose hardware is being reset.
// SystemSpecific2 - Not used.
// SystemSpecific3 - Not used.
//
// Output:
// None.
//
// Called By:
// via acb->ResetTimer
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID
NetFlexResetHandler(
IN PVOID SystemSpecific1,
IN PACB acb,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
{
NDIS_STATUS Status;
BOOLEAN ReceiveResult;
BOOLEAN DoneWReset;
//
// Cancel the reset timer
//
NdisMCancelTimer(&acb->ResetTimer,&ReceiveResult);
do
{
DoneWReset = TRUE; // default to true...
//
// Based on the current acb->ResetState, proceed with the reset.
//
switch(acb->ResetState)
{
case RESET_STAGE_1:
acb->ResetRetries = 0;
acb->InitRetries = 0;
//
// Issue Close
//
NetFlexCloseAdapter(acb);
//
// Remove all xmit mappings, and clean up queues
//
NetFlexRemoveRequests(acb);
acb->ResetState = RESET_STAGE_2;
case RESET_STAGE_2:
//
// Try soft resetting adapter
//
Status = NetFlexAdapterReset(acb,SOFT_RESET);
//
// Was the reset successful?
//
if (Status != NDIS_STATUS_SUCCESS)
{
// No!
// Increment the retry count
//
acb->ResetRetries++;
//
// have we tried 3 times?
//
if (acb->ResetRetries < 3 )
{
// no, try it again in 10 sec
//
NdisMSetTimer(&acb->ResetTimer,10000 );
}
else
{
// yes, try a hard reset
//
acb->ResetState = RESET_STAGE_3;
acb->ResetRetries = 0;
DoneWReset = FALSE;
}
break;
}
//
// Yes, soft reset was successful, send open request...
// Note: When the Open request completes/fails
// we wind up in Reset_Stage_4.
//
acb->ResetState = RESET_STAGE_4;
acb->InitRetries++;
NetFlexOpenAdapter(acb);
//
// Give the Open 20 seconds to Complete
//
NdisMSetTimer(&acb->ResetTimer,20000);
break;
case RESET_STAGE_3:
//
// Perform Hard Reset!
//
Status = NetFlexAdapterReset(acb,HARD_RESET);
//
// Was the reset successful?
//
if (Status != NDIS_STATUS_SUCCESS)
{
// No!
// Increment the retry count
//
acb->ResetRetries++;
//
// have we tried Hard Reset 3 times?
//
if (acb->ResetRetries < 3 )
{
// no, try it again in 10 sec
//
acb->ResetState = RESET_STAGE_3;
NdisMSetTimer(&acb->ResetTimer,10000 );
}
else
{
// Hard Reset timed out, do the reset indications.
//
DebugPrint(0,("NF(%d): Reset - Exceeded Hard Reset Retries\n",acb->anum));
NetFlexDoResetIndications(acb,NDIS_STATUS_FAILURE);
}
break;
}
//
// Yes, hard reset was successful, go do init stuff...
//
acb->ResetState = RESET_STAGE_4;
//
// Send Open Comand, when complete, we end up in Reset_Stage_4
//
NetFlexOpenAdapter(acb);
//
// Give the Open 20 seconds to Complete
//
NdisMSetTimer(&acb->ResetTimer,20000);
break;
case RESET_STAGE_4:
//
// Increment the retry count
//
acb->InitRetries++;
if (acb->acb_state != AS_OPENED)
{
// Have we expired the retry count, do the indications
//
if (acb->InitRetries > 4)
{
DebugPrint(0,("NF(%d): Reset - Exceeded Open Retries\n",acb->anum));
NetFlexDoResetIndications(acb,NDIS_STATUS_FAILURE);
}
else
{
// Perform a Soft Reset again!
//
acb->ResetState = RESET_STAGE_2;
DoneWReset = FALSE;
}
}
else
{
// We were successful!
//
NetFlexDoResetIndications(acb,NDIS_STATUS_SUCCESS);
}
break;
}
} while (!DoneWReset);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexDoResetIndications
//
// Description:
// This routine is called by NetFlexResetHandler to perform any
// indications which need to be done after a reset. Note that
// this routine will be called after either a successful reset
// or a failed reset.
//
// Input:
// acb - Our Driver Context.
//
// Output:
// Status - The status of the reset to send to the protocol(s).
//
// Called By:
// NetFlexResetHandler
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID
NetFlexDoResetIndications(
IN PACB acb,
IN NDIS_STATUS Status
)
{
USHORT actl_reg;
//
// If we have a bad result, we stop the chip and do the indication
// back to the protocol(s).
//
if (Status != NDIS_STATUS_SUCCESS)
{
DebugPrint(0,("NF(%d): Reset failed!\n",acb->anum));
//
// Stop the chip
//
NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&actl_reg));
actl_reg |= ACTL_ARESET;
NdisRawWritePortUshort( acb->SifActlPort, (USHORT) actl_reg);
//
// Reset has failed, errorlog an entry if
// did not already send out a message.
//
if (!acb->ResetErrorLogged)
{
NdisWriteErrorLogEntry( acb->acb_handle,
EVENT_NDIS_RESET_FAILURE_ERROR,
1,
NETFLEX_RESET_FAILURE_ERROR_CODE
);
acb->ResetErrorLogged = TRUE;
}
acb->ResetState = RESET_HALTED;
acb->acb_state = AS_CARDERROR;
Status = NDIS_STATUS_HARD_ERRORS;
}
//
// Verify that the dpc timer is set.
//
NdisMSetTimer(&acb->DpcTimer,10);
NdisMResetComplete( acb->acb_handle,
Status,
TRUE );
//
// We are no longer resetting the Adapter.
//
if (Status == NDIS_STATUS_SUCCESS)
{
acb->ResetState = 0;
//
// Did we send out a message that a reset failed before?
//
if (acb->ResetErrorLogged)
{
//
// Log the fact that everything is ok now...
//
NdisWriteErrorLogEntry( acb->acb_handle,
EVENT_NDIS_RESET_FAILURE_CORRECTION,
0);
acb->ResetErrorLogged = FALSE;
}
else
{
if (acb->acb_lastringstatus &
( NDIS_RING_SIGNAL_LOSS |
NDIS_RING_LOBE_WIRE_FAULT |
NDIS_RING_AUTO_REMOVAL_ERROR |
NDIS_RING_REMOVE_RECEIVED
))
{
//
// Log the fact that we have reinserted in a TR MAU...
//
acb->SentRingStatusLog = FALSE;
acb->acb_lastringstatus = 0;
NdisWriteErrorLogEntry( acb->acb_handle,
EVENT_NDIS_TOKEN_RING_CORRECTION,
0);
}
}
}
DebugPrint(1,("NF(%d): Reset Complete.\n",acb->anum));
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexCheckForHang
//
// Description:
// This function simply gets call once every two seconds to
// check on the head of the command block queue.
// It will fire off the queue if the head has been sleeping on
// the job.
//
// It also detects when the NetFlex adapter has failed, where the
// symptoms are that the adapter will transmit packets, but will
// not receive them.
//
// Input: acb - Our Driver Context.
//
// Output: True if we think the adapter is hung..
//
// Called By: Miniport Wrapper
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOLEAN
NetFlexCheckForHang(
IN NDIS_HANDLE MiniportAdapterContext
)
{
PXMIT xmitptr;
PMACREQ macreq;
PSCBREQ scbreq;
PACB acb = (PACB) MiniportAdapterContext;
//
// If we're run into a hard error, return true
//
if (acb->acb_state == AS_HARDERROR)
{
return TRUE;
}
//
// If we're not open return false
//
else if (acb->acb_state != AS_OPENED)
{
return FALSE;
}
//
// Is there a command outstanding?
//
if (acb->acb_scbreq_head != NULL)
{
scbreq = acb->acb_scbreq_head;
macreq = scbreq->req_macreq;
if (macreq != NULL)
{
// See if the command block has timed-out.
//
if (macreq->req_timeout)
{
// See if we have given it enough time
//
if ( macreq->req_timeoutcount >= 40)
{
DebugPrint(1,("NF(%d): CheckHang - Command Timed Out!\n",acb->anum));
return TRUE;
}
else
{
macreq->req_timeoutcount++;
}
}
else
{
// Start testing this command to check timeout
//
macreq->req_timeout = TRUE;
macreq->req_timeoutcount = 0;
}
}
}
if (acb->FullDuplexEnabled)
{
NdisAcquireSpinLock(&acb->XmitLock);
}
//
// See if there is any xmits which have not been processed
//
if (acb->acb_xmit_ahead != NULL)
{
xmitptr = acb->acb_xmit_ahead;
if (xmitptr->XMIT_Timeout)
{
#if DBG
if (xmitptr->XMIT_CSTAT & XCSTAT_COMPLETE)
{
DebugPrint(0,("NF(%d): CheckHang - Xmit Complete but Xmit Timed Out!\n",acb->anum));
}
else
{
DebugPrint(0,("NF(%d): CheckHang - Xmit Timed Out!\n",acb->anum));
}
#endif
if (acb->FullDuplexEnabled)
{
NdisReleaseSpinLock(&acb->XmitLock);
}
return TRUE;
}
xmitptr->XMIT_Timeout++;
}
//
// If we are in full-duplex mode then that is the extent of our
// checking to see if we are hung. If we are in half-duplex mode
// then we might want to send a dummy packet to see if our receiver
// is working correctly....
//
if (acb->FullDuplexEnabled)
{
NdisReleaseSpinLock(&acb->XmitLock);
}
//
// Should we do extreme checking?
//
if (!acb->acb_parms->utd_extremecheckforhang)
{
return(FALSE);
}
//
// Have we been getting interrupts?
//
if (acb->acb_int_count != 0)
{
//
// We got some, initialize the counts.
//
acb->acb_int_count = 0;
acb->acb_int_timeout = 0;
}
else
{
//
// Increment the timeout count.
//
acb->acb_int_timeout++;
//
// We will do this 5 times before we reset.
//
if (5 == acb->acb_int_timeout)
{
//
// Clear our counts and request a reset.
//
acb->acb_int_timeout = 0;
acb->acb_int_count = 0;
return(TRUE);
}
}
//
// Not certain we're hung yet...
//
return FALSE;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexOpenAdapter
//
// Description:
// This routine is called to queue up and issue
// an open command to the adapter.
//
// If the system is still in initialization, then
// the routine polls for the open command to complete,
// otherwise, the interrupt hander processes the complete
// and then returns to the reset handler for completion.
//
// Input:
// acb - Our Driver Context.
//
// Output:
// Success or Failure.
//
// Called By:
// NetFlexResetHandler, NetFlexBoardInitandReg
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NDIS_STATUS
NetFlexOpenAdapter(
PACB acb
)
{
NDIS_STATUS Status;
PMACREQ macreq;
PSCBREQ scbreq;
ULONG Counter=0;
//
// Open Adapter
//
acb->acb_state = AS_OPENING;
acb->acb_lastringstate = NdisRingStateOpening;
//
// Are we doing an open for reset or during initialization?
//
if (!acb->AdapterInitializing)
{
//
// Get a free block.
//
Status = NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_scbreq_free),
(PVOID *)&scbreq);
if (Status != NDIS_STATUS_SUCCESS)
{
DebugPrint(0,("NF(%d): Could not get an SCBREQ for the Open Command\n",acb->anum));
return Status;
}
acb->acb_opnblk_virtptr->OPEN_Options = acb->acb_openoptions;
scbreq->req_scb.SCB_Cmd = TMS_OPEN;
scbreq->req_scb.SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_opnblk_physptr)));
Status = NetFlexDequeue_OnePtrQ_Head( (PVOID *)&(acb->acb_macreq_free),
(PVOID *)&macreq);
if (Status != NDIS_STATUS_SUCCESS)
{
// We have no more room for another request currently
//
DebugPrint(0,("NF(%d): No macreq for the Open Command\n",acb->anum));
//
// Put the SCBREQ back...
//
NetFlexEnqueue_OnePtrQ_Head((PVOID *)&acb->acb_scbreq_free,(PVOID)scbreq);
return Status;
}
macreq->req_info = 0;
macreq->req_type = OPENADAPTER_CMP;
macreq->req_status = NDIS_STATUS_SUCCESS;
scbreq->req_macreq = macreq;
NetFlexEnqueue_TwoPtrQ_Tail((PVOID *)&(acb->acb_macreq_head),
(PVOID *)&(acb->acb_macreq_tail),
(PVOID)macreq);
//
// Verify that interrupts are enabled!
//
NetFlexEnableInterrupt(acb);
//
// Send the command out...
//
NetFlexQueueSCB(acb, scbreq);
//
// Note: acb->ErrorCode will be set while processing the
// open command complete if there is an error.
//
}
else
{
//
// Open for Initialization
//
ULONG Counter = 0;
ULONG CounterTimeOut = 2000; // 2 seconds in miliseconds
USHORT sifint_reg;
Status = NDIS_STATUS_FAILURE;
//
// Make sure the command is clear, try for 2 seconds
//
while ((acb->acb_scb_virtptr->SCB_Cmd != 0) && (Counter++ < CounterTimeOut))
NdisStallExecution((UINT)1000);
if (Counter < CounterTimeOut)
{
// Get the command together...
//
acb->acb_opnblk_virtptr->OPEN_Options = acb->acb_openoptions;
acb->acb_scb_virtptr->SCB_Cmd = TMS_OPEN;
acb->acb_scb_virtptr->SCB_Ptr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_opnblk_physptr)));
//
// Make sure interrupts are disabled!
//
NetFlexDisableInterrupt(acb);
//
// Send the SCB to the adapter.
//
NdisRawWritePortUshort(acb->SifIntPort, SIFINT_CMD);
Counter = 0;
CounterTimeOut = 20000; // 20 seconds in miliseconds
do
{
Counter++;
NdisStallExecution((UINT)1000); // 1 milisecond in microseconds
//
// Read the Sifint register.
//
NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
//
// Is there an interrupt pending?
//
if ((sifint_reg & SIFINT_SYSINT) && ((sifint_reg & INT_CODES) == INT_COMMAND))
{
// Ack the interrupt
//
sifint_reg &= ~SIFINT_SYSINT;
NdisRawWritePortUshort( acb->SifIntPort, sifint_reg);
if (acb->acb_ssb_virtptr->SSB_Status == SSB_GOOD)
{
Status = NDIS_STATUS_SUCCESS;
}
else
{
DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
if (acb->acb_ssb_virtptr->SSB_Status & SSB_OPENERR) // only Token Ring
{
Status = NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
acb->acb_lastopenstat = NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
}
else
{
acb->acb_lastopenstat = 0;
}
acb->acb_lastringstate = NdisRingStateOpenFailure;
}
//
// Issue a ssb clear.
//
NdisRawWritePortUshort( acb->SifIntPort, SIFINT_SSBCLEAR);
break;
}
} while (Counter < CounterTimeOut);
}
//
// Did it work?
//
if (Status == NDIS_STATUS_SUCCESS)
{
// Set State to Opened
//
acb->acb_state = AS_OPENED;
//
// Now lets finish the open by sending a receive command to the adapter.
//
acb->acb_rcv_whead = acb->acb_rcv_head;
//
// Now lets finish the open by sending a
// transmit command to the adapter.
//
acb->acb_xmit_whead = acb->acb_xmit_wtail = acb->acb_xmit_head;
//
// Verify that interrupts are enabled!
//
NetFlexEnableInterrupt(acb);
//
// If the adapter is ready for a command, call a
// routine that will kick off the transmit command.
//
if (acb->acb_scb_virtptr->SCB_Cmd == 0)
{
NetFlexSendNextSCB(acb);
}
else if (!acb->acb_scbclearout)
{
// Make sure we are interrupted when the SCB is
// available so that we can send the transmit command.
//
acb->acb_scbclearout = TRUE;
NdisRawWritePortUshort( acb->SifIntPort, (USHORT) SIFINT_SCBREQST);
}
}
else
{
// Set State back to Initialized since the open failed.
//
acb->acb_state = AS_INITIALIZED;
}
}
return Status;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexCloseAdapter
//
// Description:
// This routine is called to queue up and issue an close
// command to the adapter.
//
// Input:
// acb - Our Driver Context.
//
// Output:
// Success or Failure.
//
// Called By:
// NetFlexResetHandler
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOLEAN
NetFlexCloseAdapter(
PACB acb)
{
USHORT Counter = 0;
USHORT CounterTimeOut = 500;
if ((acb->acb_state == AS_OPENED) ||
(acb->acb_state == AS_RESETTING))
{
//
// Make sure the command is clear, try for 5 seconds
//
while ((acb->acb_scb_virtptr->SCB_Cmd != 0) && (Counter++ < CounterTimeOut)) {
NdisStallExecution((UINT)1000);
}
if (acb->acb_scb_virtptr->SCB_Cmd == 0)
{
//
// Send Close,
//
acb->acb_scb_virtptr->SCB_Cmd = TMS_CLOSE;
NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_CMD);
acb->acb_state = AS_CLOSING;
//
// Give it a little time...
//
NdisStallExecution((UINT)10000);
}
return (Counter >= CounterTimeOut);
}
return TRUE;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexHalt
//
// Description:
// Removes an adapter previously initialized.
//
// Input:
// MacAdapterContext - Actually as pointer to an PACB.
//
// Output:
// None.
//
// Called By:
// Miniport Wrapper.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID
NetFlexHalt(
IN NDIS_HANDLE MiniportAdapterContext
)
{
USHORT actl_reg;
BOOLEAN ReceiveResult1;
BOOLEAN ReceiveResult2;
//
// The adapter to halt
//
PACB acb = (PACB) MiniportAdapterContext;
DebugPrint(1,("NF(%d): Halt Called!\n", acb->anum));
//
// Cancel all of our timers.
//
NdisMCancelTimer(&acb->DpcTimer, &ReceiveResult1);
NdisMCancelTimer(&acb->ResetTimer, &ReceiveResult2);
//
// Is one of the timer dpc's going to fire?
//
if (!ReceiveResult1 || !ReceiveResult2)
{
NdisStallExecution(500000);
}
//
// Send Close
//
NetFlexCloseAdapter(acb);
//
// Stop Adapter
//
NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&actl_reg));
actl_reg |= ACTL_ARESET;
NdisRawWritePortUshort( acb->SifActlPort, (USHORT) actl_reg);
//
// Complete mappings
//
NetFlexRemoveRequests(acb);
//
// Free adapter resources
//
NetFlexDeregisterAdapter(acb);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexShutdown
//
// Description:
// Removes an adapter previously initialized.
//
// Input:
// MacAdapterContext - Actually as pointer to an PACB.
//
// Output:
// None.
//
// Called By:
// Miniport Wrapper.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID
NetFlexShutdown(
IN NDIS_HANDLE MiniportAdapterContext
)
{
PACB acb = (PACB) MiniportAdapterContext;
USHORT actl_reg;
//
// Send Close.
//
NetFlexCloseAdapter(acb);
//
// Stop Adapter
//
NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&actl_reg));
actl_reg |= ACTL_ARESET;
NdisRawWritePortUshort( acb->SifActlPort, (USHORT) actl_reg);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexRemoveRequests
//
// Description:
// Clean up queues during a Reset and Halt
//
// Input:
// acb - Pointer to acb
//
// Output:
// None
//
// Called By:
// NetFlexResetHandler,
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID
NetFlexRemoveRequests(
PACB acb
)
{
PXMIT xmitptr;
PRCV rcvptr;
UINT curmap;
PNDIS_PACKET packet;
PNDIS_BUFFER curbuf;
PMULTI_TABLE mt;
PETH_OBJS ethobjs;
USHORT i;
PSCBREQ scbreq;
PMACREQ macreq;
//
// Terminate all the transmits on the active queue.
//
xmitptr = acb->acb_xmit_ahead;
while (xmitptr != NULL)
{
// Did we use an internal buffer?
//
if (xmitptr->XMIT_OurBufferPtr != NULL)
{
// We've used one of our adapter buffers, so put the adapter
// buffer back on the free list.
//
if (xmitptr->XMIT_OurBufferPtr->BufferSize != acb->acb_smallbufsz) {
xmitptr->XMIT_OurBufferPtr->Next = acb->OurBuffersListHead;
acb->OurBuffersListHead = xmitptr->XMIT_OurBufferPtr;
}
else { // small buffer
xmitptr->XMIT_OurBufferPtr->Next = acb->SmallBuffersListHead;
acb->SmallBuffersListHead = xmitptr->XMIT_OurBufferPtr;
}
xmitptr->XMIT_OurBufferPtr = NULL;
}
else
{
packet = xmitptr->XMIT_Packet;
if ( packet != NULL ) {
curmap = xmitptr->XMIT_MapReg;
// Complete mappings, but don't complete the sends...
//
NdisQueryPacket(
packet,
NULL,
NULL,
(PNDIS_BUFFER *) &curbuf,
NULL
);
while (curbuf)
{
NdisMCompleteBufferPhysicalMapping(
acb->acb_handle,
(PNDIS_BUFFER) curbuf,
curmap
);
curmap++;
if (curmap == acb->acb_maxmaps)
{
curmap = 0;
}
NdisGetNextBuffer(curbuf, &curbuf);
}
}
}
xmitptr->XMIT_CSTAT = 0;
xmitptr->XMIT_Packet = NULL;
//
// If we've reached the active queue tail, we are done.
//
if (xmitptr == acb->acb_xmit_atail)
xmitptr = NULL;
else
xmitptr = xmitptr->XMIT_Next;
}
acb->acb_xmit_ahead = acb->acb_xmit_atail = NULL;
acb->acb_avail_xmit = acb->acb_parms->utd_maxtrans;
//
// Clean up the Receive Lists
//
rcvptr = acb->acb_rcv_head;
do {
//
// Mark receive list available
//
rcvptr->RCV_CSTAT =
((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO;
//
// Get next receive list
//
rcvptr = rcvptr->RCV_Next;
} while (rcvptr != acb->acb_rcv_head);
//
// Clean up multicast if ethernet.
//
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
{
ethobjs = (PETH_OBJS)acb->acb_spec_objs;
NdisZeroMemory(
ethobjs->MulticastEntries,
ethobjs->MaxMulticast * NET_ADDR_SIZE
);
ethobjs->NumberOfEntries = 0;
}
//
// Clean up SCB Requests
//
while (acb->acb_scbreq_head)
{
NetFlexDequeue_TwoPtrQ_Head((PVOID *)&acb->acb_scbreq_head,
(PVOID *)&acb->acb_scbreq_tail,
(PVOID *)&scbreq);
NdisZeroMemory(scbreq, sizeof(SCBREQ));
NetFlexEnqueue_OnePtrQ_Head((PVOID *)&acb->acb_scbreq_free,(PVOID)scbreq);
}
//
// Clean up MacReq Requests
//
while (acb->acb_macreq_head)
{
NetFlexDequeue_TwoPtrQ_Head((PVOID *)&acb->acb_macreq_head,
(PVOID *)&acb->acb_macreq_tail,
(PVOID *)&macreq);
NdisZeroMemory(macreq, sizeof(MACREQ));
NetFlexEnqueue_OnePtrQ_Head( (PVOID *)&acb->acb_macreq_free,
(PVOID)macreq);
}
//
// Clean Up some more State stuff...
//
acb->RequestInProgress = FALSE;
acb->acb_scbclearout = FALSE;
acb->acb_scbreq_next = NULL;
acb->acb_gen_objs.cur_filter = 0;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexAdapterReset
//
// Description:
// This routine resets the Super Eagle or Eagle
//
// Input:
// mode - 0 = Hard Reset, ~0 = Soft Reset
//
// Output:
// status - NDIS_STATUS_SUCCESS if Success
//
// Called By:
// NetFlexResetHandler
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NDIS_STATUS
NetFlexAdapterReset(
PACB acb,
INT mode)
{
NDIS_STATUS status;
//
// Which Reset?
//
if (mode == HARD_RESET)
{
// Do the reset
//
NdisRawWritePortUshort(acb->SifActlPort, ACTL_HARD_RESET);
//
// Wait 15 milliseconds to let the reset take place.
//
NdisStallExecution((UINT)15000); // Wait 15 milliseconds
//
// Call NetFlexSetupNetType to verify everything gets set correctly.
//
NetFlexSetupNetType(acb);
//
// Make sure that promiscuous mode is turned off
//
acb->acb_opnblk_virtptr->OPEN_Options &= SWAPS((USHORT) ~(OOPTS_CNMAC | OOPTS_CMAC));
//
// Download and initialize the adapter
//
if ((status = NetFlexDownload(acb)) == NDIS_STATUS_SUCCESS)
{
// Verify Bring Up Diagnostics
//
if ((status = NetFlexBudWait(acb))== NDIS_STATUS_SUCCESS)
{
// Initialize the adapter
//
if ((status = NetFlexInitializeAdapter(acb)) == NDIS_STATUS_SUCCESS)
{
// Yes, do we need to save the address that will give up our upstream address?
//
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
{
// Yes, get it...
//
NetFlexGetUpstreamAddrPtr(acb);
}
}
}
}
if (status != NDIS_STATUS_SUCCESS)
{
DebugPrint(0,("NF(%d): Hard Reset Failed!\n",acb->anum));
}
}
else
{
// A Soft Reset was requested. Write the reset code into the
// SIF interrupt register.
//
NdisRawWritePortUshort(acb->SifIntPort, SIF_SOFT_RESET);
//
// Write the saved ACTL Settings.
//
NdisRawWritePortUshort( acb->SifActlPort, acb->actl_reg);
//
// Go check to see if the bring up diagnostics worked...
//
if ((status = NetFlexBudWait(acb)) == NDIS_STATUS_SUCCESS)
{
status = NetFlexInitializeAdapter(acb);
}
if (status != NDIS_STATUS_SUCCESS)
{
DebugPrint(0,("NF(%d): Soft Reset Failed!\n",acb->anum));
}
}
return status;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexBudWait
//
// Description:
// This routine waits for the Bring Up Diags
// (BUD) code to finish on the Super Eagle or Eagle
//
// Input:
// acb - Our Driver Context.
//
// Output:
// status - 0 = SUCCESS, ~0 = failure
//
// Called By:
// NetFlexAdapterReset, NetFlexDownload
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NDIS_STATUS
NetFlexBudWait(
PACB acb
)
{
int i;
USHORT value;
//
// Wait for Bring Up Diagnotics to start.
//
for (i = 0; i < 3000; i++)
{
NdisStallExecution((UINT)1000); /* Wait 1 millisecond */
NdisRawReadPortUshort(acb->SifIntPort, (PUSHORT) &value);
if ((value & 0x00f0) >= 0x0020)
break;
}
if (i >= 3000)
{
// Diags never got started!!
//
DebugPrint(0,("NF(%d): Diags never got started\n",acb->anum));
DebugPrint(0,("NF(%d): Sif int is 0x%x\n",acb->anum,value));
return(NDIS_STATUS_FAILURE);
}
//
// Wait for either success or failure.
//
for (i = 0; i < 3000; i++)
{
NdisStallExecution((UINT)1000); /* Wait 1 millisecond */
NdisRawReadPortUshort(acb->SifIntPort, (PUSHORT) (&value));
if ((value & 0x00f0) >= 0x0030)
break;
}
if (i >= 3000)
{
// Diags never finished!!
//
DebugPrint(0,("NetFlex: Diags never finished\n"));
return(NDIS_STATUS_FAILURE);
}
if ((value & 0x00f0) != 0x0040)
{
// Diags failed!!
//
DebugPrint(0,("NF(%d): Diags Failed!\n",acb->anum));
return(NDIS_STATUS_FAILURE);
}
else
{
// The Diags passed OK!
//
DebugPrint(0,("NF(%d): Diags Passed OK\n",acb->anum));
return(NDIS_STATUS_SUCCESS);
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexInitializeAdapter
//
// Description:
// This routine initializes the adapter for open.
//
// Input:
// acb - Our Driver Context
//
// Output:
// Returns a NDIS_STATUS_SUCCESS if the adapter
// initialized properly. Otherwise, an error code is returned,
// showing that an initialization error has occurred.
//
// Called By:
// NetFlexProcess_Open_Request
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NDIS_STATUS
NetFlexInitializeAdapter(
PACB acb
)
{
ULONG temp;
INT i;
SHORT *ps;
//
// Set the SIF address register to point to the INIT block location
// and copy the INIT block info into the data inc register.
// make sure we are at chapter 1.
//
NdisRawWritePortUshort(acb->SifAddrxPort, (USHORT) 1);
NdisRawWritePortUshort(acb->SifAddrPort, (USHORT) ADDR_INIT);
for (i = 0, ps = (SHORT *) &acb->acb_initblk;
i < (SIZE_INIT / 2); i++, ps++)
{
NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) *ps);
}
//
// Now write the SCB and SSB addresses into the
// data inc register.
//
temp = CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_scb_physptr) + sizeof(USHORT));
NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) (temp >> 16));
NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) temp);
temp = CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_ssb_physptr));
NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) (temp >> 16));
NdisRawWritePortUshort(acb->SifDIncPort, (USHORT) temp);
//
// Now write the execute command out to the SIF.
//
NdisRawWritePortUshort(acb->SifIntPort, (USHORT) SIFINT_CMD);
//
// Wait for the intialization to complete.
//
for (i = 0; i < 3000; i++)
{
NdisStallExecution((UINT)1000); /* Wait 1 millisecond */
NdisRawReadPortUshort(acb->SifIntPort, (PUSHORT) (&temp));
if ((temp & 0x00ff) != 0x0040)
break;
}
if ( (i >= 3000) || ((temp & 0x00ff) != 0x0000) )
{
//
// Initialization never finished!! OR Initialization failed!!
//
return(NDIS_STATUS_FAILURE);
}
return(NDIS_STATUS_SUCCESS);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexDownload
//
// Description:
// This routine downloads the TMS380 MAC code to the
// Super Eagle or Eagle.
//
// Input:
// acb - Our Driver Context.
//
// Output:
// status - 0 = SUCCESS, ~0 = failure
//
// Called By:
// NetFlexAdapterReset
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NDIS_STATUS
NetFlexDownload(
PACB acb
)
{
LONG j;
USHORT temp_value;
LONG totalbytes;
PUSHORT MappedBuffer;
PDL_STRUCT ds;
PUCHAR dataptr;
if (macgbls.DownloadCode == NULL)
{
DebugPrint(0,("NF(%d) - No Download code!\n",acb->anum));
return NDIS_STATUS_FAILURE;
}
//
// Get our pointers ready. Currently the MappedBuffer is pointing
// to the length of the header. The data begins after the header.
// Also the section headers are contained within the header just
// past the length field which is 2 bytes long.
//
MappedBuffer = macgbls.DownloadCode;
dataptr = (PUCHAR)(*MappedBuffer + (PUCHAR)(MappedBuffer) );
ds = (PDL_STRUCT)( (PUCHAR)(MappedBuffer) + 2);
//
// If we're using FPA skip to the second set of mac code. The
// order of the mac code is TOK, ETH, TOKFPA and ETHFPA.
//
if (acb->acb_usefpa)
{
for (j=0; j<2; j++)
{
totalbytes = 0;
while (ds->dl_chap != 0x7ffe)
{
totalbytes += ds->dl_bytes;
ds++;
}
MappedBuffer = (PUSHORT)(dataptr + totalbytes);
dataptr = (PUCHAR)(*MappedBuffer + (PUCHAR)(MappedBuffer) );
ds = (PDL_STRUCT)( (PUCHAR)(MappedBuffer) + 2);
}
}
//
// No need to perform a hard reset of the Super Eagle or Eagle
// since we have already done.
//
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3)
{
//
// We need to skip around the download code for Token Ring.
// Therefore, find the end of the token ring download code.
//
totalbytes = 0;
while (ds->dl_chap != 0x7ffe)
{
totalbytes += ds->dl_bytes;
ds++;
}
MappedBuffer = (PUSHORT)(dataptr + totalbytes);
dataptr = (PUCHAR)(*MappedBuffer + (PUCHAR)(MappedBuffer) );
ds = (PDL_STRUCT)( (PUCHAR)(MappedBuffer) + 2);
}
//
// Download each section of data
//
while (ds->dl_chap != 0x7ffe)
{
NdisRawWritePortUshort( acb->SifAddrxPort, (USHORT) ds->dl_chap);
NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) ds->dl_addr);
for (j = 0; j < (ds->dl_bytes / 2); j++)
{
NdisRawWritePortUshort( acb->SifDIncPort,
(USHORT)(SWAPS(*( (PUSHORT)(dataptr)))) );
dataptr += 2;
}
ds++;
}
//
// Now turn off the CP halt bit in the ACTL register to let the
// TMS380 chipset startup. Wait for the BUD to finish and report
// the appropriate status code.
//
NdisRawReadPortUshort( acb->SifActlPort, (PUSHORT) (&temp_value));
temp_value &= ~ACTL_CPHALT;
NdisRawWritePortUshort( acb->SifActlPort, (USHORT) temp_value);
//
// Save the Current Actl value
//
acb->actl_reg = temp_value;
return NDIS_STATUS_SUCCESS;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexSetupNetType
//
// Description:
// This routine sets up the Super Eagle to run the type of
// network and network speed requested by config. It assumes
// that the adapter is in a halted state after reset.
//
// Input:
// acb - Our Driver Context.
//
// Output:
// Returns NDIS_STATUS_SUCCESS for a successful
// completion. Otherwise, an error code is returned.
//
// Called By:
// NetFlexResetHandler, NetFlexBoardInitandReg
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID
NetFlexSetupNetType(
PACB acb
)
{
USHORT cfg_reg, actl_reg;
USHORT cfg_reg2, tmp_reg;
UCHAR cfg_regl, cfg_regh;
NDIS_MEDIUM nettype;
ULONG netspeed;
USHORT board_id = acb->acb_boardid;
//
// Get the network type and speed the user set up in EISA config.
// The port address for the cfg port is odd which will cause an
// alignment fault on RISC.
//
// NdisRawReadPortUshort(acb->AdapterConfigPort, &cfg_reg);
NdisRawReadPortUchar(acb->AdapterConfigPort, &cfg_regl);
NdisRawReadPortUchar(acb->AdapterConfigPort+1, &cfg_regh);
cfg_reg = (cfg_regh << 8) + cfg_regl;
//
// Read the actl register and turn off the reset bit.
//
NdisRawReadPortUshort( acb->SifActlPort, &actl_reg);
actl_reg &= ~ACTL_ARESET;
//
// If we're using FPA turn on ROM reserved bit 11
//
if (acb->acb_usefpa)
{
actl_reg |= ACTL_ROM;
}
//
// If the board is a Cpqtok board, just fill in the parameters,
// reset the board, and get out. If the board is a Netflx board,
// fill in the parameters, reset the board specifying the type and
// speed of the network, make sure we get what we asked for, and
// then get out.
if ( (board_id & NETFLEX_REVMASK) == CPQTOK_ID &&
(board_id != DURANGO_ID))
{
// This is a JUPITER board
//
DebugPrint(1,("NF(%d): Setting up Jupiter\n",acb->anum));
if (acb->AdapterInitializing)
{
nettype = NdisMedium802_5;
if (cfg_reg & CFG_16MBS)
netspeed = 4;
else
netspeed = 16;
//
// Setup the ProcessReceiveHandler
//
acb->ProcessReceiveHandler = &NetFlexProcessTrRcv;
}
}
else if ( ((board_id & NETFLEX_REVMASK) == NETFLEX_ID) ||
((board_id & NETFLEX_REVMASK) == RODAN_ID) ||
(board_id == DURANGO_ID) )
{
//
// This is a NETFLEX, MAPLE, DURANGO or RODAN board
//
// The Nselout1 bit has been redefined as the media bit. If this
// bit is set to a 1, AUI/DB-9 has been selected. Otherwise,
// unshielded has been selected.
// If the CFG_MEDIA bit is set, Unshielded has been selected.
DebugPrint(1,("NF(%d): Setting up Netflx, Durango, or Rodan\n",acb->anum));
if (cfg_reg & CFG_MEDIA)
{
actl_reg &= (~ACTL_NSELOUT1);
}
else
{
actl_reg |= ACTL_NSELOUT1;
}
if (cfg_reg & CFG_16MBS)
{
actl_reg |= ACTL_NSELOUT0;
}
else
{
actl_reg &= (~ACTL_NSELOUT0);
}
}
else
{
// This is a BONSAI board
//
// Bits 3 and 2 represent net type for head 1 and 2, respectively.
DebugPrint(1,("NF(%d): Setting up Bonsai head %d\n",acb->anum,acb->acb_portnumber));
if (acb->acb_portnumber == PORT1)
{
if (cfg_reg & CFG_DUALPT_ADP1)
{
actl_reg &= (~ACTL_NSELOUT1);
}
else
{
actl_reg |= ACTL_NSELOUT1;
}
}
else
{
if (cfg_reg & CFG_DUALPT_ADP2)
{
actl_reg &= (~ACTL_NSELOUT1);
}
else
{
actl_reg |= ACTL_NSELOUT1;
}
}
}
NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
//
// If this is during an initial initialization
//
if (acb->AdapterInitializing)
{
//
// If this is a NETFLEX type board, make sure we got what
// we were asking for
//
if ( ( (board_id & NETFLEX_REVMASK) == NETFLEX_ID ) ||
( (board_id & NETFLEX_REVMASK) == BONSAI_ID ) ||
( (board_id & NETFLEX_REVMASK) == RODAN_ID ) ||
(board_id == DURANGO_ID) )
{
NdisRawReadPortUshort( acb->SifActlPort, &actl_reg);
//
// Now, find out our network type and speed.
//
if (actl_reg & ACTL_TEST1)
{
//
// We are token ring. Are we 16 mbps or 4 mbps.
//
nettype = NdisMedium802_5;
if (actl_reg & ACTL_TEST0)
netspeed = 4;
else
netspeed = 16;
//
// Setup the ProcessReceiveHandler
//
acb->ProcessReceiveHandler = &NetFlexProcessTrRcv;
}
else
{
// Ethernet is selected
nettype = NdisMedium802_3;
netspeed = 10;
//
// Setup the ProcessReceiveHandler
//
acb->ProcessReceiveHandler = &NetFlexProcessEthRcv;
}
}
//
// Initialize some of acb fields as well as adapter information.
//
acb->acb_gen_objs.media_type_in_use = nettype;
acb->acb_gen_objs.link_speed = netspeed;
}
else
{
nettype = acb->acb_gen_objs.media_type_in_use;
netspeed = acb->acb_gen_objs.link_speed;
}
//
// Check Full Duplex Support... Ethernet Only!
//
if (nettype == NdisMedium802_3)
{
// Do we want Full Duplex?
//
if (acb->acb_portnumber != PORT2)
{
NdisRawReadPortUchar( acb->BasePorts + CFG_REG2_OFF , &cfg_reg2);
if (cfg_reg2 & CFG_FULL_DUPLEX)
{
acb->FullDuplexEnabled = TRUE;
}
}
else
{
NdisRawReadPortUchar( acb->BasePorts + CFG_REG2_OFF - DUALHEAD_CFG_PORT_OFFSET, &cfg_reg2);
if (cfg_reg2 & CFG_FULL_DUPLEX_HEAD2)
{
acb->FullDuplexEnabled = TRUE;
}
}
if (acb->FullDuplexEnabled)
{
DebugPrint(1,("NF(%d): Enabling FullDuplex Support!\n",acb->anum));
if ( (board_id & NETFLEX_REVMASK) == BONSAI_ID )
{
// On Bansai, disable colision detect by writing to 0xZc67 for H2 0xZc66 for H1
//
if (acb->acb_portnumber == PORT2)
{
NdisRawWritePortUchar( acb->ExtConfigPorts + LOOP_BACK_ENABLE_HEAD2_OFF , 0xff);
}
else
{
NdisRawWritePortUchar( acb->ExtConfigPorts + LOOP_BACK_ENABLE_HEAD1_OFF , 0xff);
}
}
else
{
// On NetFlex/NetFlex-2, disable colision detect by writing to 0xZc65
// until status indicates that it is ok, per Ray...
//
do
{
NdisRawWritePortUchar( acb->ExtConfigPorts + LOOP_BACK_ENABLE_OFF , 0xff);
NdisStallExecution((UINT)1000); // Wait 1 milliseconds
NdisRawReadPortUchar( acb->ExtConfigPorts + LOOP_BACK_STATUS_OFF , &tmp_reg);
} while (tmp_reg & COLL_DETECT_ENABLED);
}
}
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexFinishUnloading
//
// Description: This routine finishes the unloading process
//
// Input: None.
//
// Output: None.
//
// Calls: NdisDeregisterMac,NdisTerminateWrapper,
//
// Called By: NetFlexUnload, NetFlexDeregisterAdapter
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID NetFlexFinishUnloading(VOID)
{
//
//
// Free the memory with the download software in it.
//
if (macgbls.DownloadCode != NULL) {
NdisFreeMemory( macgbls.DownloadCode,
macgbls.DownloadLength,
0);
}
NdisTerminateWrapper(macgbls.mac_wrapper,(PVOID)NULL);
macgbls.mac_wrapper = NULL;
macgbls.DownloadCode= NULL;
macgbls.DownloadLength = 0;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Routine Name: NetFlexDeregisterAdapter
//
// Description:
// This routine finishes the removal of an adapter.
//
// Input:
// acb - Our Driver Context.
//
// Output:
// None.
//
// Called By:
// NetFlexHalt, NetFlexInitialize
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
VOID NetFlexDeregisterAdapter(PACB acb)
{
//
// Remove the acb from the mac's acb list
//
NetFlexDequeue_OnePtrQ((PVOID *) &macgbls.mac_adapters,(PVOID)acb);
if (acb->acb_interrupt.InterruptObject != NULL)
NdisMDeregisterInterrupt(&acb->acb_interrupt);
//
// Deallocate the memory for the acb.
//
NetFlexDeallocateAcb(acb);
if ((macgbls.mac_adapters == NULL) && !macgbls.Initializing)
{
NetFlexFinishUnloading();
}
}