NT4/private/ntos/miniport/always/ntmgr.c

548 lines
14 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/* Copyright (C) 1991-1994 by Always Technology Corporation.
This module contains information proprietary to
Always Technology Corporation, and is be treated as confidential.
*/
#include "environ.h"
#include "rqm.h"
#include "api.h"
#include "apiscsi.h"
#include "debug.h"
#define HAExtentLen sizeof(struct Adapter)
#define DEVExtentLen sizeof(struct DeviceDescr)
#define REQExtentLen sizeof(struct IOReqExtension)
enum ASPI_Priority {NORMAL_REQ, PRIORTY_REQ, IPRIORTY_REQ};
void IExecuteReq(ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req, enum ASPI_Priorty Priorty);
extern void EnvLib_Init(void);
#define FreeDev(DevP)
#if !defined(APIFindDev)
DEVICE_PTR
APIFindDev (const ADAPTER_PTR HA, const unsigned TID, const unsigned LUN)
{
return ScsiPortGetLogicalUnit(HA, 0, (char)TID, (char)LUN);
}
#endif
void
APISetStatus (IO_REQ_PTR Req, // Request structure
APIStatus Status, // Status
TerminateCode Terminal, // Is this the terminal (Notify completion)
AutosenseCode IsSenseable) // Auto sense allowed?
{
static U8 REQStats[]={
SRB_STATUS_PENDING, SRB_STATUS_PENDING, SRB_STATUS_ABORTED,
SRB_STATUS_BAD_FUNCTION, SRB_STATUS_INVALID_REQUEST, SRB_STATUS_NO_HBA,
SRB_STATUS_DATA_OVERRUN, SRB_STATUS_SELECTION_TIMEOUT,
SRB_STATUS_INVALID_TARGET_ID, SRB_STATUS_INVALID_LUN
};
static U8 ADStats[]={
SRB_STATUS_NO_HBA, SRB_STATUS_BUSY, SRB_STATUS_UNEXPECTED_BUS_FREE,
SRB_STATUS_PHASE_SEQUENCE_FAILURE, SRB_STATUS_BUS_RESET,
SRB_STATUS_AUTOSENSE_VALID, SRB_STATUS_ERROR};
// Make sure the high numbers match what this module knows of:
#if S_LAST_S_REQ != 0x09
#err
#endif
#if S_LAST_S_AD != 0x06
#err
#endif
#if S_LAST_S_SYS != 0
#err
#endif
switch (ErrorClass(Status)) {
case RequestClass:
DEBUG(0, if (Status == S_REQ_ABORT)
TRACE(0, ("APISetStatus(): Set Req (%x) status to aborted\n")) );
Req->SrbStatus = REQStats[ErrorCode(Status)];
break;
case AdapterClass:
Req->SrbStatus = ADStats[ErrorCode(Status)];
break;
case TargetClass:
Req->ScsiStatus = ErrorCode(Status);
switch (ErrorCode(Status)) {
case STATUS_CKCOND:
ReqDataCount(Req) = ReqSavedIndex(Req);
#if defined(AUTOSENSE)
if ((IsSenseable == Senseable) && ReqSenseCount(Req)) {
Terminal = NonTerminal;
QueueInternalRequest(ReqAdapterPtr(Req), Req, RTAutoSenseReq);
} else
#endif
Req->SrbStatus = SRB_STATUS_ERROR;
break;
case STATUS_GOOD:
case STATUS_CONDMET:
case STATUS_INTGOOD:
case STATUS_INTCONDMET:
Req->SrbStatus = SRB_STATUS_SUCCESS;
if (ReqDataCount(Req) > ReqSavedIndex(Req)) {
Req->SrbStatus = SRB_STATUS_DATA_OVERRUN;
// Update number of bytes transferred.
// ReqSavedIndex is the number of bytes successfully transfered
// One thing the NT people will have to address is zero latency
// xfers. How will number of bytes xfered be represented
// on an error, when the xfer has holes?
ReqDataCount(Req) = ReqSavedIndex(Req);
}
break;
default:
Req->SrbStatus = SRB_STATUS_ERROR;
break;
}
TRACE(4, ("APISetStatus(): Setting target status to %02x\n",
Req->ScsiStatus));
break;
}
TRACE(4, ("APISetStatus(): Setting request status to %02x\n", Req->SrbStatus));
if (Terminal != NonTerminal) {
TRACE(3, ("APISetStatus(): Notifying completion\n"));
Notify(ReqAdapterPtr(Req), Req);
}
}
void
Notify (ADAPTER_PTR HA, IO_REQ_PTR Req)
{
if (ReqState(Req).InternalRequest)
(*(ReqPost(Req)))(Req);
else
ScsiPortNotification(RequestComplete, HA, Req);
}
void
APINotifyReset (ADAPTER_PTR HA)
{
TRACE(0, ("APINotifyReset():\n"));
ScsiPortNotification(ResetDetected, HA);
}
void
IExecuteReq (ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req, enum ASPI_Priorty Priorty)
{
TRACE(5, ("IExecuteReq(): Got request %x for device %x on adapter %x\n", Req, DevP, HA));
if (HA->DevInfo[ReqTargetID(Req)].Flags.NeedSync)
QueueInternalRequest(HA, Req, RTSyncNegReq);
else
QueueReq(HA, (IO_REQ_PTR)Req, (Priorty > NORMAL_REQ));
}
#define HAPollTime (ULONG)500000 // Time in uS for 500mS
void
HATimer (IN PVOID HAObject)
{
TRACE(6, ("HATimer(): Timer entered\n"));
((ADAPTER_PTR)HAObject)->Service(HA_TIMER, (ADAPTER_PTR)HAObject, 0l);
ScsiPortNotification(RequestTimerCall, HAObject, HATimer, HAPollTime);
}
BOOLEAN
HAInit (PVOID HAObject)
{
ADAPTER_PTR HA = HAObject;
TRACE(3, ("HAInit(): \n"));
HA->Ext->InternalRequest.Length = sizeof(HA->Ext->InternalRequest);
HA->Ext->InternalRequest.SrbExtension = &(HA->Ext->IntlReqExtension);
ReqCommand(&(HA->Ext->InternalRequest)) = SRB_FUNCTION_EXECUTE_SCSI; // internally generated command
ReqAdapterPtr(&HA->Ext->InternalRequest) = HA;
ReqState(&(HA->Ext->InternalRequest)).InternalRequest = 1;
((ADAPTER_PTR)HAObject)->Service(HA_INITIALIZE, (ADAPTER_PTR)HAObject, 0l);
ScsiPortNotification(RequestTimerCall, HAObject, HATimer, HAPollTime);
return TRUE;
}
BOOLEAN
ResetBus (PVOID HAObject, ULONG PathID)
{
TRACE(0, ("ResetBus(): \n"));
((ADAPTER_PTR)HAObject)->Service(HA_RESET_BUS, (ADAPTER_PTR)HAObject, 0l);
// Stall here, to allow the interrupt service routine to handle the reset
// and blow off requests, etc.
ScsiPortStallExecution(100l);
// Send completion of reset request:
ScsiPortCompleteRequest(HAObject, (UCHAR)PathID, (UCHAR)-1, (UCHAR)-1, SRB_STATUS_BUS_RESET);
return TRUE;
}
BOOLEAN
AdapterState (IN PVOID HAObject, IN PVOID Context, IN BOOLEAN SaveState)
{
if (SaveState)
((ADAPTER_PTR)HAObject)->Service(HA_RESTORE_STATE, (ADAPTER_PTR)HAObject,
(U32)0);
return TRUE;
}
BOOLEAN
StartIO (IN PVOID HAObject, IN PSCSI_REQUEST_BLOCK Req)
{
ADAPTER_PTR HA = HAObject;
DEVICE_PTR DevP;
int i;
TRACE(2, ("StartIO(): Req @%x, Function = 0x%x, Req->SrbExtension @%x\n", Req, Req->Function, Req->SrbExtension));
switch (Req->Function) {
case SRB_FUNCTION_EXECUTE_SCSI:
ReqNext(Req) = (IO_REQ_PTR)NILL;
ReqAdapterPtr(Req) = HA;
for (i=0; i < sizeof(ReqState(Req)); i++)
((U8 *)&ReqState(Req))[i] = 0;
ReqState(Req).ReqType = RTNormalReq;
if ( (DevP = ScsiPortGetLogicalUnit(HA, Req->PathId, ReqTargetID(Req), ReqTargetLUN(Req))) == NILL) {
TRACE(3, ("ExecuteReq(): Unable to get device info\n"));
Req->SrbStatus = SRB_STATUS_NO_DEVICE;
return FALSE;
}
ReqDevP(Req) = DevP;
if (!DevP->Flags.Initialized)
QueueInternalRequest(HA, Req, RTGetInfoReq);
else
IExecuteReq(HA, DevP, Req, NORMAL_REQ);
break;
case SRB_FUNCTION_RESET_BUS:
TRACE(3, ("StartIO(): RESET_BUS command\n"));
ResetBus(HAObject, Req->PathId);
break;
case SRB_FUNCTION_RESET_DEVICE:
case SRB_FUNCTION_TERMINATE_IO:
case SRB_FUNCTION_FLUSH:
case SRB_FUNCTION_SHUTDOWN:
Req->SrbStatus = SRB_STATUS_SUCCESS;
ScsiPortNotification(RequestComplete, HA, Req);
break;
case SRB_FUNCTION_ABORT_COMMAND:
TRACE(0, ("StartIO(): Request at %x to abort request %x\n", Req, Req->NextSrb));
if ((DevP = ScsiPortGetLogicalUnit(HA, Req->PathId, ReqTargetID(Req), ReqTargetLUN(Req))) == NILL
|| (DevP->Flags.Initialized == 0)
|| !AbortRequest(HA, DevP, Req->NextSrb) ) {
TRACE(0, ("StartIO(): Abort operation failed\n"));
Req->SrbStatus = SRB_STATUS_ABORT_FAILED;
} else {
TRACE(0, ("StartIO(): Abort operation success\n"));
Req->SrbStatus = SRB_STATUS_SUCCESS;
}
ScsiPortNotification(RequestComplete, HA, Req);
break;
case SRB_FUNCTION_RELEASE_RECOVERY:
case SRB_FUNCTION_RECEIVE_EVENT:
case SRB_FUNCTION_IO_CONTROL:
default:
TRACE(0, ("StartIO(): Unsupported command: 0x%x\n", Req->Function));
APISetStatus(Req, S_REQ_OPCODE, Terminal, NotSenseable);
return FALSE;
break;
}
ScsiPortNotification(NextLuRequest, HA, Req->PathId, Req->TargetId, Req->Lun);
return TRUE;
}
BOOLEAN
GeneralISR (PVOID HAObject)
{
return (BOOLEAN) ( ((ADAPTER_PTR)HAObject)->ISR((ADAPTER_PTR)HAObject) );
}
ULONG
FindAdapter (IN PVOID HAObject, IN PVOID PContext, IN PVOID BusInfo,
IN PCHAR ArgString, IN OUT PPORT_CONFIGURATION_INFORMATION Config,
OUT PBOOLEAN PAgain)
{
ADAPTER_PTR HA = HAObject;
TRACE(3, ("FindAdapter(): Adapter ptr = %x, Config ptr = %x, Len = 0x%x\n", HA, Config, sizeof(struct _PORT_CONFIGURATION_INFORMATION)));
/* Hunt down and register the adapters in the system: */
HA->IOBaseAddr = (U16)ScsiPortConvertPhysicalAddressToUlong(
(*Config->AccessRanges)[0].RangeStart);
if (Adapter_Init(HA, (unsigned *)PContext)) {
// Set Again TRUE, only if we're being called with a non-sepcific access range
*PAgain = ScsiPortConvertPhysicalAddressToUlong(
(*Config->AccessRanges)[0].RangeStart) == 0;
Config->BusInterruptLevel = HA->IRQNumber;
Config->ScatterGather = HA->Supports.ScatterGather;
Config->MaximumTransferLength = 0x400000;
Config->NumberOfPhysicalBreaks = 0x400;
// Config->NumberOfPhysicalBreaks = HA->MaxSGListLength;
(*Config->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(HA->IOBaseAddr);
(*Config->AccessRanges)[0].RangeLength = HA->IOAddrLen;
(*Config->AccessRanges)[0].RangeInMemory = FALSE;
Config->NumberOfBuses = 1;
Config->InitiatorBusId[0] = HA->SCSI_ID;
Config->Master = (HA->Physical.Xfermode == XM_MASTER) || (HA->Physical.Xfermode == XM_MASTER24);
Config->Dma32BitAddresses = (HA->Physical.Xfermode == XM_MASTER);
Config->DemandMode = (HA->Physical.Xfermode == XM_DMAD);
Config->NeedPhysicalAddresses = XM_PHYSICAL(HA->Physical.Xfermode);
Config->MapBuffers = TRUE;
Config->CachesData = HA->Supports.Caching;
Config->AlignmentMask = 0x3;
Config->TaggedQueuing = FALSE;
#if defined(AUTOSENSE)
Config->AutoRequestSense = TRUE;
#else
Config->AutoRequestSense = FALSE;
#endif
Config->MultipleRequestPerLu = Config->AutoRequestSense;
Config->ReceiveEvent = FALSE;
HA->Ext = ScsiPortGetUncachedExtension(HA, Config, sizeof(AdapterExtension));
return SP_RETURN_FOUND;
} else {
*PAgain = FALSE;
return SP_RETURN_NOT_FOUND;
}
}
ULONG
DriverEntry (IN PVOID HAObject, IN PVOID ARG)
{
HW_INITIALIZATION_DATA InitData; // Adapter init. struct
unsigned i;
ULONG AdapterCount;
ULONG ISAStatus, EISAStatus;
// ULONG MCAStatus, LocalStatus;
/* Initialize the environment: */
EnvLib_Init();
// Initialize the object
for (i=0; i < sizeof(InitData); i++)
((char *)&InitData)[i] = 0;
InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
// Set pointers to service functions:
InitData.HwInitialize = HAInit;
InitData.HwStartIo = StartIO;
InitData.HwInterrupt = GeneralISR;
InitData.HwFindAdapter = FindAdapter;
InitData.HwResetBus = ResetBus;
InitData.HwAdapterState = AdapterState; //
// Set capabilities
InitData.MapBuffers = TRUE; // This should be in PORT config info
InitData.NeedPhysicalAddresses = FALSE;
InitData.TaggedQueuing = FALSE;
#if defined(AUTOSENSE)
InitData.AutoRequestSense = TRUE;
#else
InitData.AutoRequestSense = FALSE;
#endif
InitData.MultipleRequestPerLu = InitData.AutoRequestSense;
InitData.ReceiveEvent = FALSE;
// Set misc. things:
InitData.NumberOfAccessRanges = 1;
// Set the size of extensions
InitData.DeviceExtensionSize = HAExtentLen;
InitData.SpecificLuExtensionSize = DEVExtentLen;
InitData.SrbExtensionSize = REQExtentLen;
AdapterCount = 0;
TRACE(3, ("DriverEntry(): Trying EISA adapters\n"));
InitData.AdapterInterfaceType = Eisa;
EISAStatus = ScsiPortInitialize(HAObject, ARG, &InitData, (PVOID)&AdapterCount);
TRACE(2, ("DriverEntry(): ScsiPortInitialize() returned: %x\n", EISAStatus));
if (EISAStatus != 0) {
TRACE(3, ("DriverEntry(): Trying ISA adapters\n"));
InitData.AdapterInterfaceType = Isa;
ISAStatus = ScsiPortInitialize(HAObject, ARG, &InitData, (PVOID)&AdapterCount);
TRACE(2, ("DriverEntry(): ScsiPortInitialize() returned: %x\n", ISAStatus));
}
return min(ISAStatus, EISAStatus);
}
void
GetXferSegment (const ADAPTER_PTR HA, IO_REQ_PTR Req, SegmentDescr *SGDescr,
U32 Offset, BOOLEAN DemandPhysicalAddr)
{
TRACE(4, ("GetXferSegment(): Offset = %d\n", Offset));
TRACE(4, ("GetXferSegment(): Non-S/G request, ReqDataCount = %d\n", ReqDataCount(Req)));
if (Offset < ReqDataCount(Req)) { // Make sure we don't over run
SGDescr->SegmentLength = ReqDataCount(Req) - Offset;
SGDescr->SegmentPtr = (U32)ReqDataPtr(Req) + Offset;
} else {
SGDescr->SegmentLength = 0; // No data left
SGDescr->SegmentPtr = 0;
BreakPoint(HA);
}
TRACE(4, ("GetXferSegment(): %d bytes remain in segment at %08x (offset %d)\n",
SGDescr->SegmentLength, SGDescr->SegmentPtr, Offset));
SGDescr->Flags.IsPhysical = FALSE;
if (DemandPhysicalAddr) {
if (ReqState(Req).InternalRequest) {
TRACE(5, ("GetXferSegment(): Mapping internal request\n"));
MapToPhysical(HA, SGDescr);
} else {
ULONG Size = SGDescr->SegmentLength;
SGDescr->SegmentPtr = (U32)ScsiPortConvertPhysicalAddressToUlong(
ScsiPortGetPhysicalAddress(HA, Req,
(PVOID)((U32)ReqDataPtr(Req) + Offset) /*(SGDescr->SegmentPtr)*/,
&Size));
if (Size < SGDescr->SegmentLength)
SGDescr->SegmentLength = Size;
DEBUG(5, {
if (SGDescr->SegmentLength < (ReqDataCount(Req) - Offset))
DPrintf("Segment length is %d out of %d\n",
SGDescr->SegmentLength, ReqDataCount(Req) - Offset);});
SGDescr->Flags.IsPhysical = TRUE;
TRACE(5, ("GetXferSegment(): Mapped to 0x%lx for %lu bytes\n",
SGDescr->SegmentPtr, Size));
}
}
}