3366 lines
82 KiB
C
3366 lines
82 KiB
C
/*++
|
||
|
||
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()
|
||
|
||
|