1618 lines
43 KiB
C
1618 lines
43 KiB
C
/* Copyright (c) 1992 Microsoft/UltrStor Corporation
|
||
|
||
Module Name:
|
||
ultra124.c
|
||
|
||
Abstract:
|
||
This is the port driver for the ULTRASTOR 124 EISA SCSI adapter.
|
||
|
||
Authors:
|
||
Mike Glass / Edward Syu
|
||
|
||
Environment:
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
-----------------------------------------------------------------------------
|
||
Date Name Description
|
||
|
||
08/25/92 Syu First time created. Modify from 24f source code.
|
||
|
||
11/04/92 Fong * Change MSCP_TARGET_ERROR from 91h to A0H
|
||
* Handle Aborted command in Startio
|
||
04/05/93 fong fix Handle Inquiry data problem for MARCH NT release
|
||
-----------------------------------------------------------------------------
|
||
|
||
--*/
|
||
|
||
#include "miniport.h"
|
||
#include "ultra124.h" // includes scsi.h
|
||
|
||
//
|
||
// Device extension
|
||
//
|
||
|
||
typedef struct _HW_DEVICE_EXTENSION {
|
||
PEISA_CONTROLLER EisaController;
|
||
UCHAR HostTargetId;
|
||
PSCSI_REQUEST_BLOCK CSIRSrb; // byte 24
|
||
} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
|
||
|
||
|
||
//
|
||
// Function declarations
|
||
//
|
||
// Functions that start with 'Ultra124' are entry points
|
||
// for the OS port driver.
|
||
//
|
||
|
||
ULONG
|
||
DriverEntry(
|
||
IN PVOID DriverObject,
|
||
IN PVOID Argument2
|
||
);
|
||
|
||
ULONG
|
||
Ultra124FindAdapter(
|
||
IN PVOID DeviceExtension,
|
||
IN PVOID Context,
|
||
IN PVOID BusInformation,
|
||
IN PCHAR ArgumentString,
|
||
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
||
OUT PBOOLEAN Again
|
||
);
|
||
|
||
BOOLEAN
|
||
Ultra124Initialize(
|
||
IN PVOID DeviceExtension
|
||
);
|
||
|
||
BOOLEAN
|
||
Ultra124StartIo(
|
||
IN PVOID DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
BOOLEAN
|
||
Ultra124Interrupt(
|
||
IN PVOID DeviceExtension
|
||
);
|
||
|
||
BOOLEAN
|
||
Ultra124ResetBus(
|
||
IN PVOID HwDeviceExtension,
|
||
IN ULONG PathId
|
||
);
|
||
|
||
//
|
||
// This function is called from Ultra124StartIo.
|
||
//
|
||
|
||
BOOLEAN
|
||
BuildMscp(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
//
|
||
// This function is called from BuildMscp.
|
||
//
|
||
|
||
VOID
|
||
BuildSgl(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
//
|
||
// This function is called from Ultra124Interrupt.
|
||
//
|
||
|
||
VOID
|
||
MapErrorToSrbStatus(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
BOOLEAN
|
||
ReadDriveCapacity(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
|
||
ULONG
|
||
DriverEntry (
|
||
IN PVOID DriverObject,
|
||
IN PVOID Argument2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Installable driver initialization entry point for system.
|
||
|
||
Arguments:
|
||
|
||
Driver Object
|
||
|
||
Return Value:
|
||
|
||
Status from ScsiPortInitialize()
|
||
|
||
--*/
|
||
|
||
{
|
||
HW_INITIALIZATION_DATA hwInitializationData;
|
||
ULONG i;
|
||
ULONG AdapterCount = 0;
|
||
|
||
DebugPrint((1,"\n\nSCSI UltraStor 124 MiniPort Driver\n"));
|
||
|
||
//
|
||
// Zero out structure.
|
||
//
|
||
|
||
for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
|
||
((PUCHAR)&hwInitializationData)[i] = 0;
|
||
}
|
||
|
||
//
|
||
// Set size of hwInitializationData.
|
||
//
|
||
|
||
hwInitializationData.HwInitializationDataSize =
|
||
sizeof(HW_INITIALIZATION_DATA);
|
||
|
||
//
|
||
// Set entry points.
|
||
//
|
||
|
||
hwInitializationData.HwInitialize = Ultra124Initialize;
|
||
hwInitializationData.HwFindAdapter = Ultra124FindAdapter;
|
||
hwInitializationData.HwStartIo = Ultra124StartIo;
|
||
hwInitializationData.HwInterrupt = Ultra124Interrupt;
|
||
hwInitializationData.HwResetBus = Ultra124ResetBus;
|
||
|
||
//
|
||
// Set number of access ranges and bus type.
|
||
//
|
||
|
||
hwInitializationData.NumberOfAccessRanges = 1;
|
||
hwInitializationData.AdapterInterfaceType = Eisa;
|
||
|
||
//
|
||
// Indicate no buffer mapping but will need physical addresses.
|
||
//
|
||
|
||
hwInitializationData.NeedPhysicalAddresses = TRUE;
|
||
|
||
//
|
||
// Indicate multiple requests per LUN is supported.
|
||
//
|
||
|
||
hwInitializationData.MultipleRequestPerLu = TRUE;
|
||
|
||
//
|
||
// Indicate auto request sense is supported.
|
||
//
|
||
|
||
hwInitializationData.AutoRequestSense = TRUE;
|
||
|
||
//
|
||
// Specify size of extensions.
|
||
//
|
||
|
||
hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
|
||
|
||
//
|
||
// Ask for SRB extensions for MSCPs.
|
||
//
|
||
|
||
hwInitializationData.SrbExtensionSize = sizeof(MSCP);
|
||
return ScsiPortInitialize(DriverObject,
|
||
Argument2,
|
||
&hwInitializationData,
|
||
&AdapterCount);
|
||
|
||
} // end DriverEntry()
|
||
|
||
|
||
ULONG
|
||
Ultra124FindAdapter(
|
||
IN PVOID HwDeviceExtension,
|
||
IN PVOID Context,
|
||
IN PVOID BusInformation,
|
||
IN PCHAR ArgumentString,
|
||
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
||
OUT PBOOLEAN Again
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called by the OS-specific port driver after
|
||
the necessary storage has been allocated, to gather information
|
||
about the adapter's configuration.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - HBA miniport driver's adapter data storage
|
||
ConfigInfo - Configuration information structure describing HBA
|
||
|
||
Return Value:
|
||
|
||
TRUE if adapter present in system
|
||
|
||
--*/
|
||
|
||
{
|
||
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
|
||
PEISA_CONTROLLER eisaController;
|
||
ULONG eisaSlotNumber;
|
||
PVOID eisaAddress;
|
||
PULONG adapterCount = Context;
|
||
UCHAR interruptLevel;
|
||
|
||
//
|
||
// Check to see if adapter present in system.
|
||
//
|
||
|
||
for (eisaSlotNumber=*adapterCount + 1;
|
||
eisaSlotNumber<MAXIMUM_EISA_SLOTS;
|
||
eisaSlotNumber++) {
|
||
|
||
//
|
||
// Update the adapter count to indicate this slot has been checked.
|
||
//
|
||
|
||
(*adapterCount)++;
|
||
|
||
//
|
||
// Get the system address for this card.
|
||
// The card uses I/O space.
|
||
//
|
||
|
||
eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
|
||
ConfigInfo->AdapterInterfaceType,
|
||
ConfigInfo->SystemIoBusNumber,
|
||
ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
|
||
0x1000,
|
||
TRUE);
|
||
|
||
eisaController =
|
||
(PEISA_CONTROLLER)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
|
||
|
||
if (ScsiPortReadPortUlong(&eisaController->BoardId) ==
|
||
ULTRASTOR_124_EISA_ID) {
|
||
DebugPrint((1,
|
||
"Ultra124: Adapter found at EISA slot %d\n",
|
||
eisaSlotNumber));
|
||
break;
|
||
}
|
||
|
||
//
|
||
// If an adapter was not found unmap it.
|
||
//
|
||
|
||
ScsiPortFreeDeviceBase(deviceExtension,
|
||
eisaAddress);
|
||
|
||
} // end for (eisaSlotNumber ...
|
||
|
||
if (!(eisaSlotNumber < MAXIMUM_EISA_SLOTS)) {
|
||
|
||
//
|
||
// No adapter was found. Indicate that we are done and there are no
|
||
// more adapters here. Clear the adapter count for the next bus.
|
||
//
|
||
|
||
*Again = FALSE;
|
||
*adapterCount = 0;
|
||
return SP_RETURN_NOT_FOUND;
|
||
}
|
||
|
||
//
|
||
// There is still more to look at.
|
||
//
|
||
|
||
*Again = TRUE;
|
||
|
||
//
|
||
// Store base address of EISA registers in device extension.
|
||
//
|
||
|
||
deviceExtension->EisaController = eisaController;
|
||
deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0] = 0x07; //fix to 7 for U124
|
||
|
||
//
|
||
// Indicate maximum transfer length in bytes.
|
||
//
|
||
|
||
ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
|
||
|
||
//
|
||
// Maximum number of physical segments is 32.
|
||
//
|
||
|
||
ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
|
||
ConfigInfo->ScatterGather = TRUE;
|
||
ConfigInfo->Master = TRUE;
|
||
ConfigInfo->NumberOfBuses = 1;
|
||
|
||
//
|
||
// Get the system interrupt vector and IRQL.
|
||
//
|
||
|
||
interruptLevel =
|
||
ScsiPortReadPortUchar(&eisaController->InterruptLevel) & 0xF0;
|
||
|
||
switch (interruptLevel) {
|
||
case US_INTERRUPT_LEVEL_15:
|
||
ConfigInfo->BusInterruptLevel = 15;
|
||
break;
|
||
|
||
case US_INTERRUPT_LEVEL_14:
|
||
ConfigInfo->BusInterruptLevel = 14;
|
||
break;
|
||
|
||
case US_INTERRUPT_LEVEL_11:
|
||
ConfigInfo->BusInterruptLevel = 11;
|
||
break;
|
||
|
||
case US_INTERRUPT_LEVEL_10:
|
||
ConfigInfo->BusInterruptLevel = 10;
|
||
break;
|
||
|
||
default:
|
||
DebugPrint((1,"Ultra124FindAdapter: No interrupt level\n"));
|
||
return SP_RETURN_ERROR;
|
||
}
|
||
|
||
//
|
||
// Fill in the access array information.
|
||
//
|
||
|
||
(*ConfigInfo->AccessRanges)[0].RangeStart =
|
||
ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + EISA_ADDRESS_BASE);
|
||
(*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
|
||
(*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
|
||
|
||
return SP_RETURN_FOUND;
|
||
|
||
} // end Ultra124FindAdapter()
|
||
|
||
|
||
BOOLEAN
|
||
Ultra124Initialize(
|
||
IN PVOID HwDeviceExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Inititialize adapter.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
TRUE - if initialization successful.
|
||
FALSE - if initialization unsuccessful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
|
||
PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
|
||
|
||
DebugPrint((3,"Ultra124Initialize: Enter routine\n"));
|
||
|
||
|
||
//
|
||
// Enable system doorbell interrupt.
|
||
//
|
||
|
||
ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
|
||
US_ENABLE_SYSTEM_INTERRUPT+US_ENABLE_CSIR_INTERRUPT+US_ENABLE_MSCP_INTERRUPT);
|
||
|
||
return(TRUE);
|
||
|
||
} // end Ultra124Initialize()
|
||
|
||
|
||
BOOLEAN
|
||
Ultra124StartIo(
|
||
IN PVOID HwDeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called from the SCSI port driver synchronized
|
||
with the kernel to send an MSCP.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - HBA miniport driver's adapter data storage
|
||
Srb - IO request packet
|
||
|
||
Return Value:
|
||
|
||
TRUE
|
||
|
||
--*/
|
||
|
||
{
|
||
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
|
||
PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
|
||
PMSCP mscp;
|
||
PUCHAR mscpbuffer;
|
||
PSCSI_REQUEST_BLOCK abortedSrb;
|
||
ULONG physicalMscp;
|
||
ULONG length;
|
||
ULONG i = 0;
|
||
|
||
DebugPrint((2,"Ultra124StartIo: Enter routine\n"));
|
||
|
||
//DEBUGSTOP();
|
||
|
||
ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
|
||
|
||
//
|
||
// Make sure that the request is for a valid SCSI bus and LUN as
|
||
// the Ultra124 SCSI card does random things if address is wrong.
|
||
//
|
||
|
||
if (Srb->PathId != 0 || Srb->Lun != 0) {
|
||
|
||
//
|
||
// The Ultra124 card only supports logical unit zero and one bus.
|
||
//
|
||
DebugPrint((1,"Ultra124StartIo: Invalid LUN\n"));
|
||
|
||
Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
//
|
||
// Adapter ready for next request.
|
||
//
|
||
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Get MSCP from SRB.
|
||
//
|
||
|
||
mscp = Srb->SrbExtension;
|
||
mscpbuffer = (PUCHAR) mscp;
|
||
|
||
for (i=0; i<sizeof(MSCP); i++) //initialize as 0
|
||
(UCHAR) mscpbuffer[i] = 0;
|
||
|
||
//
|
||
// Save SRB back pointer in MSCP.
|
||
//
|
||
|
||
mscp->SrbAddress = Srb;
|
||
|
||
//
|
||
// Get MSCP physical address.
|
||
//
|
||
|
||
physicalMscp =
|
||
ScsiPortConvertPhysicalAddressToUlong(
|
||
ScsiPortGetPhysicalAddress(deviceExtension, NULL, mscp, &length));
|
||
|
||
//
|
||
// Assume physical address is contiguous for size of ECB.
|
||
//
|
||
|
||
ASSERT(length >= sizeof(MSCP));
|
||
|
||
switch (Srb->Function) {
|
||
|
||
case SRB_FUNCTION_EXECUTE_SCSI:
|
||
DebugPrint((3,"Ultra124StartIo: SCSI Execute IO\n"));
|
||
|
||
if (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
|
||
DebugPrint((3,"Ultra124StartIo: SCSI Read Capacity\n"));
|
||
|
||
if (ReadDriveCapacity(deviceExtension, Srb)) {
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
return TRUE;
|
||
}
|
||
else {
|
||
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
return TRUE;
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// Build MSCP for this request.
|
||
//
|
||
if (!(BuildMscp(deviceExtension, Srb))) {
|
||
//
|
||
// Set error, complete request
|
||
// and signal ready for next request.
|
||
//
|
||
DebugPrint((1,"Ultra124StartIo: BuildMscp Fail\n"));
|
||
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
}
|
||
break;
|
||
|
||
//{$8_24
|
||
case SRB_FUNCTION_RESET_BUS:
|
||
|
||
//
|
||
// Reset Ultra124 and SCSI bus.
|
||
//
|
||
|
||
DebugPrint((1, "Ultra124StartIo: Reset bus request received\n"));
|
||
|
||
if (!Ultra124ResetBus( deviceExtension, Srb->PathId)) {
|
||
DebugPrint((1,"Ultra124StartIo: Reset bus failed\n"));
|
||
Srb->SrbStatus = SRB_STATUS_ERROR;
|
||
}
|
||
else {
|
||
DebugPrint((1,"Ultra124StartIo: Reset bus O.K.\n"));
|
||
Srb->SrbStatus = SRB_STATUS_SUCCESS;
|
||
}
|
||
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
return TRUE;
|
||
|
||
//$11_4
|
||
case SRB_FUNCTION_ABORT_COMMAND:
|
||
|
||
DebugPrint((1, "Ultra124StartIo: Received Abort command\n"));
|
||
//
|
||
// Verify that SRB to abort is still outstanding.
|
||
//
|
||
|
||
abortedSrb = ScsiPortGetSrb(deviceExtension,
|
||
Srb->PathId,
|
||
Srb->TargetId,
|
||
Srb->Lun,
|
||
Srb->QueueTag);
|
||
|
||
if (abortedSrb != Srb->NextSrb ||
|
||
abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
|
||
|
||
DebugPrint((1, "Ultra124StartIo: SRB to abort already completed\n"));
|
||
|
||
//
|
||
// Complete abort SRB.
|
||
//
|
||
Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
//
|
||
// Adapter ready for next request.
|
||
//
|
||
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
}
|
||
else {
|
||
|
||
abortedSrb->SrbStatus = SRB_STATUS_ABORTED;
|
||
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
abortedSrb);
|
||
//
|
||
// Complete abort SRB.
|
||
//
|
||
|
||
Srb->SrbStatus = SRB_STATUS_SUCCESS;
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
|
||
//
|
||
// Adapter ready for next request.
|
||
//
|
||
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
}
|
||
return TRUE;
|
||
|
||
//$8_24}
|
||
default:
|
||
|
||
//
|
||
// Set error, complete request
|
||
// and signal ready for next request.
|
||
//
|
||
|
||
DebugPrint((1,"Ultra124StartIo: Request Not Support\n"));
|
||
|
||
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
||
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
return TRUE;
|
||
|
||
} // end switch
|
||
|
||
//
|
||
// Write MSCP pointer and command to mailbox.
|
||
//
|
||
|
||
|
||
DebugPrint((3,"Ultra124StartIo: Check if OGM available\n"));
|
||
|
||
for (i=0; i<500; i++) {
|
||
|
||
if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) & US_MSCP_IN_USE)) {
|
||
break;
|
||
}
|
||
else {
|
||
//
|
||
// Stall 1 microsecond before trying again.
|
||
//
|
||
ScsiPortStallExecution(1);
|
||
}
|
||
}
|
||
|
||
if (i == 500) {
|
||
//
|
||
// Let operating system time out SRB.
|
||
//
|
||
DebugPrint((1,"Ultra124StartIo: Timed out waiting for mailbox\n"));
|
||
//
|
||
// Set error, complete request
|
||
// and signal ready for next request.
|
||
//
|
||
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
||
ScsiPortNotification(RequestComplete,
|
||
deviceExtension,
|
||
Srb);
|
||
ScsiPortNotification(NextRequest,
|
||
deviceExtension,
|
||
NULL);
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Write MSCP pointer to mailbox.
|
||
//
|
||
DebugPrint((2,"Ultra124StartIo: Send out OGM (Log.Addr %lx)\n",mscp));
|
||
ScsiPortWritePortUlong(&eisaController->OutGoingMailPointer,
|
||
physicalMscp);
|
||
//
|
||
// Send MAIL OUT
|
||
// Ring the local doorbell.
|
||
//
|
||
ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
|
||
US_MSCP_IN_USE);
|
||
}
|
||
|
||
//
|
||
// Adapter ready for next request.
|
||
//
|
||
ScsiPortNotification(NextLuRequest,
|
||
deviceExtension,
|
||
Srb->PathId,
|
||
Srb->TargetId,
|
||
Srb->Lun);
|
||
|
||
return TRUE;
|
||
|
||
} // end Ultra124StartIo()
|
||
|
||
|
||
BOOLEAN
|
||
Ultra124Interrupt(
|
||
IN PVOID HwDeviceExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the interrupt service routine for the Ultra124 SCSI adapter.
|
||
It reads the interrupt register to determine if the adapter is indeed
|
||
the source of the interrupt and clears the interrupt at the device.
|
||
If the adapter is interrupting because a mailbox is full, the MSCP is
|
||
retrieved to complete the request.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
TRUE if MailboxIn full
|
||
|
||
--*/
|
||
|
||
{
|
||
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
|
||
PMSCP mscp;
|
||
PSCSI_REQUEST_BLOCK srb;
|
||
PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
|
||
ULONG physicalMscp;
|
||
UCHAR mscpStatus, csirStatus;
|
||
UCHAR InterruptMode;
|
||
UCHAR CDBOpcode;
|
||
ULONG BlockSize, TotalBlock;
|
||
PINQUIRYDATA InquiryBuffer;
|
||
PSCSI_READCAPACITY ReadCapacityBuffer;
|
||
|
||
CONST UCHAR VendorId[] = "ULTRSTOR";
|
||
CONST UCHAR ProductId[] = "U124 DiskArray ";
|
||
CONST UCHAR ProductRevisionLevel[] = "1.00";
|
||
UCHAR i;
|
||
|
||
//
|
||
// Check interrupt pending.
|
||
//
|
||
// Check CSIR command
|
||
|
||
|
||
DebugPrint((2,"Ultra124Interrupt: Enter routine\n"));
|
||
|
||
//DEBUGSTOP();
|
||
|
||
|
||
InterruptMode = ScsiPortReadPortUchar(&eisaController->SystemDoorBellInterrupt);
|
||
|
||
InterruptMode &= US_CSIR_COMPLETE + US_MSCP_COMPLETE;
|
||
|
||
switch (InterruptMode) {
|
||
|
||
case US_CSIR_COMPLETE:
|
||
|
||
DebugPrint((3, "U124Interrupt: CSIR interrupt\n"));
|
||
|
||
csirStatus = ScsiPortReadPortUchar(&eisaController->CSPByte0);
|
||
|
||
srb = deviceExtension->CSIRSrb;
|
||
|
||
if (!(csirStatus & CSIR_ERROR)) {
|
||
|
||
CDBOpcode = srb->Cdb[0];
|
||
|
||
switch (CDBOpcode) {
|
||
|
||
case SCSIOP_READ_CAPACITY:
|
||
|
||
TotalBlock = ScsiPortReadPortUlong((PULONG)(&eisaController->CSPByte2));
|
||
BlockSize = 0x200;
|
||
DebugPrint((3, "U124Interrupt(ReadCapacity): TotalBock %ld\n",TotalBlock ));
|
||
ReadCapacityBuffer = (PSCSI_READCAPACITY) srb->DataBuffer;
|
||
DebugPrint((3, "U124Interrupt: SRB Data Buffer -> %lx\n",
|
||
srb->DataBuffer));
|
||
DebugPrint((3, "U124Interrupt: Inquiry Buffer -> %lx\n",
|
||
ReadCapacityBuffer));
|
||
INTEL4_TO_SCSI4((PSCSI_4_BYTE) ReadCapacityBuffer->BlockCount,
|
||
(PINTEL_4_BYTE) &TotalBlock);
|
||
INTEL4_TO_SCSI4((PSCSI_4_BYTE) ReadCapacityBuffer->BlockLength,
|
||
(PINTEL_4_BYTE) &BlockSize);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
||
srb->ScsiStatus = SCSISTAT_GOOD;
|
||
|
||
}
|
||
else {
|
||
DebugPrint((1, "U124Interrupt: CSIR interrupt with Error\n"));
|
||
MapErrorToSrbStatus(deviceExtension, srb);
|
||
}
|
||
|
||
// Call notification routine for the SRB.
|
||
|
||
ScsiPortNotification( RequestComplete,
|
||
(PVOID)deviceExtension,
|
||
srb);
|
||
|
||
// Reset system doorbell interrupt.
|
||
|
||
ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
|
||
US_RESET_CSIR_COMPLETE);
|
||
|
||
return TRUE;
|
||
|
||
case US_MSCP_COMPLETE:
|
||
|
||
DebugPrint((3, "U124Interrupt: MSCP interrupt\n"));
|
||
physicalMscp = ScsiPortReadPortUlong(&eisaController->InComingMailPointer);
|
||
//
|
||
// Get virtual MSCP address.
|
||
//
|
||
mscp = ScsiPortGetVirtualAddress(deviceExtension,
|
||
ScsiPortConvertUlongToPhysicalAddress(physicalMscp));
|
||
//
|
||
// Make sure the physical address was valid.
|
||
//
|
||
if (mscp == NULL) {
|
||
DebugPrint((1,"Ultra124Interrupt: No MSCP found\n"));
|
||
// Reset system doorbell interrupt.
|
||
ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
|
||
US_RESET_MSCP_COMPLETE);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
srb = mscp->SrbAddress; // get SRB
|
||
if (srb == NULL) {
|
||
|
||
DebugPrint((1, "U124Interrupt: Srb in MSCP is NULL.\n"));
|
||
|
||
ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
|
||
US_RESET_MSCP_COMPLETE);
|
||
return FALSE;
|
||
}
|
||
|
||
DebugPrint((2, "U124Interrupt: MSCP Log. Addr ->%lx\n",mscp));
|
||
DebugPrint((2, "U124Interrupt: SRB Log. Addr ->%lx\n",srb));
|
||
mscpStatus = mscp->OperationCode; //Error Code
|
||
|
||
if (mscpStatus & MSCP_ERROR) {
|
||
|
||
//
|
||
// Translate adapter status to SRB status
|
||
// and log error if necessary.
|
||
//
|
||
|
||
DebugPrint((1, "U124Interrupt: MSCP Done Fail.\n"));
|
||
MapErrorToSrbStatus(deviceExtension, srb);
|
||
}
|
||
else {
|
||
DebugPrint((3, "U124Interrupt: MSCP Status O.K.\n"));
|
||
CDBOpcode = srb->Cdb[0];
|
||
|
||
switch (CDBOpcode) {
|
||
case SCSIOP_INQUIRY:
|
||
DebugPrint((3, "U124Interrupt: SCSI Inquiry Command done\n"));
|
||
|
||
InquiryBuffer = (PINQUIRYDATA) srb->DataBuffer;
|
||
|
||
//
|
||
// clear the InquiryBuffer before filling in data to avoid
|
||
// garbage data in buffer (because some field in Inquiry data
|
||
// structure are defined in bits value.
|
||
//
|
||
|
||
for (i=0; i<srb->DataTransferLength; i++) {
|
||
*((PUCHAR) InquiryBuffer+i) = 0;
|
||
}
|
||
|
||
DebugPrint((3, "U124Interrupt: SRB Data Buffer -> %lx\n",
|
||
srb->DataBuffer));
|
||
|
||
DebugPrint((3, "U124Interrupt: Inquiry Buffer -> %lx\n",
|
||
InquiryBuffer));
|
||
InquiryBuffer->DeviceType = DIRECT_ACCESS_DEVICE;
|
||
InquiryBuffer->DeviceTypeModifier = 0; //not removable
|
||
|
||
InquiryBuffer->Versions = 0x02; //scsi 2
|
||
InquiryBuffer->ResponseDataFormat = 0x02; //scsi 2
|
||
InquiryBuffer->AdditionalLength = 0x8f; //scsi 2
|
||
|
||
InquiryBuffer->SoftReset = 0; //scsi 2
|
||
InquiryBuffer->CommandQueue = 1;
|
||
InquiryBuffer->Reserved2 = 0;
|
||
InquiryBuffer->LinkedCommands = 1;
|
||
InquiryBuffer->Synchronous = 1;
|
||
InquiryBuffer->Wide16Bit = 0;
|
||
InquiryBuffer->Wide32Bit = 0;
|
||
InquiryBuffer->RelativeAddressing = 1;
|
||
|
||
for (i=0; i<8; i++)
|
||
(UCHAR) InquiryBuffer->VendorId[i] = (UCHAR) VendorId[i];
|
||
|
||
for (i=0; i<16; i++)
|
||
(UCHAR) InquiryBuffer->ProductId[i] = (UCHAR) ProductId[i];
|
||
|
||
for (i=0; i<4; i++)
|
||
(UCHAR) InquiryBuffer->ProductRevisionLevel[i] = (UCHAR) ProductRevisionLevel[i];
|
||
|
||
break;
|
||
|
||
default:
|
||
DebugPrint((2, "U124Interrupt: SCSI command -> %x\n", CDBOpcode));
|
||
break;
|
||
}
|
||
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
||
srb->ScsiStatus = SCSISTAT_GOOD;
|
||
}
|
||
//
|
||
// Call notification routine for the SRB.
|
||
//
|
||
ScsiPortNotification(RequestComplete,
|
||
(PVOID)deviceExtension,
|
||
srb);
|
||
ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
|
||
US_RESET_MSCP_COMPLETE);
|
||
|
||
return TRUE;
|
||
|
||
default:
|
||
//
|
||
// Handle spurious interrupt.
|
||
//
|
||
DebugPrint((1,"Ultra124Interrupt: Spurious interrupt\n"));
|
||
//
|
||
// Log the error.
|
||
//
|
||
|
||
ScsiPortLogError(HwDeviceExtension,
|
||
NULL,
|
||
0,
|
||
deviceExtension->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
0
|
||
);
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
|
||
} // end Ultra124Interrupt()
|
||
|
||
|
||
BOOLEAN
|
||
BuildMscp(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build MSCP for Ultra124 from SRB.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtenson
|
||
SRB
|
||
|
||
Return Value:
|
||
TRUE: MSCP command ready to send
|
||
FALSE: no U124 command match this SCSI pass thru command
|
||
--*/
|
||
|
||
{
|
||
PMSCP mscp = Srb->SrbExtension;
|
||
UCHAR CDBopcode;
|
||
|
||
|
||
DebugPrint((3,"BuildMscp: Enter routine\n"));
|
||
|
||
//
|
||
// Set MSCP command.
|
||
//
|
||
|
||
mscp->DriveControl = Srb->TargetId << 5;
|
||
CDBopcode = Srb->Cdb[0]; //get SCSI CDB opcode
|
||
DebugPrint((2, "U124BuildMSCP: SCSI command -> %x\n", CDBopcode));
|
||
|
||
switch (CDBopcode) {
|
||
case SCSIOP_INQUIRY:
|
||
mscp->OperationCode = MSCP_TEST_DRIVE_READY; //use for inquiry
|
||
break;
|
||
|
||
case SCSIOP_TEST_UNIT_READY:
|
||
mscp->OperationCode = MSCP_TEST_DRIVE_READY;
|
||
break;
|
||
|
||
case SCSIOP_REZERO_UNIT:
|
||
mscp->OperationCode = MSCP_REZERO_DRIVE;
|
||
break;
|
||
|
||
case SCSIOP_READ:
|
||
mscp->OperationCode = MSCP_READ_SECTOR;
|
||
SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
|
||
break;
|
||
|
||
case SCSIOP_READ6:
|
||
mscp->OperationCode = MSCP_READ_SECTOR;
|
||
SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
|
||
break;
|
||
|
||
case SCSIOP_WRITE:
|
||
mscp->OperationCode = MSCP_WRITE_SECTOR;
|
||
SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
|
||
break;
|
||
|
||
case SCSIOP_WRITE6:
|
||
mscp->OperationCode = MSCP_WRITE_SECTOR;
|
||
SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
|
||
break;
|
||
|
||
case SCSIOP_VERIFY:
|
||
mscp->OperationCode = MSCP_VERIFY_SECTOR;
|
||
SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
|
||
break;
|
||
|
||
case SCSIOP_VERIFY6:
|
||
mscp->OperationCode = MSCP_VERIFY_SECTOR;
|
||
SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
|
||
break;
|
||
|
||
case SCSIOP_SEEK:
|
||
mscp->OperationCode = MSCP_SEEK_DRIVE;
|
||
SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
|
||
break;
|
||
|
||
case SCSIOP_SEEK6:
|
||
mscp->OperationCode = MSCP_SEEK_DRIVE;
|
||
SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
|
||
break;
|
||
|
||
default:
|
||
return FALSE; // no U124 command match this SCSI pass thru command
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Build SGL in MSCP if data transfer.
|
||
//
|
||
if (Srb->DataTransferLength > 0) {
|
||
//
|
||
// Build scattergather descriptor list.
|
||
//
|
||
BuildSgl(DeviceExtension, Srb);
|
||
}
|
||
else {
|
||
//
|
||
// Set up MSCP for no data transfer.
|
||
//
|
||
mscp->DataLength = 0;
|
||
mscp->SgDescriptorCount = 0;
|
||
}
|
||
DebugPrint((2, "U124StartIO: Build MSCP done, MSCP-> %lx\n",mscp));
|
||
|
||
return TRUE;
|
||
|
||
} // end BuildMscp()
|
||
|
||
|
||
VOID
|
||
BuildSgl(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine builds a scatter/gather descriptor list in the MSCP.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension
|
||
Srb
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID dataPointer = Srb->DataBuffer;
|
||
ULONG bytesLeft = Srb->DataTransferLength;
|
||
PMSCP mscp = Srb->SrbExtension;
|
||
PSDL sdl = &mscp->Sdl;
|
||
ULONG physicalSdl;
|
||
ULONG physicalAddress;
|
||
ULONG length;
|
||
ULONG descriptorCount = 0;
|
||
|
||
//
|
||
// Get physical SDL address.
|
||
//
|
||
|
||
physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
|
||
ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
|
||
sdl, &length));
|
||
|
||
//
|
||
// Assume physical memory contiguous for sizeof(SGL) bytes.
|
||
//
|
||
|
||
ASSERT(length >= sizeof(SDL));
|
||
|
||
//
|
||
// Create SDL segment descriptors.
|
||
//
|
||
|
||
do {
|
||
DebugPrint((3, "BuildSgl: Data buffer %lx\n", dataPointer));
|
||
//
|
||
// Get physical address and length of contiguous
|
||
// physical buffer.
|
||
//
|
||
physicalAddress =
|
||
ScsiPortConvertPhysicalAddressToUlong(
|
||
ScsiPortGetPhysicalAddress(DeviceExtension,
|
||
Srb,
|
||
dataPointer,
|
||
&length));
|
||
|
||
DebugPrint((3, "BuildSgl: Physical address %lx\n", physicalAddress));
|
||
DebugPrint((3, "Sgl: Data length %lx\n", length));
|
||
DebugPrint((3, "BuildSgl: Bytes left %lx\n", bytesLeft));
|
||
|
||
//
|
||
// If length of physical memory is more
|
||
// than bytes left in transfer, use bytes
|
||
// left as final length.
|
||
//
|
||
|
||
if (length > bytesLeft) {
|
||
length = bytesLeft;
|
||
}
|
||
|
||
sdl->Descriptor[descriptorCount].Address = physicalAddress;
|
||
sdl->Descriptor[descriptorCount].Length = length;
|
||
|
||
//
|
||
// Adjust counts.
|
||
//
|
||
|
||
dataPointer = (PUCHAR)dataPointer + length;
|
||
bytesLeft -= length;
|
||
descriptorCount++;
|
||
|
||
} while (bytesLeft);
|
||
|
||
//
|
||
// Check for only one descriptor. As an optimization, in these
|
||
// cases, use nonscattergather requests.
|
||
//
|
||
|
||
if (descriptorCount == 1) {
|
||
//
|
||
// Set descriptor count to 0.
|
||
//
|
||
mscp->SgDescriptorCount = 0;
|
||
|
||
//
|
||
// Set data pointer to data buffer.
|
||
//
|
||
mscp->DataPointer = physicalAddress;
|
||
|
||
//
|
||
// Set data transfer length.
|
||
//
|
||
mscp->DataLength = Srb->DataTransferLength;
|
||
|
||
//
|
||
// Clear scattergather bit.
|
||
//
|
||
|
||
}
|
||
else {
|
||
//
|
||
// Write SDL count to MSCP.
|
||
//
|
||
mscp->SgDescriptorCount = (UCHAR)descriptorCount;
|
||
|
||
//
|
||
// Write SGL address to ECB.
|
||
//
|
||
mscp->DataPointer = physicalSdl;
|
||
mscp->DataLength = Srb->DataTransferLength;
|
||
|
||
//
|
||
// Indicate scattergather operation.
|
||
//
|
||
mscp->DriveControl |= EnableScatterGather;
|
||
}
|
||
|
||
DebugPrint((2,"BuildSgl: SG-> %d, XfrBuffer-> %lx, XfrLength-> %lx\n",
|
||
descriptorCount, mscp->DataPointer, mscp->DataLength));
|
||
return;
|
||
|
||
} // end BuildSgl()
|
||
|
||
|
||
BOOLEAN
|
||
Ultra124ResetBus(
|
||
IN PVOID HwDeviceExtension,
|
||
IN ULONG PathId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reset Ultra124 SCSI adapter and SCSI bus.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
|
||
PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
|
||
ULONG j;
|
||
|
||
//
|
||
// The Ultra124 only supports a single SCSI channel.
|
||
//
|
||
|
||
|
||
|
||
UNREFERENCED_PARAMETER(PathId);
|
||
DebugPrint((1,"ResetBus: Reset Ultra124 and SCSI bus\n"));
|
||
DebugPrint((3,"Ultra124ResetBUS: Enter routine\n"));
|
||
|
||
//
|
||
// Reset SCSI bus (use Reset HostAdapter).
|
||
//
|
||
ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
|
||
US_HBA_RESET);
|
||
|
||
//
|
||
// Wait for local processor to clear reset bit.
|
||
//
|
||
for (j=0; j<200000; j++) {
|
||
if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
|
||
US_HBA_RESET)) {
|
||
DebugPrint((1,"Ultra124ResetBUS: Reset H/A O.K.\n"));
|
||
break;
|
||
}
|
||
|
||
ScsiPortStallExecution(10);
|
||
|
||
} // end for (j=0 ...
|
||
|
||
|
||
if (j == 200000) {
|
||
DebugPrint((1,"Ultra124ResetBUS: Reset H/A Fail\n"));
|
||
//
|
||
// Busy has not gone low. Assume the card is gone.
|
||
// Log the error and fail the request.
|
||
//
|
||
ScsiPortLogError(deviceExtension,
|
||
NULL,
|
||
0,
|
||
deviceExtension->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
3 << 16);
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
DebugPrint((1,"Ultra124ResetBUS: Reset H/A Fail\n"));
|
||
|
||
//
|
||
// Complete all outstanding requests.
|
||
//
|
||
ScsiPortCompleteRequest(deviceExtension,
|
||
(UCHAR)0,
|
||
(UCHAR)-1,
|
||
(UCHAR)-1,
|
||
SRB_STATUS_BUS_RESET);
|
||
|
||
return TRUE;
|
||
|
||
} // end Ultra124ResetBus()
|
||
|
||
|
||
VOID
|
||
MapErrorToSrbStatus(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Translate Ultra124 error to SRB error.
|
||
|
||
Arguments:
|
||
|
||
Device Extension for logging error
|
||
SRB
|
||
|
||
Return Value:
|
||
|
||
Updated SRB
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG logError = 0;
|
||
UCHAR srbStatus;
|
||
PMSCP mscp = Srb->SrbExtension;
|
||
PUCHAR mscpbuffer;
|
||
PSENSE_DATA sensebuffer = Srb->SenseInfoBuffer;
|
||
UCHAR i;
|
||
|
||
DebugPrint((3,"Ultra124MapErrorToSrbStatus: Enter routine\n"));
|
||
mscpbuffer = (PUCHAR) Srb->SrbExtension;
|
||
Srb->ScsiStatus = SCSISTAT_GOOD; //only check-condition set when TARGET error
|
||
|
||
switch (mscp->OperationCode) {
|
||
case MSCP_TARGET_ERROR:
|
||
|
||
//
|
||
// clear the sensebuffer to 0
|
||
//
|
||
for (i=0; i< Srb->SenseInfoBufferLength; i++) {
|
||
*((PUCHAR) sensebuffer+i) = 0;
|
||
}
|
||
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_TARGET_ERROR\n"));
|
||
DebugPrint((1,"MapErrorToSrbStatus: srb->SenseInfoBufferLength = %d\n",Srb->SenseInfoBufferLength));
|
||
|
||
sensebuffer->SenseKey = (UCHAR) mscpbuffer[7];
|
||
sensebuffer->AdditionalSenseCode = (UCHAR) mscpbuffer[6];
|
||
sensebuffer->AdditionalSenseCodeQualifier = (UCHAR) mscpbuffer[5];
|
||
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
|
||
srbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
|
||
break;
|
||
|
||
case MSCP_DRIVE_FAULT:
|
||
DebugPrint((1,"MapErrorToSrbStatus: Device not found\n"));
|
||
srbStatus = SRB_STATUS_NO_DEVICE;
|
||
break;
|
||
|
||
case MSCP_DRIVE_NOT_PRESENT:
|
||
case MSCP_LOG_DRIVE_UNDEFINE:
|
||
case MSCP_LOG_DRIVE_NOT_READY:
|
||
DebugPrint((1,"MapErrorToSrbStatus: MSCP_LOG_DRIVE_NOT_READY\n"));
|
||
srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
|
||
break;
|
||
|
||
case MSCP_ADAPTER_ERROR:
|
||
switch ((UCHAR) mscpbuffer[7]) {
|
||
case HA_SELECTION_TIME_OUT:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_SELECTION_TIME_OUT\n"));
|
||
srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
|
||
break;
|
||
|
||
case HA_DATA_OVER_UNDER_RUN:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_DATA_OVER_UNDER_RUN\n"));
|
||
logError = SP_PROTOCOL_ERROR;
|
||
srbStatus = SRB_STATUS_DATA_OVERRUN;
|
||
break;
|
||
|
||
case HA_BUS_FREE_ERROR:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_BUS_FREE\n"));
|
||
logError = SP_PROTOCOL_ERROR;
|
||
srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
|
||
break;
|
||
|
||
case HA_INVALID_PHASE:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_INVALID_PHASE\n"));
|
||
logError = SP_PROTOCOL_ERROR;
|
||
srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
|
||
break;
|
||
|
||
case HA_ILLEGAL_COMMAND:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_ILLEGAL_COMMAND\n"));
|
||
srbStatus = SRB_STATUS_INVALID_REQUEST;
|
||
break;
|
||
|
||
case HA_REQ_SENSE_ERROR:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_REQ_SENSE_ERROR\n"));
|
||
srbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
|
||
break;
|
||
|
||
case HA_BUS_RESET_ERROR:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_BUS_RESET_ERROR\n"));
|
||
srbStatus = SRB_STATUS_BUS_RESET;
|
||
break;
|
||
|
||
case HA_TIME_OUT_ERROR:
|
||
DebugPrint((1,"MapErrorToSrbStatus: HA_DATA_TIME_OUT_ERROR\n"));
|
||
srbStatus = SRB_STATUS_COMMAND_TIMEOUT;
|
||
break;
|
||
|
||
default:
|
||
DebugPrint((1,"MapErrorToSrbStatus: General Failure\n"));
|
||
srbStatus = SRB_STATUS_ERROR;
|
||
|
||
}
|
||
break;
|
||
|
||
case MSCP_INVALID_COMMAND:
|
||
case MSCP_INVALID_PARAMETER:
|
||
case MSCP_INVALID_DATA_LIST:
|
||
DebugPrint((1,"MapErrorToSrbStatus: Invalid command\n"));
|
||
srbStatus = SRB_STATUS_INVALID_REQUEST;
|
||
break;
|
||
|
||
default:
|
||
DebugPrint((1,"MapErrorToSrbStatus: Unknown Error\n"));
|
||
logError = SP_PROTOCOL_ERROR;
|
||
srbStatus = SRB_STATUS_ERROR;
|
||
break;
|
||
|
||
} // end switch ...
|
||
|
||
//
|
||
// Log error if indicated.
|
||
//
|
||
|
||
if (logError) {
|
||
ScsiPortLogError(
|
||
DeviceExtension,
|
||
Srb,
|
||
Srb->PathId,
|
||
Srb->TargetId,
|
||
Srb->Lun,
|
||
logError,
|
||
2 << 16 | mscp->OperationCode
|
||
);
|
||
}
|
||
|
||
//
|
||
// Set SRB status.
|
||
//
|
||
Srb->SrbStatus = srbStatus;
|
||
|
||
//
|
||
// Set target SCSI status in SRB.
|
||
//
|
||
return;
|
||
|
||
} // end MapErrorToSrbStatus()
|
||
|
||
|
||
BOOLEAN
|
||
ReadDriveCapacity(
|
||
IN PHW_DEVICE_EXTENSION DeviceExtension,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build Read Drive Capacity CSIR command from SRB
|
||
|
||
Arguments:
|
||
|
||
DeviceExtenson
|
||
SRB
|
||
|
||
Return Value:
|
||
TRUE: CSIR command
|
||
FALSE: CSIR command not ready
|
||
--*/
|
||
|
||
{
|
||
PHW_DEVICE_EXTENSION deviceExtension = DeviceExtension;
|
||
PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
|
||
PMSCP mscp = Srb->SrbExtension;
|
||
ULONG i;
|
||
UCHAR CDBopcode;
|
||
|
||
|
||
DebugPrint((3,"ReadDriveCapcity: Enter routine\n"));
|
||
|
||
//
|
||
// Set CSIR command.
|
||
//
|
||
|
||
deviceExtension->CSIRSrb = Srb; //save for later reference
|
||
CDBopcode = Srb->Cdb[0]; //get SCSI CDB opcode
|
||
mscp->CSIRBuffer.CSIROpcode = CSIR_READ_CAPACITY;
|
||
mscp->CSIRBuffer.CSIR1 = (Srb->TargetId) << 5; //drive ID
|
||
ScsiPortWritePortUchar(&eisaController->CSPByte0,
|
||
CSIR_READ_CAPACITY);
|
||
ScsiPortWritePortUchar(&eisaController->CSPByte1,
|
||
mscp->CSIRBuffer.CSIR1);
|
||
|
||
for (i=0; i<500; i++) {
|
||
if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
|
||
US_CSIR_IN_USE)) {
|
||
|
||
DebugPrint((3,"Ultra124StartIo: Read Capacity (CSIR)\n"));
|
||
break;
|
||
}
|
||
else {
|
||
//
|
||
// Stall 1 microsecond before trying again.
|
||
//
|
||
ScsiPortStallExecution(1);
|
||
}
|
||
}
|
||
|
||
if (i == 500) {
|
||
//
|
||
// Let operating system time out SRB.
|
||
//
|
||
DebugPrint((1,"Ultra124StartIo: Timed out waiting for CSIR\n"));
|
||
return FALSE;
|
||
|
||
}
|
||
else {
|
||
//
|
||
// Send CSIR command IN
|
||
// Ring the local doorbell.
|
||
//
|
||
|
||
DebugPrint((1,"Ultra124StartIo: Send out CSIR\n"));
|
||
ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
|
||
US_CSIR_IN_USE);
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // end ReadDriveCapacity()
|
||
|
||
|