978 lines
27 KiB
C
978 lines
27 KiB
C
|
||
//**********************************************************************
|
||
//**********************************************************************
|
||
//
|
||
// File Name: INT.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: NetFlexISR
|
||
//
|
||
// Description:
|
||
// This routine is the ISR for this Netflx mac driver.
|
||
// This routine determines if the interrupt is for it
|
||
// and if so, it clears the system interrupt bit of
|
||
// the sifint register.
|
||
//
|
||
// Input:
|
||
// Context - Our Driver Context for this adapter or head.
|
||
//
|
||
// Output:
|
||
// Returns TRUE if the interrupt belongs to the
|
||
// adapter and returns FALSE if it does not
|
||
// belong to the adapter.
|
||
//
|
||
// Called By:
|
||
// Miniport Wrapper
|
||
//
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
VOID NetFlexISR(
|
||
OUT PBOOLEAN InterruptRecognized,
|
||
OUT PBOOLEAN QueueDpc,
|
||
IN PVOID Context )
|
||
{
|
||
PACB acb;
|
||
USHORT sifint_reg;
|
||
USHORT actl_reg;
|
||
|
||
acb = (PACB) Context;
|
||
|
||
//
|
||
// Read the Sifint register.
|
||
//
|
||
NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
|
||
|
||
//
|
||
// See if the System Interrupt bit is set. If it is, this is an
|
||
// interrupt for us.
|
||
//
|
||
if (sifint_reg & SIFINT_SYSINT)
|
||
{
|
||
//
|
||
// Acknowledge and Clear Int
|
||
//
|
||
if (!acb->InterruptsDisabled)
|
||
{
|
||
actl_reg = acb->actl_reg & ~ACTL_SINTEN;
|
||
NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
|
||
DebugPrint(3,("NF(%d)(D)\n",acb->anum));
|
||
acb->InterruptsDisabled = TRUE;
|
||
|
||
//
|
||
// Return that we recognize it
|
||
//
|
||
*InterruptRecognized = TRUE;
|
||
*QueueDpc = TRUE;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// It appears that a second head is generating
|
||
// the interrupt, and we have a DPC queued to
|
||
// process our int, return that we don't recognize it
|
||
// so that the oterh head's isr gets called...
|
||
//
|
||
*InterruptRecognized = FALSE;
|
||
*QueueDpc = FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Return that we don't recognize it
|
||
//
|
||
*InterruptRecognized = FALSE;
|
||
*QueueDpc = FALSE;
|
||
}
|
||
}
|
||
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
//
|
||
// Routine Name: NetFlexDeferredTimer
|
||
//
|
||
// Description:
|
||
// This routine is called every 10ms to check to see
|
||
// if there is any receives or transmits which need
|
||
// to be cleaned up since we don't require an interrupt
|
||
// for each frame.
|
||
//
|
||
// Input:
|
||
// acb - Our Driver Context for this adapter or head.
|
||
//
|
||
// Output:
|
||
// None.
|
||
//
|
||
// Called By:
|
||
// Miniport Wrapper via acb->DpcTimer
|
||
//
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
|
||
#ifdef NEW_DYNAMIC_RATIO
|
||
UINT MaxIntRatio = 4;
|
||
|
||
//
|
||
// New Threshold for xmit disabled case.
|
||
//
|
||
UINT RaiseIntThreshold = 26;
|
||
|
||
//
|
||
// Run threshold of 1.5 seconds instead of 200msecs.
|
||
//
|
||
UINT RunThreshold = 15;
|
||
UINT RatioCheckCount = 10;
|
||
#else
|
||
|
||
UINT sw24 = 220;
|
||
UINT sw21 = 40;
|
||
#endif
|
||
|
||
#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
|
||
BOOLEAN EnableDynamicRatio = TRUE;
|
||
UINT ratio = 1;
|
||
#endif
|
||
|
||
VOID NetFlexDeferredTimer(
|
||
IN PVOID SystemSpecific1,
|
||
IN PACB acb,
|
||
IN PVOID SystemSpecific2,
|
||
IN PVOID SystemSpecific3
|
||
)
|
||
{
|
||
USHORT ReceivesProcessed = 0;
|
||
USHORT sifint_reg;
|
||
UINT IntAve;
|
||
|
||
//
|
||
// Indicate that a timer has expired.
|
||
//
|
||
DebugPrint(3,("NF(%d) - Defered Timer Expired!\n",acb->anum));
|
||
|
||
//
|
||
// If we are resetting, get out...
|
||
//
|
||
if (acb->acb_state == AS_RESETTING)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// See if there are any recieves to do...
|
||
//
|
||
|
||
if (acb->acb_rcv_head->RCV_CSTAT & RCSTAT_COMPLETE)
|
||
{
|
||
//
|
||
// Increment the interrupt count.
|
||
//
|
||
acb->acb_int_count++;
|
||
|
||
// yes, do them...
|
||
//
|
||
ReceivesProcessed = acb->ProcessReceiveHandler(acb);
|
||
}
|
||
|
||
//
|
||
// See if there are any transmits to do...
|
||
//
|
||
NetFlexProcessXmit(acb);
|
||
|
||
//
|
||
// Processed any receives which need IndicateReceiveComplete?
|
||
//
|
||
if (ReceivesProcessed)
|
||
{
|
||
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
|
||
{
|
||
// Token Ring
|
||
//
|
||
NdisMTrIndicateReceiveComplete(acb->acb_handle);
|
||
}
|
||
else
|
||
{
|
||
// Ethernet
|
||
//
|
||
NdisMEthIndicateReceiveComplete(acb->acb_handle);
|
||
}
|
||
}
|
||
|
||
|
||
if ( ++acb->timer_run_count >= RatioCheckCount )
|
||
{
|
||
acb->timer_run_count = 0;
|
||
|
||
#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
|
||
if ( EnableDynamicRatio )
|
||
{
|
||
#endif
|
||
|
||
#ifdef NEW_DYNAMIC_RATIO
|
||
|
||
//
|
||
// Should we increase the ratio?
|
||
//
|
||
if ( acb->handled_interrupts > RaiseIntThreshold)
|
||
{
|
||
acb->current_run_down = 0;
|
||
if (acb->XmitIntRatio == 1)
|
||
{
|
||
if ( ++acb->current_run_up > RunThreshold )
|
||
{
|
||
#ifdef XMIT_INTS
|
||
acb->XmitIntRatio = acb->acb_maxtrans;
|
||
#endif
|
||
acb->acb_gen_objs.interrupt_ratio_changes++;
|
||
acb->current_run_up = 0;
|
||
DebugPrint(1,("NF(%d) - RcvIntRatio = %d\n",acb->anum,acb->RcvIntRatio));
|
||
}
|
||
}
|
||
}
|
||
//
|
||
// Or, should we decrease it?
|
||
//
|
||
else //if ( acb->handled_interrupts < LowerIntThreshold )
|
||
{
|
||
acb->current_run_up = 0;
|
||
if (acb->XmitIntRatio != 1)
|
||
|
||
{
|
||
if ( ++acb->current_run_down > RunThreshold )
|
||
{
|
||
|
||
#ifdef XMIT_INTS
|
||
acb->XmitIntRatio = 1;
|
||
#endif
|
||
acb->acb_gen_objs.interrupt_ratio_changes++;
|
||
acb->current_run_down = 0;
|
||
DebugPrint(1,("NF(%d) - RcvIntRatio = %d\n",acb->anum,acb->RcvIntRatio));
|
||
}
|
||
}
|
||
}
|
||
|
||
#else // !defined(NEW_DYNAMIC_RATIO)
|
||
|
||
if ( acb->XmitIntRatio != 1 )
|
||
{
|
||
if ( acb->handled_interrupts < sw21 )
|
||
{
|
||
if ( ++acb->current_run > RunThreshold )
|
||
{
|
||
|
||
#ifdef XMIT_INTS
|
||
acb->XmitIntRatio = 1;
|
||
#endif
|
||
acb->RcvIntRatio = 1;
|
||
acb->acb_gen_objs.interrupt_ratio_changes++;
|
||
acb->current_run = 0;
|
||
acb->sw24 += 3;
|
||
|
||
acb->cleartime = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
acb->current_run = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( acb->handled_interrupts > sw24 )
|
||
{
|
||
if ( ++acb->current_run > RunThreshold )
|
||
{
|
||
|
||
#ifdef XMIT_INTS
|
||
acb->XmitIntRatio = ratio;
|
||
#endif
|
||
acb->RcvIntRatio = ratio;
|
||
acb->acb_gen_objs.interrupt_ratio_changes++;
|
||
acb->current_run = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
acb->current_run = 0;
|
||
}
|
||
}
|
||
|
||
#ifdef DYNAMIC_RATIO_HISTORY
|
||
acb->IntHistory[acb->Hndx] = acb->handled_interrupts;
|
||
acb->RatioHistory[acb->Hndx] = (UCHAR)acb->RcvIntRatio;
|
||
|
||
if ( ++acb->Hndx >= 1024 )
|
||
{
|
||
acb->Hndx = 0;
|
||
}
|
||
#endif
|
||
//
|
||
// The switchover value to turbo gets incremented each time
|
||
// we drop to normal mode. We reset this value every x seconds.
|
||
// This will prevent the driver from toggling rapidly between
|
||
// turbo <-> normal mode.
|
||
//
|
||
if ( ++acb->cleartime > 50 )
|
||
{
|
||
acb->sw24 = sw24;
|
||
acb->cleartime = 0;
|
||
}
|
||
|
||
#endif // !NEW_DYNAMIC_RATIO
|
||
|
||
#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
|
||
}
|
||
else
|
||
{
|
||
|
||
#ifdef XMIT_INTS
|
||
acb->XmitIntRatio = ratio;
|
||
#endif
|
||
acb->RcvIntRatio = ratio;
|
||
}
|
||
#endif // ALLOW_DISABLE_DYNAMIC_RATIO
|
||
|
||
acb->acb_gen_objs.interrupt_count = acb->handled_interrupts;
|
||
acb->handled_interrupts = 0;
|
||
}
|
||
|
||
//
|
||
// Set the timer...
|
||
//
|
||
NdisMSetTimer(&acb->DpcTimer, 10);
|
||
|
||
} // NetFlexDeferredTimer
|
||
|
||
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
//
|
||
// Routine Name: NetFlexHandleInterrupt
|
||
//
|
||
// Description:
|
||
// This routine is the deferred processing
|
||
// routine for all adapter interrupts.
|
||
//
|
||
// Input:
|
||
// acb - Our Driver Context for this adapter or head.
|
||
//
|
||
// Output:
|
||
// None
|
||
//
|
||
// Called By:
|
||
// Miniport Wrapper
|
||
//
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
VOID
|
||
NetFlexHandleInterrupt(
|
||
IN NDIS_HANDLE MiniportAdapterContext
|
||
)
|
||
{
|
||
USHORT sifint_reg;
|
||
USHORT tmp_reg;
|
||
USHORT ReceivesProcessed = 0;
|
||
|
||
PACB acb = (PACB) MiniportAdapterContext;
|
||
|
||
//
|
||
// Read the SifInt
|
||
//
|
||
NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
|
||
|
||
while (sifint_reg & SIFINT_SYSINT)
|
||
{
|
||
//
|
||
// Ack the interrupt
|
||
//
|
||
sifint_reg &= ~SIFINT_SYSINT;
|
||
NdisRawWritePortUshort( acb->SifIntPort, sifint_reg);
|
||
|
||
//
|
||
// mask off the int code
|
||
//
|
||
sifint_reg &= INT_CODES;
|
||
|
||
//
|
||
// See if there are any recieves to do...
|
||
//
|
||
if (acb->acb_rcv_head->RCV_CSTAT & RCSTAT_COMPLETE)
|
||
{
|
||
//
|
||
// Increment the interrupt count.
|
||
//
|
||
acb->acb_int_count++;
|
||
|
||
//
|
||
// yes, do them...
|
||
//
|
||
acb->handled_interrupts++;
|
||
ReceivesProcessed += acb->ProcessReceiveHandler(acb);
|
||
}
|
||
|
||
//
|
||
// See if there are any transmits to do...
|
||
//
|
||
NetFlexProcessXmit(acb);
|
||
|
||
switch (sifint_reg)
|
||
{
|
||
case INT_SCBCLEAR:
|
||
acb->acb_scbclearout = FALSE;
|
||
//
|
||
// Is the SCB really clear?
|
||
//
|
||
// If the SCB is clear, send a SCB command off now.
|
||
// Otherwise, if we are not currently waiting for an SCB clear
|
||
// interrupt, signal the adapter to send us a SCB clear interrupt
|
||
// when it is done with the SCB.
|
||
//
|
||
if (acb->acb_scb_virtptr->SCB_Cmd == 0)
|
||
{
|
||
NetFlexSendNextSCB(acb);
|
||
}
|
||
else if ((acb->acb_xmit_whead) ||
|
||
(acb->acb_rcv_whead) ||
|
||
(acb->acb_scbreq_next))
|
||
{
|
||
acb->acb_scbclearout = TRUE;
|
||
NdisRawWritePortUshort(
|
||
acb->SifIntPort,
|
||
(USHORT)SIFINT_SCBREQST);
|
||
}
|
||
break;
|
||
|
||
case INT_COMMAND:
|
||
NetFlexCommand(acb);
|
||
|
||
//
|
||
// Do we have any commands to complete?
|
||
//
|
||
if (acb->acb_confirm_qhead != NULL)
|
||
{
|
||
NetFlexProcessMacReq(acb);
|
||
}
|
||
break;
|
||
|
||
case INT_ADPCHECK:
|
||
//
|
||
// Read the Adapter Check Status @ 1.05e0
|
||
//
|
||
NdisRawWritePortUshort(acb->SifAddrxPort, (USHORT) 1);
|
||
NdisRawWritePortUshort(acb->SifAddrPort, (USHORT) 0x5e0);
|
||
NdisRawReadPortUshort( acb->SifDIncPort, &tmp_reg);
|
||
|
||
DebugPrint(1,("NF(%d): Adapter Check - 0x%x\n",acb->anum,tmp_reg));
|
||
|
||
//
|
||
// Reset has failed, errorlog an entry.
|
||
//
|
||
|
||
NdisWriteErrorLogEntry( acb->acb_handle,
|
||
EVENT_NDIS_ADAPTER_CHECK_ERROR,
|
||
2,
|
||
NETFLEX_ADAPTERCHECK_ERROR_CODE,
|
||
tmp_reg );
|
||
|
||
//
|
||
// Set the variables up showing that the hardware has an unrecoverable
|
||
// error.
|
||
//
|
||
acb->acb_state = AS_HARDERROR;
|
||
break;
|
||
|
||
case INT_RINGSTAT:
|
||
NetFlexRingStatus(acb);
|
||
break;
|
||
|
||
case INT_RECEIVE:
|
||
break;
|
||
|
||
case INT_TRANSMIT:
|
||
//
|
||
// If we reached the end of the xmit lists,
|
||
// then the xmit status will indicate COMMAND_COMPLETE.
|
||
// The transmiter will be stalled until another transmit
|
||
// command is issued with a valid list.
|
||
//
|
||
if (acb->acb_ssb_virtptr->SSB_Status & XSTAT_LERROR)
|
||
{
|
||
//
|
||
// We have a list error...
|
||
//
|
||
NetFlexTransmitStatus(acb);
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Issue a ssb clear. After this we may see SIFCMD interrupts.
|
||
//
|
||
NdisRawWritePortUshort(acb->SifIntPort, SIFINT_SSBCLEAR);
|
||
|
||
//
|
||
// Read the SifInt
|
||
//
|
||
NdisRawReadPortUshort(acb->SifIntPort, &sifint_reg);
|
||
}
|
||
|
||
//
|
||
// Processed any receives which need IndicateReceiveComplete?
|
||
//
|
||
if (ReceivesProcessed)
|
||
{
|
||
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
|
||
{
|
||
// Token Ring
|
||
//
|
||
NdisMTrIndicateReceiveComplete(acb->acb_handle);
|
||
}
|
||
else
|
||
{
|
||
// Ethernet
|
||
//
|
||
NdisMEthIndicateReceiveComplete(acb->acb_handle);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
//
|
||
// Routine Name: NetFlexRingStatus
|
||
//
|
||
// Description:
|
||
// This routine does the clean up work necessary
|
||
// when a ring status occurs.
|
||
//
|
||
// Input:
|
||
// acb - Our Driver Context for this adapter or head.
|
||
//
|
||
// Output:
|
||
// None
|
||
//
|
||
// Called By:
|
||
// NetFlexHandleInterrupt
|
||
//
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
VOID
|
||
NetFlexRingStatus(
|
||
PACB acb
|
||
)
|
||
{
|
||
USHORT value;
|
||
ULONG RingStatus = 0;
|
||
|
||
value = acb->acb_ssb_virtptr->SSB_Status;
|
||
|
||
DebugPrint(1,("NF(%d): RingStatus value = %x\n",acb->anum, value));
|
||
|
||
//
|
||
// Determine the reason for the ring interrupt.
|
||
//
|
||
if (value & RING_STATUS_SIGNAL_LOSS)
|
||
{
|
||
RingStatus |= NDIS_RING_SIGNAL_LOSS;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_SIGNAL_LOSS\n",acb->anum));
|
||
|
||
//
|
||
// Have we already reported the error?
|
||
//
|
||
if (!acb->SentRingStatusLog &&
|
||
((acb->acb_lastringstatus & RING_STATUS_SIGNAL_LOSS) == 0))
|
||
{
|
||
// no, so send one.
|
||
NdisWriteErrorLogEntry( acb->acb_handle,
|
||
EVENT_NDIS_SIGNAL_LOSS_ERROR,
|
||
3,
|
||
NETFLEX_RINGSTATUS_ERROR_CODE,
|
||
(ULONG) acb->acb_baseaddr,
|
||
(ULONG) value
|
||
);
|
||
acb->SentRingStatusLog = TRUE;
|
||
}
|
||
}
|
||
|
||
if (value & RING_STATUS_HARD_ERROR)
|
||
{
|
||
RingStatus |= NDIS_RING_HARD_ERROR;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_HARD_ERROR\n",acb->anum));
|
||
}
|
||
if (value & RING_STATUS_SOFT_ERROR)
|
||
{
|
||
RingStatus |= NDIS_RING_SOFT_ERROR;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_SOFT_ERROR\n",acb->anum));
|
||
}
|
||
if (value & RING_STATUS_XMIT_BEACON)
|
||
{
|
||
RingStatus |= NDIS_RING_TRANSMIT_BEACON;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_XMIT_BEACON\n",acb->anum));
|
||
}
|
||
if (value & RING_STATUS_LOBE_WIRE_FAULT)
|
||
{
|
||
RingStatus |= NDIS_RING_LOBE_WIRE_FAULT;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_LOBE_WIRE_FAULT\n",acb->anum));
|
||
//
|
||
// Have we already reported the error?
|
||
//
|
||
if (!acb->SentRingStatusLog &&
|
||
((acb->acb_lastringstatus & NDIS_RING_LOBE_WIRE_FAULT) == 0))
|
||
{
|
||
// no, so send one.
|
||
NdisWriteErrorLogEntry( acb->acb_handle,
|
||
EVENT_NDIS_LOBE_FAILUE_ERROR,
|
||
3,
|
||
NETFLEX_RINGSTATUS_ERROR_CODE,
|
||
(ULONG) acb->acb_baseaddr,
|
||
(ULONG) value
|
||
);
|
||
|
||
acb->SentRingStatusLog = TRUE;
|
||
}
|
||
}
|
||
|
||
if (value & (RING_STATUS_AUTO_REMOVE_1 | RING_STATUS_REMOVE_RECEIVED))
|
||
{
|
||
if (value & RING_STATUS_AUTO_REMOVE_1)
|
||
{
|
||
RingStatus |= NDIS_RING_AUTO_REMOVAL_ERROR;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_AUTO_REMOVE_1\n",acb->anum));
|
||
}
|
||
if (value & RING_STATUS_REMOVE_RECEIVED)
|
||
{
|
||
RingStatus |= NDIS_RING_REMOVE_RECEIVED;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_REMOVE_RECEIVED\n",acb->anum));
|
||
}
|
||
//
|
||
// Have we already reported the error?
|
||
//
|
||
if ((acb->acb_lastringstatus &
|
||
(RING_STATUS_AUTO_REMOVE_1 | RING_STATUS_REMOVE_RECEIVED )) == 0)
|
||
{
|
||
// no, so send one.
|
||
NdisWriteErrorLogEntry( acb->acb_handle,
|
||
EVENT_NDIS_REMOVE_RECEIVED_ERROR,
|
||
3,
|
||
NETFLEX_RINGSTATUS_ERROR_CODE,
|
||
(ULONG) acb->acb_baseaddr,
|
||
(ULONG) value
|
||
);
|
||
}
|
||
}
|
||
|
||
if (value & RING_STATUS_OVERFLOW)
|
||
{
|
||
RingStatus |= NDIS_RING_COUNTER_OVERFLOW;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_OVERFLOW\n",acb->anum));
|
||
}
|
||
|
||
if (value & RING_STATUS_SINGLESTATION)
|
||
{
|
||
RingStatus |= NDIS_RING_SINGLE_STATION;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_SINGLESTATION\n",acb->anum));
|
||
}
|
||
|
||
if (value & RING_STATUS_RINGRECOVERY)
|
||
{
|
||
RingStatus |= NDIS_RING_RING_RECOVERY;
|
||
DebugPrint(1,("NF(%d): RING_STATUS_RINGRECOVERY\n",acb->anum));
|
||
}
|
||
|
||
//
|
||
// Save the Ring Status
|
||
//
|
||
acb->acb_lastringstatus = RingStatus;
|
||
|
||
|
||
//
|
||
// Indicate to the filter the ring status.
|
||
//
|
||
NdisMIndicateStatus(
|
||
acb->acb_handle,
|
||
NDIS_STATUS_RING_STATUS,
|
||
&RingStatus,
|
||
sizeof(ULONG)
|
||
);
|
||
|
||
//
|
||
// Tell the filter that we have completed the ring status.
|
||
//
|
||
NdisMIndicateStatusComplete(acb->acb_handle);
|
||
}
|
||
|
||
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
//
|
||
// Routine Name: NetFlexCommand
|
||
//
|
||
// Description:
|
||
// This routine looks at the current SSB struct
|
||
// and places the corresponding request on the
|
||
// Request Confirm Queue. If the command that
|
||
// has completed is an open, a receive and
|
||
// transmit command are issued.
|
||
//
|
||
// Input:
|
||
// acb - Our Driver Context for this adapter or head.
|
||
//
|
||
// Output:
|
||
// None
|
||
//
|
||
// Called By:
|
||
// NetFlexHandleInterrupt
|
||
//
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
VOID
|
||
NetFlexCommand(
|
||
PACB acb
|
||
)
|
||
{
|
||
PSCBREQ scbreq;
|
||
PMACREQ macreq;
|
||
PTR_OBJS trobjs;
|
||
PETH_OBJS ethobjs;
|
||
SHORT value,i;
|
||
PUSHORT tempptr;
|
||
NDIS_STATUS Status;
|
||
|
||
#if (DBG || DBGPRINT)
|
||
//
|
||
// I wanted to know if I'm getting bad commands
|
||
//
|
||
if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_CMDREJECT)
|
||
{
|
||
DebugPrint(0,("NF(%d): Command rejected\n",acb->anum));
|
||
DebugPrint(0,("NF(%d): SSB Status %x\n",acb->anum,SWAPS(acb->acb_ssb_virtptr->SSB_Status)));
|
||
DebugPrint(0,("NF(%d): SSB Ptr %x\n",acb->anum,SWAPL(acb->acb_ssb_virtptr->SSB_Ptr)));
|
||
}
|
||
else if (acb->acb_ssb_virtptr->SSB_Status != SSB_GOOD)
|
||
{
|
||
DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
|
||
DebugPrint(0,("NF(%d): cmd is %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Cmd));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Get the scb request associated with the completed request.
|
||
//
|
||
Status = NetFlexDequeue_TwoPtrQ_Head(
|
||
(PVOID *)&(acb->acb_scbreq_head),
|
||
(PVOID *)&(acb->acb_scbreq_tail),
|
||
(PVOID *)&scbreq
|
||
);
|
||
if (Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
DebugPrint(0,("NF(%d) NetFlexCommand - dequeue scbreq failed!\n",acb->anum));
|
||
return;
|
||
}
|
||
|
||
//
|
||
// If we have a Macreq to place on the confirm q. Do this now.
|
||
//
|
||
macreq = scbreq->req_macreq;
|
||
|
||
if (macreq)
|
||
{
|
||
//
|
||
// If the command had a problem, save the failure reason and
|
||
// exit out of the routine. Otherwise, save the success code
|
||
// and see if the completed command is an open or a read error log.
|
||
//
|
||
if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_CMDREJECT)
|
||
{
|
||
DebugPrint(0,("NF(%d): Command rejected\n",acb->anum));
|
||
DebugPrint(0,("NF(%d): SSB Status %x\n",acb->anum,SWAPS(acb->acb_ssb_virtptr->SSB_Status)));
|
||
DebugPrint(0,("NF(%d): SSB Ptr %x\n",acb->anum,SWAPL(acb->acb_ssb_virtptr->SSB_Ptr)));
|
||
macreq->req_status = NDIS_STATUS_FAILURE;
|
||
}
|
||
else if (acb->acb_ssb_virtptr->SSB_Status != SSB_GOOD)
|
||
{
|
||
DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
|
||
DebugPrint(0,("NF(%d): cmd is %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Cmd));
|
||
|
||
if ((acb->acb_ssb_virtptr->SSB_Cmd == TMS_OPEN) &&
|
||
(acb->acb_ssb_virtptr->SSB_Status & SSB_OPENERR)
|
||
)
|
||
{
|
||
macreq->req_status = NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
|
||
macreq->req_info = (PVOID)(acb->acb_ssb_virtptr->SSB_Status >> 8);
|
||
}
|
||
else
|
||
{
|
||
macreq->req_status = NDIS_STATUS_FAILURE;
|
||
}
|
||
}
|
||
else if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_READLOG)
|
||
{
|
||
acb->acb_logbuf_valid = TRUE;
|
||
//
|
||
// Fill in the appropriate fields with the information
|
||
// given by the log buffer.
|
||
//
|
||
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
|
||
{
|
||
// TOKEN RING
|
||
trobjs = (PTR_OBJS)(acb->acb_spec_objs);
|
||
trobjs->REL_Congestion += ((PREL)(acb->acb_logbuf_virtptr))->REL_Congestion;
|
||
trobjs->REL_LineError += ((PREL)(acb->acb_logbuf_virtptr))->REL_LineError;
|
||
trobjs->REL_LostError += ((PREL)(acb->acb_logbuf_virtptr))->REL_LostError;
|
||
trobjs->REL_BurstError += ((PREL)(acb->acb_logbuf_virtptr))->REL_BurstError;
|
||
trobjs->REL_ARIFCIError += ((PREL)(acb->acb_logbuf_virtptr))->REL_ARIFCIError;
|
||
trobjs->REL_Congestion += ((PREL)(acb->acb_logbuf_virtptr))->REL_Congestion;
|
||
trobjs->REL_CopiedError += ((PREL)(acb->acb_logbuf_virtptr))->REL_CopiedError;
|
||
trobjs->REL_TokenError += ((PREL)(acb->acb_logbuf_virtptr))->REL_TokenError;
|
||
}
|
||
else
|
||
{
|
||
// ETHERNET
|
||
ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
|
||
ethobjs->RSL_AlignmentErr = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_AlignmentErr);
|
||
ethobjs->RSL_1_Collision = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_1_Collision);
|
||
ethobjs->RSL_FrameCheckSeq = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_FrameCheckSeq);
|
||
ethobjs->RSL_DeferredXmit = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_DeferredXmit);
|
||
ethobjs->RSL_LateCollision = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_LateCollision);
|
||
ethobjs->RSL_Excessive = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_Excessive);
|
||
ethobjs->RSL_CarrierErr = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_CarrierErr);
|
||
tempptr = (PUSHORT)&(((PRSL)(acb->acb_logbuf_virtptr))->RSL_2_Collision);
|
||
value = 0;
|
||
for (i = 0; i < 14; i++)
|
||
{
|
||
value += SWAPS( *(tempptr+i) );
|
||
}
|
||
ethobjs->RSL_More_Collision = value;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Take the Mac request off the macreq queue and place it on
|
||
// the confirm queue so that the command can be completed.
|
||
//
|
||
NetFlexDequeue_TwoPtrQ(
|
||
(PVOID *)&(acb->acb_macreq_head),
|
||
(PVOID *)&(acb->acb_macreq_tail),
|
||
(PVOID)macreq
|
||
);
|
||
|
||
NetFlexEnqueue_TwoPtrQ_Tail(
|
||
(PVOID *)&(acb->acb_confirm_qhead),
|
||
(PVOID *)&(acb->acb_confirm_qtail),
|
||
(PVOID)macreq
|
||
);
|
||
} // if (macreq)
|
||
|
||
//
|
||
// Free up the SCB request associated with this command.
|
||
//
|
||
scbreq->req_macreq = NULL;
|
||
|
||
NetFlexEnqueue_OnePtrQ_Head(
|
||
(PVOID *)&(acb->acb_scbreq_free),
|
||
(PVOID)scbreq
|
||
);
|
||
}
|
||
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
//
|
||
// Routine Name: NetFlexEnableInterrupt
|
||
//
|
||
// Description:
|
||
// This routine is used to enable the adapter to
|
||
// interrupt the system.
|
||
//
|
||
// Input:
|
||
// Context - Our Driver Context for this adapter or head.
|
||
//
|
||
// Output:
|
||
// None
|
||
//
|
||
// Called By:
|
||
// Miniport Wrapper
|
||
//
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
VOID
|
||
NetFlexEnableInterrupt(
|
||
IN NDIS_HANDLE Context
|
||
)
|
||
{
|
||
USHORT actl_reg;
|
||
PACB acb = (PACB) Context;
|
||
|
||
DebugPrint(3,("NF(%d)(E)\n",acb->anum));
|
||
//
|
||
// Enable System Interrupts
|
||
//
|
||
actl_reg = acb->actl_reg | ACTL_SINTEN;
|
||
|
||
NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
|
||
|
||
acb->InterruptsDisabled = FALSE;
|
||
}
|
||
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
//
|
||
// Routine Name: NetFlexDisableInterrupt
|
||
//
|
||
// Description:
|
||
// This routine is used to disable the adapter from being
|
||
// able to interrupt the system.
|
||
//
|
||
// Input:
|
||
// Context - Our Driver Context for this adapter or head.
|
||
//
|
||
// Output:
|
||
// None
|
||
//
|
||
// Called By:
|
||
// Miniport Wrapper
|
||
//
|
||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
VOID
|
||
NetFlexDisableInterrupt(
|
||
IN NDIS_HANDLE Context
|
||
)
|
||
{
|
||
USHORT actl_reg;
|
||
PACB acb = (PACB) Context;
|
||
|
||
//
|
||
// Disable System Interrupts
|
||
//
|
||
actl_reg = acb->actl_reg & ~ACTL_SINTEN;
|
||
|
||
NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
|
||
|
||
acb->InterruptsDisabled = TRUE;
|
||
|
||
DebugPrint(3,("NF(%d)(D)\n",acb->anum));
|
||
}
|