📄 atapi.c
字号:
/*
* PROJECT: ReactOS Storage Stack
* LICENSE: DDK - see license.txt in the root dir
* FILE: drivers/storage/atapi/atapi.c
* PURPOSE: ATAPI IDE miniport driver
* PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
*/
#include <ntddk.h>
#include "atapi.h" // includes scsi.h
#include <ntddscsi.h>
#include <ntdddisk.h>
#include <ntddstor.h>
//#define NDEBUG
#include <debug.h>
//
// Device extension
//
typedef struct _HW_DEVICE_EXTENSION {
//
// Current request on controller.
//
PSCSI_REQUEST_BLOCK CurrentSrb;
//
// Base register locations
//
PIDE_REGISTERS_1 BaseIoAddress1[2];
PIDE_REGISTERS_2 BaseIoAddress2[2];
//
// Interrupt level
//
ULONG InterruptLevel;
//
// Interrupt Mode (Level or Edge)
//
ULONG InterruptMode;
//
// Data buffer pointer.
//
PUSHORT DataBuffer;
//
// Data words left.
//
ULONG WordsLeft;
//
// Number of channels being supported by one instantiation
// of the device extension. Normally (and correctly) one, but
// with so many broken PCI IDE controllers being sold, we have
// to support them.
//
ULONG NumberChannels;
//
// Count of errors. Used to turn off features.
//
ULONG ErrorCount;
//
// Indicates number of platters on changer-ish devices.
//
ULONG DiscsPresent[4];
//
// Flags word for each possible device.
//
USHORT DeviceFlags[4];
//
// Indicates the number of blocks transferred per int. according to the
// identify data.
//
UCHAR MaximumBlockXfer[4];
//
// Indicates expecting an interrupt
//
BOOLEAN ExpectingInterrupt;
//
// Indicate last tape command was DSC Restrictive.
//
BOOLEAN RDP;
//
// Driver is being used by the crash dump utility or ntldr.
//
BOOLEAN DriverMustPoll;
//
// Indicates use of 32-bit PIO
//
BOOLEAN DWordIO;
//
// Indicates whether '0x1f0' is the base address. Used
// in SMART Ioctl calls.
//
BOOLEAN PrimaryAddress;
//
// Placeholder for the sub-command value of the last
// SMART command.
//
UCHAR SmartCommand;
//
// Placeholder for status register after a GET_MEDIA_STATUS command
//
UCHAR ReturningMediaStatus;
UCHAR Reserved[1];
//
// Identify data for device
//
IDENTIFY_DATA FullIdentifyData;
IDENTIFY_DATA2 IdentifyData[4];
//
// Mechanism Status Srb Data
//
PSCSI_REQUEST_BLOCK OriginalSrb;
SCSI_REQUEST_BLOCK InternalSrb;
MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData;
SENSE_DATA MechStatusSense;
ULONG MechStatusRetryCount;
} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
//
// Logical unit extension
//
typedef struct _HW_LU_EXTENSION {
ULONG Reserved;
} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
PSCSI_REQUEST_BLOCK
STDCALL
BuildMechanismStatusSrb (
IN PVOID HwDeviceExtension,
IN ULONG PathId,
IN ULONG TargetId
);
PSCSI_REQUEST_BLOCK
STDCALL
BuildRequestSenseSrb (
IN PVOID HwDeviceExtension,
IN ULONG PathId,
IN ULONG TargetId
);
VOID
STDCALL
AtapiHwInitializeChanger (
IN PVOID HwDeviceExtension,
IN ULONG TargetId,
IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus
);
ULONG
STDCALL
AtapiSendCommand(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
);
VOID
STDCALL
AtapiZeroMemory(
IN PCHAR Buffer,
IN ULONG Count
);
VOID
STDCALL
AtapiHexToString (
ULONG Value,
PCHAR *Buffer
);
LONG
STDCALL
AtapiStringCmp (
PCHAR FirstStr,
PCHAR SecondStr,
ULONG Count
);
BOOLEAN
STDCALL
AtapiInterrupt(
IN PVOID HwDeviceExtension
);
BOOLEAN
STDCALL
AtapiHwInitialize(
IN PVOID HwDeviceExtension
);
ULONG
STDCALL
IdeBuildSenseBuffer(
IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb
);
VOID
STDCALL
IdeMediaStatus(
IN BOOLEAN EnableMSN,
IN PVOID HwDeviceExtension,
IN ULONG Channel
);
BOOLEAN
STDCALL
IssueIdentify(
IN PVOID HwDeviceExtension,
IN ULONG DeviceNumber,
IN ULONG Channel,
IN UCHAR Command
)
/*++
Routine Description:
Issue IDENTIFY command to a device.
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
DeviceNumber - Indicates which device.
Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.
Return Value:
TRUE if all goes well.
--*/
{
PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel] ;
PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
ULONG waitCount = 20000;
ULONG i,j;
UCHAR statusByte;
UCHAR signatureLow,
signatureHigh;
//
// Select device 0 or 1.
//
ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
(UCHAR)((DeviceNumber << 4) | 0xA0));
//
// Check that the status register makes sense.
//
GetBaseStatus(baseIoAddress1, statusByte);
if (Command == IDE_COMMAND_IDENTIFY) {
//
// Mask status byte ERROR bits.
//
statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);
DebugPrint((1,
"IssueIdentify: Checking for IDE. Status (%x)\n",
statusByte));
//
// Check if register value is reasonable.
//
if (statusByte != IDE_STATUS_IDLE) {
//
// Reset the controller.
//
AtapiSoftReset(baseIoAddress1,DeviceNumber);
ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
(UCHAR)((DeviceNumber << 4) | 0xA0));
WaitOnBusy(baseIoAddress2,statusByte);
signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
if (signatureLow == 0x14 && signatureHigh == 0xEB) {
//
// Device is Atapi.
//
return FALSE;
}
DebugPrint((1,
"IssueIdentify: Resetting controller.\n"));
ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );
ScsiPortStallExecution(500 * 1000);
ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);
// We really should wait up to 31 seconds
// The ATA spec. allows device 0 to come back from BUSY in 31 seconds!
// (30 seconds for device 1)
do {
//
// Wait for Busy to drop.
//
ScsiPortStallExecution(100);
GetStatus(baseIoAddress2, statusByte);
} while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
(UCHAR)((DeviceNumber << 4) | 0xA0));
//
// Another check for signature, to deal with one model Atapi that doesn't assert signature after
// a soft reset.
//
signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
if (signatureLow == 0x14 && signatureHigh == 0xEB) {
//
// Device is Atapi.
//
return FALSE;
}
statusByte &= ~IDE_STATUS_INDEX;
if (statusByte != IDE_STATUS_IDLE) {
//
// Give up on this.
//
return FALSE;
}
}
} else {
DebugPrint((1,
"IssueIdentify: Checking for ATAPI. Status (%x)\n",
statusByte));
}
//
// Load CylinderHigh and CylinderLow with number bytes to transfer.
//
ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, (0x200 >> 8));
ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, (0x200 & 0xFF));
for (j = 0; j < 2; j++) {
//
// Send IDENTIFY command.
//
WaitOnBusy(baseIoAddress2,statusByte);
ScsiPortWritePortUchar(&baseIoAddress1->Command, Command);
//
// Wait for DRQ.
//
for (i = 0; i < 4; i++) {
WaitForDrq(baseIoAddress2, statusByte);
if (statusByte & IDE_STATUS_DRQ) {
//
// Read status to acknowledge any interrupts generated.
//
GetBaseStatus(baseIoAddress1, statusByte);
//
// One last check for Atapi.
//
signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
if (signatureLow == 0x14 && signatureHigh == 0xEB) {
//
// Device is Atapi.
//
return FALSE;
}
break;
}
if (Command == IDE_COMMAND_IDENTIFY) {
//
// Check the signature. If DRQ didn't come up it's likely Atapi.
//
signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
if (signatureLow == 0x14 && signatureHigh == 0xEB) {
//
// Device is Atapi.
//
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -