/* * PROJECT: ReactOS Storage Stack * LICENSE: DDK - see license.txt in the root dir * FILE: drivers/storage/atapi/atapi.h * PURPOSE: ATAPI IDE miniport driver * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK */ #include #include // // IDE register definition // typedef struct _IDE_REGISTERS_1 { USHORT Data; UCHAR BlockCount; UCHAR BlockNumber; UCHAR CylinderLow; UCHAR CylinderHigh; UCHAR DriveSelect; UCHAR Command; } IDE_REGISTERS_1, *PIDE_REGISTERS_1; typedef struct _IDE_REGISTERS_2 { UCHAR AlternateStatus; UCHAR DriveAddress; } IDE_REGISTERS_2, *PIDE_REGISTERS_2; typedef struct _IDE_REGISTERS_3 { ULONG Data; UCHAR Others[4]; } IDE_REGISTERS_3, *PIDE_REGISTERS_3; // // Device Extension Device Flags // #define DFLAGS_DEVICE_PRESENT 0x0001 // Indicates that some device is present. #define DFLAGS_ATAPI_DEVICE 0x0002 // Indicates whether Atapi commands can be used. #define DFLAGS_TAPE_DEVICE 0x0004 // Indicates whether this is a tape device. #define DFLAGS_INT_DRQ 0x0008 // Indicates whether device interrupts as DRQ is set after // receiving Atapi Packet Command #define DFLAGS_REMOVABLE_DRIVE 0x0010 // Indicates that the drive has the 'removable' bit set in // identify data (offset 128) #define DFLAGS_MEDIA_STATUS_ENABLED 0x0020 // Media status notification enabled #define DFLAGS_ATAPI_CHANGER 0x0040 // Indicates atapi 2.5 changer present. #define DFLAGS_SANYO_ATAPI_CHANGER 0x0080 // Indicates multi-platter device, not conforming to the 2.5 spec. #define DFLAGS_CHANGER_INITED 0x0100 // Indicates that the init path for changers has already been done. // // Used to disable 'advanced' features. // #define MAX_ERRORS 4 // // ATAPI command definitions // #define ATAPI_MODE_SENSE 0x5A #define ATAPI_MODE_SELECT 0x55 #define ATAPI_FORMAT_UNIT 0x24 // // ATAPI Command Descriptor Block // typedef struct _MODE_SENSE_10 { UCHAR OperationCode; UCHAR Reserved1; UCHAR PageCode : 6; UCHAR Pc : 2; UCHAR Reserved2[4]; UCHAR ParameterListLengthMsb; UCHAR ParameterListLengthLsb; UCHAR Reserved3[3]; } MODE_SENSE_10, *PMODE_SENSE_10; typedef struct _MODE_SELECT_10 { UCHAR OperationCode; UCHAR Reserved1 : 4; UCHAR PFBit : 1; UCHAR Reserved2 : 3; UCHAR Reserved3[5]; UCHAR ParameterListLengthMsb; UCHAR ParameterListLengthLsb; UCHAR Reserved4[3]; } MODE_SELECT_10, *PMODE_SELECT_10; typedef struct _MODE_PARAMETER_HEADER_10 { UCHAR ModeDataLengthMsb; UCHAR ModeDataLengthLsb; UCHAR MediumType; UCHAR Reserved[5]; }MODE_PARAMETER_HEADER_10, *PMODE_PARAMETER_HEADER_10; // // IDE command definitions // #define IDE_COMMAND_ATAPI_RESET 0x08 #define IDE_COMMAND_RECALIBRATE 0x10 #define IDE_COMMAND_READ 0x20 #define IDE_COMMAND_WRITE 0x30 #define IDE_COMMAND_VERIFY 0x40 #define IDE_COMMAND_SEEK 0x70 #define IDE_COMMAND_SET_DRIVE_PARAMETERS 0x91 #define IDE_COMMAND_ATAPI_PACKET 0xA0 #define IDE_COMMAND_ATAPI_IDENTIFY 0xA1 #define IDE_COMMAND_READ_MULTIPLE 0xC4 #define IDE_COMMAND_WRITE_MULTIPLE 0xC5 #define IDE_COMMAND_SET_MULTIPLE 0xC6 #define IDE_COMMAND_READ_DMA 0xC8 #define IDE_COMMAND_WRITE_DMA 0xCA #define IDE_COMMAND_GET_MEDIA_STATUS 0xDA #define IDE_COMMAND_ENABLE_MEDIA_STATUS 0xEF #define IDE_COMMAND_IDENTIFY 0xEC #define IDE_COMMAND_MEDIA_EJECT 0xED // // IDE status definitions // #define IDE_STATUS_ERROR 0x01 #define IDE_STATUS_INDEX 0x02 #define IDE_STATUS_CORRECTED_ERROR 0x04 #define IDE_STATUS_DRQ 0x08 #define IDE_STATUS_DSC 0x10 #define IDE_STATUS_DRDY 0x40 #define IDE_STATUS_IDLE 0x50 #define IDE_STATUS_BUSY 0x80 // // IDE drive select/head definitions // #define IDE_DRIVE_SELECT_1 0xA0 #define IDE_DRIVE_SELECT_2 0x10 // // IDE drive control definitions // #define IDE_DC_DISABLE_INTERRUPTS 0x02 #define IDE_DC_RESET_CONTROLLER 0x04 #define IDE_DC_REENABLE_CONTROLLER 0x00 // // IDE error definitions // #define IDE_ERROR_BAD_BLOCK 0x80 #define IDE_ERROR_DATA_ERROR 0x40 #define IDE_ERROR_MEDIA_CHANGE 0x20 #define IDE_ERROR_ID_NOT_FOUND 0x10 #define IDE_ERROR_MEDIA_CHANGE_REQ 0x08 #define IDE_ERROR_COMMAND_ABORTED 0x04 #define IDE_ERROR_END_OF_MEDIA 0x02 #define IDE_ERROR_ILLEGAL_LENGTH 0x01 // // ATAPI register definition // typedef struct _ATAPI_REGISTERS_1 { USHORT Data; UCHAR InterruptReason; UCHAR Unused1; UCHAR ByteCountLow; UCHAR ByteCountHigh; UCHAR DriveSelect; UCHAR Command; } ATAPI_REGISTERS_1, *PATAPI_REGISTERS_1; typedef struct _ATAPI_REGISTERS_2 { UCHAR AlternateStatus; UCHAR DriveAddress; } ATAPI_REGISTERS_2, *PATAPI_REGISTERS_2; // // ATAPI interrupt reasons // #define ATAPI_IR_COD 0x01 #define ATAPI_IR_IO 0x02 // // IDENTIFY data // typedef struct _IDENTIFY_DATA { USHORT GeneralConfiguration; // 00 00 USHORT NumberOfCylinders; // 02 1 USHORT Reserved1; // 04 2 USHORT NumberOfHeads; // 06 3 USHORT UnformattedBytesPerTrack; // 08 4 USHORT UnformattedBytesPerSector; // 0A 5 USHORT SectorsPerTrack; // 0C 6 USHORT VendorUnique1[3]; // 0E 7-9 USHORT SerialNumber[10]; // 14 10-19 USHORT BufferType; // 28 20 USHORT BufferSectorSize; // 2A 21 USHORT NumberOfEccBytes; // 2C 22 USHORT FirmwareRevision[4]; // 2E 23-26 USHORT ModelNumber[20]; // 36 27-46 UCHAR MaximumBlockTransfer; // 5E 47 UCHAR VendorUnique2; // 5F USHORT DoubleWordIo; // 60 48 USHORT Capabilities; // 62 49 USHORT Reserved2; // 64 50 UCHAR VendorUnique3; // 66 51 UCHAR PioCycleTimingMode; // 67 UCHAR VendorUnique4; // 68 52 UCHAR DmaCycleTimingMode; // 69 USHORT TranslationFieldsValid:1; // 6A 53 USHORT Reserved3:15; USHORT NumberOfCurrentCylinders; // 6C 54 USHORT NumberOfCurrentHeads; // 6E 55 USHORT CurrentSectorsPerTrack; // 70 56 ULONG CurrentSectorCapacity; // 72 57-58 USHORT CurrentMultiSectorSetting; // 59 ULONG UserAddressableSectors; // 60-61 USHORT SingleWordDMASupport : 8; // 62 USHORT SingleWordDMAActive : 8; USHORT MultiWordDMASupport : 8; // 63 USHORT MultiWordDMAActive : 8; USHORT AdvancedPIOModes : 8; // 64 USHORT Reserved4 : 8; USHORT MinimumMWXferCycleTime; // 65 USHORT RecommendedMWXferCycleTime; // 66 USHORT MinimumPIOCycleTime; // 67 USHORT MinimumPIOCycleTimeIORDY; // 68 USHORT Reserved5[2]; // 69-70 USHORT ReleaseTimeOverlapped; // 71 USHORT ReleaseTimeServiceCommand; // 72 USHORT MajorRevision; // 73 USHORT MinorRevision; // 74 USHORT Reserved6[50]; // 75-126 USHORT SpecialFunctionsEnabled; // 127 USHORT Reserved7[128]; // 128-255 } IDENTIFY_DATA, *PIDENTIFY_DATA; // // Identify data without the Reserved4. // typedef struct _IDENTIFY_DATA2 { USHORT GeneralConfiguration; // 00 USHORT NumberOfCylinders; // 02 USHORT Reserved1; // 04 USHORT NumberOfHeads; // 06 USHORT UnformattedBytesPerTrack; // 08 USHORT UnformattedBytesPerSector; // 0A USHORT SectorsPerTrack; // 0C USHORT VendorUnique1[3]; // 0E USHORT SerialNumber[10]; // 14 USHORT BufferType; // 28 USHORT BufferSectorSize; // 2A USHORT NumberOfEccBytes; // 2C USHORT FirmwareRevision[4]; // 2E USHORT ModelNumber[20]; // 36 UCHAR MaximumBlockTransfer; // 5E UCHAR VendorUnique2; // 5F USHORT DoubleWordIo; // 60 USHORT Capabilities; // 62 USHORT Reserved2; // 64 UCHAR VendorUnique3; // 66 UCHAR PioCycleTimingMode; // 67 UCHAR VendorUnique4; // 68 UCHAR DmaCycleTimingMode; // 69 USHORT TranslationFieldsValid:1; // 6A USHORT Reserved3:15; USHORT NumberOfCurrentCylinders; // 6C USHORT NumberOfCurrentHeads; // 6E USHORT CurrentSectorsPerTrack; // 70 ULONG CurrentSectorCapacity; // 72 } IDENTIFY_DATA2, *PIDENTIFY_DATA2; #define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA) // // IDENTIFY capability bit definitions. // #define IDENTIFY_CAPABILITIES_DMA_SUPPORTED 0x0100 #define IDENTIFY_CAPABILITIES_LBA_SUPPORTED 0x0200 // // IDENTIFY DMA timing cycle modes. // #define IDENTIFY_DMA_CYCLES_MODE_0 0x00 #define IDENTIFY_DMA_CYCLES_MODE_1 0x01 #define IDENTIFY_DMA_CYCLES_MODE_2 0x02 typedef struct _BROKEN_CONTROLLER_INFORMATION { PCHAR VendorId; ULONG VendorIdLength; PCHAR DeviceId; ULONG DeviceIdLength; }BROKEN_CONTROLLER_INFORMATION, *PBROKEN_CONTROLLER_INFORMATION; BROKEN_CONTROLLER_INFORMATION const BrokenAdapters[] = { { "1095", 4, "0640", 4}, { "1039", 4, "0601", 4} }; #define BROKEN_ADAPTERS (sizeof(BrokenAdapters) / sizeof(BROKEN_CONTROLLER_INFORMATION)) typedef struct _NATIVE_MODE_CONTROLLER_INFORMATION { PCHAR VendorId; ULONG VendorIdLength; PCHAR DeviceId; ULONG DeviceIdLength; }NATIVE_MODE_CONTROLLER_INFORMATION, *PNATIVE_MODE_CONTROLLER_INFORMATION; NATIVE_MODE_CONTROLLER_INFORMATION const NativeModeAdapters[] = { { "10ad", 4, "0105", 4} }; #define NUM_NATIVE_MODE_ADAPTERS (sizeof(NativeModeAdapters) / sizeof(NATIVE_MODE_CONTROLLER_INFORMATION)) // // Beautification macros // #define GetStatus(BaseIoAddress, Status) \ Status = ScsiPortReadPortUchar(&BaseIoAddress->AlternateStatus); #define GetBaseStatus(BaseIoAddress, Status) \ Status = ScsiPortReadPortUchar(&BaseIoAddress->Command); #define WriteCommand(BaseIoAddress, Command) \ ScsiPortWritePortUchar(&BaseIoAddress->Command, Command); #define ReadBuffer(BaseIoAddress, Buffer, Count) \ ScsiPortReadPortBufferUshort(&BaseIoAddress->Data, \ Buffer, \ Count); #define WriteBuffer(BaseIoAddress, Buffer, Count) \ ScsiPortWritePortBufferUshort(&BaseIoAddress->Data, \ Buffer, \ Count); #define ReadBuffer2(BaseIoAddress, Buffer, Count) \ ScsiPortReadPortBufferUlong(&BaseIoAddress->Data, \ Buffer, \ Count); #define WriteBuffer2(BaseIoAddress, Buffer, Count) \ ScsiPortWritePortBufferUlong(&BaseIoAddress->Data, \ Buffer, \ Count); #define WaitOnBusy(BaseIoAddress, Status) \ { \ ULONG i; \ for (i=0; i<20000; i++) { \ GetStatus(BaseIoAddress, Status); \ if (Status & IDE_STATUS_BUSY) { \ ScsiPortStallExecution(150); \ continue; \ } else { \ break; \ } \ } \ } #define WaitOnBaseBusy(BaseIoAddress, Status) \ { \ ULONG i; \ for (i=0; i<20000; i++) { \ GetBaseStatus(BaseIoAddress, Status); \ if (Status & IDE_STATUS_BUSY) { \ ScsiPortStallExecution(150); \ continue; \ } else { \ break; \ } \ } \ } #define WaitForDrq(BaseIoAddress, Status) \ { \ ULONG i; \ for (i=0; i<1000; i++) { \ GetStatus(BaseIoAddress, Status); \ if (Status & IDE_STATUS_BUSY) { \ ScsiPortStallExecution(100); \ } else if (Status & IDE_STATUS_DRQ) { \ break; \ } else { \ ScsiPortStallExecution(200); \ } \ } \ } #define WaitShortForDrq(BaseIoAddress, Status) \ { \ ULONG i; \ for (i=0; i<2; i++) { \ GetStatus(BaseIoAddress, Status); \ if (Status & IDE_STATUS_BUSY) { \ ScsiPortStallExecution(100); \ } else if (Status & IDE_STATUS_DRQ) { \ break; \ } else { \ ScsiPortStallExecution(100); \ } \ } \ } #define AtapiSoftReset(BaseIoAddress,DeviceNumber) \ {\ UCHAR statusByte; \ ULONG i = 1000*1000;\ ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)(((DeviceNumber & 0x1) << 4) | 0xA0)); \ ScsiPortStallExecution(500);\ ScsiPortWritePortUchar(&BaseIoAddress->Command, IDE_COMMAND_ATAPI_RESET); \ while ((ScsiPortReadPortUchar(&BaseIoAddress->Command) & IDE_STATUS_BUSY) && i--)\ ScsiPortStallExecution(30);\ ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)((DeviceNumber << 4) | 0xA0)); \ WaitOnBusy( ((PIDE_REGISTERS_2)((PUCHAR)BaseIoAddress + 0x206)), statusByte); \ ScsiPortStallExecution(500);\ } #define IdeHardReset(BaseIoAddress,result) \ {\ UCHAR statusByte;\ ULONG i;\ ScsiPortWritePortUchar(&BaseIoAddress->AlternateStatus,IDE_DC_RESET_CONTROLLER );\ ScsiPortStallExecution(50 * 1000);\ ScsiPortWritePortUchar(&BaseIoAddress->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);\ for (i = 0; i < 1000 * 1000; i++) {\ statusByte = ScsiPortReadPortUchar(&BaseIoAddress->AlternateStatus);\ if (statusByte != IDE_STATUS_IDLE && statusByte != 0x0) {\ ScsiPortStallExecution(5);\ } else {\ break;\ }\ }\ if (i == 1000*1000) {\ result = FALSE;\ }\ result = TRUE;\ } #define IS_RDP(OperationCode)\ ((OperationCode == SCSIOP_ERASE)||\ (OperationCode == SCSIOP_LOAD_UNLOAD)||\ (OperationCode == SCSIOP_LOCATE)||\ (OperationCode == SCSIOP_REWIND) ||\ (OperationCode == SCSIOP_SPACE)||\ (OperationCode == SCSIOP_SEEK)||\ (OperationCode == SCSIOP_WRITE_FILEMARKS))