NT4/private/ntos/miniport/mitsumi/mitsumi.c
2020-09-30 17:12:29 +02:00

3366 lines
82 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
Mitsumi.c
Abstract:
This is the miniport driver for the Panasonic MKE CR5xx Proprietary CDROM drive.
Author:
Chuck Park (chuckp)
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include "miniport.h"
#include "Mitsumi.h"
#if DBG
#define GATHER_STATS 1
#endif
//
// Device extension
//
typedef struct _HW_DEVICE_EXTENSION {
//
// I/O port base address.
//
PREGISTERS BaseIoAddress;
//
// Srb being currently serviced.
//
PSCSI_REQUEST_BLOCK CurrentSrb;
//
// Pointer to data buffer
//
PUCHAR DataBuffer;
//
// Bytes left to transfer for current request.
//
ULONG ByteCount;
//
// Identifies the model.
//
DRIVE_TYPE DriveType;
//
// Current status of audio
//
ULONG AudioStatus;
//
// Saved position after pausing play.
//
ULONG SavedPosition;
//
// Ending LBA from last audio play.
//
ULONG EndPosition;
//
// Number of retries to get valid status.
//
ULONG StatusRetries;
//
// Number of microseconds to go away on CallBack requests
//
ULONG PollRate;
ULONG PollRateMultiplier;
#ifdef GATHER_STATS
//
// Used to determine hit rate for various polling increments
//
ULONG Hits[4];
ULONG Misses[4];
ULONG Requests;
BOOLEAN FirstCall;
BOOLEAN FirstStatusTry;
#endif
//
// Status from last NoOp
//
UCHAR DriveStatus;
//
// Determines whether MSF addressing is used.
//
BOOLEAN MSFAddress;
} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
#define MAX_STATUS_RETRIES 512
//
// Function declarations
//
//
ULONG
DriverEntry(
IN PVOID DriverObject,
IN PVOID Argument2
);
ULONG
MitsumiFindAdapter(
IN PVOID HwDeviceExtension,
IN PVOID Context,
IN PVOID BusInformation,
IN PCHAR ArgumentString,
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
OUT PBOOLEAN Again
);
BOOLEAN
MitsumiHwInitialize(
IN PVOID DeviceExtension
);
BOOLEAN
MitsumiStartIo(
IN PVOID DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
);
VOID
MitsumiCallBack(
IN PVOID HwDeviceExtension
);
BOOLEAN
MitsumiReset(
IN PVOID HwDeviceExtension,
IN ULONG PathId
);
BOOLEAN
FindMitsumi(
IN PHW_DEVICE_EXTENSION HwDeviceExtension
);
BOOLEAN
ReadAndMapError(
IN PHW_DEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
);
BOOLEAN
CheckStatus(
IN PVOID HwDeviceExtension
);
BOOLEAN
MitsumiBuildCommand(
IN PHW_DEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
);
BOOLEAN
MitsumiSendCommand(
IN PHW_DEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
);
UCHAR
WaitForSTEN(
IN PHW_DEVICE_EXTENSION DeviceExtension
);
BOOLEAN
UpdateCurrentPosition(
IN PHW_DEVICE_EXTENSION DeviceExtension
);
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;
DebugPrint((1,"\n\nMitsumi Proprietary CDROM 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 = MitsumiHwInitialize;
hwInitializationData.HwResetBus = MitsumiReset;
hwInitializationData.HwStartIo = MitsumiStartIo;
hwInitializationData.HwFindAdapter = MitsumiFindAdapter;
//
// Specify size of extensions.
//
hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
hwInitializationData.SrbExtensionSize = sizeof(CMD_PACKET);
//
// Specifiy the bus type and access ranges.
//
hwInitializationData.AdapterInterfaceType = Isa;
hwInitializationData.NumberOfAccessRanges = 1;
//
// Indicate PIO device.
//
hwInitializationData.MapBuffers = TRUE;
adapterCount = 0;
return (ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount));
} // end MitsumiEntry()
ULONG
MitsumiFindAdapter(
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
Context - Register base address
ConfigInfo - Configuration information structure describing HBA
This structure is defined in PORT.H.
Return Value:
ULONG
--*/
{
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
PULONG AdapterCount = Context;
CONST ULONG AdapterAddresses[] = {0x230, 0x250,0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360, 0x370, 0x380,
0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0, 0};
while (AdapterAddresses[*AdapterCount] != 0) {
//
// Map I/O space.
//
deviceExtension->BaseIoAddress = (PREGISTERS)ScsiPortGetDeviceBase(HwDeviceExtension,
ConfigInfo->AdapterInterfaceType,
ConfigInfo->SystemIoBusNumber,
ScsiPortConvertUlongToPhysicalAddress(
AdapterAddresses[*AdapterCount]),
0x4,
TRUE
);
if (!deviceExtension->BaseIoAddress) {
return SP_RETURN_ERROR;
}
(*AdapterCount)++;
if (!FindMitsumi(deviceExtension)) {
//
// CD is not at this address.
//
ScsiPortFreeDeviceBase(HwDeviceExtension,
deviceExtension->BaseIoAddress
);
continue;
} else {
//
// Indicate further searches are to be attempted.
// Why anyone would want more than one of these drives...
//
*Again = TRUE;
//
// Fill in the access ranges.
//
(*ConfigInfo->AccessRanges)[0].RangeStart =
ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*AdapterCount - 1]);
(*ConfigInfo->AccessRanges)[0].RangeLength = 4;
(*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
ConfigInfo->NumberOfBuses = 1;
ConfigInfo->InitiatorBusId[0] = 1;
ConfigInfo->MaximumTransferLength = 0x8000;
deviceExtension->AudioStatus = AUDIO_STATUS_NO_STATUS;
return SP_RETURN_FOUND;
}
}
*Again = FALSE;
*AdapterCount = 0;
return SP_RETURN_NOT_FOUND;
} // end MitsumiFindAdapter()
BOOLEAN
FindMitsumi(
IN PHW_DEVICE_EXTENSION HwDeviceExtension
)
/*++
Routine Description:
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
Return Value:
TRUE if device found.
--*/
{
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
ULONG i;
UCHAR status;
UCHAR driveId[2];
//
// If status is not 0xFF, something else is living at this location.
//
status = ScsiPortReadPortUchar(&baseIoAddress->Reset);
if (status != 0xFF) {
DebugPrint((1,
"FindMitsumi: Something else is living at %x\n",
baseIoAddress));
return FALSE;
}
status = ScsiPortReadPortUchar(&baseIoAddress->Data);
if (status != 0xFF) {
DebugPrint((1,
"FindMitsumi: Something else is living at %x\n",
baseIoAddress));
return FALSE;
}
//
// Reset the device.
//
ScsiPortWritePortUchar(&baseIoAddress->Reset,0);
ScsiPortStallExecution(10);
ScsiPortWritePortUchar(&baseIoAddress->Status, 0);
ScsiPortStallExecution (10);
ScsiPortStallExecution(10000);
ReadStatus(deviceExtension,baseIoAddress,status);
//
// Issue read drive Id command.
//
ScsiPortWritePortUchar(&baseIoAddress->Data,OP_READ_DRIVE_ID);
ReadStatus(deviceExtension,baseIoAddress,status);
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the drive id and version #.
//
for (i = 0; i < 2; i++) {
ReadStatus(deviceExtension,baseIoAddress,driveId[i]);
if (driveId[i] == 0xFF) {
return FALSE;
}
}
//
// Check the id for validity and drive type.
//
switch (driveId[0]) {
case 'M':
DebugPrint((1,
"FindMitsumi: Found LU005 at %x\n",
baseIoAddress));
deviceExtension->DriveType = LU005;
break;
case 'D':
DebugPrint((1,
"FindMitsumi: Found FX001D at %x\n",
baseIoAddress));
deviceExtension->DriveType = FX001D;
break;
case 'F':
DebugPrint((1,
"FindMitsumi: Found FX001 at %x\n",
baseIoAddress));
deviceExtension->DriveType = FX001;
break;
default:
DebugPrint((1,
"FindMitsumi: No drive found at %x\n",
baseIoAddress));
return FALSE;
}
} else {
DebugPrint((1,
"FindMitsumi: No drive found at %x\n",
baseIoAddress));
return FALSE;
}
return TRUE;
} // end FindMitsumi
BOOLEAN
MitsumiHwInitialize(
IN PVOID HwDeviceExtension
)
/*++
Routine Description:
This routine is called from ScsiPortInitialize
to set up the adapter so that it is ready to service requests.
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
Return Value:
TRUE - if initialization successful.
FALSE - if initialization unsuccessful.
--*/
{
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
deviceExtension->PollRate = 1500;
deviceExtension->PollRateMultiplier = 15;
return TRUE;
} // end MitsumiHwInitialize()
BOOLEAN
MitsumiStartIo(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
Srb - IO request packet
Return Value:
TRUE
--*/
{
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
UCHAR status;
//
// Determine which function.
//
switch (Srb->Function) {
case SRB_FUNCTION_EXECUTE_SCSI:
//
// Indicate that a request is active on the controller.
//
deviceExtension->CurrentSrb = Srb;
//
// Build the command packet.
//
if (!MitsumiBuildCommand(deviceExtension,Srb)) {
status = Srb->SrbStatus;
break;
}
//
// Send command to device.
//
if (MitsumiSendCommand(deviceExtension,Srb)) {
if ( Srb->SrbStatus == SRB_STATUS_PENDING) {
//
// Request a timer callback to finish request.
//
ScsiPortNotification(RequestTimerCall,
HwDeviceExtension,
MitsumiCallBack,
deviceExtension->PollRate * deviceExtension->PollRateMultiplier);
return TRUE;
}
}
status = Srb->SrbStatus;
break;
case SRB_FUNCTION_ABORT_COMMAND:
//
// Verify that SRB to abort is still outstanding.
//
if (!deviceExtension->CurrentSrb) {
//
// Complete abort SRB.
//
status = SRB_STATUS_ABORT_FAILED;
break;
}
//
// Fall through to reset
//
case SRB_FUNCTION_RESET_BUS:
//
// Reset the device.
//
ScsiPortWritePortUchar(&baseIoAddress->Reset,0);
ScsiPortStallExecution(10);
ScsiPortWritePortUchar(&baseIoAddress->Status, 0);
ScsiPortStallExecution (10);
//
// Update drive status in device ext.
//
ReadStatus(deviceExtension,baseIoAddress,status);
//
// Port driver will give 5 sec. to recover.
//
status = SRB_STATUS_BUS_RESET;
break;
default:
//
// Indicate unsupported command.
//
status = SRB_STATUS_INVALID_REQUEST;
break;
} // end switch
if (status != SRB_STATUS_PENDING) {
//
// Clear current SRB.
//
deviceExtension->CurrentSrb = NULL;
//
// Map status to Srb status
//
Srb->SrbStatus = (UCHAR)status;
//
// Indicate command complete.
//
ScsiPortNotification(RequestComplete,
deviceExtension,
Srb);
//
// Indicate ready for next request.
//
ScsiPortNotification(NextRequest,
deviceExtension,
NULL);
return TRUE;
}
return TRUE;
} // end MitsumiStartIo()
BOOLEAN
MitsumiReadCapacity(
IN PHW_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Extracts the 'TOC' data and manipulates it to determine
the size of the disc.
Arguments:
DeviceExtension - HBA miniport driver's adapter data storage
Return Value:
TRUE - if command was successful.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
PUCHAR data = DeviceExtension->DataBuffer;
ULONG dataLength,lba,i;
UCHAR minutes,seconds,frames;
UCHAR status;
dataLength = 8;
ReadStatus(DeviceExtension,baseIoAddress,status);
if (!(status & STATUS_DISC_IN) || (status & STATUS_DOOR_OPEN) ) {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
if (Srb->SenseInfoBufferLength) {
PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
senseBuffer->AdditionalSenseCodeQualifier = 0;
Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
}
return FALSE;
}
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the Toc data
//
for (i = 0; i < dataLength; i++) {
ReadStatus(DeviceExtension,baseIoAddress,*data);
if (*data == 0xFF) {
//
// Timeout occurred.
//
DebugPrint((1,
"MitsumiReadCapacity: Error occurred on data read.\n"));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
data++;
}
//
// All of the Toc data has been read. Now munge it into a form that is useable.
//
DeviceExtension->ByteCount = 0;
data = &DeviceExtension->DataBuffer[2];
minutes = *data++;
seconds = *data++;
frames = *data;
BCD_TO_DEC(minutes);
BCD_TO_DEC(seconds);
BCD_TO_DEC(frames);
lba = MSF_TO_LBA(minutes,seconds,frames);
DeviceExtension->DataBuffer[0] = ((PFOUR_BYTE)&lba)->Byte3;
DeviceExtension->DataBuffer[1] = ((PFOUR_BYTE)&lba)->Byte2;
DeviceExtension->DataBuffer[2] = ((PFOUR_BYTE)&lba)->Byte1;
DeviceExtension->DataBuffer[3] = ((PFOUR_BYTE)&lba)->Byte0;
*((ULONG *) &(DeviceExtension->DataBuffer[4])) = 0x00080000;
} else {
DebugPrint((1,
"MitsumiReadCapacity: Status %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
return TRUE;
} //End MitsumiReadCapacity
BOOLEAN
MitsumiRead(
IN PHW_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Carries out the read command. Each sector will be transferred to the
Srb's data buffer individually. Afterwards, a new timer call-back will
be requested.
Arguments:
DeviceExtension - HBA miniport driver's adapter data storage
Return Value:
TRUE - if data transfer is complete.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
ULONG dataLength = DeviceExtension->ByteCount;
PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
ULONG i,j;
UCHAR status;
while (DeviceExtension->ByteCount) {
//
// Check whether ready to transfer.
//
for (i = 0; i < 400; i++) {
status = ScsiPortReadPortUchar(&baseIoAddress->Status);
if (!(status & DTEN)) {
break;
} else if (!(status & STEN)){
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
status = ScsiPortReadPortUchar(&baseIoAddress->Data);
DeviceExtension->DriveStatus = status;
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
if (status & STATUS_READ_ERROR) {
DebugPrint((1,
"MitsumiRead: Read error %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
}
ScsiPortStallExecution(10);
}
if (i == 400) {
#ifdef GATHER_STATS
if (DeviceExtension->ByteCount == Srb->DataTransferLength) {
DeviceExtension->FirstCall = FALSE;
DeviceExtension->Misses[0]++;
} else {
DeviceExtension->Misses[1]++;
}
#endif
if (DeviceExtension->StatusRetries >= MAX_STATUS_RETRIES) {
DebugPrint((1,
"MitsumiRead: Resetting due to timeout waiting for DTEN\n"));
DeviceExtension->StatusRetries = 0;
//
// Clear state fields.
//
DeviceExtension->CurrentSrb = NULL;
DeviceExtension->ByteCount = 0;
DeviceExtension->DataBuffer = NULL;
//
// Reset the device.
//
MitsumiReset((PVOID)DeviceExtension, Srb->PathId);
ScsiPortNotification(ResetDetected,
DeviceExtension,
NULL);
Srb->SrbStatus = SRB_STATUS_BUS_RESET;
return FALSE;
} else {
DeviceExtension->StatusRetries++;
//
// Schedule another callback.
//
DebugPrint((2,
"MitsumiRead: DTEN timed out waiting for seek. Scheduling another callback %x\n",
status));
ScsiPortNotification(RequestTimerCall,
(PVOID)DeviceExtension,
MitsumiCallBack,
DeviceExtension->PollRate);
return FALSE;
}
}
#ifdef GATHER_STATS
else {
if (DeviceExtension->ByteCount == Srb->DataTransferLength) {
if (DeviceExtension->FirstCall) {
DeviceExtension->Hits[0]++;
DeviceExtension->FirstCall = FALSE;
}
} else {
DeviceExtension->Hits[1]++;
}
}
#endif
//
// Some unknown check that seems to be essential.
//
if (DeviceExtension->DriveType != LU005) {
//
// TODO: Fix this loop. Don't want to spin forever.
//
while (TRUE) {
status = ScsiPortReadPortUchar(&baseIoAddress->Status);
if (status & 0x01) {
break;
} else {
ScsiPortStallExecution(20);
}
}
}
//
// Ready to transfer. Set the drive in 'data' mode.
//
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
ScsiPortReadPortBufferUchar(&baseIoAddress->Data,
DeviceExtension->DataBuffer,
2048);
//
// Set the drive back to 'status' mode.
//
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
//
// Adjust Bytes left and Buffer pointer
//
DeviceExtension->DataBuffer += 2048;
DeviceExtension->ByteCount -= 2048;
DeviceExtension->StatusRetries = 0;
if (DeviceExtension->ByteCount) {
//
// If ready to transfer another sector quick enough, go and
// do so.
//
for (j = 0; j < 20; j++) {
status = ScsiPortReadPortUchar(&baseIoAddress->Status);
if ((status & DTEN)) {
if (!(status & STEN)) {
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
status = ScsiPortReadPortUchar(&baseIoAddress->Data);
DeviceExtension->DriveStatus = status;
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
if (status & STATUS_READ_ERROR) {
DebugPrint((1,
"MitsumiRead: Read error %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
}
} else {
break;
}
ScsiPortStallExecution(100);
}
if (j == 20) {
#ifdef GATHER_STATS
DeviceExtension->Misses[2]++;
#endif
DebugPrint((2,
"MitsumiRead: Request another timer\n"));
ScsiPortNotification(RequestTimerCall,
(PVOID)DeviceExtension,
MitsumiCallBack,
DeviceExtension->PollRate);
return FALSE;
}
#ifdef GATHER_STATS
else {
DeviceExtension->Hits[2]++;
}
#endif
//
// Update dataLength and try for another sector.
//
dataLength = DeviceExtension->ByteCount / 2048;
} else {
//
// Prepare to try for status.
//
DeviceExtension->StatusRetries = 0;
#ifdef GATHER_STATS
DeviceExtension->FirstStatusTry = TRUE;
#endif
ScsiPortNotification(RequestTimerCall,
(PVOID)DeviceExtension,
MitsumiCallBack,
DeviceExtension->PollRate / 2);
return FALSE;
}
}
//
// Read final status.
//
for (i = 0; i < 200; i++) {
status = ScsiPortReadPortUchar(&baseIoAddress->Status);
if (status & STEN) {
ScsiPortStallExecution(10);
} else {
break;
}
}
if (i == 200) {
#ifdef GATHER_STATS
DeviceExtension->FirstStatusTry = FALSE;
DeviceExtension->Misses[3]++;
#endif
if (DeviceExtension->StatusRetries >= MAX_STATUS_RETRIES) {
DebugPrint((1,
"MitsumiRead: Resetting due to timeout waiting for status\n"));
DeviceExtension->StatusRetries = 0;
//
// Clear state fields.
//
DeviceExtension->CurrentSrb = NULL;
DeviceExtension->ByteCount = 0;
DeviceExtension->DataBuffer = NULL;
//
// Reset the device.
//
MitsumiReset((PVOID)DeviceExtension, Srb->PathId);
ScsiPortNotification(ResetDetected,
DeviceExtension,
NULL);
Srb->SrbStatus = SRB_STATUS_BUS_RESET;
return FALSE;
} else {
DebugPrint((2,
"MitsumiRead: Status Retries for Status %x\n",
DeviceExtension->StatusRetries));
DeviceExtension->StatusRetries++;
//
// Request another callback to pick up the status
//
ScsiPortNotification(RequestTimerCall,
(PVOID)DeviceExtension,
MitsumiCallBack,
DeviceExtension->PollRate);
return FALSE;
}
}
#ifdef GATHER_STATS
if (DeviceExtension->StatusRetries == 0) {
if (DeviceExtension->FirstStatusTry) {
DeviceExtension->Hits[3]++;
} else {
DebugPrint((1,"StatusRetries = 0, FirstStatusTry = FALSE\n"));
}
}
#endif
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
status = ScsiPortReadPortUchar(&baseIoAddress->Data);
DeviceExtension->DriveStatus = status;
ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
if (status & STATUS_READ_ERROR) {
DebugPrint((1,
"MitsumiRead: Read error %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
return TRUE;
} //End MitsumiRead
BOOLEAN
GetTrackData(
IN PHW_DEVICE_EXTENSION DeviceExtension,
IN ULONG NumberTracks
)
/*++
Routine Description:
Puts the drive in 'TOC' mode so the TOC info. can be extracted for the
Subchannel Q.
Arguments:
DeviceExtension - HBA miniport driver's adapter data storage
NumberTracks - The number of tracks determined to be on the disc.
Return Value:
TRUE - if successful.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
PUCHAR data = DeviceExtension->DataBuffer;
UCHAR mask[100];
ULONG tracksFound = 0;
ULONG i,lba;
ULONG dataLength;
UCHAR status,minutes,seconds,frames,control,track,index;
UCHAR controlLow, controlHigh;
UCHAR dataBuffer[10];
ULONG zeroCount = 0,retry = 20000;
for (i = 0; i < 100; i++) {
mask[i] = 0;
}
//
// Seek to start of disk
//
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_READ_PLAY);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
ScsiPortWritePortUchar(&baseIoAddress->Data, 2);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
//
// Wait for seek to complete
//
for (i = 0; i < 40000; i++) {
status = ScsiPortReadPortUchar(&baseIoAddress->Status);
if (!(status & STEN)) {
break;
} else if (!(status & DTEN)){
DebugPrint((1,
"GetTrackData: DTEN active %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
} else {
ScsiPortStallExecution(10);
}
}
if (i == 40000) {
DebugPrint((1,
"GetTrackData: STEN timed out %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
ReadStatus(DeviceExtension,baseIoAddress,status);
if (status & (STATUS_CMD_ERROR | STATUS_READ_ERROR)) {
DebugPrint((1,
"GetTrackData: Status %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
//
// Switch drive into "TOC DATA"
//
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0x5);
ScsiPortStallExecution(1500);
ReadStatus(DeviceExtension,baseIoAddress,status);
DebugPrint((2,
"GetTrackData: Status after SET_DRV_MODE %x\n",
status));
//
// Set buffer pointer to start of track descriptors.
//
dataLength = 10;
while (tracksFound < NumberTracks) {
//
// Read sub-q to extract the embedded TOC data. This isn't pretty.
// So for the faint at heart - goto line 1245.
//
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_READ_SUB_CHANNEL);
ScsiPortStallExecution(500);
ReadStatus(DeviceExtension,baseIoAddress,status);
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the Toc data
//
for (i = 0; i < dataLength; i++) {
ReadStatus(DeviceExtension,baseIoAddress,dataBuffer[i]);
if (dataBuffer[i] == 0xFF) {
//
// Timeout occurred.
//
DebugPrint((1,
"GetTrackData: Error occurred on data read.\n"));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
ScsiPortStallExecution(1500);
ReadStatus(DeviceExtension,baseIoAddress,status);
return FALSE;
}
}
} else {
//
// Bogus packet.
//
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
ScsiPortStallExecution(1500);
ReadStatus(DeviceExtension,baseIoAddress,status);
DebugPrint((1,
"GetTrackData: Error occurred sending command.\n"));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
//
// Update bitmask of tracks found, including dealing with First, last, and multisession.
//
track = BCD_TO_DEC(dataBuffer[1]);
index = BCD_TO_DEC(dataBuffer[2]);
if (track == 0 && retry--) {
switch (index) {
case 0xA0:
//
// First track
//
DebugPrint((2,"First track\n"));
break;
case 0xA1:
//
// Last track
//
DebugPrint((2,"Last track\n"));
break;
case 0xB0:
//
// Multi-session. Through it away.
//
break;
default:
//
// Normal tracks
//
if ( (!(mask[index])) && (index < 100)) {
DebugPrint((2,"Track %d\n",index));
//
// Set the appropriate bit.
//
mask[index] = 1;
//
// Munge data into buffer
//
DebugPrint((2,"GetTrackData: track %x raw control %x\n",
index,
dataBuffer[0]));
//
// These fines drives have ADR and CONTROL flipped. Have to
// swizzle the nibbles.
//
control = dataBuffer[0];
controlHigh = (control & 0xF0) >> 4;
controlLow = control & 0x0F;
control = controlHigh | (controlLow << 4);
DebugPrint((2,"GetTrackData: track %x munged control %x\n",
index,
control));
minutes = BCD_TO_DEC(dataBuffer[7]);
seconds = BCD_TO_DEC(dataBuffer[8]);
frames = BCD_TO_DEC(dataBuffer[9]);
DebugPrint((2,"GetTrackData: control %x, msf %x %x %x\n",
control,
minutes,
seconds,
frames));
if (!DeviceExtension->MSFAddress) {
lba = MSF_TO_LBA(minutes,seconds,frames);
//
// Swizzle the block address.
//
data[7+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte3;
data[6+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte2;
data[5+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte1;
data[4+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte0;
} else {
data[7+(8*(index-1))] = frames;
data[6+(8*(index-1))] = seconds;
data[5+(8*(index-1))] = minutes;
data[4+(8*(index-1))] = 0;
}
data[3+(8*(index-1))] = 0;
data[2+(8*(index-1))] = index;
data[1+(8*(index-1))] = control;
data[0+(8*(index-1))] = 0;
//
// Update number of tracks found.
//
tracksFound++;
}
break;
} // switch
} else {
if (zeroCount++ >= 2000) {
//
// A little defensive work. It's possible that this thing
// could spin forever.
//
DebugPrint((1,"Too many zeros\n"));
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
ScsiPortStallExecution(1500);
ReadStatus(DeviceExtension,baseIoAddress,status);
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
}
} // while
DebugPrint((2,"Retry = %d\n",retry));
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
return TRUE;
} // End ReadToc
BOOLEAN
MitsumiReadToc(
IN PHW_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Arguments:
DeviceExtension - HBA miniport driver's adapter data storage
Return Value:
TRUE - if successful.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
PUCHAR data = DeviceExtension->DataBuffer;
PCDB cdb = (PCDB)Srb->Cdb;
ULONG dataLength;
ULONG i,j,lba;
UCHAR status,leadOutM,leadOutS,leadOutF;
if (cdb->READ_TOC.Format == 0) {
dataLength = 8;
//
// Ensure that the drive is ready for this.
//
ReadStatus(DeviceExtension,baseIoAddress,status);
if (!(status & STATUS_DISC_IN) || (status & STATUS_DOOR_OPEN) ) {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
if (Srb->SenseInfoBufferLength) {
PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
senseBuffer->AdditionalSenseCodeQualifier = 0;
Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
}
return FALSE;
}
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the Toc data
//
for (i = 0; i < dataLength; i++) {
ReadStatus(DeviceExtension,baseIoAddress,*data);
if (*data == 0xFF) {
//
// Timeout occurred.
//
DebugPrint((1,
"MitsumiReadToc: Error occurred on data read.\n"));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
data++;
}
//
// All of the 'Toc' data has been read. Now munge it into a form that is useable.
// The Mitsumi TOC data is abbreviated at best. The exciting GetTrackData routine
// gets the actual stuff in which we are interested.
//
DeviceExtension->ByteCount = 0;
data = DeviceExtension->DataBuffer;
leadOutM = BCD_TO_DEC(data[2]);
leadOutS = BCD_TO_DEC(data[3]);
leadOutF = BCD_TO_DEC(data[4]);
//
// Set First and Last track.
//
data[2] = BCD_TO_DEC(data[0]);
data[3] = BCD_TO_DEC(data[1]);
//
// Set sizeof TOC data
//
data[0] = ((( data[3] - data[2]) * 8) + 2) >> 8;
data[1] = ((( data[3] - data[2]) * 8) + 2) & 0xFF;
DeviceExtension->DataBuffer += 4;
if (!GetTrackData(DeviceExtension,(data[3] - data[2] + 1))) {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
//
// Push buffer pointer to end of TOC data
//
DeviceExtension->DataBuffer += 8*(data[3]-data[2] + 1);
//
// Lead out area
//
DeviceExtension->DataBuffer[0] = 0;
DeviceExtension->DataBuffer[1] = 0x10;
DeviceExtension->DataBuffer[3] = 0;
DeviceExtension->DataBuffer[2] = 0xAA;
if (!DeviceExtension->MSFAddress) {
lba = MSF_TO_LBA(leadOutM,leadOutS,leadOutF);
DeviceExtension->DataBuffer[4] = ((PFOUR_BYTE)&lba)->Byte3;
DeviceExtension->DataBuffer[5] = ((PFOUR_BYTE)&lba)->Byte2;
DeviceExtension->DataBuffer[6] = ((PFOUR_BYTE)&lba)->Byte1;
DeviceExtension->DataBuffer[7] = ((PFOUR_BYTE)&lba)->Byte0;
} else {
DeviceExtension->DataBuffer[4] = 0;
DeviceExtension->DataBuffer[5] = leadOutM;
DeviceExtension->DataBuffer[6] = leadOutS;
DeviceExtension->DataBuffer[7] = leadOutF;
}
} else {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
} else {
//
// Session info.
//
dataLength = 4;
ReadStatus(DeviceExtension,baseIoAddress,status);
if (!(status & STATUS_DISC_IN) || (status & STATUS_DOOR_OPEN) ) {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
if (Srb->SenseInfoBufferLength) {
PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
senseBuffer->AdditionalSenseCodeQualifier = 0;
Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
}
return FALSE;
}
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the 'session info' data
//
for (i = 0; i < dataLength; i++) {
ReadStatus(DeviceExtension,baseIoAddress,*data);
if (*data == 0xFF) {
//
// Timeout occurred.
//
DebugPrint((1,
"MitsumiReadToc: Error occurred on data read.\n"));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
data++;
}
DeviceExtension->ByteCount = 0;
data = DeviceExtension->DataBuffer;
leadOutM = BCD_TO_DEC(data[1]);
leadOutS = BCD_TO_DEC(data[2]);
leadOutF = BCD_TO_DEC(data[3]);
if (!DeviceExtension->MSFAddress) {
lba = MSF_TO_LBA(leadOutM,leadOutS,leadOutF);
//
// Check for non-multi session disk. The data will
// be bogus if it is.
//
if ((LONG)lba < 0) {
lba = 0;
}
DeviceExtension->DataBuffer[8] = ((PFOUR_BYTE)&lba)->Byte3;
DeviceExtension->DataBuffer[9] = ((PFOUR_BYTE)&lba)->Byte2;
DeviceExtension->DataBuffer[10] = ((PFOUR_BYTE)&lba)->Byte1;
DeviceExtension->DataBuffer[11] = ((PFOUR_BYTE)&lba)->Byte0;
} else {
data[11] = leadOutF;
data[10] = leadOutS;
data[9] = leadOutM;
data[8] = 0;
}
//
// Stuff the rest of the buffer with meaningful data.(Look in the spec.)
//
data[7] = 0;
data[6] = 0;
data[5] = 0;
data[4] = 0;
data[3] = 0x1;
data[2] = 0x1;
data[1] = 0xA;
data[0] = 0;
} else {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
}
return TRUE;
}
BOOLEAN
MitsumiReadSubQ(
IN PHW_DEVICE_EXTENSION DeviceExtension
)
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
ULONG dataLength = DeviceExtension->ByteCount;
PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
PUCHAR dataBuffer = DeviceExtension->DataBuffer;
PCDB cdb = (PCDB)Srb->Cdb;
ULONG i,j;
ULONG lba;
UCHAR status,minutes,seconds,frames;
UCHAR format = cdb->SUBCHANNEL.Format;
if (format == 1) {
ReadStatus(DeviceExtension,baseIoAddress,status);
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the position data
//
for (i = 0; i < 9; i++) {
ReadStatus(DeviceExtension,baseIoAddress,dataBuffer[i]);
if (dataBuffer[i] == 0xFF) {
//
// Timeout occurred.
//
DebugPrint((1,
"GetTrackData: Error occurred on data read.\n"));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
}
} else {
//
// Bogus packet.
//
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
ScsiPortStallExecution(1500);
ReadStatus(DeviceExtension,baseIoAddress,status);
DebugPrint((1,
"GetTrackData: Error occurred sending command.\n"));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
//
// Format the data correctly. Refer to the scsi spec.
//
if (DeviceExtension->MSFAddress) {
dataBuffer[15] = BCD_TO_DEC(dataBuffer[5]);
dataBuffer[14] = BCD_TO_DEC(dataBuffer[4]);
dataBuffer[13] = BCD_TO_DEC(dataBuffer[3]);
dataBuffer[12] = 0;
dataBuffer[11] = BCD_TO_DEC(dataBuffer[9]);
dataBuffer[10] = BCD_TO_DEC(dataBuffer[8]);
dataBuffer[9] = BCD_TO_DEC(dataBuffer[7]);
dataBuffer[8] = 0;
DebugPrint((3,"MitsumiSubQ: Current MSF %x %x %x\n",
dataBuffer[9],
dataBuffer[10],
dataBuffer[11]));
} else {
minutes = BCD_TO_DEC(dataBuffer[3]);
seconds = BCD_TO_DEC(dataBuffer[4]);
frames = BCD_TO_DEC(dataBuffer[5]);
lba = MSF_TO_LBA(minutes,seconds,frames);
dataBuffer[15] = ((PFOUR_BYTE)&lba)->Byte0;
dataBuffer[14] = ((PFOUR_BYTE)&lba)->Byte1;
dataBuffer[13] = ((PFOUR_BYTE)&lba)->Byte2;
dataBuffer[12] = ((PFOUR_BYTE)&lba)->Byte3;
minutes = BCD_TO_DEC(dataBuffer[7]);
seconds = BCD_TO_DEC(dataBuffer[8]);
frames = BCD_TO_DEC(dataBuffer[9]);
lba = MSF_TO_LBA(minutes,seconds,frames);
dataBuffer[11] = ((PFOUR_BYTE)&lba)->Byte0;
dataBuffer[10] = ((PFOUR_BYTE)&lba)->Byte1;
dataBuffer[9] = ((PFOUR_BYTE)&lba)->Byte2;
dataBuffer[8] = ((PFOUR_BYTE)&lba)->Byte3;
DebugPrint((3,"MitsumiSubQ: Current LBA %x\n",
lba));
}
dataBuffer[7] = BCD_TO_DEC(dataBuffer[2]);
dataBuffer[6] = BCD_TO_DEC(dataBuffer[1]);
dataBuffer[5] = BCD_TO_DEC(dataBuffer[0]);
dataBuffer[4] = format;
DebugPrint((3,"MitsumiSubQ: Track %x, index %x\n",
dataBuffer[6],
dataBuffer[7]));
dataBuffer[3] = 12;
dataBuffer[2] = 0;
if (status & STATUS_AUDIO) {
dataBuffer[1] = AUDIO_STATUS_PLAYING;
} else {
dataBuffer[1] = (UCHAR)DeviceExtension->AudioStatus;
DeviceExtension->AudioStatus = AUDIO_STATUS_NO_STATUS;
}
DebugPrint((3,"MitsumiSubQ: Audio Status %x\n",
dataBuffer[1]));
dataBuffer[0] = 0;
DeviceExtension->ByteCount = 0;
} else {
//
// Not supported right now.
//
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return FALSE;
}
return TRUE;
}
VOID
MitsumiCallBack(
IN PVOID HwDeviceExtension
)
/*++
Routine Description:
Timer call-back routine which functions as the ISR for this polling driver.
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
Return Value:
None
--*/
{
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
ULONG dataLength = deviceExtension->ByteCount;
PSCSI_REQUEST_BLOCK Srb = deviceExtension->CurrentSrb;
PCMD_PACKET packet;
PCDB cdb;
BOOLEAN requestSuccess = FALSE;
UCHAR scsiOp;
UCHAR status;
if (!Srb) {
//
// Something is hosed, just return.
//
DebugPrint((1,
"MitsumiCallBack: Null Srb.\n"));
return;
}
cdb = (PCDB)Srb->Cdb;
packet = (PCMD_PACKET)Srb->SrbExtension;
scsiOp = Srb->Cdb[0];
switch (scsiOp) {
case SCSIOP_READ_CAPACITY:
if (MitsumiReadCapacity(deviceExtension)) {
requestSuccess = TRUE;
}
break;
case SCSIOP_READ:
if (MitsumiRead(deviceExtension)) {
//
// Read was successful
//
requestSuccess = TRUE;
} else if (Srb->SrbStatus == SRB_STATUS_PENDING) {
//
// We have more data to transfer. Go away while the lightning fast
// mechanism does its work.
//
return;
}
break;
case SCSIOP_READ_TOC:
if (MitsumiReadToc(deviceExtension)) {
requestSuccess = TRUE;
}
break;
case SCSIOP_READ_SUB_CHANNEL:
if (MitsumiReadSubQ(deviceExtension)) {
requestSuccess = TRUE;
}
break;
case SCSIOP_PLAY_AUDIO_MSF:
ReadStatus(deviceExtension,baseIoAddress,status);
if (SUCCESS(status)) {
deviceExtension->AudioStatus = AUDIO_STATUS_SUCCESS;
requestSuccess = TRUE;
} else {
deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
}
break;
case SCSIOP_PAUSE_RESUME:
if(cdb->PAUSE_RESUME.Action) {
ULONG i;
UCHAR minutes,seconds,frames;
//
// We did a seek to the saved position. Now issue a play from here
// to the saved ending MSF.
//
ReadStatus(deviceExtension,baseIoAddress,status);
if (SUCCESS(status)) {
deviceExtension->AudioStatus = AUDIO_STATUS_SUCCESS;
requestSuccess = TRUE;
} else {
deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
}
minutes = (UCHAR)(deviceExtension->EndPosition / (60 * 75));
seconds = (UCHAR)((deviceExtension->EndPosition % (60 * 75)) / 75);
frames = (UCHAR)((deviceExtension->EndPosition % (60 * 75)) % 75);
DebugPrint((2,
"MitsumiBuildCommand: resume: lba %x, m %x, s %x, f%x\n",
deviceExtension->SavedPosition,
minutes,
seconds,
frames));
//
// Convert MSF to BCD. Don't need to setup start address and opcode since they are
// already there.
//
packet->Parameters[3] = DEC_TO_BCD(minutes);
packet->Parameters[4] = DEC_TO_BCD(seconds);
packet->Parameters[5] = DEC_TO_BCD(frames);
//
// Send the packet.
//
ScsiPortWritePortUchar(&baseIoAddress->Data,packet->OperationCode);
for (i = 0; i < 6; i++) {
ScsiPortWritePortUchar(&baseIoAddress->Data,packet->Parameters[i]);
}
//
// Wait for completion, and update status.
//
ScsiPortStallExecution(4000);
ReadStatus(deviceExtension,baseIoAddress,status);
if (SUCCESS(status)) {
deviceExtension->AudioStatus = AUDIO_STATUS_SUCCESS;
requestSuccess = TRUE;
} else {
deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
}
} else {
ReadStatus(deviceExtension,baseIoAddress,status);
if (SUCCESS(status)) {
deviceExtension->AudioStatus = AUDIO_STATUS_PAUSED;
UpdateCurrentPosition(deviceExtension);
requestSuccess = TRUE;
} else {
DebugPrint((1,"MitsumiCallBack: Error on pause %x\n",
status));
deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
}
}
break;
case SCSIOP_START_STOP_UNIT:
ReadStatus(deviceExtension,baseIoAddress,status);
if (SUCCESS(status)) {
requestSuccess = TRUE;
} else {
DebugPrint((1,"MitsumiCallBack: Error on start/stop %x\n",
status));
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
}
break;
default:
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
} //switch scsiOp
if (requestSuccess) {
//
// Update srb and scsi status.
//
if (deviceExtension->ByteCount) {
Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
} else {
Srb->SrbStatus = SRB_STATUS_SUCCESS;
}
Srb->ScsiStatus = SCSISTAT_GOOD;
}
//
// Indicate command complete.
//
ScsiPortNotification(RequestComplete,
deviceExtension,
Srb);
//
// Indicate ready for next request.
//
ScsiPortNotification(NextRequest,
deviceExtension,
NULL);
return;
}
BOOLEAN
MitsumiReset(
IN PVOID HwDeviceExtension,
IN ULONG PathId
)
/*++
Routine Description:
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
Return Value:
Nothing.
--*/
{
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
UCHAR status;
//
// Clean out device extension and complete outstanding commands.
//
if (deviceExtension->CurrentSrb) {
//
// Complete outstanding request with SRB_STATUS_BUS_RESET.
//
ScsiPortCompleteRequest(deviceExtension,
0xFF,
0xFF,
0xFF,
(ULONG)SRB_STATUS_BUS_RESET);
}
//
// Clear state fields.
//
deviceExtension->CurrentSrb = NULL;
deviceExtension->ByteCount = 0;
deviceExtension->DataBuffer = NULL;
//
// Reset the device.
//
ScsiPortWritePortUchar(&baseIoAddress->Reset,0);
ScsiPortStallExecution(10);
ScsiPortWritePortUchar(&baseIoAddress->Status, 0);
ScsiPortStallExecution (10);
ReadStatus(deviceExtension,baseIoAddress,status);
//
// Wait 1 second for unit to recover.
//
ScsiPortStallExecution (1000 * 1000);
//
// Indicate ready for next request.
//
ScsiPortNotification(NextRequest,
deviceExtension,
NULL);
return TRUE;
} // end MitsumiReset()
BOOLEAN
MitsumiBuildCommand(
IN PHW_DEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
Arguments:
HwDeviceExtension - The hardware device extension.
Srb - The current Srb.
Return Value:
status
--*/
{
PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
PCDB cdb = (PCDB)Srb->Cdb;
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
ULONG i;
UCHAR minutes,seconds,frames;
//
// Zero the packet.
//
packet->OperationCode = 0;
for (i = 0; i < 6; i++) {
packet->Parameters[i] = 0;
}
DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
DeviceExtension->ByteCount = Srb->DataTransferLength;
DeviceExtension->MSFAddress = FALSE;
Srb->SrbStatus = SRB_STATUS_PENDING;
//
// Map CDB to Panasonic packet command
//
switch (Srb->Cdb[0]) {
case SCSIOP_READ:
DeviceExtension->StatusRetries = 0;
#ifdef GATHER_STATS
DeviceExtension->Requests++;
DeviceExtension->FirstCall = TRUE;
#endif
packet->OperationCode = (DeviceExtension->DriveType == FX001D) ? OP_READ_PLAY_DBL : OP_READ_PLAY;
//
// Convert starting LBA to MSF
//
LBA_TO_MSF(cdb,minutes,seconds,frames);
//
// Convert MSF to BCD
//
packet->Parameters[0] = DEC_TO_BCD(minutes);
packet->Parameters[1] = DEC_TO_BCD(seconds);
packet->Parameters[2] = DEC_TO_BCD(frames);
//
// Convert blocks to transfer to BCD
//
packet->Parameters[3] = 0;
packet->Parameters[4] = cdb->CDB10.TransferBlocksMsb;
packet->Parameters[5] = cdb->CDB10.TransferBlocksLsb;
packet->ParameterLength = 6;
break;
case SCSIOP_START_STOP_UNIT:
if (cdb->START_STOP.Start) {
if (cdb->START_STOP.LoadEject) {
//
// Load an ejected disk and spin up.
//
packet->OperationCode = OP_LOAD;
packet->ParameterLength = 0;
} else {
//
// Spin up the device by issuing a seek to start of disk.
//
packet->OperationCode = (DeviceExtension->DriveType == FX001D) ? OP_READ_PLAY_DBL : OP_READ_PLAY;
packet->Parameters[0] = 0;
packet->Parameters[1] = 2;
packet->Parameters[2] = 0;
packet->Parameters[3] = 0;
packet->Parameters[4] = 0;
packet->Parameters[5] = 0;
packet->ParameterLength = 6;
}
} else {
if (cdb->START_STOP.LoadEject) {
//
// Eject the disk
//
packet->OperationCode = OP_EJECT;
packet->ParameterLength = 0;
} else {
//
// Seek to start and hold.
//
packet->OperationCode = OP_READ_PLAY;
packet->Parameters[0] = 0;
packet->Parameters[1] = 2;
packet->Parameters[2] = 0;
packet->Parameters[3] = 0;
packet->Parameters[4] = 0;
packet->Parameters[5] = 0;
packet->ParameterLength = 6;
}
}
break;
case SCSIOP_PAUSE_RESUME:
//
// Issue pause/resume.
//
if(cdb->PAUSE_RESUME.Action) {
//
// Resume - issue a zero length play to the "saved" MSF.
//
packet->OperationCode = OP_READ_PLAY;
//
// Convert starting LBA to MSF
//
minutes = (UCHAR)(DeviceExtension->SavedPosition / (60 * 75));
seconds = (UCHAR)((DeviceExtension->SavedPosition % (60 * 75)) / 75);
frames = (UCHAR)((DeviceExtension->SavedPosition % (60 * 75)) % 75);
DebugPrint((2,
"MitsumiBuildCommand: resume: lba %x, m %x, s %x, f%x\n",
DeviceExtension->SavedPosition,
minutes,
seconds,
frames));
//
// Convert MSF to BCD
//
packet->Parameters[0] = DEC_TO_BCD(minutes);
packet->Parameters[1] = DEC_TO_BCD(seconds);
packet->Parameters[2] = DEC_TO_BCD(frames);
//
// Setup a 'play' of zero length.
//
packet->Parameters[3] = 0;
packet->Parameters[4] = 0;
packet->Parameters[5] = 0;
packet->ParameterLength = 6;
} else {
//
// Pause - issue Hold command.
//
packet->OperationCode = OP_PAUSE;
packet->ParameterLength = 0;
}
break;
case SCSIOP_PLAY_AUDIO_MSF:
//
// Update the status to ensure that a current audio play
// is not in progress.
//
CheckStatus(DeviceExtension);
if (DeviceExtension->DriveStatus & STATUS_AUDIO) {
//
// stop the current play by issuing hold command.
//
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_PAUSE);
ScsiPortStallExecution(1000);
CheckStatus(DeviceExtension);
if (DeviceExtension->DriveStatus & STATUS_AUDIO) {
DebugPrint((1,"MitsumiBuildcommand: Audio still not paused. %x\n",
DeviceExtension->DriveStatus));
}
}
packet->OperationCode = OP_READ_PLAY;
//
// Convert MSF to BCD
//
packet->Parameters[0] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.StartingM);
packet->Parameters[1] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.StartingS);
packet->Parameters[2] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.StartingF);
//
// Convert end address to BCD
//
packet->Parameters[3] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.EndingM);
packet->Parameters[4] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.EndingS);
packet->Parameters[5] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.EndingF);
//
// Setup EndPosition in DevExt. since we may get a pause/resume.
//
DeviceExtension->EndPosition = MSF_TO_LBA(cdb->PLAY_AUDIO_MSF.EndingM,
cdb->PLAY_AUDIO_MSF.EndingS,
cdb->PLAY_AUDIO_MSF.EndingF);
//
// Determine is this is a seek. If so, zero the ending address fields to indicate
// a play of zero length.
//
if (packet->Parameters[0] == packet->Parameters[3] &&
packet->Parameters[1] == packet->Parameters[4] &&
packet->Parameters[2] == packet->Parameters[5] ) {
packet->Parameters[3] = 0;
packet->Parameters[4] = 0;
packet->Parameters[5] = 0;
}
packet->ParameterLength = 6;
break;
case SCSIOP_READ_TOC:
//
// See if MSF addresses are enabled.
//
if ( cdb->READ_TOC.Msf) {
DeviceExtension->MSFAddress = TRUE;
}
//
// Setup the appropriate command - full read toc or session info.
//
if (cdb->READ_TOC.Format == 0) {
packet->OperationCode = OP_READ_TOC;
packet->ParameterLength = 0;
} else {
packet->OperationCode = OP_READ_SESSION;
packet->ParameterLength = 0;
}
break;
case SCSIOP_INQUIRY: {
PINQUIRYDATA inquiryData = Srb->DataBuffer;
//
// For now, support only one drive at drive select 0 on this controller.
// Actually, I have no idea if more can be supported.
//
if (Srb->Lun > 0 || Srb->TargetId > 0) {
Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
return FALSE;
}
//
// Zero inquiry buffer.
//
for (i = 0; i < INQUIRYDATABUFFERSIZE; i++) {
((PUCHAR)inquiryData)[i] = 0;
}
//
// Fill in the necessary fields of inquiry data.
//
inquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
inquiryData->RemovableMedia = 1;
inquiryData->VendorId[0] = 'M';
inquiryData->VendorId[1] = 'I';
inquiryData->VendorId[2] = 'T';
inquiryData->VendorId[3] = 'S';
inquiryData->VendorId[4] = 'U';
inquiryData->VendorId[5] = 'M';
inquiryData->VendorId[6] = 'I';
inquiryData->VendorId[7] = ' ';
inquiryData->ProductId[0] = 'C';
inquiryData->ProductId[1] = 'R';
inquiryData->ProductId[2] = 'M';
inquiryData->ProductId[3] = 'C';
inquiryData->ProductId[4] = '-';
if (DeviceExtension->DriveType == LU005) {
inquiryData->ProductId[5] = 'L';
inquiryData->ProductId[6] = 'U';
inquiryData->ProductId[9] = '5';
inquiryData->ProductId[10] = 'S';
} else if (DeviceExtension->DriveType == FX001) {
inquiryData->ProductId[5] = 'F';
inquiryData->ProductId[6] = 'X';
inquiryData->ProductId[9] = '1';
inquiryData->ProductId[10] = ' ';
} else {
inquiryData->ProductId[5] = 'F';
inquiryData->ProductId[6] = 'X';
inquiryData->ProductId[9] = '1';
inquiryData->ProductId[10] = 'D';
}
inquiryData->ProductId[7] = '0';
inquiryData->ProductId[8] = '0';
inquiryData->ProductId[11] = ' ';
inquiryData->ProductId[12] = ' ';
inquiryData->ProductId[13] = ' ';
inquiryData->ProductId[14] = ' ';
inquiryData->ProductId[15] = ' ';
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Srb->ScsiStatus = SCSISTAT_GOOD;
break;
}
case SCSIOP_READ_CAPACITY:
//
// Create the READ_TOC_DATA packet. The returned values will be munged
// into a usable form.
//
packet->OperationCode = OP_READ_TOC;
packet->ParameterLength = 0;
break;
case SCSIOP_READ_SUB_CHANNEL:
if ( cdb->SUBCHANNEL.Msf) {
DeviceExtension->MSFAddress = TRUE;
}
//
// determine what sub-channel data format is required, since this device has 3 different commands
// for the SCSI READ_SUB_CHANNEL Opcode. In the callback routine, the remaining calls, if any, will
// be issued.
//
switch (cdb->SUBCHANNEL.Format) {
case 1:
//
// Current position.
//
packet->OperationCode = OP_READ_SUB_CHANNEL;
packet->ParameterLength = 0;
break;
case 2:
//
// Media catalogue number. TODO: support the rest of these.
//
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
case 3:
//
// Track ISRC
//
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
default:
//
// Bogus value.
//
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return FALSE;
}
break;
case SCSIOP_TEST_UNIT_READY:
case SCSIOP_REQUEST_SENSE:
break;
case SCSIOP_MODE_SENSE:
case SCSIOP_MODE_SELECT:
case SCSIOP_MEDIUM_REMOVAL:
case SCSIOP_READ_HEADER:
//
// Dont support this for now. Fall through to default.
//
default:
DebugPrint((1,
"MitsumiBuildCommand: Unsupported command %x\n",
Srb->Cdb[0]));
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return FALSE;
} // end switch
return TRUE;
}
BOOLEAN
MitsumiSendCommand(
IN PHW_DEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
Arguments:
HwDeviceExtension - The hardware device extension.
Srb - The current Srb.
Return Value:
TRUE if command sent successfully.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
PCDB cdb = (PCDB)Srb->Cdb;
PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
ULONG i;
UCHAR sessionData[6];
UCHAR minutes,seconds,frames,frameData;
UCHAR status = DeviceExtension->DriveStatus;
//
// Map CDB to Mitsumi packet command
//
switch (Srb->Cdb[0]) {
case SCSIOP_READ:
break;
case SCSIOP_INQUIRY:
//
// Data buffer filled in during MitsumiBuildCommand.
//
return TRUE;
case SCSIOP_READ_TOC:
case SCSIOP_PAUSE_RESUME:
case SCSIOP_PLAY_AUDIO_MSF:
case SCSIOP_READ_CAPACITY:
case SCSIOP_READ_SUB_CHANNEL:
case SCSIOP_START_STOP_UNIT:
//
// Nothing to do here. Everything setup in BuildCommand.
//
break;
case SCSIOP_TEST_UNIT_READY:
if (!CheckStatus(DeviceExtension)) {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
return FALSE;
}
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Srb->ScsiStatus = SCSISTAT_GOOD;
return TRUE;
case SCSIOP_REQUEST_SENSE:
//
// Issue the ReadAndMapError command, which will create a request sense packet.
//
if (ReadAndMapError(DeviceExtension,Srb)) {
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Srb->ScsiStatus = SCSISTAT_GOOD;
} else {
Srb->SrbStatus = SRB_STATUS_ERROR;
Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
}
//
// Update the drive status.
//
CheckStatus(DeviceExtension);
return TRUE;
case SCSIOP_MODE_SENSE:
case SCSIOP_MODE_SELECT:
case SCSIOP_READ_HEADER:
case SCSIOP_MEDIUM_REMOVAL:
//
// Dont support this for now. Fall through.
//
default:
DebugPrint((1,
"MitsumiSendCommand: Unsupported command %x\n",
Srb->Cdb[0]));
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
} // end switch
if (Srb->SrbStatus == SRB_STATUS_PENDING) {
//
// Write the packet
//
ScsiPortWritePortUchar(&baseIoAddress->Data,packet->OperationCode);
for (i = 0; i < packet->ParameterLength; i++) {
ScsiPortWritePortUchar(&baseIoAddress->Data,packet->Parameters[i]);
}
return TRUE;
} else {
return FALSE;
}
} // End MitsumiSendCommand()
UCHAR
WaitForSTEN(
IN PHW_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Arguments:
DeviceExtension - The device extension.
Return Value:
TRUE if STEN signal asserted within timeout period.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
ULONG i;
UCHAR status;
for (i = 0; i < 40 * 1000; i++) {
status = ScsiPortReadPortUchar(&baseIoAddress->Status);
if (status & STEN) {
ScsiPortStallExecution(10);
} else {
break;
}
}
if (i == 1000 * 40) {
return 0xFF;
}
return status;
}
BOOLEAN
CheckStatus(
IN PHW_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Arguments:
DeviceExtension - The device extension.
Return Value:
Drive status.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
CMD_PACKET packet;
ULONG i;
UCHAR status;
ScsiPortWritePortUchar(&baseIoAddress->Data,OP_READ_STATUS);
do {
ReadStatus(DeviceExtension,baseIoAddress,status);
} while (status == 0xFF);
DeviceExtension->DriveStatus = status;
// TODO: Change to SUCCESS macro
if ( (status & (STATUS_DOOR_OPEN | STATUS_CMD_ERROR | STATUS_MEDIA_CHANGE | STATUS_READ_ERROR)) ||
(!(status & (STATUS_SPIN_UP | STATUS_DISC_IN))) ) {
return FALSE;
}
return TRUE;
}
BOOLEAN
UpdateCurrentPosition(
IN PHW_DEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Determines the current MSF and stores it in the deviceExtension in LBA form.
Arguments:
HwDeviceExtension - The hardware device extension.
Return Value:
TRUE - If command succeeded.
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
ULONG i,
lba;
UCHAR status;
UCHAR dataBuffer[10];
//
// Issue SubQ command.
//
ScsiPortWritePortUchar(&baseIoAddress->Data, OP_READ_SUB_CHANNEL);
ScsiPortStallExecution(1000);
ReadStatus(DeviceExtension,baseIoAddress,status);
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the position data
//
for (i = 0; i < 9; i++) {
ReadStatus(DeviceExtension,baseIoAddress,dataBuffer[i]);
if (dataBuffer[i] == 0xFF) {
//
// Timeout occurred.
//
DebugPrint((1,
"UpdateCurrentPosition: Error occurred on data read. %x\n",
status));
return FALSE;
}
}
} else {
DebugPrint((1,
"UpdateCurrentPosition: Error occurred sending command. %x\n",
status));
return FALSE;
}
//
// Convert the MSF to LBA and store in devExt.
//
BCD_TO_DEC(dataBuffer[7]);
BCD_TO_DEC(dataBuffer[8]);
BCD_TO_DEC(dataBuffer[9]);
lba = MSF_TO_LBA(dataBuffer[7],dataBuffer[8],dataBuffer[9]);
DebugPrint((2,
"UpdateCurrentPosition: M %x, S %x, F %x LBA %x\n",
dataBuffer[7],
dataBuffer[8],
dataBuffer[9],
lba));
DeviceExtension->SavedPosition = lba;
return TRUE;
}
BOOLEAN
ReadAndMapError(
IN PHW_DEVICE_EXTENSION DeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
)
/*++
Routine Description:
Arguments:
HwDeviceExtension - The hardware device extension.
Srb - The failing Srb.
Return Value:
SRB Error
--*/
{
PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->DataBuffer;
UCHAR status = DeviceExtension->DriveStatus;
ULONG i;
UCHAR errorData;
//
// Check drive status. It may have been updated at the point of error.
//
if ( (status & STATUS_DOOR_OPEN) ||
!(status & STATUS_DISC_IN)) {
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
senseBuffer->AdditionalSenseCodeQualifier = 0;
return TRUE;
}
if (status & STATUS_CMD_ERROR ) {
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
senseBuffer->AdditionalSenseCode = 0x24;
senseBuffer->AdditionalSenseCodeQualifier = 0;
return TRUE;
}
if (status & STATUS_MEDIA_CHANGE) {
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
senseBuffer->AdditionalSenseCodeQualifier = 0x0;
return TRUE;
}
if (!(status & STATUS_SPIN_UP)) {
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_LUN_NOT_READY;
senseBuffer->AdditionalSenseCodeQualifier = 0;
return TRUE;
}
//
// Setup sense buffer common values.
//
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
senseBuffer->AdditionalSenseLength = 0xb;
senseBuffer->IncorrectLength = FALSE;
senseBuffer->SenseKey = 0;
senseBuffer->AdditionalSenseCode = 0;
senseBuffer->AdditionalSenseCodeQualifier = 0;
if (status & STATUS_READ_ERROR ) {
//
// Issue the request sense command.
//
ScsiPortWritePortUchar(&baseIoAddress->Data,OP_REQUEST_SENSE);
ReadStatus(DeviceExtension,baseIoAddress,status);
if (!(status & STATUS_CMD_ERROR)) {
//
// Read the sense data
//
ReadStatus(DeviceExtension,baseIoAddress,errorData);
if (errorData == 0xFF) {
//
// Timeout occurred.
//
DebugPrint((1,
"ReadAndMapError: Error occurred on data read.\n"));
return FALSE;
}
} else {
DebugPrint((1,
"ReadAndMapError: Error reading sense data\n"));
return FALSE;
}
//
// Map Mitsumi error code to Srb status
//
switch (errorData) {
case 0:
//
// No error.
//
senseBuffer->SenseKey = 0x00;
senseBuffer->AdditionalSenseCode = 0x00;
senseBuffer->AdditionalSenseCodeQualifier = 0x0;
break;
case 1:
//
// Mode error.
//
senseBuffer->SenseKey = 0x02;
senseBuffer->AdditionalSenseCode = 0x30;
senseBuffer->AdditionalSenseCodeQualifier = 0x02;
break;
case 2:
//
// Address error.
//
senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_ILLEGAL_BLOCK;
break;
case 3:
//
// Fatal error.
//
senseBuffer->SenseKey = SCSI_SENSE_HARDWARE_ERROR;
break;
case 4:
//
// Seek error.
//
senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_SEEK_ERROR;
break;
default:
senseBuffer->SenseKey = 0x00;
senseBuffer->AdditionalSenseCode = 0x00;
senseBuffer->AdditionalSenseCodeQualifier = 0x0;
}
}
return TRUE;
} // end ReadAndMapError()