548 lines
14 KiB
C
548 lines
14 KiB
C
/* 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));
|
|
|
|
}
|
|
}
|
|
}
|