diff --git a/reactos/drivers/storage/ide/uniata/atapi.h b/reactos/drivers/storage/ide/uniata/atapi.h new file mode 100644 index 00000000000..edcb54ca103 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/atapi.h @@ -0,0 +1,1280 @@ +/*++ + +Copyright (c) 2002-2005 Alexandr A. Telyatnikov (Alter) + +Module Name: + atapi.h + +Abstract: + This file contains IDE, ATA, ATAPI and SCSI Miniport definitions + and function prototypes. + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + + Some definitions were taken from standard ATAPI.SYS sources from NT4 DDK by + Mike Glass (MGlass) + + Some definitions were taken from FreeBSD 4.3-4.6 ATA driver by + Søren Schmidt, Copyright (c) 1998,1999,2000,2001 + + Code was changed/updated by + Alter, Copyright (c) 2002-2004 + + +--*/ +#ifndef __GLOBAL_H__ +#define __GLOBAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#ifndef USER_MODE +#include "config.h" +#endif //USER_MODE + +#include "scsi.h" +#include "stdio.h" +#include "string.h" + +#ifdef _DEBUG + + +#ifndef _DBGNT_ + +#ifdef KdPrint +#undef KdPrint +#endif + +#ifdef USE_DBGPRINT_LOGGER +#include "inc\PostDbgMesg.h" +#define DbgPrint DbgDump_Printf +#define Connect_DbgPrint() {DbgDump_SetAutoReconnect(TRUE); DbgDump_Reconnect();} +#else // USE_DBGPRINT_LOGGER +#define Connect_DbgPrint() {;} +#endif // USE_DBGPRINT_LOGGER + +#ifdef SCSI_PORT_DBG_PRINT + +SCSIPORT_API +VOID +DDKCDECLAPI +ScsiDebugPrint( + ULONG DebugPrintLevel, + PCCHAR DebugMessage, + ... + ); + +#define PRINT_PREFIX 0, + +#define KdPrint2(_x_) {ScsiDebugPrint("%x: ", PsGetCurrentThread()) ; ScsiDebugPrint _x_ ; } +#define KdPrint(_x_) ScsiDebugPrint _x_ + +#else // SCSI_PORT_DBG_PRINT + +#ifndef USE_DBGPRINT_LOGGER +ULONG +_cdecl +DbgPrint( + PCH Format, + ... + ); +#endif // USE_DBGPRINT_LOGGER + +#define PRINT_PREFIX + +// Note, that using DbgPrint on raised IRQL will crash w2k +// tis will not happen immediately, so we shall see some logs +//#define LOG_ON_RAISED_IRQL_W2K TRUE +//#define LOG_ON_RAISED_IRQL_W2K FALSE + +#define KdPrint2(_x_) {if(LOG_ON_RAISED_IRQL_W2K || MajorVersion < 0x05 || KeGetCurrentIrql() <= 2){/*DbgPrint("%x: ", PsGetCurrentThread()) ;*/ DbgPrint _x_ ; if(g_LogToDisplay){ PrintNtConsole _x_ ;} }} +#define KdPrint(_x_) {if(LOG_ON_RAISED_IRQL_W2K || MajorVersion < 0x05 || KeGetCurrentIrql() <= 2){/*DbgPrint("%x: ", PsGetCurrentThread()) ;*/ DbgPrint _x_ ; if(g_LogToDisplay){ PrintNtConsole _x_ ;} }} +/* +#define PRINT_PREFIX_PTR ((PCHAR)&__tmp__kdprint__buff__) +#define PRINT_UPREFIX_PTR ((PWCHAR)&__tmp__kdprint__ubuff__) +#define PRINT_PREFIX PRINT_PREFIX_PTR, +#define KdPrint2(_x_) \ +{ \ + WCHAR __tmp__kdprint__ubuff__[256]; \ + CHAR __tmp__kdprint__buff__[256]; \ + UNICODE_STRING __tmp__usrt__buff__; \ + sprintf _x_; \ + swprintf (PRINT_UPREFIX_PTR, L"%hs", PRINT_PREFIX_PTR); \ + __tmp__usrt__buff__.Buffer = PRINT_UPREFIX_PTR; \ + __tmp__usrt__buff__.Length = \ + __tmp__usrt__buff__.MaximumLength = strlen(PRINT_PREFIX_PTR); \ + NtDisplayString(&__tmp__usrt__buff__); \ +}; +#define KdPrint(_x_) DbgPrint _x_ +*/ +#endif // SCSI_PORT_DBG_PRINT + +//#define AtapiStallExecution(dt) { KdPrint2((" AtapiStallExecution(%d)\n", dt)); ScsiPortStallExecution(dt); } +#define AtapiStallExecution(dt) { ScsiPortStallExecution(dt); } + +#endif // _DBGNT_ + +#else // _DEBUG + +#define KdPrint2(_x_) +#define KdPrint(_x_) +#define Connect_DbgPrint() {;} + +#define AtapiStallExecution(dt) ScsiPortStallExecution(dt) + +#endif // _DEBUG + +// IDE register definition + +#pragma pack(push, 1) + +typedef union _IDE_REGISTERS_1 { + struct _o { + UCHAR Data; + UCHAR Feature; + UCHAR BlockCount; + UCHAR BlockNumber; + UCHAR CylinderLow; + UCHAR CylinderHigh; + UCHAR DriveSelect; + UCHAR Command; + } o; + + struct _i { + UCHAR Data; + UCHAR Error; + UCHAR BlockCount; + UCHAR BlockNumber; + UCHAR CylinderLow; + UCHAR CylinderHigh; + UCHAR DriveSelect; + UCHAR Status; + } i; + +} IDE_REGISTERS_1, *PIDE_REGISTERS_1; + +#define IDX_IO1 0 +#define IDX_IO1_SZ sizeof(IDE_REGISTERS_1) + +#define IDX_IO1 0 +#define IDX_IO1_SZ sizeof(IDE_REGISTERS_1) +#define IDX_IO1_i_Data (FIELD_OFFSET(IDE_REGISTERS_1, i.Data )+IDX_IO1) +#define IDX_IO1_i_Error (FIELD_OFFSET(IDE_REGISTERS_1, i.Error )+IDX_IO1) +#define IDX_IO1_i_BlockCount (FIELD_OFFSET(IDE_REGISTERS_1, i.BlockCount )+IDX_IO1) +#define IDX_IO1_i_BlockNumber (FIELD_OFFSET(IDE_REGISTERS_1, i.BlockNumber )+IDX_IO1) +#define IDX_IO1_i_CylinderLow (FIELD_OFFSET(IDE_REGISTERS_1, i.CylinderLow )+IDX_IO1) +#define IDX_IO1_i_CylinderHigh (FIELD_OFFSET(IDE_REGISTERS_1, i.CylinderHigh)+IDX_IO1) +#define IDX_IO1_i_DriveSelect (FIELD_OFFSET(IDE_REGISTERS_1, i.DriveSelect )+IDX_IO1) +#define IDX_IO1_i_Status (FIELD_OFFSET(IDE_REGISTERS_1, i.Status )+IDX_IO1) + +#define IDX_IO1_o IDX_IO1_SZ +#define IDX_IO1_o_SZ sizeof(IDE_REGISTERS_1) + +#define IDX_IO1_o_Data (FIELD_OFFSET(IDE_REGISTERS_1, o.Data )+IDX_IO1_o) +#define IDX_IO1_o_Feature (FIELD_OFFSET(IDE_REGISTERS_1, o.Feature )+IDX_IO1_o) +#define IDX_IO1_o_BlockCount (FIELD_OFFSET(IDE_REGISTERS_1, o.BlockCount )+IDX_IO1_o) +#define IDX_IO1_o_BlockNumber (FIELD_OFFSET(IDE_REGISTERS_1, o.BlockNumber )+IDX_IO1_o) +#define IDX_IO1_o_CylinderLow (FIELD_OFFSET(IDE_REGISTERS_1, o.CylinderLow )+IDX_IO1_o) +#define IDX_IO1_o_CylinderHigh (FIELD_OFFSET(IDE_REGISTERS_1, o.CylinderHigh)+IDX_IO1_o) +#define IDX_IO1_o_DriveSelect (FIELD_OFFSET(IDE_REGISTERS_1, o.DriveSelect )+IDX_IO1_o) +#define IDX_IO1_o_Command (FIELD_OFFSET(IDE_REGISTERS_1, o.Command )+IDX_IO1_o) + +typedef struct _IDE_REGISTERS_2 { + UCHAR AltStatus; + UCHAR DriveAddress; +} IDE_REGISTERS_2, *PIDE_REGISTERS_2; + +#define IDX_IO2 (IDX_IO1_o+IDX_IO1_o_SZ) +#define IDX_IO2_SZ sizeof(IDE_REGISTERS_2) + +#define IDX_IO2_AltStatus (FIELD_OFFSET(IDE_REGISTERS_2, AltStatus )+IDX_IO2) +#define IDX_IO2_DriveAddress (FIELD_OFFSET(IDE_REGISTERS_2, DriveAddress)+IDX_IO2) + +#define IDX_IO2_o (IDX_IO2+IDX_IO2_SZ) +#define IDX_IO2_o_SZ sizeof(IDE_REGISTERS_2) + +#define IDX_IO2_o_Control (FIELD_OFFSET(IDE_REGISTERS_2, AltStatus )+IDX_IO2_o) +// +// 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. +#define DFLAGS_LBA_ENABLED 0x0200 // Indicates that we should use LBA addressing rather than CHS +#define DFLAGS_DWORDIO_ENABLED 0x0400 // Indicates that we should use 32-bit IO +#define DFLAGS_WCACHE_ENABLED 0x0800 // Indicates that we use write cache +#define DFLAGS_RCACHE_ENABLED 0x1000 // Indicates that we use read cache +#define DFLAGS_ORIG_GEOMETRY 0x2000 // +#define DFLAGS_REINIT_DMA 0x4000 // +// +// 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_READ48 0x24 +#define IDE_COMMAND_READ_DMA48 0x25 +#define IDE_COMMAND_READ_DMA_Q48 0x26 +#define IDE_COMMAND_READ_NATIVE_SIZE48 0x27 +#define IDE_COMMAND_READ_MUL48 0x29 +#define IDE_COMMAND_READ_STREAM_DMA48 0x2A +#define IDE_COMMAND_READ_STREAM48 0x2B +#define IDE_COMMAND_READ_LOG48 0x2f +#define IDE_COMMAND_WRITE 0x30 +#define IDE_COMMAND_WRITE48 0x34 +#define IDE_COMMAND_WRITE_DMA48 0x35 +#define IDE_COMMAND_WRITE_DMA_Q48 0x36 +#define IDE_COMMAND_SET_NATIVE_SIZE48 0x37 +#define IDE_COMMAND_WRITE_MUL48 0x39 +#define IDE_COMMAND_WRITE_STREAM_DMA48 0x3a +#define IDE_COMMAND_WRITE_STREAM48 0x3b +#define IDE_COMMAND_WRITE_FUA_DMA48 0x3d +#define IDE_COMMAND_WRITE_FUA_DMA_Q48 0x3e +#define IDE_COMMAND_WRITE_LOG48 0x3f +#define IDE_COMMAND_VERIFY 0x40 +#define IDE_COMMAND_VERIFY48 0x42 +#define IDE_COMMAND_READ_LOG_DMA48 0x47 +#define IDE_COMMAND_WRITE_LOG_DMA48 0x57 +#define IDE_COMMAND_TRUSTED_RCV 0x5c +#define IDE_COMMAND_TRUSTED_RCV_DMA 0x5d +#define IDE_COMMAND_TRUSTED_SEND 0x5e +#define IDE_COMMAND_TRUSTED_SEND_DMA 0x5f +#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_Q 0xC7 +#define IDE_COMMAND_READ_DMA 0xC8 +#define IDE_COMMAND_WRITE_DMA 0xCA +#define IDE_COMMAND_WRITE_DMA_Q 0xCC +#define IDE_COMMAND_WRITE_MUL_FUA48 0xCE +#define IDE_COMMAND_GET_MEDIA_STATUS 0xDA +#define IDE_COMMAND_DOOR_LOCK 0xDE +#define IDE_COMMAND_DOOR_UNLOCK 0xDF +#define IDE_COMMAND_STANDBY_IMMED 0xE0 // flush and spin down +#define IDE_COMMAND_STANDBY 0xE2 // flush and spin down and enable autopowerdown timer +#define IDE_COMMAND_SLEEP 0xE6 // flush, spin down and deactivate interface +#define IDE_COMMAND_FLUSH_CACHE 0xE7 +#define IDE_COMMAND_IDENTIFY 0xEC +#define IDE_COMMAND_MEDIA_EJECT 0xED +#define IDE_COMMAND_FLUSH_CACHE48 0xEA +#define IDE_COMMAND_ENABLE_MEDIA_STATUS 0xEF +#define IDE_COMMAND_SET_FEATURES 0xEF /* features command, + IDE_COMMAND_ENABLE_MEDIA_STATUS */ +#define IDE_COMMAND_READ_NATIVE_SIZE 0xF8 +#define IDE_COMMAND_SET_NATIVE_SIZE 0xF9 + +#define SCSIOP_ATA_PASSTHROUGH 0xCC // + +// +// IDE status definitions +// + +#define IDE_STATUS_SUCCESS 0x00 +#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_DWF 0x10 /* drive write fault */ +#define IDE_STATUS_DMA 0x20 /* DMA ready */ +#define IDE_STATUS_DWF 0x20 /* drive write fault */ +#define IDE_STATUS_DRDY 0x40 +#define IDE_STATUS_IDLE 0x50 +#define IDE_STATUS_BUSY 0x80 + + +// +// IDE drive select/head definitions +// + +#define IDE_DRIVE_SELECT 0xA0 +#define IDE_DRIVE_1 0x00 +#define IDE_DRIVE_2 0x10 +#define IDE_DRIVE_SELECT_1 (IDE_DRIVE_SELECT | IDE_DRIVE_1) +#define IDE_DRIVE_SELECT_2 (IDE_DRIVE_SELECT | IDE_DRIVE_2) + +#define IDE_USE_LBA 0x40 + +// +// IDE drive control definitions +// + +#define IDE_DC_DISABLE_INTERRUPTS 0x02 +#define IDE_DC_RESET_CONTROLLER 0x04 +#define IDE_DC_A_4BIT 0x80 +#define IDE_DC_USE_HOB 0x80 // use high-order byte(s) +#define IDE_DC_REENABLE_CONTROLLER 0x00 + +// IDE error definitions +// + +#define IDE_ERROR_ICRC 0x80 +#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_NO_MEDIA 0x02 +#define IDE_ERROR_ILLEGAL_LENGTH 0x01 + +// +// ATAPI register definition +// + +typedef union _ATAPI_REGISTERS_1 { + struct _o { + UCHAR Data; + UCHAR Feature; + UCHAR Unused0; + UCHAR Unused1; + UCHAR ByteCountLow; + UCHAR ByteCountHigh; + UCHAR DriveSelect; + UCHAR Command; + } o; + + struct _i { + UCHAR Data; + UCHAR Error; + UCHAR InterruptReason; + UCHAR Unused1; + UCHAR ByteCountLow; + UCHAR ByteCountHigh; + UCHAR DriveSelect; + UCHAR Status; + } i; + + //IDE_REGISTERS_1 ide; + +} ATAPI_REGISTERS_1, *PATAPI_REGISTERS_1; + +#define IDX_ATAPI_IO1 IDX_IO1 +#define IDX_ATAPI_IO1_SZ sizeof(ATAPI_REGISTERS_1) + +#define IDX_ATAPI_IO1_i_Data (FIELD_OFFSET(ATAPI_REGISTERS_1, i.Data )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_i_Error (FIELD_OFFSET(ATAPI_REGISTERS_1, i.Error )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_i_InterruptReason (FIELD_OFFSET(ATAPI_REGISTERS_1, i.InterruptReason)+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_i_Unused1 (FIELD_OFFSET(ATAPI_REGISTERS_1, i.Unused1 )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_i_ByteCountLow (FIELD_OFFSET(ATAPI_REGISTERS_1, i.ByteCountLow )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_i_ByteCountHigh (FIELD_OFFSET(ATAPI_REGISTERS_1, i.ByteCountHigh )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_i_DriveSelect (FIELD_OFFSET(ATAPI_REGISTERS_1, i.DriveSelect )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_i_Status (FIELD_OFFSET(ATAPI_REGISTERS_1, i.Status )+IDX_ATAPI_IO1) + +#define IDX_ATAPI_IO1_o_Data (FIELD_OFFSET(ATAPI_REGISTERS_1, o.Data )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_o_Feature (FIELD_OFFSET(ATAPI_REGISTERS_1, o.Feature )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_o_Unused0 (FIELD_OFFSET(ATAPI_REGISTERS_1, o.Unused0 )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_o_Unused1 (FIELD_OFFSET(ATAPI_REGISTERS_1, o.Unused1 )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_o_ByteCountLow (FIELD_OFFSET(ATAPI_REGISTERS_1, o.ByteCountLow )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_o_ByteCountHigh (FIELD_OFFSET(ATAPI_REGISTERS_1, o.ByteCountHigh)+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_o_DriveSelect (FIELD_OFFSET(ATAPI_REGISTERS_1, o.DriveSelect )+IDX_ATAPI_IO1) +#define IDX_ATAPI_IO1_o_Command (FIELD_OFFSET(ATAPI_REGISTERS_1, o.Command )+IDX_ATAPI_IO1) + +/* +typedef union _ATAPI_REGISTERS_2 { + struct { + UCHAR AltStatus; + UCHAR DriveAddress; + }; + + //IDE_REGISTERS_2 ide; + +} ATAPI_REGISTERS_2, *PATAPI_REGISTERS_2; + +#define IDX_ATAPI_IO2 IDX_ATAPI_IO2_SZ +#define IDX_ATAPI_IO2_SZ sizeof(ATAPI_REGISTERS_2) +*/ + +// +// ATAPI interrupt reasons +// + +#define ATAPI_IR_COD 0x01 +#define ATAPI_IR_IO 0x02 + +// +// ATA Features +// + +#define ATA_F_DMA 0x01 /* enable DMA */ +#define ATA_F_OVL 0x02 /* enable overlap */ + +#define ATA_C_F_SETXFER 0x03 /* set transfer mode */ + +#define ATA_C_F_ENAB_WCACHE 0x02 /* enable write cache */ +#define ATA_C_F_DIS_WCACHE 0x82 /* disable write cache */ + +#define ATA_C_F_ENAB_RCACHE 0xaa /* enable readahead cache */ +#define ATA_C_F_DIS_RCACHE 0x55 /* disable readahead cache */ + +#define ATA_C_F_ENAB_RELIRQ 0x5d /* enable release interrupt */ +#define ATA_C_F_DIS_RELIRQ 0xdd /* disable release interrupt */ + +#define ATA_C_F_ENAB_SRVIRQ 0x5e /* enable service interrupt */ +#define ATA_C_F_DIS_SRVIRQ 0xde /* disable service interrupt */ + +#define ATA_C_F_ENAB_MEDIASTAT 0x95 /* enable media status */ +#define ATA_C_F_DIS_MEDIASTAT 0x31 /* disable media status */ + +// +// ATAPI interrupt reasons +// + +#define ATA_I_CMD 0x01 /* cmd (1) | data (0) */ +#define ATA_I_IN 0x02 /* read (1) | write (0) */ +#define ATA_I_RELEASE 0x04 /* released bus (1) */ +#define ATA_I_TAGMASK 0xf8 /* tag mask */ + +// IDENTIFY data +// + +typedef struct _IDENTIFY_DATA { + UCHAR AtapiCmdSize:2; // 00 00 +#define ATAPI_PSIZE_12 0 /* 12 bytes */ +#define ATAPI_PSIZE_16 1 /* 16 bytes */ + UCHAR :3; + UCHAR DrqType:2; // 00 00 +#define ATAPI_DRQT_MPROC 0 /* cpu 3 ms delay */ +#define ATAPI_DRQT_INTR 1 /* intr 10 ms delay */ +#define ATAPI_DRQT_ACCEL 2 /* accel 50 us delay */ + UCHAR Removable:1; + + UCHAR DeviceType:5; +#define ATAPI_TYPE_DIRECT 0 /* disk/floppy */ +#define ATAPI_TYPE_TAPE 1 /* streaming tape */ +#define ATAPI_TYPE_CDROM 5 /* CD-ROM device */ +#define ATAPI_TYPE_OPTICAL 7 /* optical disk */ + UCHAR :1; + UCHAR CmdProtocol:2; // 00 00 +#define ATAPI_PROTO_ATAPI 2 +// USHORT GeneralConfiguration; // 00 00 + + USHORT NumberOfCylinders; // 02 1 + USHORT Reserved1; // 04 2 + USHORT NumberOfHeads; // 06 3 + USHORT UnformattedBytesPerTrack; // 08 4 // Now obsolete + USHORT UnformattedBytesPerSector; // 0A 5 // Now obsolete + USHORT SectorsPerTrack; // 0C 6 + + USHORT VendorUnique1[3]; // 0E 7-9 + UCHAR SerialNumber[20]; // 14 10-19 + + USHORT BufferType; // 28 20 +#define ATA_BT_SINGLEPORTSECTOR 1 /* 1 port, 1 sector buffer */ +#define ATA_BT_DUALPORTMULTI 2 /* 2 port, mult sector buffer */ +#define ATA_BT_DUALPORTMULTICACHE 3 /* above plus track cache */ + + 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 Reserved62_0:8; // 62 49 + USHORT SupportDma:1; + USHORT SupportLba:1; + USHORT DisableIordy:1; + USHORT SupportIordy:1; + USHORT SoftReset:1; + USHORT StandbyOverlap:1; + USHORT SupportQTag:1; /* supports queuing overlap */ + USHORT SupportIDma:1; /* interleaved DMA supported */ +/* USHORT Capabilities; // 62 49 +#define IDENTIFY_CAPABILITIES_SUPPORT_DMA 0x0100 +#define IDENTIFY_CAPABILITIES_SUPPORT_LBA 0x0200 +#define IDENTIFY_CAPABILITIES_DISABLE_IORDY 0x0400 +#define IDENTIFY_CAPABILITIES_SUPPORT_IORDY 0x0800 +#define IDENTIFY_CAPABILITIES_SOFT_RESET 0x1000 +#define IDENTIFY_CAPABILITIES_STDBY_OVLP 0x2000 +#define IDENTIFY_CAPABILITIES_SUPPORT_QTAG 0x4000 +#define IDENTIFY_CAPABILITIES_SUPPORT_IDMA 0x8000*/ + + USHORT DeviceStandbyMin:1; // 64 50 + USHORT Reserved50_1:13; + USHORT DeviceCapability1:1; + USHORT DeviceCapability0:1; +// USHORT Reserved2; + + UCHAR Vendor51; // 66 51 + UCHAR PioCycleTimingMode; // 67 + + UCHAR Vendor52; // 68 52 + UCHAR DmaCycleTimingMode; // 69 + + USHORT TranslationFieldsValid:1; // 6A 53 /* 54-58 */ + USHORT PioTimingsValid:1; /* 64-70 */ + USHORT UdmaModesValid:1; /* 88 */ + USHORT Reserved3:13; + + USHORT NumberOfCurrentCylinders; // 6C 54 \- + USHORT NumberOfCurrentHeads; // 6E 55 \- + USHORT CurrentSectorsPerTrack; // 70 56 /- obsolete USHORT[5] + ULONG CurrentSectorCapacity; // 72 57-58 /- + + USHORT CurrentMultiSector:8; // 59 + USHORT CurrentMultiSectorValid:1; + USHORT Reserved59_9:7; + + ULONG UserAddressableSectors; // 60-61 + + USHORT SingleWordDMASupport : 8; // 62 \- obsolete + USHORT SingleWordDMAActive : 8; // /- + + USHORT MultiWordDMASupport : 8; // 63 + USHORT MultiWordDMAActive : 8; + + USHORT AdvancedPIOModes : 8; // 64 + USHORT Reserved4 : 8; + +#define AdvancedPIOModes_3 1 +#define AdvancedPIOModes_4 2 +#define AdvancedPIOModes_5 4 // non-standard + + USHORT MinimumMWXferCycleTime; // 65 + USHORT RecommendedMWXferCycleTime; // 66 + USHORT MinimumPIOCycleTime; // 67 + USHORT MinimumPIOCycleTimeIORDY; // 68 + + USHORT Reserved69_70[2]; // 69-70 + USHORT ReleaseTimeOverlapped; // 71 + USHORT ReleaseTimeServiceCommand; // 72 + USHORT Reserved73_74[2]; // 73-74 + + USHORT QueueLength : 5; // 75 + USHORT Reserved75_6 : 11; + + USHORT SataCapabilities; // 76 +#define ATA_SATA_GEN1 0x0002 +#define ATA_SATA_GEN2 0x0004 +#define ATA_SUPPORT_NCQ 0x0100 +#define ATA_SUPPORT_IFPWRMNGTRCV 0x0200 + + USHORT Reserved77; // 77 + + USHORT SataSupport; // 78 +#define ATA_SUPPORT_NONZERO 0x0002 +#define ATA_SUPPORT_AUTOACTIVATE 0x0004 +#define ATA_SUPPORT_IFPWRMNGT 0x0008 +#define ATA_SUPPORT_INORDERDATA 0x0010 + + USHORT SataEnable; // 79 + USHORT MajorRevision; // 80 + USHORT MinorRevision; // 81 + + struct { + USHORT Smart:1; // 82/85 + USHORT Security:1; + USHORT Removable:1; + USHORT PowerMngt:1; + USHORT Packet:1; + USHORT WriteCache:1; + USHORT LookAhead:1; + USHORT ReleaseDRQ:1; + USHORT ServiceDRQ:1; + USHORT Reset:1; + USHORT Protected:1; + USHORT Reserved_82_11:1; + USHORT WriteBuffer:1; + USHORT ReadBuffer:1; + USHORT Nop:1; + USHORT Reserved_82_15:1; + + USHORT Microcode:1; // 83/86 + USHORT Queued:1; // + USHORT CFA:1; // + USHORT APM:1; // + USHORT Notify:1; // + USHORT Standby:1; // + USHORT Spinup:1; // + USHORT Reserver_83_7:1; + USHORT MaxSecurity:1; // + USHORT AutoAcoustic:1; // + USHORT Address48:1; // + USHORT ConfigOverlay:1; // + USHORT FlushCache:1; // + USHORT FlushCache48:1; // + USHORT SupportOne:1; // + USHORT SupportZero:1; // + + USHORT SmartErrorLog:1; // 84/87 + USHORT SmartSelfTest:1; + USHORT MediaSerialNo:1; + USHORT MediaCardPass:1; + USHORT Streaming:1; + USHORT Logging:1; + USHORT Reserver_84_6:8; + USHORT ExtendedOne:1; // + USHORT ExtendedZero:1; // + } FeaturesSupport, FeaturesEnabled; + + USHORT UltraDMASupport : 8; // 88 + USHORT UltraDMAActive : 8; + + USHORT EraseTime; // 89 + USHORT EnhancedEraseTime; // 90 + USHORT CurentAPMLevel; // 91 + + USHORT MasterPasswdRevision; // 92 + + USHORT HwResMaster : 8; // 93 + USHORT HwResSlave : 5; + USHORT HwResCableId : 1; + USHORT HwResValid : 2; + + USHORT CurrentAcoustic : 8; // 94 + USHORT VendorAcoustic : 8; + + USHORT StreamMinReqSize; // 95 + USHORT StreamTransferTime; // 96 + USHORT StreamAccessLatency; // 97 + ULONG StreamGranularity; // 98-99 + + ULONGLONG UserAddressableSectors48; // 100-103 + + USHORT Reserved104[2]; // 104-105 + union { + USHORT PhysLogSectorSize; // 106 + struct { + USHORT PLSS_Size:4; + USHORT PLSS_Reserved:8; + USHORT PLSS_LargeL:1; // =1 if 117-118 are valid + USHORT PLSS_LargeP:1; + USHORT PLSS_Signature:2; // = 0x01 = 01b + }; + }; + USHORT Reserved107[10]; // 107-116 + + ULONG LargeSectorSize; // 117-118 + + USHORT Reserved117[8]; // 119-126 + + USHORT RemovableStatus; // 127 + USHORT SecurityStatus; // 128 + + USHORT FeaturesSupport4; // 129 + USHORT Reserved130[30]; // 130-159 + USHORT CfAdvPowerMode; // 160 + USHORT Reserved161[14]; // 161-175 + USHORT MediaSerial[30]; // 176-205 + USHORT Reserved206[49]; // 205-254 + USHORT Integrity; // 255 +} IDENTIFY_DATA, *PIDENTIFY_DATA; + +// +// Identify data without the Reserved4. +// + +#define IDENTIFY_DATA2 IDENTIFY_DATA +#define PIDENTIFY_DATA2 PIDENTIFY_DATA + +/*typedef struct _IDENTIFY_DATA2 { + UCHAR AtapiCmdSize:2; // 00 00 + UCHAR :3; + UCHAR DrqType:2; // 00 00 + UCHAR Removable:1; + + UCHAR DeviceType:5; + UCHAR :1; + UCHAR CmdProtocol:2; // 00 00 +// 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 + UCHAR SerialNumber[20]; // 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 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 +/* +#define PCI_DEV_HW_SPEC(idhi, idlo) \ + { #idlo, 4, #idhi, 4} + +typedef struct _BROKEN_CONTROLLER_INFORMATION { + PCHAR VendorId; + ULONG VendorIdLength; + PCHAR DeviceId; + ULONG DeviceIdLength; +}BROKEN_CONTROLLER_INFORMATION, *PBROKEN_CONTROLLER_INFORMATION; + +BROKEN_CONTROLLER_INFORMATION const BrokenAdapters[] = { + // CMD 640 ATA controller !WARNING! buggy chip data loss possible + PCI_DEV_HW_SPEC( 0640, 1095 ), //{ "1095", 4, "0640", 4}, + // ?? + PCI_DEV_HW_SPEC( 0601, 1039 ), //{ "1039", 4, "0601", 4} + // RZ 100? ATA controller !WARNING! buggy chip data loss possible + PCI_DEV_HW_SPEC( 1000, 1042 ), + PCI_DEV_HW_SPEC( 1001, 1042 ) +}; + +#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[] = { + PCI_DEV_HW_SPEC( 0105, 10ad ) //{ "10ad", 4, "0105", 4} +}; + +#define NUM_NATIVE_MODE_ADAPTERS (sizeof(NativeModeAdapters) / sizeof(NATIVE_MODE_CONTROLLER_INFORMATION)) +*/ +// +// Beautification macros +// + +#ifndef USER_MODE + +#define GetStatus(chan, Status) \ + Status = AtapiReadPort1(chan, IDX_IO2_AltStatus); + +#define GetBaseStatus(chan, pStatus) \ + pStatus = AtapiReadPort1(chan, IDX_IO1_i_Status); + +#define WriteCommand(chan, _Command) \ + AtapiWritePort1(chan, IDX_IO1_o_Command, _Command); + + +#define SelectDrive(chan, unit) \ + AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (unit) ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1); + + +#define ReadBuffer(chan, Buffer, Count, timing) \ + AtapiReadBuffer2(chan, IDX_IO1_i_Data, \ + Buffer, \ + Count, \ + timing); + +#define WriteBuffer(chan, Buffer, Count, timing) \ + AtapiWriteBuffer2(chan, IDX_IO1_o_Data, \ + Buffer, \ + Count, \ + timing); + +#define ReadBuffer2(chan, Buffer, Count, timing) \ + AtapiReadBuffer4(chan, IDX_IO1_i_Data, \ + Buffer, \ + Count, \ + timing); + +#define WriteBuffer2(chan, Buffer, Count, timing) \ + AtapiWriteBuffer4(chan, IDX_IO1_o_Data, \ + Buffer, \ + Count, \ + timing); + +UCHAR +DDKFASTAPI +WaitOnBusy( + IN struct _HW_CHANNEL* chan/*, + PIDE_REGISTERS_2 BaseIoAddress*/ + ); + +UCHAR +DDKFASTAPI +WaitOnBusyLong( + IN struct _HW_CHANNEL* chan/*, + PIDE_REGISTERS_2 BaseIoAddress*/ + ); + +UCHAR +DDKFASTAPI +WaitOnBaseBusy( + IN struct _HW_CHANNEL* chan/*, + PIDE_REGISTERS_1 BaseIoAddress*/ + ); + +UCHAR +DDKFASTAPI +WaitOnBaseBusyLong( + IN struct _HW_CHANNEL* chan/*, + PIDE_REGISTERS_1 BaseIoAddress*/ + ); + +UCHAR +DDKFASTAPI +WaitForDrq( + IN struct _HW_CHANNEL* chan/*, + PIDE_REGISTERS_2 BaseIoAddress*/ + ); + +UCHAR +DDKFASTAPI +WaitShortForDrq( + IN struct _HW_CHANNEL* chan/*, + PIDE_REGISTERS_2 BaseIoAddress*/ + ); + +VOID +DDKFASTAPI +AtapiSoftReset( + IN struct _HW_CHANNEL* chan,/* + PIDE_REGISTERS_1 BaseIoAddress*/ + ULONG DeviceNumber + ); + +/*#define IdeHardReset(BaseIoAddress,result) \ +{\ + UCHAR statusByte;\ + ULONG i;\ + SelectDrive(BaseIoAddress,DeviceNumber); \ + AtapiWritePort1(&BaseIoAddress->AltStatus,/*IDE_DC_DISABLE_INTERRUPTS | *//*IDE_DC_RESET_CONTROLLER );\ +/* ScsiPortStallExecution(50 * 1000);\ + AtapiWritePort1(&BaseIoAddress->AltStatus,IDE_DC_REENABLE_CONTROLLER);\ + /* 5 seconds for reset */ \ +/* for (i = 0; i < 1000 * (1+11); i++) {\ + statusByte = AtapiReadPort1(&BaseIoAddress->AltStatus);\ + if (statusByte != IDE_STATUS_IDLE && statusByte != IDE_STATUS_SUCCESS) {\ + ScsiPortStallExecution((i<1000) ? 5 : 500);\ + } else {\ + break;\ + }\ + }\ + KdPrint2((PRINT_PREFIX "IdeHardReset: Status %x\n", statusByte)); \ + if (i == 1000*1000) {\ + result = FALSE;\ + }\ + result = TRUE;\ +}*/ + +#endif //USER_MODE + +#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_FORMAT_UNIT)||\ + (OperationCode == SCSIOP_BLANK)||*/ \ + (OperationCode == SCSIOP_WRITE_FILEMARKS)) + +#ifndef USER_MODE + +PSCSI_REQUEST_BLOCK +BuildMechanismStatusSrb ( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +PSCSI_REQUEST_BLOCK +BuildRequestSenseSrb ( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +VOID +AtapiHwInitializeChanger ( + IN PVOID HwDeviceExtension, + IN ULONG TargetId, + IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus + ); + +ULONG +AtapiSendCommand( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN ULONG CmdAction + ); + +ULONG +IdeSendCommand( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN ULONG CmdAction + ); + +#define AtapiCopyMemory RtlCopyMemory + +VOID +AtapiHexToString ( + ULONG Value, + PCHAR *Buffer + ); + +#define AtapiStringCmp(s1, s2, n) _strnicmp(s1, s2, n) + +BOOLEAN +AtapiInterrupt( + IN PVOID HwDeviceExtension + ); + +BOOLEAN +AtapiInterrupt__( + IN PVOID HwDeviceExtension, + IN UCHAR c + ); + +BOOLEAN +AtapiHwInitialize( + IN PVOID HwDeviceExtension + ); + +ULONG +IdeBuildSenseBuffer( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +VOID +IdeMediaStatus( + IN BOOLEAN EnableMSN, + IN PVOID HwDeviceExtension, + IN UCHAR Channel + ); + +ULONG DDKAPI +AtapiFindController( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ); + +ULONG +AtapiParseArgumentString( + IN PCHAR String, + IN PCHAR KeyWord + ); + +BOOLEAN +IssueIdentify( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG Channel, + IN UCHAR Command, + IN BOOLEAN NoSetup + ); + +BOOLEAN +SetDriveParameters( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG Channel + ); + +ULONG +CheckDevice( + IN PVOID HwDeviceExtension, + IN ULONG Channel, + IN ULONG deviceNumber, + IN BOOLEAN ResetBus + ); + +BOOLEAN +FindDevices( + IN PVOID HwDeviceExtension, + IN BOOLEAN AtapiOnly, + IN ULONG Channel + ); + +#endif //USER_MODE + +#ifdef __cplusplus +}; +#endif //__cplusplus + +#ifndef USER_MODE + +BOOLEAN +AtapiResetController( + IN PVOID HwDeviceExtension, + IN ULONG PathId + ); + +BOOLEAN +AtapiStartIo( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +BOOLEAN +AtapiStartIo__( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN BOOLEAN TopLevel + ); + +extern UCHAR +AtaCommand48( +// IN PVOID HwDeviceExtension, + IN struct _HW_DEVICE_EXTENSION* deviceExtension, + IN ULONG DeviceNumber, + IN ULONG Channel, + IN UCHAR command, + IN ULONGLONG lba, + IN USHORT count, + IN USHORT feature, + IN ULONG flags + ); + +extern UCHAR +AtaCommand( +// IN PVOID HwDeviceExtension, + IN struct _HW_DEVICE_EXTENSION* deviceExtension, + IN ULONG DeviceNumber, + IN ULONG Channel, + IN UCHAR command, + IN USHORT cylinder, + IN UCHAR head, + IN UCHAR sector, + IN UCHAR count, + IN UCHAR feature, + IN ULONG flags + ); + +extern LONG +AtaPioMode(PIDENTIFY_DATA2 ident); + +extern LONG +AtaWmode(PIDENTIFY_DATA2 ident); + +extern LONG +AtaUmode(PIDENTIFY_DATA2 ident); + +extern VOID +AtapiDpcDispatch( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + + +//#define AtaCommand(de, devn, chan, cmd, cyl, hd, sec, cnt, feat, flg) \ + +extern LONG +AtaPio2Mode(LONG pio); + +extern LONG +AtaPioMode(PIDENTIFY_DATA2 ident); + +extern VOID +AtapiEnableInterrupts( + IN PVOID HwDeviceExtension, + IN ULONG c + ); + +extern VOID +AtapiDisableInterrupts( + IN PVOID HwDeviceExtension, + IN ULONG c + ); + +#define CHAN_NOT_SPECIFIED (0xffffffffL) +#define DEVNUM_NOT_SPECIFIED (0xffffffffL) + +extern ULONG +AtapiRegCheckDevValue( + IN PVOID HwDeviceExtension, + IN ULONG chan, + IN ULONG dev, + IN PWSTR Name, + IN ULONG Default + ); + +extern ULONG +AtapiRegCheckParameterValue( + IN PVOID HwDeviceExtension, + IN PWSTR PathSuffix, + IN PWSTR Name, + IN ULONG Default + ); + +extern ULONG g_LogToDisplay; + +extern "C" +VOID +_cdecl +_PrintNtConsole( + PCHAR DebugMessage, + ... + ); + +VOID +UniataInitMapBM( + IN struct _HW_DEVICE_EXTENSION* deviceExtension, + IN struct _IDE_BUSMASTER_REGISTERS* BaseIoAddressBM_0, + IN BOOLEAN MemIo + ); + +VOID +UniataInitMapBase( + IN struct _HW_CHANNEL* chan, + IN PIDE_REGISTERS_1 BaseIoAddress1, + IN PIDE_REGISTERS_2 BaseIoAddress2 + ); + +VOID +UniataInitSyncBaseIO( + IN struct _HW_CHANNEL* chan + ); + +UCHAR +DDKFASTAPI +UniataIsIdle( + IN struct _HW_DEVICE_EXTENSION* deviceExtension, + IN UCHAR Status + ); + +VOID +UniataDumpATARegs( + IN struct _HW_CHANNEL* chan + ); + +ULONG +EncodeVendorStr( + OUT PWCHAR Buffer, + IN PUCHAR Str, + IN ULONG Length + ); + +ULONGLONG +UniAtaCalculateLBARegsBack( + struct _HW_LU_EXTENSION* LunExt, + ULONGLONG lba + ); + +BOOLEAN +UniataAnybodyHome( + IN PVOID HwDeviceExtension, + IN ULONG Channel, + IN ULONG deviceNumber + ); + +#define ATA_CMD_FLAG_LBAIOsupp 0x01 +#define ATA_CMD_FLAG_48supp 0x02 +#define ATA_CMD_FLAG_48 0x04 +#define ATA_CMD_FLAG_DMA 0x08 + +extern UCHAR AtaCommands48[256]; +extern UCHAR AtaCommandFlags[256]; + +#ifdef _DEBUG +#define PrintNtConsole _PrintNtConsole +#else //_DEBUG +#define PrintNtConsole(x) {;} +#endif //_DEBUG + +#endif //USER_MODE + +#pragma pack(pop) + +#endif // __GLOBAL_H__ diff --git a/reactos/drivers/storage/ide/uniata/badblock.h b/reactos/drivers/storage/ide/uniata/badblock.h new file mode 100644 index 00000000000..871cf9b0836 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/badblock.h @@ -0,0 +1,78 @@ +/*++ + +Copyright (C) 2006 VorontSOFT + +Module Name: + badblock.h + +Abstract: + This is the artificial badblock simulation part of the + miniport driver for ATA/ATAPI IDE controllers + with Busmaster DMA support + +Author: + Nikolai Vorontsov (NickViz) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + 2006/08/03 Initial implementation. + 2006/08/06 Added registry work. + +--*/ + + +#ifndef _BADBLOCK_H_INCLUDED_ +#define _BADBLOCK_H_INCLUDED_ + +#pragma pack(push, 4) +typedef struct _SBadBlockRange +{ +// ULONG m_ldev; + ULONGLONG m_lbaStart; + ULONGLONG m_lbaEnd; +} SBadBlockRange, *PSBadBlockRange; + +typedef struct _SBadBlockListItem { + LIST_ENTRY List; + PHW_LU_EXTENSION LunExt; + WCHAR SerNumStr[128]; + SBadBlockRange* arrBadBlocks; + ULONG nBadBlocks; +} SBadBlockListItem, *PSBadBlockListItem; + +#pragma pack(pop) + +void +InitBadBlocks( + IN PHW_LU_EXTENSION LunExt + ); + +void +ForgetBadBlocks( + IN PHW_LU_EXTENSION LunExt + ); + +bool +CheckIfBadBlock( + IN PHW_LU_EXTENSION LunExt, +// IN UCHAR command, + IN ULONGLONG lba, + IN ULONG count + ); + +#endif // _BADBLOCK_H_INCLUDED_ \ No newline at end of file diff --git a/reactos/drivers/storage/ide/uniata/bm_devs.h b/reactos/drivers/storage/ide/uniata/bm_devs.h new file mode 100644 index 00000000000..2ba12f75ec1 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/bm_devs.h @@ -0,0 +1,737 @@ +/*++ + +Copyright (c) 2002-2005 Alexandr A. Telyatnikov (Alter) + +Module Name: + bm_devs.h + +Abstract: + This file contains list of 'well known' PCI IDE controllers + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + +--*/ + +#define IDE_MAX_CHAN 8 +// Thanks to SATA Port Multipliers: +#define IDE_MAX_LUN_PER_CHAN 16 +#define IDE_MAX_LUN (AHCI_MAX_PORT*IDE_MAX_LUN_PER_CHAN) + +#define MAX_QUEUE_STAT 8 + +// +// values for TransferMode +// +#define ATA_PIO 0x00 +#define ATA_PIO_NRDY 0x01 + +#define ATA_PIO0 0x08 +#define ATA_PIO1 0x09 +#define ATA_PIO2 0x0a +#define ATA_PIO3 0x0b +#define ATA_PIO4 0x0c +#define ATA_PIO5 0x0d + +#define ATA_DMA 0x10 +#define ATA_SDMA 0x10 +#define ATA_SDMA0 0x10 +#define ATA_SDMA1 0x11 +#define ATA_SDMA2 0x12 + +#define ATA_WDMA 0x20 +#define ATA_WDMA0 0x20 +#define ATA_WDMA1 0x21 +#define ATA_WDMA2 0x22 + +#define ATA_UDMA 0x40 +#define ATA_UDMA0 0x40 // ATA-16 +#define ATA_UDMA1 0x41 // ATA-25 +#define ATA_UDMA2 0x42 // ATA-33 +#define ATA_UDMA3 0x43 // ATA-44 +#define ATA_UDMA4 0x44 // ATA-66 +#define ATA_UDMA5 0x45 // ATA-100 +#define ATA_UDMA6 0x46 // ATA-133 +//#define ATA_UDMA7 0x47 // ATA-166 + +#define ATA_SA150 0x47 /*0x80*/ +#define ATA_SA300 0x48 /*0x81*/ + +// define PIO timings in nanoseconds +#define PIO0_TIMING 600 + +#define UniataGetPioTiming(LunExt) ((LunExt->TransferMode <= ATA_PIO0) ? PIO0_TIMING : 0) + +#ifndef __IDE_BUSMASTER_DEVICES_H__ +#define __IDE_BUSMASTER_DEVICES_H__ + +typedef struct _BUSMASTER_CONTROLLER_INFORMATION { + PCHAR VendorId; + ULONG VendorIdLength; + ULONG nVendorId; + PCHAR DeviceId; + ULONG DeviceIdLength; + ULONG nDeviceId; + ULONG nRevId; + ULONG MaxTransferMode; + PCHAR FullDevName; + ULONG RaidFlags; + CHAR VendorIdStr[4]; + CHAR DeviceIdStr[4]; + ULONG slotNumber; + ULONG busNumber; + CHAR channel; +// CHAR numOfChannes; + CHAR MasterDev; +#ifndef USER_MODE + CHAR ChanInitOk; // 0x01 - primary, 0x02 - secondary + BOOLEAN Isr2Enable; + PDEVICE_OBJECT Isr2DevObj; + KIRQL Isr2Irql; + KAFFINITY Isr2Affinity; + ULONG Isr2Vector; + PKINTERRUPT Isr2InterruptObject; + CHAR AltInitMasterDev; // 0xff - uninitialized, 0x00 - normal, 0x01 - change ISA to PCI +#endif + +}BUSMASTER_CONTROLLER_INFORMATION, *PBUSMASTER_CONTROLLER_INFORMATION; + +/* defines for known chipset PCI id's */ +#define ATA_ACARD_ID 0x1191 +#define ATA_ATP850 0x00021191 +#define ATA_ATP850A 0x00041191 +#define ATA_ATP850R 0x00051191 +#define ATA_ATP860A 0x00061191 +#define ATA_ATP860R 0x00071191 +#define ATA_ATP865A 0x00081191 +#define ATA_ATP865R 0x00091191 + +#define ATA_AMD_ID 0x1022 +#define ATA_AMD755 0x74011022 +#define ATA_AMD756 0x74091022 +#define ATA_AMD766 0x74111022 +#define ATA_AMD768 0x74411022 +#define ATA_AMD8111 0x74691022 + +#define ATA_ACER_LABS_ID 0x10b9 +#define ATA_ALI_1533 0x153310b9 +#define ATA_ALI_5229 0x522910b9 +#define ATA_ALI_5281 0x528110b9 +#define ATA_ALI_5287 0x528710b9 +#define ATA_ALI_5288 0x528810b9 +#define ATA_ALI_5289 0x528910b9 + +#define ATA_ATI_ID 0x1002 +#define ATA_ATI_IXP200 0x43491002 +#define ATA_ATI_IXP300 0x43691002 +#define ATA_ATI_IXP400 0x43761002 +#define ATA_ATI_IXP300_S1 0x436e1002 +#define ATA_ATI_IXP400_S1 0x43791002 +#define ATA_ATI_IXP400_S2 0x437a1002 + +#define ATA_CYRIX_ID 0x1078 +#define ATA_CYRIX_5530 0x01021078 + +#define ATA_CYPRESS_ID 0x1080 +#define ATA_CYPRESS_82C693 0xc6931080 + +#define ATA_DEC_21150 0x00221011 +#define ATA_DEC_21150_1 0x00231011 + +#define ATA_HIGHPOINT_ID 0x1103 +#define ATA_HPT366 0x00041103 +#define ATA_HPT372 0x00051103 +#define ATA_HPT302 0x00061103 +#define ATA_HPT371 0x00071103 +#define ATA_HPT374 0x00081103 + +#define ATA_INTEL_ID 0x8086 +#define ATA_I960RM 0x09628086 +#define ATA_I82371FB 0x12308086 +#define ATA_I82371SB 0x70108086 +#define ATA_I82371AB 0x71118086 +#define ATA_I82443MX 0x71998086 +#define ATA_I82451NX 0x84ca8086 +#define ATA_I82372FB 0x76018086 +#define ATA_I82801AB 0x24218086 +#define ATA_I82801AA 0x24118086 +#define ATA_I82801BA 0x244a8086 +#define ATA_I82801BA_1 0x244b8086 +#define ATA_I82801CA 0x248a8086 +#define ATA_I82801CA_1 0x248b8086 +#define ATA_I82801DB 0x24cb8086 +#define ATA_I82801DB_1 0x24ca8086 +#define ATA_I82801EB 0x24db8086 +#define ATA_I82801EB_1 0x24d18086 +#define ATA_I82801EB_2 0x24df8086 +#define ATA_I6300ESB 0x25a28086 +#define ATA_I6300ESB_1 0x25a38086 +#define ATA_I6300ESB_2 0x25b08086 +#define ATA_I82801FB 0x266f8086 +#define ATA_I82801FB_S1 0x26518086 +#define ATA_I82801FB_R1 0x26528086 +#define ATA_I82801FB_M 0x26538086 +#define ATA_I82801GB 0x27df8086 +#define ATA_I82801GB_S1 0x27c08086 +#define ATA_I82801GB_R1 0x27c38086 +#define ATA_I82801GB_AH 0x27c18086 +#define ATA_I82801GB_M 0x27c58086 + +#define ATA_NATIONAL_ID 0x100b +#define ATA_SC1100 0x0502100b + +#define ATA_NVIDIA_ID 0x10de +#define ATA_NFORCE1 0x01bc10de +#define ATA_NFORCE2 0x006510de +#define ATA_NFORCE2_MCP 0x008510de +#define ATA_NFORCE3 0x00d510de +#define ATA_NFORCE3_PRO 0x00e510de +#define ATA_NFORCE3_PRO_S1 0x00e310de +#define ATA_NFORCE3_PRO_S2 0x00ee10de +#define ATA_NFORCE3_MCP 0x003510de +#define ATA_NFORCE3_MCP_S1 0x003610de +#define ATA_NFORCE3_MCP_S2 0x003e10de +#define ATA_NFORCE4 0x005310de +#define ATA_NFORCE4_S1 0x005410de +#define ATA_NFORCE4_S2 0x005510de + +#define ATA_PROMISE_ID 0x105a +#define ATA_PDC20246 0x4d33105a +#define ATA_PDC20262 0x4d38105a +#define ATA_PDC20263 0x0d38105a +#define ATA_PDC20265 0x0d30105a +#define ATA_PDC20267 0x4d30105a +#define ATA_PDC20268 0x4d68105a +#define ATA_PDC20269 0x4d69105a +#define ATA_PDC20270 0x6268105a +#define ATA_PDC20271 0x6269105a +#define ATA_PDC20275 0x1275105a +#define ATA_PDC20276 0x5275105a +#define ATA_PDC20277 0x7275105a +#define ATA_PDC20318 0x3318105a +#define ATA_PDC20319 0x3319105a +#define ATA_PDC20371 0x3371105a +#define ATA_PDC20375 0x3375105a +#define ATA_PDC20376 0x3376105a +#define ATA_PDC20377 0x3377105a +#define ATA_PDC20378 0x3373105a +#define ATA_PDC20379 0x3372105a +#define ATA_PDC20617 0x6617105a +#define ATA_PDC20618 0x6626105a +#define ATA_PDC20619 0x6629105a +#define ATA_PDC20620 0x6620105a +#define ATA_PDC20621 0x6621105a +#define ATA_PDC20622 0x6622105a + +#define ATA_SERVERWORKS_ID 0x1166 +#define ATA_ROSB4_ISA 0x02001166 +#define ATA_ROSB4 0x02111166 +#define ATA_CSB5 0x02121166 +#define ATA_CSB6 0x02131166 +#define ATA_CSB6_1 0x02171166 +#define ATA_HT1000 0x02141166 +#define ATA_HT1000_S1 0x024b1166 +#define ATA_HT1000_S2 0x024a1166 +#define ATA_K2 0x02401166 +#define ATA_FRODO4 0x02411166 +#define ATA_FRODO8 0x02421166 + +#define ATA_SILICON_IMAGE_ID 0x1095 +#define ATA_SII3114 0x31141095 +#define ATA_SII3512 0x35121095 +#define ATA_SII3112 0x31121095 +#define ATA_SII3112_1 0x02401095 +#define ATA_SII0680 0x06801095 +#define ATA_CMD646 0x06461095 +#define ATA_CMD648 0x06481095 +#define ATA_CMD649 0x06491095 + +#define ATA_SIS_ID 0x1039 +#define ATA_SISSOUTH 0x00081039 +#define ATA_SIS5511 0x55111039 +#define ATA_SIS5513 0x55131039 +#define ATA_SIS5517 0x55171039 +#define ATA_SIS5518 0x55181039 +#define ATA_SIS5571 0x55711039 +#define ATA_SIS5591 0x55911039 +#define ATA_SIS5596 0x55961039 +#define ATA_SIS5597 0x55971039 +#define ATA_SIS5598 0x55981039 +#define ATA_SIS5600 0x56001039 +#define ATA_SIS530 0x05301039 +#define ATA_SIS540 0x05401039 +#define ATA_SIS550 0x05501039 +#define ATA_SIS620 0x06201039 +#define ATA_SIS630 0x06301039 +#define ATA_SIS635 0x06351039 +#define ATA_SIS633 0x06331039 +#define ATA_SIS640 0x06401039 +#define ATA_SIS645 0x06451039 +#define ATA_SIS646 0x06461039 +#define ATA_SIS648 0x06481039 +#define ATA_SIS650 0x06501039 +#define ATA_SIS651 0x06511039 +#define ATA_SIS652 0x06521039 +#define ATA_SIS655 0x06551039 +#define ATA_SIS658 0x06581039 +#define ATA_SIS661 0x06611039 +#define ATA_SIS730 0x07301039 +#define ATA_SIS733 0x07331039 +#define ATA_SIS735 0x07351039 +#define ATA_SIS740 0x07401039 +#define ATA_SIS745 0x07451039 +#define ATA_SIS746 0x07461039 +#define ATA_SIS748 0x07481039 +#define ATA_SIS750 0x07501039 +#define ATA_SIS751 0x07511039 +#define ATA_SIS752 0x07521039 +#define ATA_SIS755 0x07551039 +#define ATA_SIS961 0x09611039 +#define ATA_SIS962 0x09621039 +#define ATA_SIS963 0x09631039 +#define ATA_SIS964 0x09641039 +#define ATA_SIS964_1 0x01801039 + +#define ATA_VIA_ID 0x1106 +#define ATA_VIA82C571 0x05711106 +#define ATA_VIA82C586 0x05861106 +#define ATA_VIA82C596 0x05961106 +#define ATA_VIA82C686 0x06861106 +#define ATA_VIA8231 0x82311106 +#define ATA_VIA8233 0x30741106 +#define ATA_VIA8233A 0x31471106 +#define ATA_VIA8233C 0x31091106 +#define ATA_VIA8235 0x31771106 +#define ATA_VIA8237 0x32271106 +#define ATA_VIA8251 0x33491106 +#define ATA_VIA8361 0x31121106 +#define ATA_VIA8363 0x03051106 +#define ATA_VIA8371 0x03911106 +#define ATA_VIA8662 0x31021106 +#define ATA_VIA6410 0x31641106 +#define ATA_VIA6420 0x31491106 +#define ATA_VIA6421 0x32491106 + +#define ATA_ITE_ID 0x1283 +#define ATA_IT8172G 0x81721283 +#define ATA_IT8212F 0x82121283 + +#define ATA_OPTI_ID 0x1045 +#define ATA_OPTI82C621 0xc6211045 +#define ATA_OPTI82C625 0xd5681045 + +#define ATA_HINT_ID 0x3388 +#define ATA_HINTEIDE_ID 0x80133388 + +/* chipset setup related defines */ +/* Used in HW_DEVICE_EXTENSION.InitMethod */ + +#define CHIPTYPE_MASK 0x000000ff +#define CHIPFLAG_MASK 0xffffff00 + +#define UNIATA_RAID_CONTROLLER 0x80000000 +#define UNIATA_SIMPLEX_ONLY 0x40000000 +#define UNIATA_NO_SLAVE 0x20000000 +#define UNIATA_SATA 0x10000000 +#define UNIATA_NO_DPC 0x08000000 +#define UNIATA_NO_DPC_ATAPI 0x04000000 +#define UNIATA_AHCI 0x02000000 + +#define ATPOLD 0x0100 + +#define ALIOLD 0x0100 +#define ALINEW 0x0200 + +#define HPT366 0 +#define HPT370 1 +#define HPT372 2 +#define HPT374 3 +#define HPTOLD 0x0100 + +#define PROLD 0 +#define PRNEW 1 +#define PRTX 2 +#define PRMIO 3 +#define PRIDX 4 +#define PRTX4 0x0100 +#define PRSX4K 0x0200 +#define PRSX6K 0x0400 +#define PRSATA 0x0800 +#define PRDUAL 0x1000 + +#define SWKS33 0 +#define SWKS66 1 +#define SWKS100 2 +#define SWKSMIO 3 + +#define SIIOLD 0 +#define SIICMD 1 +#define SIIMIO 2 + +#define SIIINTR 0x0100 +#define SIIENINTR 0x0200 +#define SII4CH 0x0400 +#define SIISETCLK 0x0800 +#define SIIBUG 0x1000 +#define SIINOSATAIRQ 0x2000 + +//#define SIS_SOUTH 1 +#define SISSATA 2 +#define SIS133NEW 3 +#define SIS133OLD 4 +#define SIS100NEW 5 +#define SIS100OLD 6 +#define SIS66 7 +#define SIS33 8 + +#define SIS_BASE 0x0100 +#define SIS_SOUTH 0x0200 + +#define ICH4_FIX 0x0100 + +#define NV4OFF 0x0100 +#define NVQ 0x0200 + +#define VIA33 0 +#define VIA66 1 +#define VIA100 2 +#define VIA133 3 +#define AMDNVIDIA 4 +#define AMDCABLE 0x0100 +#define AMDBUG 0x0200 +#define VIABAR 0x0400 +#define VIACLK 0x0800 +#define VIABUG 0x1000 +#define VIASOUTH 0x2000 +#define VIAAST 0x4000 +#define VIAPRQ 0x8000 + +#define ITE_33 0 +#define ITE_133 1 + +#ifdef USER_MODE + #define PCI_DEV_HW_SPEC_BM(idhi, idlo, rev, mode, name, flags) \ + { #idlo, 4, 0x##idlo, #idhi, 4, 0x##idhi, rev, mode, name, flags} +#else + #define PCI_DEV_HW_SPEC_BM(idhi, idlo, rev, mode, name, flags) \ + { #idlo, 4, 0x##idlo, #idhi, 4, 0x##idhi, rev, mode, NULL, flags} +#endif + +#define BMLIST_TERMINATOR (0xffffffffL) + +BUSMASTER_CONTROLLER_INFORMATION const BusMasterAdapters[] = { + + PCI_DEV_HW_SPEC_BM( 0005, 1191, 0x00, ATA_UDMA2, "Acard ATP850" , ATPOLD | UNIATA_SIMPLEX_ONLY ), + PCI_DEV_HW_SPEC_BM( 0006, 1191, 0x00, ATA_UDMA4, "Acard ATP860A" , 0 ), + PCI_DEV_HW_SPEC_BM( 0007, 1191, 0x00, ATA_UDMA4, "Acard ATP860R" , 0 ), + PCI_DEV_HW_SPEC_BM( 0008, 1191, 0x00, ATA_UDMA6, "Acard ATP865A" , 0 ), + PCI_DEV_HW_SPEC_BM( 0009, 1191, 0x00, ATA_UDMA6, "Acard ATP865R" , 0 ), + + PCI_DEV_HW_SPEC_BM( 5289, 10b9, 0x00, ATA_SA150, "ALI M5289" , UNIATA_SATA | UNIATA_NO_SLAVE ), + PCI_DEV_HW_SPEC_BM( 5288, 10b9, 0x00, ATA_SA300, "ALI M5288" , UNIATA_SATA | UNIATA_NO_SLAVE ), + PCI_DEV_HW_SPEC_BM( 5287, 10b9, 0x00, ATA_SA150, "ALI M5287" , UNIATA_SATA | UNIATA_NO_SLAVE ), + PCI_DEV_HW_SPEC_BM( 5281, 10b9, 0x00, ATA_SA150, "ALI M5281" , UNIATA_SATA | UNIATA_NO_SLAVE ), + PCI_DEV_HW_SPEC_BM( 5229, 10b9, 0xc5, ATA_UDMA6, "ALI M5229 UDMA6" , ALINEW ), + PCI_DEV_HW_SPEC_BM( 5229, 10b9, 0xc4, ATA_UDMA5, "ALI M5229 UDMA5" , ALINEW ), + PCI_DEV_HW_SPEC_BM( 5229, 10b9, 0xc2, ATA_UDMA4, "ALI M5229 UDMA4" , ALINEW ), + PCI_DEV_HW_SPEC_BM( 5229, 10b9, 0x20, ATA_UDMA2, "ALI M5229 UDMA2" , ALIOLD ), + PCI_DEV_HW_SPEC_BM( 5229, 10b9, 0x00, ATA_WDMA2, "ALI M5229 WDMA2" , ALIOLD ), + + PCI_DEV_HW_SPEC_BM( 7409, 1022, 0x00, ATA_UDMA4, "AMD 756" , AMDNVIDIA | 0x00 ), + PCI_DEV_HW_SPEC_BM( 7411, 1022, 0x00, ATA_UDMA5, "AMD 766" , AMDNVIDIA | AMDCABLE|AMDBUG ), + PCI_DEV_HW_SPEC_BM( 7441, 1022, 0x00, ATA_UDMA5, "AMD 768" , AMDNVIDIA | AMDCABLE ), + PCI_DEV_HW_SPEC_BM( 7469, 1022, 0x00, ATA_UDMA6, "AMD 8111" , AMDNVIDIA | AMDCABLE ), + + PCI_DEV_HW_SPEC_BM( 4349, 1002, 0x00, ATA_UDMA5, "ATI IXP200" , 0 ), + PCI_DEV_HW_SPEC_BM( 4369, 1002, 0x00, ATA_UDMA6, "ATI IXP300" , 0 ), + PCI_DEV_HW_SPEC_BM( 4376, 1002, 0x00, ATA_UDMA6, "ATI IXP400" , 0 ), + PCI_DEV_HW_SPEC_BM( 436e, 1002, 0x00, ATA_SA150, "ATI IXP300" , SIIMIO | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 4379, 1002, 0x00, ATA_SA150, "ATI IXP400" , SIIMIO | SIINOSATAIRQ | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 437a, 1002, 0x00, ATA_SA150, "ATI IXP400" , SIIMIO | SIINOSATAIRQ | UNIATA_SATA ), + + PCI_DEV_HW_SPEC_BM( 0004, 1103, 0x05, ATA_UDMA6, "HighPoint HPT372" , HPT372 | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0004, 1103, 0x03, ATA_UDMA5, "HighPoint HPT370" , HPT370 | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0004, 1103, 0x02, ATA_UDMA4, "HighPoint HPT368" , HPT366 | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0004, 1103, 0x00, ATA_UDMA4, "HighPoint HPT366" , HPT366 | HPTOLD | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0005, 1103, 0x01, ATA_UDMA6, "HighPoint HPT372" , HPT372 | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0005, 1103, 0x00, ATA_UDMA4, "HighPoint HPT372" , HPT372 | HPTOLD | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0006, 1103, 0x01, ATA_UDMA6, "HighPoint HPT302" , HPT372 | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0007, 1103, 0x01, ATA_UDMA6, "HighPoint HPT371" , HPT372 | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0008, 1103, 0x07, ATA_UDMA6, "HighPoint HPT374" , HPT374 | 0x00 | UNIATA_RAID_CONTROLLER), + + PCI_DEV_HW_SPEC_BM( 1230, 8086, 0x00, ATA_WDMA2, "Intel PIIX" , 0 ), + PCI_DEV_HW_SPEC_BM( 7010, 8086, 0x00, ATA_WDMA2, "Intel PIIX3" , 0 ), + PCI_DEV_HW_SPEC_BM( 7111, 8086, 0x00, ATA_UDMA3, "Intel PIIX4" , 0 ), + PCI_DEV_HW_SPEC_BM( 7199, 8086, 0x00, ATA_UDMA2, "Intel PIIX4" , 0 ), + PCI_DEV_HW_SPEC_BM( 84ca, 8086, 0x00, ATA_UDMA2, "Intel PIIX4" , 0 ), + PCI_DEV_HW_SPEC_BM( 7601, 8086, 0x00, ATA_UDMA2, "Intel ICH0" , 0 ), + PCI_DEV_HW_SPEC_BM( 2421, 8086, 0x00, ATA_UDMA4, "Intel ICH" , 0 ), + PCI_DEV_HW_SPEC_BM( 2411, 8086, 0x00, ATA_UDMA4, "Intel ICH" , 0 ), + PCI_DEV_HW_SPEC_BM( 244a, 8086, 0x00, ATA_UDMA5, "Intel ICH2" , 0 ), + PCI_DEV_HW_SPEC_BM( 244b, 8086, 0x00, ATA_UDMA5, "Intel ICH2" , 0 ), + PCI_DEV_HW_SPEC_BM( 248a, 8086, 0x00, ATA_UDMA5, "Intel ICH3" , 0 ), + PCI_DEV_HW_SPEC_BM( 248b, 8086, 0x00, ATA_UDMA5, "Intel ICH3" , 0 ), + PCI_DEV_HW_SPEC_BM( 24cb, 8086, 0x00, ATA_UDMA5, "Intel ICH4" , ICH4_FIX | UNIATA_NO_DPC ), + PCI_DEV_HW_SPEC_BM( 24ca, 8086, 0x00, ATA_UDMA5, "Intel ICH4" , ICH4_FIX | UNIATA_NO_DPC ), + PCI_DEV_HW_SPEC_BM( 24db, 8086, 0x00, ATA_UDMA5, "Intel ICH5 EB" , 0 ), + PCI_DEV_HW_SPEC_BM( 24d1, 8086, 0x00, ATA_SA150, "Intel ICH5 EB1" , UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 24df, 8086, 0x00, ATA_SA150, "Intel ICH5 EB2" , UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 25a2, 8086, 0x00, ATA_UDMA5, "Intel 6300ESB" , 0 ), + PCI_DEV_HW_SPEC_BM( 25a3, 8086, 0x00, ATA_SA150, "Intel 6300ESB1" , UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 25b0, 8086, 0x00, ATA_SA150, "Intel 6300ESB2" , UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 266f, 8086, 0x00, ATA_UDMA5, "Intel ICH6" , 0 ), + PCI_DEV_HW_SPEC_BM( 2651, 8086, 0x00, ATA_SA150, "Intel ICH6" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2652, 8086, 0x00, ATA_SA150, "Intel ICH6" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2653, 8086, 0x00, ATA_SA150, "Intel ICH6M" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 27df, 8086, 0x00, ATA_UDMA5, "Intel ICH7" , 0 ), + PCI_DEV_HW_SPEC_BM( 27c0, 8086, 0x00, ATA_SA300, "Intel ICH7" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 27c1, 8086, 0x00, ATA_SA300, "Intel ICH7" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 27c3, 8086, 0x00, ATA_SA300, "Intel ICH7" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 27c4, 8086, 0x00, ATA_SA300, "Intel ICH7M" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 27c5, 8086, 0x00, ATA_SA300, "Intel ICH7M" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 27c6, 8086, 0x00, ATA_SA300, "Intel ICH7M" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 269e, 8086, 0x00, ATA_UDMA5, "Intel 63XXESB2" , 0 ), + PCI_DEV_HW_SPEC_BM( 2680, 8086, 0x00, ATA_SA300, "Intel 63XXESB2" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2681, 8086, 0x00, ATA_SA300, "Intel 63XXESB2" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2682, 8086, 0x00, ATA_SA300, "Intel 63XXESB2" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2683, 8086, 0x00, ATA_SA300, "Intel 63XXESB2" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2820, 8086, 0x00, ATA_SA300, "Intel ICH8" , 0 ), + PCI_DEV_HW_SPEC_BM( 2821, 8086, 0x00, ATA_SA300, "Intel ICH8" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2822, 8086, 0x00, ATA_SA300, "Intel ICH8" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2824, 8086, 0x00, ATA_SA300, "Intel ICH8" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2825, 8086, 0x00, ATA_SA300, "Intel ICH8" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 2829, 8086, 0x00, ATA_SA300, "Intel ICH8M" , UNIATA_SATA | UNIATA_AHCI ), + PCI_DEV_HW_SPEC_BM( 282a, 8086, 0x00, ATA_SA300, "Intel ICH8M" , UNIATA_SATA | UNIATA_AHCI ), +// PCI_DEV_HW_SPEC_BM( 3200, 8086, 0x00, ATA_SA150, "Intel 31244" , UNIATA_SATA ), + + PCI_DEV_HW_SPEC_BM( 01bc, 10de, 0x00, ATA_UDMA5, "nVidia nForce" , AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 0065, 10de, 0x00, ATA_UDMA6, "nVidia nForce2" , AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 0085, 10de, 0x00, ATA_UDMA6, "nVidia nForce2 Pro",AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 008e, 10de, 0x00, ATA_SA150, "nVidia nForce2 Pro S1",UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 00d5, 10de, 0x00, ATA_UDMA6, "nVidia nForce3" , AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 00e5, 10de, 0x00, ATA_UDMA6, "nVidia nForce3 Pro",AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 00e3, 10de, 0x00, ATA_SA150, "nVidia nForce3 Pro S1",UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 00ee, 10de, 0x00, ATA_SA150, "nVidia nForce3 Pro S2",UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0035, 10de, 0x00, ATA_UDMA6, "nVidia nForce MCP", AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 0036, 10de, 0x00, ATA_SA150, "nVidia nForce MCP S1",NV4OFF | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 003e, 10de, 0x00, ATA_SA150, "nVidia nForce MCP S2",NV4OFF | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0053, 10de, 0x00, ATA_UDMA6, "nVidia nForce CK804", AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 0054, 10de, 0x00, ATA_SA300, "nVidia nForce CK804 S1",NV4OFF | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0055, 10de, 0x00, ATA_SA300, "nVidia nForce CK804 S2",NV4OFF | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0265, 10de, 0x00, ATA_UDMA6, "nVidia nForce MCP51", AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 0266, 10de, 0x00, ATA_SA300, "nVidia nForce MCP51 S1",NV4OFF | NVQ | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0267, 10de, 0x00, ATA_SA300, "nVidia nForce MCP51 S2",NV4OFF | NVQ | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 036e, 10de, 0x00, ATA_UDMA6, "nVidia nForce MCP55", AMDNVIDIA ), + PCI_DEV_HW_SPEC_BM( 037e, 10de, 0x00, ATA_SA300, "nVidia nForce MCP55 S1",NV4OFF | NVQ | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 037f, 10de, 0x00, ATA_SA300, "nVidia nForce MCP55 S2",NV4OFF | NVQ | UNIATA_SATA ), + + PCI_DEV_HW_SPEC_BM( 0502, 100b, 0x00, ATA_UDMA2, "National Geode SC1100", 0 ), + + PCI_DEV_HW_SPEC_BM( 4d33, 105a, 0x00, ATA_UDMA2, "Promise PDC20246" , PROLD | 0x00 ), + PCI_DEV_HW_SPEC_BM( 4d38, 105a, 0x00, ATA_UDMA4, "Promise PDC20262" , PRNEW | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0d38, 105a, 0x00, ATA_UDMA4, "Promise PDC20263" , PRNEW | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0d30, 105a, 0x00, ATA_UDMA5, "Promise PDC20265" , PRNEW | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 4d30, 105a, 0x00, ATA_UDMA5, "Promise PDC20267" , PRNEW | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 4d68, 105a, 0x00, ATA_UDMA5, "Promise PDC20268" , PRTX | PRTX4 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 4d69, 105a, 0x00, ATA_UDMA6, "Promise PDC20269" , PRTX | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6268, 105a, 0x00, ATA_UDMA5, "Promise PDC20270" , PRTX | PRTX4 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6269, 105a, 0x00, ATA_UDMA6, "Promise PDC20271" , PRTX | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 1275, 105a, 0x00, ATA_UDMA6, "Promise PDC20275" , PRTX | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 5275, 105a, 0x00, ATA_UDMA6, "Promise PDC20276" , PRTX | PRSX6K | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 7275, 105a, 0x00, ATA_UDMA6, "Promise PDC20277" , PRTX | 0x00 | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 3318, 105a, 0x00, ATA_SA150, "Promise PDC20318" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 3319, 105a, 0x00, ATA_SA150, "Promise PDC20319" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 3371, 105a, 0x00, ATA_SA150, "Promise PDC20371" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 3375, 105a, 0x00, ATA_SA150, "Promise PDC20375" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 3376, 105a, 0x00, ATA_SA150, "Promise PDC20376" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 3377, 105a, 0x00, ATA_SA150, "Promise PDC20377" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 3373, 105a, 0x00, ATA_SA150, "Promise PDC20378" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 3372, 105a, 0x00, ATA_SA150, "Promise PDC20379" , PRMIO | PRSATA | UNIATA_RAID_CONTROLLER | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 6617, 105a, 0x00, ATA_UDMA6, "Promise PDC20617" , PRMIO | PRDUAL | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6626, 105a, 0x00, ATA_UDMA6, "Promise PDC20618" , PRMIO | PRDUAL | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6629, 105a, 0x00, ATA_UDMA6, "Promise PDC20619" , PRMIO | PRDUAL | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6620, 105a, 0x00, ATA_UDMA6, "Promise PDC20620" , PRMIO | PRDUAL | UNIATA_RAID_CONTROLLER), +/* PCI_DEV_HW_SPEC_BM( 6621, 105a, 0x00, ATA_UDMA6, "Promise PDC20621" , PRMIO | PRSX4X | UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6622, 105a, 0x00, ATA_UDMA6, "Promise PDC20622" , PRMIO | PRSX4X | UNIATA_RAID_CONTROLLER),*/ + + PCI_DEV_HW_SPEC_BM( 0211, 1166, 0x00, ATA_UDMA2, "ServerWorks ROSB4", SWKS33 | UNIATA_NO_DPC ), + PCI_DEV_HW_SPEC_BM( 0212, 1166, 0x92, ATA_UDMA5, "ServerWorks CSB5" , SWKS100 ), + PCI_DEV_HW_SPEC_BM( 0212, 1166, 0x00, ATA_UDMA4, "ServerWorks CSB5" , SWKS66 ), + PCI_DEV_HW_SPEC_BM( 0213, 1166, 0x00, ATA_UDMA5, "ServerWorks CSB6" , SWKS100 ), + PCI_DEV_HW_SPEC_BM( 0217, 1166, 0x00, ATA_UDMA4, "ServerWorks CSB6" , SWKS66 ), + PCI_DEV_HW_SPEC_BM( 0214, 1166, 0x00, ATA_UDMA5, "ServerWorks HT1000" , SWKS100 ), + PCI_DEV_HW_SPEC_BM( 024b, 1166, 0x00, ATA_SA150, "ServerWorks HT1000" , SWKS100 ), + PCI_DEV_HW_SPEC_BM( 024a, 1166, 0x00, ATA_SA150, "ServerWorks HT1000" , SWKSMIO ), + PCI_DEV_HW_SPEC_BM( 0240, 1166, 0x00, ATA_SA150, "ServerWorks K2" , SWKSMIO ), + PCI_DEV_HW_SPEC_BM( 0241, 1166, 0x00, ATA_SA150, "ServerWorks Frodo4" , SWKSMIO ), + PCI_DEV_HW_SPEC_BM( 0242, 1166, 0x00, ATA_SA150, "ServerWorks Frodo8" , SWKSMIO ), + + PCI_DEV_HW_SPEC_BM( 3114, 1095, 0x00, ATA_SA150, "SiI 3114" , SIIMIO | SII4CH | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 3512, 1095, 0x02, ATA_SA150, "SiI 3512" , SIIMIO | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 3112, 1095, 0x02, ATA_SA150, "SiI 3112" , SIIMIO | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0240, 1095, 0x02, ATA_SA150, "SiI 3112" , SIIMIO | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 3512, 1095, 0x00, ATA_SA150, "SiI 3512" , SIIMIO | SIIBUG | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 3112, 1095, 0x00, ATA_SA150, "SiI 3112" , SIIMIO | SIIBUG | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0240, 1095, 0x00, ATA_SA150, "SiI 3112" , SIIMIO | SIIBUG | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0680, 1095, 0x00, ATA_UDMA6, "SiI 0680" , SIIMIO | SIISETCLK ), + PCI_DEV_HW_SPEC_BM( 0649, 1095, 0x00, ATA_UDMA5, "CMD 649" , SIICMD | SIIINTR | UNIATA_NO_DPC_ATAPI ), + PCI_DEV_HW_SPEC_BM( 0648, 1095, 0x00, ATA_UDMA4, "CMD 648" , SIICMD | SIIINTR ), + PCI_DEV_HW_SPEC_BM( 0646, 1095, 0x07, ATA_UDMA2, "CMD 646U2" , SIICMD | 0 ), + PCI_DEV_HW_SPEC_BM( 0646, 1095, 0x00, ATA_WDMA2, "CMD 646" , SIICMD | 0 ), + PCI_DEV_HW_SPEC_BM( 0640, 1095, 0x00, ATA_PIO4 , "CMD 640" , SIIOLD | SIIENINTR | UNIATA_SIMPLEX_ONLY), + +/** PCI_DEV_HW_SPEC_BM( 0963, 1039, 0x00, ATA_UDMA6, "SiS 963" , SIS133NEW ), + PCI_DEV_HW_SPEC_BM( 0962, 1039, 0x00, ATA_UDMA6, "SiS 962" , SIS133NEW ), + + PCI_DEV_HW_SPEC_BM( 0755, 1039, 0x00, ATA_UDMA6, "SiS 755" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0752, 1039, 0x00, ATA_UDMA6, "SiS 752" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0751, 1039, 0x00, ATA_UDMA6, "SiS 751" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0750, 1039, 0x00, ATA_UDMA6, "SiS 750" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0748, 1039, 0x00, ATA_UDMA6, "SiS 748" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0746, 1039, 0x00, ATA_UDMA6, "SiS 746" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0745, 1039, 0x00, ATA_UDMA5, "SiS 745" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0740, 1039, 0x00, ATA_UDMA5, "SiS 740" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0735, 1039, 0x00, ATA_UDMA5, "SiS 735" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0733, 1039, 0x00, ATA_UDMA5, "SiS 733" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0730, 1039, 0x00, ATA_UDMA5, "SiS 730" , SIS100OLD ), + + PCI_DEV_HW_SPEC_BM( 0658, 1039, 0x00, ATA_UDMA6, "SiS 658" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0655, 1039, 0x00, ATA_UDMA6, "SiS 655" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0652, 1039, 0x00, ATA_UDMA6, "SiS 652" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0651, 1039, 0x00, ATA_UDMA6, "SiS 651" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0650, 1039, 0x00, ATA_UDMA6, "SiS 650" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0648, 1039, 0x00, ATA_UDMA6, "SiS 648" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0646, 1039, 0x00, ATA_UDMA6, "SiS 645DX" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0645, 1039, 0x00, ATA_UDMA6, "SiS 645" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0640, 1039, 0x00, ATA_UDMA4, "SiS 640" , SIS_SOUTH ), + PCI_DEV_HW_SPEC_BM( 0635, 1039, 0x00, ATA_UDMA5, "SiS 635" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0633, 1039, 0x00, ATA_UDMA5, "SiS 633" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0630, 1039, 0x00, ATA_UDMA5, "SiS 630S" , SIS100OLD ), + PCI_DEV_HW_SPEC_BM( 0630, 1039, 0x00, ATA_UDMA4, "SiS 630" , SIS66, ), + PCI_DEV_HW_SPEC_BM( 0620, 1039, 0x00, ATA_UDMA4, "SiS 620" , SIS66, ), + + PCI_DEV_HW_SPEC_BM( 0550, 1039, 0x00, ATA_UDMA5, "SiS 550" , SIS66, ), + PCI_DEV_HW_SPEC_BM( 0540, 1039, 0x00, ATA_UDMA4, "SiS 540" , SIS66, ), + PCI_DEV_HW_SPEC_BM( 0530, 1039, 0x00, ATA_UDMA4, "SiS 530" , SIS66, ), +*/ + PCI_DEV_HW_SPEC_BM( 5513, 1039, 0xc2, ATA_UDMA2, "SiS ATA-xxx" , 0 ), + PCI_DEV_HW_SPEC_BM( 5513, 1039, 0x00, ATA_WDMA2, "SiS ATA-xxx" , 0 ), + PCI_DEV_HW_SPEC_BM( 0601, 1039, 0x00, ATA_WDMA2, "SiS ATA-xxx" , 0 ), + +/* PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x41, ATA_UDMA2, "VIA 82C586B" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x40, ATA_UDMA2, "VIA 82C586B" , VIA33 | VIAPRQ ), + PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x02, ATA_UDMA2, "VIA 82C586B" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x00, ATA_WDMA2, "VIA 82C586" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0596, 1106, 0x12, ATA_UDMA4, "VIA 82C596B" , VIA66 | VIACLK ), + PCI_DEV_HW_SPEC_BM( 0596, 1106, 0x00, ATA_UDMA2, "VIA 82C596" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0686, 1106, 0x40, ATA_UDMA5, "VIA 82C686B" , VIA100 | VIABUG ), + PCI_DEV_HW_SPEC_BM( 0686, 1106, 0x10, ATA_UDMA4, "VIA 82C686A" , VIA66 | VIACLK ), + PCI_DEV_HW_SPEC_BM( 0686, 1106, 0x00, ATA_UDMA2, "VIA 82C686" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 8231, 1106, 0x00, ATA_UDMA5, "VIA 8231" , VIA100 | VIABUG ), + PCI_DEV_HW_SPEC_BM( 3074, 1106, 0x00, ATA_UDMA5, "VIA 8233" , VIA100 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 3109, 1106, 0x00, ATA_UDMA5, "VIA 8233C" , VIA100 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 3147, 1106, 0x00, ATA_UDMA6, "VIA 8233A" , VIA133 | VIAAST ), + PCI_DEV_HW_SPEC_BM( 3177, 1106, 0x00, ATA_UDMA6, "VIA 8235" , VIA133 | VIAAST ), +*/ + PCI_DEV_HW_SPEC_BM( 0571, 1106, 0x00, ATA_UDMA2, "VIA ATA-xxx" , 0 ), + PCI_DEV_HW_SPEC_BM( 3164, 1106, 0x00, ATA_UDMA6, "VIA 6410" , 0 ), + PCI_DEV_HW_SPEC_BM( 3149, 1106, 0x00, ATA_SA150, "VIA 6420" , 0 | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 3249, 1106, 0x00, ATA_SA150, "VIA 6421" , VIABAR | UNIATA_SATA ), + PCI_DEV_HW_SPEC_BM( 0591, 1106, 0x00, ATA_SA150, "VIA 8237A" , 0 | UNIATA_SATA ), + //PCI_DEV_HW_SPEC_BM( 3349, 1106, 0x00, ATA_SA150, "VIA 8251" , VIAAHCI| UNIATA_SATA ), + + PCI_DEV_HW_SPEC_BM( c693, 1080, 0x00, ATA_WDMA2, "Cypress 82C693" ,0 ), + +/* + PCI_DEV_HW_SPEC_BM( 4d68, 105a, 0, 0, "Promise TX2 ATA-100 controller", UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6268, 105a, 0, 0, "Promise TX2 ATA-100 controller", UNIATA_RAID_CONTROLLER), + + PCI_DEV_HW_SPEC_BM( 4d69, 105a, 0, 0, "Promise TX2 ATA-133 controller", UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 5275, 105a, 0, 0, "Promise TX2 ATA-133 controller", UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 6269, 105a, 0, 0, "Promise TX2 ATA-133 controller", UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 7275, 105a, 0, 0, "Promise TX2 ATA-133 controller", UNIATA_RAID_CONTROLLER), + + PCI_DEV_HW_SPEC_BM( 4d33, 105a, 0, 0, "Promise Ultra/FastTrak-33 controller", UNIATA_RAID_CONTROLLER), + + PCI_DEV_HW_SPEC_BM( 0d38, 105a, 0, 0, "Promise FastTrak 66 controller", 0), + PCI_DEV_HW_SPEC_BM( 4d38, 105a, 0, 0, "Promise Ultra/FastTrak-66 controller", UNIATA_RAID_CONTROLLER), + + PCI_DEV_HW_SPEC_BM( 4d30, 105a, 0, 0, "Promise Ultra/FastTrak-100 controller", UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0d30, 105a, 0, 0, "Promise OEM ATA-100 controllers", UNIATA_RAID_CONTROLLER), + + PCI_DEV_HW_SPEC_BM( 0004, 1103, 0, 0, "HighPoint HPT366/368/370/372 controller", UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0005, 1103, 0, 0, "HighPoint HPT372 controller", UNIATA_RAID_CONTROLLER), + PCI_DEV_HW_SPEC_BM( 0008, 1103, 0, 0, "HighPoint HPT374 controller", UNIATA_RAID_CONTROLLER), +*/ + PCI_DEV_HW_SPEC_BM( 0001, 16ca, 0x00, ATA_WDMA2, "Cenatek Rocket Drive",0 ), + + PCI_DEV_HW_SPEC_BM( 0102, 1078, 0x00, ATA_UDMA2, "Cyrix 5530" , 0 ), + + PCI_DEV_HW_SPEC_BM( 0102, 1042, 0x00, ATA_PIO4, "RZ 100x" , 0 ), + + PCI_DEV_HW_SPEC_BM( 8172, 1283, 0x00, ATA_UDMA2, "IT8172" , 0 ), + PCI_DEV_HW_SPEC_BM( 8212, 1283, 0x00, ATA_UDMA6, "IT8212F" , ITE_133 ), + + PCI_DEV_HW_SPEC_BM( 8013, 3388, 0x00, ATA_DMA, "HiNT VXII EIDE" , 0 ), + + // Terminator + PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR, NULL , BMLIST_TERMINATOR ) +}; + +#define NUM_BUSMASTER_ADAPTERS (sizeof(BusMasterAdapters) / sizeof(BUSMASTER_CONTROLLER_INFORMATION)) + +/* + Looks for device with specified Device/Vendor and Revision + in specified device list and returnts its index. + If no matching record found, -1 is returned +*/ +__inline +ULONG +Ata_is_dev_listed( + PBUSMASTER_CONTROLLER_INFORMATION BusMasterAdapters, + ULONG VendorId, + ULONG DeviceId, + ULONG RevId, // min suitable revision + ULONG lim + ) +{ + for(ULONG k=0; kBaseClass == PCI_DEV_CLASS_STORAGE && \ + (pciData)->SubClass == PCI_DEV_SUBCLASS_IDE) + + +#endif //__IDE_BUSMASTER_H__ diff --git a/reactos/drivers/storage/ide/uniata/bsmaster.h b/reactos/drivers/storage/ide/uniata/bsmaster.h new file mode 100644 index 00000000000..af984f7d391 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/bsmaster.h @@ -0,0 +1,1345 @@ +/*++ + +Copyright (c) 2002-2005 Alexandr A. Telyatnikov (Alter) + +Module Name: + bsmaster.h + +Abstract: + This file contains DMA/UltraDMA and IDE BusMastering related definitions, + internal structures and useful macros + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + + Code was created by + Alter, Copyright (c) 2002-2007 + + Some definitions were taken from FreeBSD 4.3-4.6 ATA driver by + Søren Schmidt, Copyright (c) 1998,1999,2000,2001 + +--*/ + +#ifndef __IDE_BUSMASTER_H__ +#define __IDE_BUSMASTER_H__ + +#include "config.h" + +#include "tools.h" + +// +// +// +#define ATA_IDLE 0x0 +#define ATA_IMMEDIATE 0x1 +#define ATA_WAIT_INTR 0x2 +#define ATA_WAIT_READY 0x3 +#define ATA_ACTIVE 0x4 +#define ATA_ACTIVE_ATA 0x5 +#define ATA_ACTIVE_ATAPI 0x6 +#define ATA_REINITING 0x7 +#define ATA_WAIT_BASE_READY 0x8 +#define ATA_WAIT_IDLE 0x9 + + +#include "bm_devs.h" + +#include "uata_ctl.h" + +#define MAX_RETRIES 6 +#define RETRY_UDMA2 1 +#define RETRY_WDMA 2 +#define RETRY_PIO 3 + + +#define IO_WD1 0x1F0 /* Primary Fixed Disk Controller */ +#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */ +#define IP_PC98_BANK 0x432 + +#define PCI_ADDRESS_IOMASK 0xfffffff0 + +#define ATA_BM_OFFSET1 0x08 +#define ATA_DMA_ENTRIES 256 /* PAGESIZE/2/sizeof(BM_DMA_ENTRY)*/ +#define ATA_DMA_EOT 0x80000000 +#define ATA_IOSIZE 0x08 +#define ATA_ALTOFFSET 0x206 /* alternate registers offset */ +#define ATA_PCCARD_ALTOFFSET 0x0e /* do for PCCARD devices */ +#define ATA_ALTIOSIZE 0x01 /* alternate registers size */ +#define ATA_BMIOSIZE 0x20 +#define ATA_PC98_BANKIOSIZE 0x01 +#define ATA_MAX_LBA28 DEF_U64(0x0fffffff) + +#define DEV_BSIZE 512 + +#define ATAPI_MAGIC_LSB 0x14 +#define ATAPI_MAGIC_MSB 0xeb + +#define AHCI_MAX_PORT 32 + +typedef struct _BUSMASTER_CTX { + PBUSMASTER_CONTROLLER_INFORMATION* BMListPtr; + ULONG* BMListLen; +} BUSMASTER_CTX, *PBUSMASTER_CTX; + +#define PCI_DEV_CLASS_STORAGE 0x01 + +#define PCI_DEV_SUBCLASS_IDE 0x01 +#define PCI_DEV_SUBCLASS_RAID 0x04 +#define PCI_DEV_SUBCLASS_ATA 0x05 +#define PCI_DEV_SUBCLASS_SATA 0x06 + +/* structure for holding DMA address data */ +typedef struct BM_DMA_ENTRY { + ULONG base; + ULONG count; +} BM_DMA_ENTRY, *PBM_DMA_ENTRY; + +typedef struct _IDE_BUSMASTER_REGISTERS { + UCHAR Command; + UCHAR DeviceSpecific0; + UCHAR Status; + UCHAR DeviceSpecific1; + ULONG PRD_Table; +} IDE_BUSMASTER_REGISTERS, *PIDE_BUSMASTER_REGISTERS; + +#define BM_STATUS_ACTIVE 0x01 +#define BM_STATUS_ERR 0x02 +#define BM_STATUS_INTR 0x04 +#define BM_STATUS_MASK 0x07 +#define BM_STATUS_DRIVE_0_DMA 0x20 +#define BM_STATUS_DRIVE_1_DMA 0x40 +#define BM_STATUS_SIMPLEX_ONLY 0x80 + +#define BM_COMMAND_START_STOP 0x01 +/*#define BM_COMMAND_WRITE 0x08 +#define BM_COMMAND_READ 0x00*/ +#define BM_COMMAND_WRITE 0x00 +#define BM_COMMAND_READ 0x08 + +#define BM_DS0_SII_DMA_ENABLE (1 << 0) /* DMA run switch */ +#define BM_DS0_SII_IRQ (1 << 3) /* ??? */ +#define BM_DS0_SII_DMA_SATA_IRQ (1 << 4) /* OR of all SATA IRQs */ +#define BM_DS0_SII_DMA_ERROR (1 << 17) /* PCI bus error */ +#define BM_DS0_SII_DMA_COMPLETE (1 << 18) /* cmd complete / IRQ pending */ + + +#define IDX_BM_IO (IDX_IO2_o+IDX_IO2_o_SZ) +//#define IDX_BM_IO_SZ sizeof(IDE_BUSMASTER_REGISTERS) +#define IDX_BM_IO_SZ 5 + +#define IDX_BM_Command (FIELD_OFFSET(IDE_BUSMASTER_REGISTERS, Command )+IDX_BM_IO) +#define IDX_BM_DeviceSpecific0 (FIELD_OFFSET(IDE_BUSMASTER_REGISTERS, DeviceSpecific0)+IDX_BM_IO) +#define IDX_BM_Status (FIELD_OFFSET(IDE_BUSMASTER_REGISTERS, Status )+IDX_BM_IO) +#define IDX_BM_DeviceSpecific1 (FIELD_OFFSET(IDE_BUSMASTER_REGISTERS, DeviceSpecific1)+IDX_BM_IO) +#define IDX_BM_PRD_Table (FIELD_OFFSET(IDE_BUSMASTER_REGISTERS, PRD_Table )+IDX_BM_IO) + +typedef struct _IDE_AHCI_REGISTERS { + // HBA Capabilities + struct { + ULONG NOP:5; // number of ports + ULONG Reserved5_7:1; + ULONG NCS:5; // number of command slots + ULONG PSC:1; // partial state capable + ULONG SSC:1; // slumber state capable + ULONG PMD:1; // PIO multiple DRQ block + ULONG Reserved16:1; + + ULONG SPM:1; // port multiplier + ULONG SAM:1; // AHCI mode only + ULONG SNZO:1; // non-zero DMA offset + ULONG ISS:4; // interface speed + ULONG SCLO:1; // command list override + ULONG SAL:1; // activity LED + ULONG SALP:1; // aggressive link power management + ULONG SSS:1; // staggered spin-up + ULONG SIS:1; // interlock switch + ULONG Reserved29:1; + ULONG SNCQ:1; // native command queue + ULONG S64A:1; // 64bit addr + } CAP; + +#define AHCI_CAP_NOP_MASK 0x0000001f +#define AHCI_CAP_S64A 0x80000000 + + // Global HBA Control + struct { + ULONG HR:1; // HBA Reset + ULONG IE:1; // interrupt enable + ULONG Reserved2_30:1; + ULONG AE:1; // AHCI enable + } GHC; + +#define AHCI_GHC_HR 0x00000001 +#define AHCI_GHC_IE 0x00000002 +#define AHCI_GHC_AE 0x80000000 + + // Interrupt status (bit mask) + ULONG IS; + // Ports implemented (bit mask) + ULONG PI; + // AHCI Version + ULONG VS; + ULONG Reserved[3]; + + UCHAR Reserved2[0x80]; + + UCHAR VendorSpec[0x60]; +} IDE_AHCI_REGISTERS, *PIDE_AHCI_REGISTERS; + +#define IDX_AHCI_CAP (FIELD_OFFSET(IDE_AHCI_REGISTERS, CAP)) +#define IDX_AHCI_GHC (FIELD_OFFSET(IDE_AHCI_REGISTERS, GHC)) +#define IDX_AHCI_IS (FIELD_OFFSET(IDE_AHCI_REGISTERS, IS)) +#define IDX_AHCI_VS (FIELD_OFFSET(IDE_AHCI_REGISTERS, VS)) +#define IDX_AHCI_PI (FIELD_OFFSET(IDE_AHCI_REGISTERS, PI)) + + +typedef union _SATA_SSTATUS_REG { + + struct { + ULONG DET:4; // Device Detection + +#define SStatus_DET_NoDev 0x00 +#define SStatus_DET_Dev_NoPhy 0x01 +#define SStatus_DET_Dev_Ok 0x03 +#define SStatus_DET_Offline 0x04 + + ULONG SPD:4; // Current Interface Speed + +#define SStatus_SPD_NoDev 0x00 +#define SStatus_SPD_Gen1 0x01 +#define SStatus_SPD_Gen2 0x02 + + ULONG IPM:4; // Interface Power Management + +#define SStatus_IPM_NoDev 0x00 +#define SStatus_IPM_Active 0x01 +#define SStatus_IPM_Partial 0x02 +#define SStatus_IPM_Slumber 0x06 + + ULONG Reserved:20; + }; + ULONG Reg; + +} SATA_SSTATUS_REG, *PSATA_SSTATUS_REG; + + +typedef union _SATA_SCONTROL_REG { + + struct { + ULONG DET:4; // Device Detection Init + +#define SControl_DET_DoNothing 0x00 +#define SControl_DET_Idle 0x00 +#define SControl_DET_Init 0x01 +#define SControl_DET_Disable 0x04 + + ULONG SPD:4; // Speed Allowed + +#define SControl_SPD_NoRestrict 0x00 +#define SControl_SPD_LimGen1 0x01 +#define SControl_SPD_LimGen2 0x02 + + ULONG IPM:4; // Interface Power Management Transitions Allowed + +#define SControl_IPM_NoRestrict 0x00 +#define SControl_IPM_NoPartial 0x01 +#define SControl_IPM_NoSlumber 0x02 +#define SControl_IPM_NoPartialSlumber 0x03 + + ULONG SPM:4; // Select Power Management, unused by AHCI + ULONG PMP:4; // Port Multiplier Port, unused by AHCI + ULONG Reserved:12; + }; + ULONG Reg; + +} SATA_SCONTROL_REG, *PSATA_SCONTROL_REG; + + +typedef union _SATA_SERROR_REG { + + struct { + struct { + UCHAR I:1; // Recovered Data Integrity Error + UCHAR M:1; // Recovered Communications Error + UCHAR Reserved_2_7:6; + + UCHAR T:1; // Transient Data Integrity Error + UCHAR C:1; // Persistent Communication or Data Integrity Error + UCHAR P:1; // Protocol Error + UCHAR E:1; // Internal Error + UCHAR Reserved_12_15:4; + } ERR; + + struct { + UCHAR N:1; // PhyRdy Change, PIS.PRCS + UCHAR I:1; // Phy Internal Error + UCHAR W:1; // Comm Wake + UCHAR B:1; // 10B to 8B Decode Error + UCHAR D:1; // Disparity Error, not used by AHCI + UCHAR C:1; // CRC Error + UCHAR H:1; // Handshake Error + UCHAR S:1; // Link Sequence Error + + UCHAR T:1; // Transport state transition error + UCHAR F:1; // Unknown FIS Type + UCHAR X:1; // Exchanged + UCHAR Reserved_27_31:5; + } DIAG; + }; + ULONG Reg; + +} SATA_SERROR_REG, *PSATA_SERROR_REG; + + +typedef struct _IDE_SATA_REGISTERS { + union { + SATA_SSTATUS_REG SStatus; + ULONG SStatus_Reg; + }; + union { + SATA_SERROR_REG SError; + ULONG SError_Reg; + }; + union { + SATA_SCONTROL_REG SControl; + ULONG SControl_Reg; + }; + + // SATA 1.2 + + ULONG SActive; + union { + ULONG Reg; + struct { + USHORT PMN; // PM Notify, bitmask + USHORT Reserved; + }; + } SNTF; + ULONG SReserved[11]; +} IDE_SATA_REGISTERS, *PIDE_SATA_REGISTERS; + +#define IDX_SATA_IO (IDX_BM_IO+IDX_BM_IO_SZ) +//#define IDX_SATA_IO_SZ sizeof(IDE_SATA_REGISTERS) +#define IDX_SATA_IO_SZ 5 + +#define IDX_SATA_SStatus (0+IDX_SATA_IO) +#define IDX_SATA_SError (1+IDX_SATA_IO) +#define IDX_SATA_SControl (2+IDX_SATA_IO) +#define IDX_SATA_SActive (3+IDX_SATA_IO) +#define IDX_SATA_SNTF_PMN (4+IDX_SATA_IO) + +#define IDX_MAX_REG (IDX_SATA_IO+IDX_SATA_IO_SZ) + +typedef struct _IDE_AHCI_PORT_REGISTERS { + union { + struct { + ULONG CLB; // command list base address + ULONG CLBU; // command list base address (upper 32bits) + }; + ULONGLONG CLB64; + }; + + union { + struct { + ULONG FB; // FIS base address + ULONG FBU; // FIS base address (upper 32bits) + }; + ULONGLONG FB64; + }; + + union { + ULONG Reg; // interrupt status + struct { + ULONG DHRS:1;// Device to Host Register FIS Interrupt + ULONG PSS:1; // PIO Setup FIS Interrupt + ULONG DSS:1; // DMA Setup FIS Interrupt + ULONG SDBS:1;// Set Device Bits Interrupt + ULONG UFS:1; // Unknown FIS Interrupt + ULONG DPS:1; // Descriptor Processed + ULONG PCS:1; // Port Connect Change Status + ULONG DMPS:1;// Device Mechanical Presence Status + + ULONG Reserved_8_21:14; + ULONG PRCS:1;// PhyRdy Change Status + ULONG IPMS:1;// Incorrect Port Multiplier Status + + ULONG OFS:1; // Overflow Status + ULONG Reserved_25:1; + ULONG INFS:1;// Interface Non-fatal Error Status + ULONG IFS:1; // Interface Fatal Error Status + ULONG HBDS:1;// Host Bus Data Error Status + ULONG HBFS:1;// Host Bus Fatal Error Status + ULONG TFES:1;// Task File Error Status + ULONG CPDS:1;// Cold Port Detect Status + }; + } IS; + + union { + ULONG Reg; // interrupt enable + struct { + ULONG DHRE:1;// Device to Host Register FIS Interrupt Enable + ULONG PSE:1; // PIO Setup FIS Interrupt Enable + ULONG DSE:1; // DMA Setup FIS Interrupt Enable + ULONG SDBE:1;// Set Device Bits FIS Interrupt Enable + ULONG UFE:1; // Unknown FIS Interrupt Enable + ULONG DPE:1; // Descriptor Processed Interrupt Enable + ULONG PCE:1; // Port Change Interrupt Enable + ULONG DPME:1;// Device Mechanical Presence Enable + + ULONG Reserved_8_21:14; + ULONG PRCE:1;// PhyRdy Change Interrupt Enable + ULONG IPME:1;// Incorrect Port Multiplier Enable + ULONG OFE:1; // Overflow Enable + ULONG Reserved_25:1; + ULONG INFE:1;// Interface Non-fatal Error Enable + ULONG IFE:1; // Interface Fatal Error Enable + ULONG HBDE:1;// Host Bus Data Error Enable + ULONG HBFE:1;// Host Bus Fatal Error Enable + ULONG TFEE:1;// Task File Error Enable + ULONG CPDE:1;// Cold Port Detect Enable + }; + } IE; + + union { + ULONG Reg; // command register + struct { + + ULONG ST:1; // Start + ULONG SUD:1; // Spin-Up Device + ULONG POD:1; // Power On Device + ULONG CLO:1; // Command List Override + ULONG FRE:1; // FIS Receive Enable + ULONG Reserved_5_7:3; + + ULONG CCS:5; // Current Command Slot + ULONG MPSS:1;// Mechanical Presence Switch State + ULONG FR:1; // FIS Receive Running + ULONG CR:1; // Command List Running + + ULONG CPS:1; // Cold Presence State + ULONG PMA:1; // Port Multiplier Attached + ULONG HPCP:1;// Hot Plug Capable Port + ULONG MPSP:1;// Mechanical Presence Switch Attached to Port + ULONG CPD:1; // Cold Presence Detection + ULONG ESP:1; // External SATA Port + ULONG Reserved_22_23:2; + + ULONG ATAPI:1; // Device is ATAPI + ULONG DLAE:1;// Drive LED on ATAPI Enable + ULONG ALPE:1;// Aggressive Link Power Management Enable + ULONG ASP:1; // Aggressive Slumber / Partial + ULONG ICC:4; // Interface Communication Control + +#define SATA_CMD_ICC_Idle 0x00 +#define SATA_CMD_ICC_NoOp 0x00 +#define SATA_CMD_ICC_Active 0x01 +#define SATA_CMD_ICC_Partial 0x02 +#define SATA_CMD_ICC_Slumber 0x06 + }; + } CMD; + + ULONG Reserved; + + union { + ULONG Reg; // Task File Data + struct { + struct { + UCHAR ERR:1; + UCHAR cs1:2;// command-specific + UCHAR DRQ:1; + UCHAR cs2:3;// command-specific + UCHAR BSY:1; + } STS; + UCHAR ERR; // Contains the latest copy of the task file error register. + UCHAR Reserved[2]; + }; + } TFD; + + union { + ULONG Reg; // signature + struct { + UCHAR SectorCount; + UCHAR LbaLow; + UCHAR LbaMid; + UCHAR LbaHigh; + }; + } SIG; + union { + ULONG SStatus; // SCR0 + SATA_SSTATUS_REG SSTS; + }; + union { + ULONG SControl; // SCR2 + SATA_SCONTROL_REG SCTL; + }; + union { + ULONG SError; // SCR1 + SATA_SERROR_REG SERR; + }; + union { + ULONG SACT; // SCR3 + ULONG SActive; // bitmask + }; + ULONG CI; // Command issue, bitmask + + // AHCI 1.1 + union { + ULONG Reg; + struct { + USHORT PMN; // PM Notify, bitmask + USHORT Reserved; + }; + } SNTF; + ULONG FIS_Switching_Reserved[12]; + UCHAR VendorSpec[16]; + +} IDE_AHCI_PORT_REGISTERS, *PIDE_AHCI_PORT_REGISTERS; + +typedef struct _IDE_AHCI_PRD_ENTRY { + union { + ULONG base; + ULONGLONG base64; + struct { + ULONG DBA; + ULONG DBAU; + }; + }; + ULONG Reserved1; + + ULONG DBC:22; + ULONG Reserved2:9; + ULONG I:1; + +} IDE_AHCI_PRD_ENTRY, *PIDE_AHCI_PRD_ENTRY; + +#define IsBusMaster(pciData) \ + ( ((pciData)->Command & (PCI_ENABLE_BUS_MASTER/* | PCI_ENABLE_IO_SPACE*/)) == \ + (PCI_ENABLE_BUS_MASTER/* | PCI_ENABLE_IO_SPACE*/)) + +#define PCI_IDE_PROGIF_NATIVE_1 0x01 +#define PCI_IDE_PROGIF_NATIVE_2 0x04 +#define PCI_IDE_PROGIF_NATIVE_ALL 0x05 + +#define IsMasterDev(pciData) \ + ( ((pciData)->ProgIf & 0x80) && \ + ((pciData)->ProgIf & PCI_IDE_PROGIF_NATIVE_ALL) != PCI_IDE_PROGIF_NATIVE_ALL ) + +//#define INT_Q_SIZE 32 +#define MIN_REQ_TTL 4 + +struct _ATA_REQ; + +typedef struct _ATA_REQ { +// ULONG reqId; // serial + struct _ATA_REQ* next_req; + struct _ATA_REQ* prev_req; + + PSCSI_REQUEST_BLOCK Srb; // Current request on controller. + + PUSHORT DataBuffer; // Data buffer pointer. + ULONG WordsLeft; // Data words left. + ULONG TransferLength; // Originally requested transfer length + LONGLONG lba; + ULONG bcount; + + UCHAR retry; + UCHAR ttl; +// UCHAR tag; + UCHAR Flags; + UCHAR ReqState; + + PSCSI_REQUEST_BLOCK OriginalSrb; // Mechanism Status Srb Data + + ULONG dma_base; + BM_DMA_ENTRY dma_tab[ATA_DMA_ENTRIES]; + +} ATA_REQ, *PATA_REQ; + +#define REQ_FLAG_FORCE_DOWNRATE 0x01 +#define REQ_FLAG_DMA_OPERATION 0x02 +#define REQ_FLAG_REORDERABLE_CMD 0x04 +#define REQ_FLAG_RW_MASK 0x08 +#define REQ_FLAG_READ 0x08 +#define REQ_FLAG_WRITE 0x00 +#define REQ_FLAG_FORCE_DOWNRATE_LBA48 0x10 +#define REQ_FLAG_DMA_DBUF 0x20 +#define REQ_FLAG_DMA_DBUF_PRD 0x40 + +// Request states +#define REQ_STATE_NONE 0x00 +#define REQ_STATE_QUEUED 0x10 + +#define REQ_STATE_PREPARE_TO_TRANSFER 0x20 +#define REQ_STATE_READY_TO_TRANSFER 0x30 + +#define REQ_STATE_EXPECTING_INTR 0x40 +#define REQ_STATE_ATAPI_EXPECTING_CMD_INTR 0x41 +#define REQ_STATE_ATAPI_EXPECTING_DATA_INTR 0x42 +#define REQ_STATE_ATAPI_DO_NOTHING_INTR 0x43 + +#define REQ_STATE_EARLY_INTR 0x48 + +#define REQ_STATE_PROCESSING_INTR 0x50 + +#define REQ_STATE_DPC_INTR_REQ 0x51 +#define REQ_STATE_DPC_RESET_REQ 0x52 +#define REQ_STATE_DPC_COMPLETE_REQ 0x53 + +#define REQ_STATE_DPC_WAIT_BUSY0 0x57 +#define REQ_STATE_DPC_WAIT_BUSY1 0x58 +#define REQ_STATE_DPC_WAIT_BUSY 0x59 +#define REQ_STATE_DPC_WAIT_DRQ 0x5a +#define REQ_STATE_DPC_WAIT_DRQ0 0x5b +#define REQ_STATE_DPC_WAIT_DRQ_ERR 0x5c + +#define REQ_STATE_TRANSFER_COMPLETE 0x7f + +// Command actions: +#define CMD_ACTION_PREPARE 0x01 +#define CMD_ACTION_EXEC 0x02 +#define CMD_ACTION_ALL (CMD_ACTION_PREPARE | CMD_ACTION_EXEC) + +// predefined Reorder costs +#define REORDER_COST_MAX ((DEF_I64(0x1) << 60) - 1) +#define REORDER_COST_TTL (REORDER_COST_MAX - 1) +#define REORDER_COST_INTERSECT (REORDER_COST_MAX - 2) +#define REORDER_COST_DENIED (REORDER_COST_MAX - 3) +#define REORDER_COST_RESELECT (REORDER_COST_MAX/4) + +#define REORDER_COST_SWITCH_RW_CD (REORDER_COST_MAX/8) +#define REORDER_MCOST_SWITCH_RW_CD (0) +#define REORDER_MCOST_SEEK_BACK_CD (16) + +#define REORDER_COST_SWITCH_RW_HDD (0) +#define REORDER_MCOST_SWITCH_RW_HDD (4) +#define REORDER_MCOST_SEEK_BACK_HDD (2) + +/*typedef struct _ATA_QUEUE { + struct _ATA_REQ* head_req; // index + struct _ATA_REQ* tail_req; // index + ULONG req_count; + ULONG dma_base; + BM_DMA_ENTRY dma_tab[ATA_DMA_ENTRIES]; +} ATA_QUEUE, *PATA_QUEUE;*/ + +struct _HW_DEVICE_EXTENSION; +struct _HW_LU_EXTENSION; + +typedef struct _IORES { + ULONG Addr; + ULONG MemIo:1; + ULONG Reserved:31; +} IORES, *PIORES; + +// Channel extension +typedef struct _HW_CHANNEL { + + PATA_REQ cur_req; + ULONG cur_cdev; +/* PATA_REQ first_req; + PATA_REQ last_req;*/ + ULONG queue_depth; + ULONG ChannelSelectWaitCount; + + UCHAR DpcState; + + BOOLEAN ExpectingInterrupt; // Indicates expecting an interrupt + BOOLEAN RDP; // Indicate last tape command was DSC Restrictive. + // 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; + // Reorder anabled + BOOLEAN UseReorder; + // Placeholder for status register after a GET_MEDIA_STATUS command + UCHAR ReturningMediaStatus; + + BOOLEAN CopyDmaBuffer; + //BOOLEAN MemIo; + BOOLEAN AltRegMap; + + //UCHAR Reserved[3]; + + MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData; + SENSE_DATA MechStatusSense; + ULONG MechStatusRetryCount; + SCSI_REQUEST_BLOCK InternalSrb; + + ULONG MaxTransferMode; // may differ from Controller's value due to 40-pin cable + + ULONG ChannelCtrlFlags; + ULONG ResetInProgress; // flag + LONG DisableIntr; + LONG CheckIntr; + + ULONG lChannel; + +#define CHECK_INTR_ACTIVE 0x03 +#define CHECK_INTR_DETECTED 0x02 +#define CHECK_INTR_CHECK 0x01 +#define CHECK_INTR_IDLE 0x00 + + ULONG NextDpcChan; + PHW_TIMER HwScsiTimer; + LONGLONG DpcTime; +/* + PHW_TIMER HwScsiTimer1; + PHW_TIMER HwScsiTimer2; + LONGLONG DpcTime1; +/* PHW_TIMER CurDpc; + LARGE_INTEGER ActivationTime;*/ + +/* KDPC Dpc; + KTIMER Timer; + PHW_TIMER HwScsiTimer;*/ +// KSPIN_LOCK QueueSpinLock; +// KIRQL QueueOldIrql; + struct _HW_DEVICE_EXTENSION* DeviceExtension; + struct _HW_LU_EXTENSION* lun[2]; + + // Double-buffering support + PVOID DB_PRD; + ULONG DB_PRD_PhAddr; + PVOID DB_IO; + ULONG DB_IO_PhAddr; + + PUCHAR DmaBuffer; + +#ifdef QUEUE_STATISTICS + LONGLONG QueueStat[MAX_QUEUE_STAT]; + LONGLONG ReorderCount; + LONGLONG IntersectCount; + LONGLONG TryReorderCount; + LONGLONG TryReorderHeadCount; + LONGLONG TryReorderTailCount; /* in-order requests */ +#endif //QUEUE_STATISTICS + + //ULONG BaseMemAddress; + //ULONG BaseMemAddressOffset; + IORES RegTranslation[IDX_MAX_REG]; + +} HW_CHANNEL, *PHW_CHANNEL; + +#define CTRFLAGS_DMA_ACTIVE 0x0001 +#define CTRFLAGS_DMA_RO 0x0002 +#define CTRFLAGS_DMA_OPERATION 0x0004 +#define CTRFLAGS_INTR_DISABLED 0x0008 +#define CTRFLAGS_DPC_REQ 0x0010 +#define CTRFLAGS_ENABLE_INTR_REQ 0x0020 +#define CTRFLAGS_LBA48 0x0040 +#define CTRFLAGS_DSC_BSY 0x0080 +#define CTRFLAGS_NO_SLAVE 0x0100 + +#define GEOM_AUTO 0xffffffff +#define GEOM_STD 0x0000 +#define GEOM_UNIATA 0x0001 +#define GEOM_ORIG 0x0002 +#define GEOM_MANUAL 0x0003 + +#define DPC_STATE_NONE 0x00 +#define DPC_STATE_ISR 0x10 +#define DPC_STATE_DPC 0x20 +#define DPC_STATE_TIMER 0x30 +#define DPC_STATE_COMPLETE 0x40 + +// Logical unit extension +typedef struct _HW_LU_EXTENSION { + IDENTIFY_DATA2 IdentifyData; + ULONGLONG NumOfSectors; + ULONG DeviceFlags; // Flags word for each possible device. DFLAGS_XXX + ULONG DiscsPresent; // Indicates number of platters on changer-ish devices. + BOOLEAN DWordIO; // Indicates use of 32-bit PIO + UCHAR ReturningMediaStatus; + + UCHAR TransferMode; // current transfer mode + UCHAR LimitedTransferMode; // user-defined or IDE cable limitation + UCHAR OrigTransferMode; // transfer mode, returned by device IDENTIFY (can be changed via IOCTL) + + UCHAR MaximumBlockXfer; + UCHAR Padding0[2]; // padding + ULONG ErrorCount; // Count of errors. Used to turn off features. + // ATA_QUEUE cmd_queue; + LONGLONG ReadCmdCost; + LONGLONG WriteCmdCost; + LONGLONG OtherCmdCost; + LONGLONG RwSwitchCost; + LONGLONG RwSwitchMCost; + LONGLONG SeekBackMCost; + // + PATA_REQ first_req; + PATA_REQ last_req; + ULONG queue_depth; + ULONG last_write; + + ULONG LunSelectWaitCount; + + // tuning options + ULONG opt_GeomType; + ULONG opt_MaxTransferMode; + ULONG opt_PreferedTransferMode; + BOOLEAN opt_ReadCacheEnable; + BOOLEAN opt_WriteCacheEnable; + // padding + BOOLEAN opt_reserved[2]; + + struct _SBadBlockListItem* bbListDescr; + struct _SBadBlockRange* arrBadBlocks; + ULONG nBadBlocks; + +#ifdef IO_STATISTICS + + LONGLONG ModeErrorCount[MAX_RETRIES]; + LONGLONG RecoverCount[MAX_RETRIES]; + LONGLONG IoCount; + +#endif//IO_STATISTICS +} HW_LU_EXTENSION, *PHW_LU_EXTENSION; + +// Device extension +typedef struct _HW_DEVICE_EXTENSION { + CHAR Signature[32]; + //PIDE_REGISTERS_1 BaseIoAddress1[IDE_MAX_CHAN]; // Base register locations + //PIDE_REGISTERS_2 BaseIoAddress2[IDE_MAX_CHAN]; + ULONG BusInterruptLevel; // Interrupt level + ULONG InterruptMode; // Interrupt Mode (Level or Edge) + ULONG BusInterruptVector; + // 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; + ULONG NumberLuns; + ULONG FirstChannelToCheck; +#if 1 + HW_LU_EXTENSION lun[IDE_MAX_LUN]; + HW_CHANNEL chan[AHCI_MAX_PORT/*IDE_MAX_CHAN*/]; +#else + PHW_LU_EXTENSION lun; + PHW_CHANNEL chan; +#endif + UCHAR LastInterruptedChannel; + // Indicates the number of blocks transferred per int. according to the + // identify data. + BOOLEAN DriverMustPoll; // Driver is being used by the crash dump utility or ntldr. + BOOLEAN BusMaster; + BOOLEAN UseDpc; // Indicates use of DPC on long waits + IDENTIFY_DATA FullIdentifyData; // Identify data for device + // BusMaster specific data +// PBM_DMA_ENTRY dma_tab_0; + //KSPIN_LOCK DpcSpinLock; + + ULONG ActiveDpcChan; + ULONG FirstDpcChan; +/* + PHW_TIMER HwScsiTimer1; + PHW_TIMER HwScsiTimer2; + LONGLONG DpcTime1; + LONGLONG DpcTime2; +*/ + ULONG queue_depth; + + PDEVICE_OBJECT Isr2DevObj; + + //PIDE_BUSMASTER_REGISTERS BaseIoAddressBM_0; + IORES BaseIoAddressBM_0; + //PIDE_BUSMASTER_REGISTERS BaseIoAddressBM[IDE_MAX_CHAN]; + + // Device identification + ULONG DevID; + ULONG RevID; + ULONG slotNumber; + ULONG SystemIoBusNumber; + ULONG DevIndex; + + ULONG InitMethod; // vendor specific + + ULONG Channel; + + ULONG HbaCtrlFlags; + BOOLEAN simplexOnly; + //BOOLEAN MemIo; + BOOLEAN AltRegMap; + BOOLEAN UnknownDev; + BOOLEAN MasterDev; + BOOLEAN Host64; + BOOLEAN DWordIO; // Indicates use of 32-bit PIO + UCHAR Reserved1[2]; + + LONG ReCheckIntr; + + ULONG MaxTransferMode; // max transfer mode supported by controller + ULONG HwFlags; + INTERFACE_TYPE OrigAdapterInterfaceType; + ULONG MaximumDmaTransferLength; + ULONG AlignmentMask; + + //ULONG BaseMemAddress; + + //PIDE_SATA_REGISTERS BaseIoAddressSATA_0; + IORES BaseIoAddressSATA_0; + //PIDE_SATA_REGISTERS BaseIoAddressSATA[IDE_MAX_CHAN]; + + IORES BaseIoAHCI_0; + //PIDE_AHCI_PORT_REGISTERS BaseIoAHCIPort[AHCI_MAX_PORT]; + + BOOLEAN opt_AtapiDmaZeroTransfer; // default FALSE + BOOLEAN opt_AtapiDmaControlCmd; // default FALSE + BOOLEAN opt_AtapiDmaRawRead; // default TRUE + BOOLEAN opt_AtapiDmaReadWrite; // default TRUE + +} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; + +typedef struct _ISR2_DEVICE_EXTENSION { + PHW_DEVICE_EXTENSION HwDeviceExtension; + ULONG DevIndex; +} ISR2_DEVICE_EXTENSION, *PISR2_DEVICE_EXTENSION; + +#define HBAFLAGS_DMA_DISABLED 0x01 +#define HBAFLAGS_DMA_DISABLED_LBA48 0x02 + +extern UCHAR pciBuffer[256]; +extern PBUSMASTER_CONTROLLER_INFORMATION BMList; +extern ULONG BMListLen; + +extern const CHAR retry_Wdma[MAX_RETRIES+1]; +extern const CHAR retry_Udma[MAX_RETRIES+1]; + +extern VOID +UniataEnumBusMasterController( + IN PVOID DriverObject, + PVOID Argument2 + ); + +extern ULONG DDKAPI +UniataFindBusMasterController( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ); + +extern NTSTATUS +UniataConnectIntr2( + IN PVOID HwDeviceExtension + ); + +extern NTSTATUS +UniataDisconnectIntr2( + IN PVOID HwDeviceExtension + ); + +extern ULONG +ScsiPortGetBusDataByOffset( + IN PVOID HwDeviceExtension, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +extern ULONG +AtapiFindListedDev( + PBUSMASTER_CONTROLLER_INFORMATION BusMasterAdapters, + ULONG lim, + IN PVOID HwDeviceExtension, + IN ULONG BusNumber, + IN ULONG SlotNumber, + OUT PCI_SLOT_NUMBER* _slotData // optional + ); + +extern ULONG +AtapiFindDev( + IN PVOID HwDeviceExtension, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN ULONG dev_id, + IN ULONG RevID + ); + +extern VOID +AtapiDmaAlloc( + IN PVOID HwDeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN ULONG lChannel // logical channel, + ); + +extern BOOLEAN +AtapiDmaSetup( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + IN PSCSI_REQUEST_BLOCK Srb, + IN PUCHAR data, + IN ULONG count + ); + +extern BOOLEAN +AtapiDmaPioSync( + PVOID HwDeviceExtension, + PSCSI_REQUEST_BLOCK Srb, + PUCHAR data, + ULONG count + ); + +extern BOOLEAN +AtapiDmaDBSync( + PHW_CHANNEL chan, + PSCSI_REQUEST_BLOCK Srb + ); + +extern VOID +AtapiDmaStart( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + IN PSCSI_REQUEST_BLOCK Srb + ); + +//#define DEVNUM_NOT_SPECIFIED (0xffffffffL) + +extern UCHAR +AtapiDmaDone( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + IN PSCSI_REQUEST_BLOCK Srb + ); + +extern VOID +AtapiDmaReinit( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG ldev, + IN PATA_REQ AtaReq + ); + +extern VOID +AtapiDmaInit__( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG ldev + ); + +extern VOID +AtapiDmaInit( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + // is always 0 except simplex-only controllers + IN CHAR apiomode, + IN CHAR wdmamode, + IN CHAR udmamode + ); + +extern BOOLEAN NTAPI +AtapiInterrupt2( + IN PKINTERRUPT Interrupt, + IN PVOID HwDeviceExtension + ); + +extern PDRIVER_OBJECT SavedDriverObject; + +extern BOOLEAN +UniataChipDetect( + IN PVOID HwDeviceExtension, + IN PPCI_COMMON_CONFIG pciData, // optional + IN ULONG DeviceNumber, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN BOOLEAN* simplexOnly + ); + +extern BOOLEAN +AtapiChipInit( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG c + ); + +extern ULONG +AtapiGetIoRange( + IN PVOID HwDeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN PPCI_COMMON_CONFIG pciData, + IN ULONG SystemIoBusNumber, + IN ULONG rid, + IN ULONG offset, + IN ULONG length //range id + ); + +/****************** 1 *****************/ +#define GetPciConfig1(offs, op) { \ + ScsiPortGetBusDataByOffset(HwDeviceExtension, \ + PCIConfiguration, \ + SystemIoBusNumber, \ + slotNumber, \ + &op, \ + offs, \ + 1); \ +} + +#define SetPciConfig1(offs, op) { \ + UCHAR _a = op; \ + ScsiPortSetBusDataByOffset(HwDeviceExtension, \ + PCIConfiguration, \ + SystemIoBusNumber, \ + slotNumber, \ + &_a, \ + offs, \ + 1); \ +} + +#define ChangePciConfig1(offs, _op) { \ + UCHAR a = 0; \ + GetPciConfig1(offs, a); \ + a = (UCHAR)(_op); \ + SetPciConfig1(offs, a); \ +} + +/****************** 2 *****************/ +#define GetPciConfig2(offs, op) { \ + ScsiPortGetBusDataByOffset(HwDeviceExtension, \ + PCIConfiguration, \ + SystemIoBusNumber, \ + slotNumber, \ + &op, \ + offs, \ + 2); \ +} + +#define SetPciConfig2(offs, op) { \ + USHORT _a = op; \ + ScsiPortSetBusDataByOffset(HwDeviceExtension, \ + PCIConfiguration, \ + SystemIoBusNumber, \ + slotNumber, \ + &_a, \ + offs, \ + 2); \ +} + +#define ChangePciConfig2(offs, _op) { \ + USHORT a = 0; \ + GetPciConfig2(offs, a); \ + a = (USHORT)(_op); \ + SetPciConfig2(offs, a); \ +} + +/****************** 4 *****************/ +#define GetPciConfig4(offs, op) { \ + ScsiPortGetBusDataByOffset(HwDeviceExtension, \ + PCIConfiguration, \ + SystemIoBusNumber, \ + slotNumber, \ + &op, \ + offs, \ + 4); \ +} + +#define SetPciConfig4(offs, op) { \ + ULONG _a = op; \ + ScsiPortSetBusDataByOffset(HwDeviceExtension, \ + PCIConfiguration, \ + SystemIoBusNumber, \ + slotNumber, \ + &_a, \ + offs, \ + 4); \ +} + +#define ChangePciConfig4(offs, _op) { \ + ULONG a = 0; \ + GetPciConfig4(offs, a); \ + a = _op; \ + SetPciConfig4(offs, a); \ +} + +#ifndef GetDmaStatus +#define GetDmaStatus(de, c) \ + (((de)->BusMaster) ? AtapiReadPort1(&((de)->chan[c]), IDX_BM_Status) : 0) +#endif //GetDmaStatus + +#ifdef USE_OWN_DMA +#define AtapiVirtToPhysAddr(hwde, srb, phaddr, plen, phaddru) \ + AtapiVirtToPhysAddr_(hwde, srb, phaddr, plen, phaddru); +#else +#define AtapiVirtToPhysAddr(hwde, srb, phaddr, plen, phaddru) \ + (ScsiPortConvertPhysicalAddressToUlong/*(ULONG)ScsiPortGetVirtualAddress*/(/*hwde,*/ \ + ScsiPortGetPhysicalAddress(hwde, srb, phaddr, plen))) +#endif //USE_OWN_DMA + +VOID +DDKFASTAPI +AtapiWritePort4( + IN PHW_CHANNEL chan, + IN ULONG port, + IN ULONG data + ); + +VOID +DDKFASTAPI +AtapiWritePort2( + IN PHW_CHANNEL chan, + IN ULONG port, + IN USHORT data + ); + +VOID +DDKFASTAPI +AtapiWritePort1( + IN PHW_CHANNEL chan, + IN ULONG port, + IN UCHAR data + ); + +VOID +DDKFASTAPI +AtapiWritePortEx4( + IN PHW_CHANNEL chan, + IN ULONG port, + IN ULONG offs, + IN ULONG data + ); + +VOID +DDKFASTAPI +AtapiWritePortEx1( + IN PHW_CHANNEL chan, + IN ULONG port, + IN ULONG offs, + IN UCHAR data + ); + +ULONG +DDKFASTAPI +AtapiReadPort4( + IN PHW_CHANNEL chan, + IN ULONG port + ); + +USHORT +DDKFASTAPI +AtapiReadPort2( + IN PHW_CHANNEL chan, + IN ULONG port + ); + +UCHAR +DDKFASTAPI +AtapiReadPort1( + IN PHW_CHANNEL chan, + IN ULONG port + ); + +ULONG +DDKFASTAPI +AtapiReadPortEx4( + IN PHW_CHANNEL chan, + IN ULONG port, + IN ULONG offs + ); + +UCHAR +DDKFASTAPI +AtapiReadPortEx1( + IN PHW_CHANNEL chan, + IN ULONG port, + IN ULONG offs + ); + +VOID +DDKFASTAPI +AtapiWriteBuffer4( + IN PHW_CHANNEL chan, + IN ULONG _port, + IN PVOID Buffer, + IN ULONG Count, + IN ULONG Timing + ); + +VOID +DDKFASTAPI +AtapiWriteBuffer2( + IN PHW_CHANNEL chan, + IN ULONG _port, + IN PVOID Buffer, + IN ULONG Count, + IN ULONG Timing + ); + +VOID +DDKFASTAPI +AtapiReadBuffer4( + IN PHW_CHANNEL chan, + IN ULONG _port, + IN PVOID Buffer, + IN ULONG Count, + IN ULONG Timing + ); + +VOID +DDKFASTAPI +AtapiReadBuffer2( + IN PHW_CHANNEL chan, + IN ULONG _port, + IN PVOID Buffer, + IN ULONG Count, + IN ULONG Timing + ); + +/*#define GET_CHANNEL(Srb) (Srb->TargetId >> 1) +#define GET_LDEV(Srb) (Srb->TargetId) +#define GET_LDEV2(P, T, L) (T)*/ + +#define GET_CHANNEL(Srb) (Srb->PathId) +#define GET_LDEV(Srb) (Srb->TargetId | (Srb->PathId << 1)) +#define GET_LDEV2(P, T, L) (T | ((P)<<1)) +#define GET_CDEV(Srb) (Srb->TargetId) + +#define AtapiSetupLunPtrs(chan, deviceExtension, c) \ +{ \ + chan->DeviceExtension = deviceExtension; \ + chan->lChannel = c; \ + chan->lun[0] = &(deviceExtension->lun[c*2+0]); \ + chan->lun[1] = &(deviceExtension->lun[c*2+1]); \ + chan->AltRegMap = deviceExtension->AltRegMap; \ + chan->NextDpcChan = -1; \ +} + +BOOLEAN +AtapiReadChipConfig( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG channel // physical channel + ); + +extern ULONG SkipRaids; +extern ULONG ForceSimplex; + +extern BOOLEAN InDriverEntry; + +extern BOOLEAN g_opt_Verbose; + +#endif //__IDE_BUSMASTER_H__ diff --git a/reactos/drivers/storage/ide/uniata/config.h b/reactos/drivers/storage/ide/uniata/config.h new file mode 100644 index 00000000000..c910a235ca6 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/config.h @@ -0,0 +1,126 @@ +#ifndef __UNIATA_CONFIG__H__ +#define __UNIATA_CONFIG__H__ + + +/***************************************************/ +/* Options */ +/***************************************************/ + +/***************************************/ +// Send Debug messages directly to DbgPrintLonner using its SDK +/***************************************/ + +//#define USE_DBGPRINT_LOGGER + +/***************************************/ +// Send Debug messages via ScsiPort API +/***************************************/ + +//#define SCSI_PORT_DBG_PRINT + +/***************************************/ +// Using DbgPrint on raised IRQL will crash w2k +// this will not happen immediately, so we shall see some logs. +// You can tune Irql checking here +// Note: you can avoid crashes if configure DbgPrintLogger to check Irql +/***************************************/ + +#define LOG_ON_RAISED_IRQL_W2K TRUE +//#define LOG_ON_RAISED_IRQL_W2K FALSE + +/***************************************/ +// Use hack to avoid PCI-ISA DMA limitations (physical memory must +// be allocated below 16Mb). Actually there is no such limitation, +// so we have to pretent to be PIO and converl logical addresses +// to physical manually +/***************************************/ + +#define USE_OWN_DMA + +/***************************************/ +// Special option, enables dumping of ATAPI cammands and data buffers +// via DbgPrint API +/***************************************/ + +//#define UNIATA_DUMP_ATAPI + +/***************************************/ +// Optimization for uni-processor machines +/***************************************/ + +//#define UNI_CPU_OPTIMIZATION + +/***************************************/ +// Enable/disable performance statistics +/***************************************/ + +#define QUEUE_STATISTICS + +#define IO_STATISTICS + +/***************************************************/ +/* Validate Options */ +/***************************************************/ + +#ifdef _DEBUG + + #ifndef DBG + #define DBG + #endif //DBG + +#else //_DEBUG + + #ifdef USE_DBGPRINT_LOGGER + #undef USE_DBGPRINT_LOGGER + #endif //USE_DBGPRINT_LOGGER + +#endif // !_DEBUG + +/***************************************************/ +/* Compiler dependencies */ +/***************************************************/ + +/* ReactOS-specific defines */ +#ifdef DDKAPI + #define USE_REACTOS_DDK +#endif DDKAPI + +/* Are we under GNU C (mingw) ??? */ +#if __GNUC__ >=3 + + #define DEF_U64(x) (x##ULL) + #define DEF_I64(x) (x##LL) + + /* ReactOS-specific defines */ + #ifdef USE_REACTOS_DDK + #else //USE_REACTOS_DDK + + #define DDKAPI __attribute__((stdcall)) + #define DDKFASTAPI __attribute__((fastcall)) + #define DDKCDECLAPI __attribute__((cdecl)) + + #endif //DDKAPI + + #define DECLSPEC_NAKED __attribute__((naked)) + +#else // !__GNUC__ => MSVC/Intel + + #define DEF_U64(x) (x##UI64) + #define DEF_I64(x) (x##I64) + + /* ReactOS-specific defines */ + #ifdef USE_REACTOS_DDK + #else //USE_REACTOS_DDK + + #define DDKAPI __stdcall + #define DDKFASTAPI __fastcall + #define DDKCDECLAPI _cdecl + + #endif //DDKAPI + + #define DECLSPEC_NAKED __declspec(naked) + +#endif //__GNUC__ + + +#endif //__UNIATA_CONFIG__H__ diff --git a/reactos/drivers/storage/ide/uniata/id_ata.cpp b/reactos/drivers/storage/ide/uniata/id_ata.cpp new file mode 100644 index 00000000000..50ea1d8bdd4 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_ata.cpp @@ -0,0 +1,8723 @@ +/*++ + +Copyright (c) 2002-2007 Alexandr A. Telyatnikov (Alter) + +Module Name: + id_ata.cpp + +Abstract: + This is the miniport driver for ATA/ATAPI IDE controllers + with Busmaster DMA and Serial ATA support + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + + The skeleton was taken from standard ATAPI.SYS from NT4 DDK by + Mike Glass (MGlass) + Chuck Park (ChuckP) + + Some parts of code were taken from FreeBSD 4.3-6.1 ATA driver by + Søren Schmidt, Copyright (c) 1998-2007 + + All parts of code are greatly changed/updated by + Alter, Copyright (c) 2002-2007: + + 1. Internal command queueing/reordering + 2. Drive identification + 3. Support for 2 _independent_ channels in a single PCI device + 4. Smart host<->drive transfer rate slowdown (for bad cable) + 5. W2k support (binary compatibility) + 6. HDD hot swap under NT4 + 7. XP support (binary compatibility) + 8. Serial ATA (SATA/SATA2) support + 9. NT 3.51 support (binary compatibility) + + etc. (See todo.txt) + + +--*/ + +#include "stdafx.h" + +#ifndef UNIATA_CORE + +static const CHAR ver_string[] = "\n\nATAPI IDE MiniPort Driver (UniATA) v 0." UNIATA_VER_STR "\n"; + +UNICODE_STRING SavedRegPath; +WCHAR SavedRegPathBuffer[256]; + +#endif //UNIATA_CORE + +UCHAR AtaCommands48[256]; +UCHAR AtaCommandFlags[256]; + +ULONG SkipRaids = 1; +ULONG ForceSimplex = 0; + +LONGLONG g_Perf = 0; +ULONG g_PerfDt = 0; + +#ifdef _DEBUG +ULONG g_LogToDisplay = 0; +#endif //_DEBUG + +ULONG g_WaitBusyInISR = 1; + +BOOLEAN InDriverEntry = TRUE; + +BOOLEAN g_opt_Verbose = 0; + +//UCHAR EnableDma = FALSE; +//UCHAR EnableReorder = FALSE; + +UCHAR g_foo = 0; + +BOOLEAN +DDKAPI +AtapiResetController__( + IN PVOID HwDeviceExtension, + IN ULONG PathId, + IN UCHAR CompleteType + ); + +VOID +AtapiHwInitialize__( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG lChannel + ); + +#define RESET_COMPLETE_CURRENT 0x00 +#define RESET_COMPLETE_ALL 0x01 +#define RESET_COMPLETE_NONE 0x02 + +#ifndef UNIATA_CORE + +VOID +DDKAPI +AtapiCallBack_X( + IN PVOID HwDeviceExtension + ); + +#ifdef UNIATA_USE_XXableInterrupts + #define RETTYPE_XXableInterrupts BOOLEAN + #define RETVAL_XXableInterrupts TRUE +#else + #define RETTYPE_XXableInterrupts VOID + #define RETVAL_XXableInterrupts +#endif + +RETTYPE_XXableInterrupts +DDKAPI +AtapiInterruptDpc( + IN PVOID HwDeviceExtension + ); + +RETTYPE_XXableInterrupts +DDKAPI +AtapiEnableInterrupts__( + IN PVOID HwDeviceExtension + ); + +VOID +AtapiQueueTimerDpc( + IN PVOID HwDeviceExtension, + IN ULONG lChannel, + IN PHW_TIMER HwScsiTimer, + IN ULONG MiniportTimerValue + ); + +SCSI_ADAPTER_CONTROL_STATUS +DDKAPI +AtapiAdapterControl( + IN PVOID HwDeviceExtension, + IN SCSI_ADAPTER_CONTROL_TYPE ControlType, + IN PVOID Parameters + ); + +#endif //UNIATA_CORE + +BOOLEAN +AtapiCheckInterrupt__( + IN PVOID HwDeviceExtension, + IN UCHAR c + ); + + +#ifndef UNIATA_CORE + +BOOLEAN +AtapiRegGetStringParameterValue( + IN PWSTR RegistryPath, + IN PWSTR Name, + IN PWCHAR Str, + IN ULONG MaxLen + ) +{ +#define ITEMS_TO_QUERY 2 // always 1 greater than what is searched + NTSTATUS status; + RTL_QUERY_REGISTRY_TABLE parameters[ITEMS_TO_QUERY]; + UNICODE_STRING ustr; + + ustr.Buffer = Str; + ustr.Length = + ustr.MaximumLength = (USHORT)MaxLen; + RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY)); + + parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + parameters[0].Name = Name; + parameters[0].EntryContext = &ustr; + parameters[0].DefaultType = REG_SZ; + parameters[0].DefaultData = Str; + parameters[0].DefaultLength = MaxLen; + + status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + RegistryPath, parameters, NULL, NULL); + + if(!NT_SUCCESS(status)) + return FALSE; + + return TRUE; + +#undef ITEMS_TO_QUERY +} // end AtapiRegGetStringParameterValue() + + +#endif //UNIATA_CORE + +VOID +DDKFASTAPI +UniataNanoSleep( + ULONG nano + ) +{ + LONGLONG t; + LARGE_INTEGER t0; + + if(!nano || !g_Perf || !g_PerfDt) + return; + t = (g_Perf * nano) / g_PerfDt / 1000; + if(!t) { + t = 1; + } + do { + KeQuerySystemTime(&t0); + t--; + } while(t); +} // end UniataNanoSleep() + + +#define AtapiWritePortN_template(_type, _Type, sz) \ +VOID \ +DDKFASTAPI \ +AtapiWritePort##sz( \ + IN PHW_CHANNEL chan, \ + IN ULONG _port, \ + IN _type data \ + ) \ +{ \ + PIORES res; \ + if(_port >= IDX_MAX_REG) { \ + res = (PIORES)(_port); \ + } else \ + if(chan) { \ + res = &chan->RegTranslation[_port]; \ + } else { \ + KdPrint(("invalid io write request @ ch %x, res* %x\n", chan, _port)); \ + return; \ + } \ + if(!res->MemIo) { \ + ScsiPortWritePort##_Type((_type*)(res->Addr), data); \ + } else { \ + /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \ + ScsiPortWriteRegister##_Type((_type*)(res->Addr), data); \ + } \ + return; \ +} + +AtapiWritePortN_template(ULONG, Ulong, 4); +AtapiWritePortN_template(USHORT, Ushort, 2); +AtapiWritePortN_template(UCHAR, Uchar, 1); + +#define AtapiWritePortExN_template(_type, _Type, sz) \ +VOID \ +DDKFASTAPI \ +AtapiWritePortEx##sz( \ + IN PHW_CHANNEL chan, \ + IN ULONG _port, \ + IN ULONG offs, \ + IN _type data \ + ) \ +{ \ + PIORES res; \ + if(_port >= IDX_MAX_REG) { \ + res = (PIORES)(_port); \ + } else \ + if(chan) { \ + res = &chan->RegTranslation[_port]; \ + } else { \ + KdPrint(("invalid io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \ + return; \ + } \ + if(!res->MemIo) { \ + ScsiPortWritePort##_Type((_type*)(res->Addr+offs), data); \ + } else { \ + /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \ + ScsiPortWriteRegister##_Type((_type*)(res->Addr+offs), data); \ + } \ + return; \ +} + +AtapiWritePortExN_template(ULONG, Ulong, 4); +//AtapiWritePortExN_template(USHORT, Ushort, 2); +AtapiWritePortExN_template(UCHAR, Uchar, 1); + +#define AtapiReadPortN_template(_type, _Type, sz) \ +_type \ +DDKFASTAPI \ +AtapiReadPort##sz( \ + IN PHW_CHANNEL chan, \ + IN ULONG _port \ + ) \ +{ \ + PIORES res; \ + if(_port >= IDX_MAX_REG) { \ + res = (PIORES)(_port); \ + } else \ + if(chan) { \ + res = &chan->RegTranslation[_port]; \ + } else { \ + KdPrint(("invalid io read request @ ch %x, res* %x\n", chan, _port)); \ + return (_type)(-1); \ + } \ + if(!res->MemIo) { \ + /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \ + return ScsiPortReadPort##_Type((_type*)(res->Addr)); \ + } else { \ + /*KdPrint(("r_mem @ (%x) %x\n", _port, res->Addr));*/ \ + return ScsiPortReadRegister##_Type((_type*)(res->Addr)); \ + } \ +} + +AtapiReadPortN_template(ULONG, Ulong, 4); +AtapiReadPortN_template(USHORT, Ushort, 2); +AtapiReadPortN_template(UCHAR, Uchar, 1); + +#define AtapiReadPortExN_template(_type, _Type, sz) \ +_type \ +DDKFASTAPI \ +AtapiReadPortEx##sz( \ + IN PHW_CHANNEL chan, \ + IN ULONG _port, \ + IN ULONG offs \ + ) \ +{ \ + PIORES res; \ + if(_port >= IDX_MAX_REG) { \ + res = (PIORES)(_port); \ + } else \ + if(chan) { \ + res = &chan->RegTranslation[_port]; \ + } else { \ + KdPrint(("invalid io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \ + return (_type)(-1); \ + } \ + if(!res->MemIo) { \ + return ScsiPortReadPort##_Type((_type*)(res->Addr+offs)); \ + } else { \ + /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \ + return ScsiPortReadRegister##_Type((_type*)(res->Addr+offs)); \ + } \ +} + +AtapiReadPortExN_template(ULONG, Ulong, 4); +//AtapiReadPortExN_template(USHORT, Ushort, 2); +AtapiReadPortExN_template(UCHAR, Uchar, 1); + +#define AtapiReadPortBufferN_template(type, Type, sz) \ +VOID \ +DDKFASTAPI \ +AtapiReadBuffer##sz( \ + IN PHW_CHANNEL chan, \ + IN ULONG _port, \ + IN PVOID Buffer, \ + IN ULONG Count, \ + IN ULONG Timing \ + ) \ +{ \ + ULONG i=0; \ + while(Count) { \ + ((type*)Buffer)[i] = AtapiReadPort##sz(chan, _port); \ + i++; \ + Count--; \ + UniataNanoSleep(Timing); \ + } \ + return; \ +} + +#define AtapiWritePortBufferN_template(type, Type, sz) \ +VOID \ +DDKFASTAPI \ +AtapiWriteBuffer##sz( \ + IN PHW_CHANNEL chan, \ + IN ULONG _port, \ + IN PVOID Buffer, \ + IN ULONG Count, \ + IN ULONG Timing \ + ) \ +{ \ + ULONG i=0; \ + while(Count) { \ + AtapiWritePort##sz(chan, _port, ((type*)Buffer)[i]); \ + i++; \ + Count--; \ + UniataNanoSleep(Timing); \ + } \ + return; \ +} + +AtapiWritePortBufferN_template(ULONG, Ulong, 4); +AtapiWritePortBufferN_template(USHORT, Ushort, 2); + +AtapiReadPortBufferN_template(ULONG, Ulong, 4); +AtapiReadPortBufferN_template(USHORT, Ushort, 2); + + +UCHAR +DDKFASTAPI +AtapiSuckPort2( + IN PHW_CHANNEL chan + ) +{ + UCHAR statusByte; + ULONG i; + + WaitOnBusyLong(chan); + for (i = 0; i < 0x10000; i++) { + + GetStatus(chan, statusByte); + if (statusByte & IDE_STATUS_DRQ) { + // Suck out any remaining bytes and throw away. + AtapiReadPort2(chan, IDX_IO1_i_Data); + } else { + break; + } + } + if(i) { + KdPrint2((PRINT_PREFIX "AtapiSuckPort2: overrun detected (%#x words)\n", i )); + } + return statusByte; +} // AtapiSuckPort2() + +UCHAR +DDKFASTAPI +WaitOnBusy( + IN PHW_CHANNEL chan + ) +{ + ULONG i; + UCHAR Status; + for (i=0; i<200; i++) { + GetStatus(chan, Status); + if (Status & IDE_STATUS_BUSY) { + AtapiStallExecution(10); + continue; + } else { + break; + } + } + return Status; +} // end WaitOnBusy() + +UCHAR +DDKFASTAPI +WaitOnBusyLong( + IN PHW_CHANNEL chan + ) +{ + ULONG i; + UCHAR Status; + + Status = WaitOnBusy(chan); + if(!(Status & IDE_STATUS_BUSY)) + return Status; + for (i=0; i<2000; i++) { + GetStatus(chan, Status); + if (Status & IDE_STATUS_BUSY) { + AtapiStallExecution(250); + continue; + } else { + break; + } + } + return Status; +} // end WaitOnBusyLong() + +UCHAR +DDKFASTAPI +WaitOnBaseBusy( + IN PHW_CHANNEL chan + ) +{ + ULONG i; + UCHAR Status; + for (i=0; i<200; i++) { + GetBaseStatus(chan, Status); + if (Status & IDE_STATUS_BUSY) { + AtapiStallExecution(10); + continue; + } else { + break; + } + } + return Status; +} // end WaitOnBaseBusy() + +UCHAR +DDKFASTAPI +WaitOnBaseBusyLong( + IN PHW_CHANNEL chan + ) +{ + ULONG i; + UCHAR Status; + + Status = WaitOnBaseBusy(chan); + if(!(Status & IDE_STATUS_BUSY)) + return Status; + for (i=0; i<2000; i++) { + GetBaseStatus(chan, Status); + if (Status & IDE_STATUS_BUSY) { + AtapiStallExecution(250); + continue; + } else { + break; + } + } + return Status; +} // end WaitOnBaseBusyLong() + +UCHAR +DDKFASTAPI +UniataIsIdle( + IN struct _HW_DEVICE_EXTENSION* deviceExtension, + IN UCHAR Status + ) +{ + UCHAR Status2; + + if(Status == 0xff) { + return 0xff; + } + if(Status & IDE_STATUS_BUSY) { + return Status; + } +// if(deviceExtension->HwFlags & UNIATA_SATA) { + if(deviceExtension->BaseIoAddressSATA_0.Addr) { + if(Status & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) { + return Status; + } + } else { + Status2 = Status & ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX); + if ((Status & IDE_STATUS_BUSY) || + (Status2 != IDE_STATUS_IDLE && Status2 != IDE_STATUS_DRDY)) { + return Status; + } + } + return IDE_STATUS_IDLE; +} // end UniataIsIdle() + +UCHAR +DDKFASTAPI +WaitForIdleLong( + IN PHW_CHANNEL chan + ) +{ + ULONG i; + UCHAR Status; + UCHAR Status2; + for (i=0; i<20000; i++) { + GetStatus(chan, Status); + Status2 = UniataIsIdle(chan->DeviceExtension, Status); + if(Status2 == 0xff) { + // no drive ? + break; + } else + if(Status2 & IDE_STATUS_BUSY) { + AtapiStallExecution(10); + continue; + } else { + break; + } + } + return Status; +} // end WaitForIdleLong() + +UCHAR +DDKFASTAPI +WaitForDrq( + IN PHW_CHANNEL chan + ) +{ + ULONG i; + UCHAR Status; + for (i=0; i<1000; i++) { + GetStatus(chan, Status); + if (Status & IDE_STATUS_BUSY) { + AtapiStallExecution(10); + } else if (Status & IDE_STATUS_DRQ) { + break; + } else { + AtapiStallExecution(10); + } + } + return Status; +} // end WaitForDrq() + +UCHAR +DDKFASTAPI +WaitShortForDrq( + IN PHW_CHANNEL chan + ) +{ + ULONG i; + UCHAR Status; + for (i=0; i<2; i++) { + GetStatus(chan, Status); + if (Status & IDE_STATUS_BUSY) { + AtapiStallExecution(10); + } else if (Status & IDE_STATUS_DRQ) { + break; + } else { + AtapiStallExecution(10); + } + } + return Status; +} // end WaitShortForDrq() + +VOID +DDKFASTAPI +AtapiSoftReset( + IN PHW_CHANNEL chan, + ULONG DeviceNumber + ) +{ + ULONG c = chan->lChannel; + ULONG i; + UCHAR dma_status = 0; + KdPrint2((PRINT_PREFIX "AtapiSoftReset:\n")); + UCHAR statusByte2; + + GetBaseStatus(chan, statusByte2); + KdPrint2((PRINT_PREFIX " statusByte2 %x:\n", statusByte2)); + SelectDrive(chan, DeviceNumber); + AtapiStallExecution(10000); + AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET); + for (i = 0; i < 1000; i++) { + AtapiStallExecution(999); + } + SelectDrive(chan, DeviceNumber); + WaitOnBusy(chan); + GetBaseStatus(chan, statusByte2); + AtapiStallExecution(500); + + GetBaseStatus(chan, statusByte2); + if(chan && chan->DeviceExtension) { + dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel); + KdPrint2((PRINT_PREFIX " DMA status %#x\n", dma_status)); + } else { + KdPrint2((PRINT_PREFIX " can't get DMA status\n")); + } + if(dma_status & BM_STATUS_INTR) { + // bullshit, we have DMA interrupt, but had never initiate DMA operation + KdPrint2((PRINT_PREFIX " clear unexpected DMA intr on ATAPI reset\n")); + AtapiDmaDone(chan->DeviceExtension, DeviceNumber, chan->lChannel, NULL); + GetBaseStatus(chan, statusByte2); + } + if(chan->DeviceExtension->HwFlags & UNIATA_SATA) { + UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT); + } + return; + +} // end AtapiSoftReset() + +/* + Send command to device. + Translate to 48-Lba form if required +*/ +UCHAR +AtaCommand48( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, + IN UCHAR command, + IN ULONGLONG lba, + IN USHORT count, + IN USHORT feature, + IN ULONG flags + ) +{ + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + UCHAR statusByte; + ULONG ldev = lChannel*2 + DeviceNumber; + ULONG i; + PUCHAR plba; + + KdPrint2((PRINT_PREFIX "AtaCommand48: cntrlr %#x:%#x ldev %#x, cmd %#x, lba %#I64x count %#x feature %#x\n", + deviceExtension->DevIndex, deviceExtension->Channel, ldev, command, lba, count, feature )); + + //if(!(deviceExtension->HwFlags & UNIATA_SATA)) { + SelectDrive(chan, DeviceNumber); + + statusByte = WaitOnBusy(chan); + + /* ready to issue command ? */ + if (statusByte & IDE_STATUS_BUSY) { + KdPrint2((PRINT_PREFIX " Returning BUSY status\n")); + return statusByte; + } + //} + // !!! We should not check ERROR condition here + // ERROR bit may be asserted durring previous operation + // and not cleared after SELECT + + //>>>>>> NV: 2006/08/03 + if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) && + CheckIfBadBlock(&(deviceExtension->lun[ldev]), lba, count)) { + KdPrint2((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count)); + return IDE_STATUS_ERROR; + //return SRB_STATUS_ERROR; + } + //<<<<<< NV: 2006/08/03 + + /* only use 48bit addressing if needed because of the overhead */ + if ((lba >= ATA_MAX_LBA28 || count > 256) && + deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) { + + KdPrint2((PRINT_PREFIX " ldev %#x USE_LBA_48\n", ldev )); + /* translate command into 48bit version */ + if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) { + command = AtaCommands48[command]; + } else { + KdPrint2((PRINT_PREFIX " unhandled LBA48 command\n")); + return (UCHAR)-1; + } + + chan->ChannelCtrlFlags |= CTRFLAGS_LBA48; + plba = (PUCHAR)&lba; + + AtapiWritePort1(chan, IDX_IO1_o_Feature, (UCHAR)(feature>>8) & 0xff); + AtapiWritePort1(chan, IDX_IO1_o_Feature, (UCHAR)feature); + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, (UCHAR)(count>>8) & 0xff); + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, (UCHAR)count & 0xff); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, (UCHAR)(plba[3])); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, (UCHAR)(plba[0])); + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, (UCHAR)(plba[4])); + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, (UCHAR)(plba[1])); + AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[5])); + AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[2])); + + //KdPrint2((PRINT_PREFIX "AtaCommand48: ldev %#x USE_LBA48 (2)\n", ldev )); + AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) ); + } else { + + chan->ChannelCtrlFlags &= ~CTRFLAGS_LBA48; + + //if(feature || + // (deviceExtension->lun[ldev].DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))) { + AtapiWritePort1(chan, IDX_IO1_o_Feature, (UCHAR)feature); + //} + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, (UCHAR)count); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, (UCHAR)lba & 0xff); + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, (UCHAR)(lba>>8) & 0xff); + AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(lba>>16) & 0xff); + if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) { + //KdPrint2((PRINT_PREFIX "AtaCommand28: ldev %#x USE_LBA\n", ldev )); + AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (UCHAR)((lba>>24) & 0xf) | IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) ); + } else { + //KdPrint2((PRINT_PREFIX "AtaCommand28: ldev %#x USE_CHS\n", ldev )); + AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (UCHAR)((lba>>24) & 0xf) | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) ); + } + } + + // write command code to device + AtapiWritePort1(chan, IDX_IO1_o_Command, command); + + switch (flags) { + case ATA_WAIT_INTR: + + // caller requested wait for interrupt + for(i=0;i<4;i++) { + WaitOnBusy(chan); + statusByte = WaitForDrq(chan); + if (statusByte & IDE_STATUS_DRQ) + break; + AtapiStallExecution(500); + KdPrint2((PRINT_PREFIX " retry waiting DRQ, status %#x\n", statusByte)); + } + + return statusByte; + + case ATA_WAIT_IDLE: + + // caller requested wait for entering Wait state + for (i=0; i<30 * 1000; i++) { + + GetStatus(chan, statusByte); + statusByte = UniataIsIdle(deviceExtension, statusByte); + if(statusByte == 0xff) { + // no drive ? + break; + } else + if(statusByte & IDE_STATUS_ERROR) { + break; + } else + if(statusByte & IDE_STATUS_BUSY) { + AtapiStallExecution(100); + continue; + } else + if(statusByte == IDE_STATUS_IDLE) { + break; + } else { + //if(deviceExtension->HwFlags & UNIATA_SATA) { + if(deviceExtension->BaseIoAddressSATA_0.Addr) { + break; + } + AtapiStallExecution(100); + } + } + //statusByte |= IDE_STATUS_BUSY; + break; + + case ATA_WAIT_READY: + statusByte = WaitOnBusyLong(chan); + break; + case ATA_WAIT_BASE_READY: + statusByte = WaitOnBaseBusyLong(chan); + break; + case ATA_IMMEDIATE: + GetStatus(chan, statusByte); + if (statusByte & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX " Warning: Immed Status %#x :(\n", statusByte)); + if(statusByte == (IDE_STATUS_IDLE | IDE_STATUS_ERROR)) { + break; + } + KdPrint2((PRINT_PREFIX " try to continue\n")); + statusByte &= ~IDE_STATUS_ERROR; + } + chan->ExpectingInterrupt = TRUE; + // !!!!! + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + statusByte = 0; + break; + } + + KdPrint2((PRINT_PREFIX " Status %#x\n", statusByte)); + + return statusByte; +} // end AtaCommand48() + +/* + Send command to device. + This is simply wrapper for AtaCommand48() +*/ +UCHAR +AtaCommand( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, + IN UCHAR command, + IN USHORT cylinder, + IN UCHAR head, + IN UCHAR sector, + IN UCHAR count, + IN UCHAR feature, + IN ULONG flags + ) +{ + return AtaCommand48(deviceExtension, DeviceNumber, lChannel, + command, + (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24), + count, feature, flags); +} // end AtaCommand() + +LONG +AtaPio2Mode(LONG pio) +{ + switch (pio) { + default: return ATA_PIO; + case 0: return ATA_PIO0; + case 1: return ATA_PIO1; + case 2: return ATA_PIO2; + case 3: return ATA_PIO3; + case 4: return ATA_PIO4; + case 5: return ATA_PIO5; + } +} // end AtaPio2Mode() + +LONG +AtaPioMode(PIDENTIFY_DATA2 ident) +{ + if (ident->PioTimingsValid) { + if (ident->AdvancedPIOModes & AdvancedPIOModes_5) + return 5; + if (ident->AdvancedPIOModes & AdvancedPIOModes_4) + return 4; + if (ident->AdvancedPIOModes & AdvancedPIOModes_3) + return 3; + } + if (ident->PioCycleTimingMode == 2) + return 2; + if (ident->PioCycleTimingMode == 1) + return 1; + if (ident->PioCycleTimingMode == 0) + return 0; + return -1; +} // end AtaPioMode() + +LONG +AtaWmode(PIDENTIFY_DATA2 ident) +{ + if (ident->MultiWordDMASupport & 0x04) + return 2; + if (ident->MultiWordDMASupport & 0x02) + return 1; + if (ident->MultiWordDMASupport & 0x01) + return 0; + return -1; +} // end AtaWmode() + +LONG +AtaUmode(PIDENTIFY_DATA2 ident) +{ + if (!ident->UdmaModesValid) + return -1; + if (ident->UltraDMASupport & 0x40) + return 6; + if (ident->UltraDMASupport & 0x20) + return 5; + if (ident->UltraDMASupport & 0x10) + return 4; + if (ident->UltraDMASupport & 0x08) + return 3; + if (ident->UltraDMASupport & 0x04) + return 2; + if (ident->UltraDMASupport & 0x02) + return 1; + if (ident->UltraDMASupport & 0x01) + return 0; + return -1; +} // end AtaUmode() + + +#ifndef UNIATA_CORE + +VOID +DDKAPI +AtapiTimerDpc( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_TIMER HwScsiTimer; + LARGE_INTEGER time; + ULONG MiniportTimerValue; + BOOLEAN recall = FALSE; + ULONG lChannel; + PHW_CHANNEL chan; + + KdPrint2((PRINT_PREFIX "AtapiTimerDpc:\n")); + + lChannel = deviceExtension->ActiveDpcChan = deviceExtension->FirstDpcChan; + if(lChannel == -1) { + KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no items\n")); + return; + } + chan = &deviceExtension->chan[lChannel]; + + while(TRUE) { + + HwScsiTimer = chan->HwScsiTimer; + chan->HwScsiTimer = NULL; + + deviceExtension->FirstDpcChan = chan->NextDpcChan; + if(deviceExtension->FirstDpcChan != -1) { + recall = TRUE; + } + + HwScsiTimer(HwDeviceExtension); + + chan->NextDpcChan = -1; + + lChannel = deviceExtension->ActiveDpcChan = deviceExtension->FirstDpcChan; + if(lChannel == -1) { + KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no more items\n")); + deviceExtension->FirstDpcChan = + deviceExtension->ActiveDpcChan = -1; + return; + } + + KeQuerySystemTime(&time); + KdPrint2((PRINT_PREFIX "AtapiTimerDpc: KeQuerySystemTime=%#x%#x\n", time.HighPart, time.LowPart)); + + chan = &deviceExtension->chan[lChannel]; + if(time.QuadPart >= chan->DpcTime - 10) { + // call now + KdPrint2((PRINT_PREFIX "AtapiTimerDpc: get next DPC, DpcTime1=%#x%#x\n", + (ULONG)(chan->DpcTime >> 32), (ULONG)(chan->DpcTime))); + continue; + } + break; + } + + if(recall) { + deviceExtension->ActiveDpcChan = -1; + MiniportTimerValue = (ULONG)(time.QuadPart - chan->DpcTime)/10; + if(!MiniportTimerValue) + MiniportTimerValue = 1; + + KdPrint2((PRINT_PREFIX "AtapiTimerDpc: recall AtapiTimerDpc\n")); + ScsiPortNotification(RequestTimerCall, HwDeviceExtension, + AtapiTimerDpc, + MiniportTimerValue + ); + } + return; + +} // end AtapiTimerDpc() + +/* + Wrapper for ScsiPort, that implements smart Dpc + queueing. We need it to allow parallel functioning + of IDE channles with shared interrupt. Standard Dpc mechanism + cancels previous Dpc request (if any), but we need Dpc queue. +*/ +VOID +AtapiQueueTimerDpc( + IN PVOID HwDeviceExtension, + IN ULONG lChannel, + IN PHW_TIMER HwScsiTimer, + IN ULONG MiniportTimerValue + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + LARGE_INTEGER time; + LARGE_INTEGER time2; + ULONG i; + PHW_CHANNEL prev_chan; + PHW_CHANNEL chan; +// BOOLEAN UseRequestTimerCall = TRUE; + + KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: dt=%d for lChn %#x\n", MiniportTimerValue, lChannel)); + KeQuerySystemTime(&time); + time2 = time; + KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime=%#x%#x\n", time.HighPart, time.LowPart)); + time.QuadPart += MiniportTimerValue*10; + KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime2=%#x%#x\n", time.HighPart, time.LowPart)); + + KdPrint2((PRINT_PREFIX " ActiveDpcChan=%d, FirstDpcChan=%d\n", deviceExtension->ActiveDpcChan, deviceExtension->FirstDpcChan)); + + i = deviceExtension->FirstDpcChan; + chan = prev_chan = NULL; + while(i != -1) { + prev_chan = chan; + chan = &deviceExtension->chan[i]; + if(chan->DpcTime > time.QuadPart) { + break; + } + i = chan->NextDpcChan; + } + chan = &deviceExtension->chan[lChannel]; + if(!prev_chan) { + deviceExtension->FirstDpcChan = lChannel; + } else { + prev_chan->NextDpcChan = lChannel; + } + chan->NextDpcChan = i; + chan->HwScsiTimer = HwScsiTimer; + chan->DpcTime = time.QuadPart; + + KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime3=%#x%#x\n", time2.HighPart, time2.LowPart)); + if(time.QuadPart <= time2.QuadPart) { + MiniportTimerValue = 1; + } else { + MiniportTimerValue = (ULONG)((time.QuadPart - time2.QuadPart) / 10); + } + + KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: dt=%d for lChn %#x\n", MiniportTimerValue, lChannel)); + ScsiPortNotification(RequestTimerCall, HwDeviceExtension, + AtapiTimerDpc, + MiniportTimerValue); + +} // end AtapiQueueTimerDpc() + +#endif //UNIATA_CORE + +VOID +UniataDumpATARegs( + IN PHW_CHANNEL chan + ) +{ + ULONG j; + UCHAR statusByteAlt; + + GetStatus(chan, statusByteAlt); + KdPrint2((PRINT_PREFIX " AltStatus (%#x)\n", statusByteAlt)); + + for(j=1; jRegTranslation[IDX_IO1+j].Addr, + statusByteAlt)); + } + for(j=0; jRegTranslation[IDX_BM_IO+j].Addr, + statusByteAlt)); + } + return; +} // end UniataDumpATARegs() + +/*++ + +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. + +--*/ +BOOLEAN +IssueIdentify( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, + IN UCHAR Command, + IN BOOLEAN NoSetup + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + ULONG waitCount = 50000; + ULONG j; + UCHAR statusByte; + UCHAR statusByte2; + UCHAR signatureLow, + signatureHigh; + BOOLEAN atapiDev = FALSE; + ULONG ldev = (lChannel * 2) + DeviceNumber; + PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]); + + if(DeviceNumber && (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) { + KdPrint2((PRINT_PREFIX "IssueIdentify: NO SLAVE\n")); + return FALSE; + } + + SelectDrive(chan, DeviceNumber); + AtapiStallExecution(10); + statusByte = WaitOnBusyLong(chan); + // Check that the status register makes sense. + GetBaseStatus(chan, statusByte2); + + UniataDumpATARegs(chan); + + if (Command == IDE_COMMAND_IDENTIFY) { + // Mask status byte ERROR bits. + statusByte = UniataIsIdle(deviceExtension, statusByte & ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX)); + KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for IDE. Status (%#x)\n", statusByte)); + // Check if register value is reasonable. + + if(statusByte != IDE_STATUS_IDLE) { + + // No reset here !!! + KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte != IDE_STATUS_IDLE\n")); + + //if(!(deviceExtension->HwFlags & UNIATA_SATA)) { + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + SelectDrive(chan, DeviceNumber); + WaitOnBusyLong(chan); + + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + + if (signatureLow == ATAPI_MAGIC_LSB && + signatureHigh == ATAPI_MAGIC_MSB) { + // Device is Atapi. + KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (ldev %d)\n", ldev)); + return FALSE; + } + + // 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. + AtapiStallExecution(100); + GetStatus(chan, statusByte); + + } while ((statusByte & IDE_STATUS_BUSY) && waitCount--); + GetBaseStatus(chan, statusByte2); + + SelectDrive(chan, DeviceNumber); + } else { + GetBaseStatus(chan, statusByte2); + } + // Another check for signature, to deal with one model Atapi that doesn't assert signature after + // a soft reset. + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + + if (signatureLow == ATAPI_MAGIC_LSB && + signatureHigh == ATAPI_MAGIC_MSB) { + KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (2) (ldev %d)\n", ldev)); + // Device is Atapi. + return FALSE; + } + + statusByte = UniataIsIdle(deviceExtension, statusByte) & ~IDE_STATUS_INDEX; + if (statusByte != IDE_STATUS_IDLE) { + // Give up on this. + KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (ldev %d)\n", ldev)); + return FALSE; + } + } + } else { + KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI. Status (%#x)\n", statusByte)); + //if(!(deviceExtension->HwFlags & UNIATA_SATA)) { + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + statusByte = WaitForIdleLong(chan); + KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI (2). Status (%#x)\n", statusByte)); + } + atapiDev = TRUE; + } + +// if(deviceExtension->HwFlags & UNIATA_SATA) { + if(deviceExtension->BaseIoAddressSATA_0.Addr) { + j = 4; + } else { + j = 0; + } + for (; j < 4*2; j++) { + // Send IDENTIFY command. + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, 0, 0, 0, (j >= 4) ? 0x200 : 0, 0, ATA_WAIT_INTR); + // Clear interrupt + + if (statusByte & IDE_STATUS_DRQ) { + // Read status to acknowledge any interrupts generated. + KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_DRQ (%#x)\n", statusByte)); + GetBaseStatus(chan, statusByte); + // One last check for Atapi. + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + + if (signatureLow == ATAPI_MAGIC_LSB && + signatureHigh == ATAPI_MAGIC_MSB) { + KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (3) (ldev %d)\n", ldev)); + // Device is Atapi. + return FALSE; + } + break; + } else { + KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (%#x)\n", statusByte)); + if (Command == IDE_COMMAND_IDENTIFY) { + // Check the signature. If DRQ didn't come up it's likely Atapi. + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + + if (signatureLow == ATAPI_MAGIC_LSB && + signatureHigh == ATAPI_MAGIC_MSB) { + // Device is Atapi. + KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (4) (ldev %d)\n", ldev)); + return FALSE; + } + } + // Device didn't respond correctly. It will be given one more chances. + KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ never asserted (%#x). Error reg (%#x)\n", + statusByte, AtapiReadPort1(chan, IDX_IO1_i_Error))); + GetBaseStatus(chan, statusByte); + AtapiSoftReset(chan,DeviceNumber); + + AtapiDisableInterrupts(deviceExtension, lChannel); + AtapiEnableInterrupts(deviceExtension, lChannel); + + GetBaseStatus(chan, statusByte); + //GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX "IssueIdentify: Status after soft reset (%#x)\n", statusByte)); + } + } + // Check for error on really stupid master devices that assert random + // patterns of bits in the status register at the slave address. + if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) { + KdPrint2((PRINT_PREFIX "IssueIdentify: Exit on error (%#x)\n", statusByte)); + return FALSE; + } + + KdPrint2((PRINT_PREFIX "IssueIdentify: Status before read words %#x\n", statusByte)); + // Suck out 256 words. After waiting for one model that asserts busy + // after receiving the Packet Identify command. + statusByte = WaitForDrq(chan); + statusByte = WaitOnBusyLong(chan); + KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte)); + + if (!(statusByte & IDE_STATUS_DRQ)) { + KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte)); + GetBaseStatus(chan, statusByte); + return FALSE; + } + GetBaseStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte)); + + if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) { + + KdPrint2((PRINT_PREFIX " use 16bit IO\n")); +#if 0 + USHORT w; + ULONG i; + // ATI/SII chipsets with memory-mapped IO hangs when + // I call ReadBuffer(), probably due to PCI burst/prefetch enabled + // Unfortunately, I don't know yet how to workaround it except the way you see below. + KdPrint2((PRINT_PREFIX + " IO_%#x (%#x), %s:\n", + IDX_IO1_i_Data, + chan->RegTranslation[IDX_IO1_i_Data].Addr, + chan->RegTranslation[IDX_IO1_i_Data].MemIo ? "Mem" : "IO")); + for(i=0; i<256; i++) { +/* + KdPrint2((PRINT_PREFIX + " IO_%#x (%#x):\n", + IDX_IO1_i_Data, + chan->RegTranslation[IDX_IO1_i_Data].Addr)); +*/ + w = AtapiReadPort2(chan, IDX_IO1_i_Data); + KdPrint2((PRINT_PREFIX + " %x\n", w)); + AtapiStallExecution(1); + ((PUSHORT)&deviceExtension->FullIdentifyData)[i] = w; + } +#else + ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING); +#endif + // Work around for some IDE and one model Atapi that will present more than + // 256 bytes for the Identify data. + KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte)); + statusByte = AtapiSuckPort2(chan); + } else { + KdPrint2((PRINT_PREFIX " use 32bit IO\n")); + ReadBuffer2(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING); + } + + KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte)); + statusByte = WaitForDrq(chan); + KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte)); + GetBaseStatus(chan, statusByte); + + KdPrint2((PRINT_PREFIX "IssueIdentify: Status after read words %#x\n", statusByte)); + + if(NoSetup) { + KdPrint2((PRINT_PREFIX "IssueIdentify: no setup, exiting\n")); + return TRUE; + } + + KdPrint2((PRINT_PREFIX "Model: %20.20s\n", deviceExtension->FullIdentifyData.ModelNumber)); + KdPrint2((PRINT_PREFIX "FW: %4.4s\n", deviceExtension->FullIdentifyData.FirmwareRevision)); + KdPrint2((PRINT_PREFIX "S/N: %20.20s\n", deviceExtension->FullIdentifyData.SerialNumber)); + KdPrint2((PRINT_PREFIX "Pio: %x\n", deviceExtension->FullIdentifyData.PioCycleTimingMode)); + if(deviceExtension->FullIdentifyData.PioTimingsValid) { + KdPrint2((PRINT_PREFIX "APio: %x\n", deviceExtension->FullIdentifyData.AdvancedPIOModes)); + } + KdPrint2((PRINT_PREFIX "SWDMA: %x\n", deviceExtension->FullIdentifyData.SingleWordDMAActive)); + KdPrint2((PRINT_PREFIX "MWDMA: %x\n", deviceExtension->FullIdentifyData.MultiWordDMAActive)); + if(deviceExtension->FullIdentifyData.UdmaModesValid) { + KdPrint2((PRINT_PREFIX "UDMA: %x\n", deviceExtension->FullIdentifyData.UltraDMAActive)); + } + KdPrint2((PRINT_PREFIX "SATA: %x\n", deviceExtension->FullIdentifyData.SataEnable)); + + // Check out a few capabilities / limitations of the device. + if (deviceExtension->FullIdentifyData.RemovableStatus & 1) { + // Determine if this drive supports the MSN functions. + KdPrint2((PRINT_PREFIX "IssueIdentify: Marking drive %d as removable. SFE = %d\n", + ldev, + deviceExtension->FullIdentifyData.RemovableStatus)); + LunExt->DeviceFlags |= DFLAGS_REMOVABLE_DRIVE; + } + if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) { + // Determine max. block transfer for this device. + LunExt->MaximumBlockXfer = + (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF); + } + LunExt->NumOfSectors = 0; + if (Command == IDE_COMMAND_IDENTIFY) { + ULONGLONG NumOfSectors=0; + ULONGLONG NativeNumOfSectors=0; + ULONGLONG cylinders=0; + ULONGLONG tmp_cylinders=0; + // Read very-old-style drive geometry + KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n", + deviceExtension->FullIdentifyData.NumberOfCylinders, + deviceExtension->FullIdentifyData.NumberOfHeads, + deviceExtension->FullIdentifyData.SectorsPerTrack + )); + NumOfSectors = deviceExtension->FullIdentifyData.NumberOfCylinders * + deviceExtension->FullIdentifyData.NumberOfHeads * + deviceExtension->FullIdentifyData.SectorsPerTrack; + KdPrint2((PRINT_PREFIX "NumOfSectors %#I64x\n", NumOfSectors)); + // Check for HDDs > 8Gb + if ((deviceExtension->FullIdentifyData.NumberOfCylinders == 0x3fff) && +/* (deviceExtension->FullIdentifyData.TranslationFieldsValid) &&*/ + (NumOfSectors < deviceExtension->FullIdentifyData.UserAddressableSectors)) { + KdPrint2((PRINT_PREFIX "NumberOfCylinders == 0x3fff\n")); + cylinders = + (deviceExtension->FullIdentifyData.UserAddressableSectors / + (deviceExtension->FullIdentifyData.NumberOfHeads * + deviceExtension->FullIdentifyData.SectorsPerTrack)); + + KdPrint2((PRINT_PREFIX "cylinders %#I64x\n", cylinders)); + + NumOfSectors = cylinders * + deviceExtension->FullIdentifyData.NumberOfHeads * + deviceExtension->FullIdentifyData.SectorsPerTrack; + + KdPrint2((PRINT_PREFIX "NumOfSectors %#I64x\n", NumOfSectors)); + } else { + + } + // Check for LBA mode + KdPrint2((PRINT_PREFIX "SupportLba flag %#x\n", deviceExtension->FullIdentifyData.SupportLba)); + KdPrint2((PRINT_PREFIX "MajorRevision %#x\n", deviceExtension->FullIdentifyData.MajorRevision)); + KdPrint2((PRINT_PREFIX "UserAddressableSectors %#x\n", deviceExtension->FullIdentifyData.UserAddressableSectors)); + if ( deviceExtension->FullIdentifyData.SupportLba + || + (deviceExtension->FullIdentifyData.MajorRevision && +/* deviceExtension->FullIdentifyData.TranslationFieldsValid &&*/ + deviceExtension->FullIdentifyData.UserAddressableSectors)) { + KdPrint2((PRINT_PREFIX "LBA mode\n")); + LunExt->DeviceFlags |= DFLAGS_LBA_ENABLED; + } else { + KdPrint2((PRINT_PREFIX "Keep orig geometry\n")); + LunExt->DeviceFlags |= DFLAGS_ORIG_GEOMETRY; + goto skip_lba_staff; + } + // Check for LBA48 support + if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) { + if(deviceExtension->FullIdentifyData.FeaturesSupport.Address48 && + deviceExtension->FullIdentifyData.FeaturesEnabled.Address48 && + (deviceExtension->FullIdentifyData.UserAddressableSectors48 > NumOfSectors) + ) { + KdPrint2((PRINT_PREFIX "LBA48\n")); + cylinders = + (deviceExtension->FullIdentifyData.UserAddressableSectors48 / + (deviceExtension->FullIdentifyData.NumberOfHeads * + deviceExtension->FullIdentifyData.SectorsPerTrack)); + + KdPrint2((PRINT_PREFIX "cylinders %#I64x\n", cylinders)); + + NativeNumOfSectors = cylinders * + deviceExtension->FullIdentifyData.NumberOfHeads * + deviceExtension->FullIdentifyData.SectorsPerTrack; + + KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors)); + + if(NativeNumOfSectors > NumOfSectors) { + KdPrint2((PRINT_PREFIX "Update NumOfSectors to %#I64x\n", NativeNumOfSectors)); + NumOfSectors = NativeNumOfSectors; + } + } + + // Check drive capacity report for LBA48-capable drives. + if(deviceExtension->FullIdentifyData.FeaturesSupport.Address48) { + ULONG hNativeNumOfSectors; + KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_READ_NATIVE_SIZE48\n")); + + statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel, + IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY); + + if(!(statusByte & IDE_STATUS_ERROR)) { + NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) | + ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) | + ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) ; + + AtapiWritePort1(chan, IDX_IO2_o_Control, + IDE_DC_USE_HOB ); + + KdPrint2((PRINT_PREFIX "Read high order bytes\n")); + NativeNumOfSectors |= + ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) << 24 ); + hNativeNumOfSectors= + (ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) | + ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 8) ; + ((PULONG)&NativeNumOfSectors)[1] = hNativeNumOfSectors; + + KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors)); + + // Some drives report LBA48 capability while has capacity below 128Gb + // Probably they support large block-counters. + // But the problem is that some of them reports higher part of Max LBA equal to lower part. + // Here we check this + if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) { + KdPrint2((PRINT_PREFIX "High-order bytes == Low-order bytes !!!\n")); + + statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel, + IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY); + + if(!(statusByte & IDE_STATUS_ERROR)) { + NativeNumOfSectors = (ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) | + ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) << 24) | + ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8 ) | + ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 32) | + ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) | + ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 40) + ; + } + + if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) { + KdPrint2((PRINT_PREFIX "High-order bytes == Low-order bytes !!! (2)\n")); + NativeNumOfSectors = 0; + } + } + + if(NumOfSectors <= ATA_MAX_LBA28 && + NativeNumOfSectors > NumOfSectors) { + + KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_SET_NATIVE_SIZE48\n")); + KdPrint2((PRINT_PREFIX "Update NumOfSectors to %#I64x\n", NativeNumOfSectors)); + + statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel, + IDE_COMMAND_SET_NATIVE_SIZE, NativeNumOfSectors, 0, 0, ATA_WAIT_READY); + if(!(statusByte & IDE_STATUS_ERROR)) { + NumOfSectors = NativeNumOfSectors; + } + } + } + } + + if(NumOfSectors < 0x2100000 /*&& NumOfSectors > 31*1000*1000*/) { + // check for native LBA size + // some drives report ~32Gb in Identify Block + KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_READ_NATIVE_SIZE\n")); + + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_READ_NATIVE_SIZE, + 0, IDE_USE_LBA, 0, 0, 0, ATA_WAIT_READY); + + if(!(statusByte & IDE_STATUS_ERROR)) { + NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) | + ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) | + ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) | + (((ULONG)AtapiReadPort1(chan, IDX_IO1_i_DriveSelect) & 0xf) << 24); + + KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors)); + + if(NativeNumOfSectors > NumOfSectors) { + + KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_SET_NATIVE_SIZE\n")); + KdPrint2((PRINT_PREFIX "Update NumOfSectors to %#I64x\n", NativeNumOfSectors)); + + statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel, + IDE_COMMAND_SET_NATIVE_SIZE, NativeNumOfSectors, 0, 0, ATA_WAIT_READY); + if(!(statusByte & IDE_STATUS_ERROR)) { + NumOfSectors = NativeNumOfSectors; + } + } + } + } + + } // if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) + + // fill IdentifyData with bogus geometry + KdPrint2((PRINT_PREFIX "requested LunExt->GeomType=%x\n", LunExt->opt_GeomType)); + tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.CurrentSectorsPerTrack * + deviceExtension->FullIdentifyData.NumberOfCurrentHeads); + KdPrint2((PRINT_PREFIX "tmp_cylinders = %#I64x\n", tmp_cylinders)); + if((tmp_cylinders < 0xffff) || (LunExt->opt_GeomType == GEOM_ORIG)) { + // ok, we can keep original values + if(LunExt->opt_GeomType == GEOM_AUTO) { + LunExt->opt_GeomType = GEOM_ORIG; + } + } else { + tmp_cylinders = NumOfSectors / (255*63); + if(tmp_cylinders < 0xffff) { + // we can use generic values for H/S for generic geometry approach + if(LunExt->opt_GeomType == GEOM_AUTO) { + LunExt->opt_GeomType = GEOM_STD; + } + } else { + // we should use UNIATA geometry approach + if(LunExt->opt_GeomType == GEOM_AUTO) { + LunExt->opt_GeomType = GEOM_UNIATA; + } + } + } + KdPrint2((PRINT_PREFIX "final LunExt->opt_GeomType=%x\n", LunExt->opt_GeomType)); + + if(LunExt->opt_GeomType == GEOM_STD) { + deviceExtension->FullIdentifyData.CurrentSectorsPerTrack = + deviceExtension->FullIdentifyData.SectorsPerTrack = 63; + + deviceExtension->FullIdentifyData.NumberOfCurrentHeads = + deviceExtension->FullIdentifyData.NumberOfHeads = 255; + + cylinders = NumOfSectors / (255*63); + KdPrint2((PRINT_PREFIX "Use GEOM_STD, CHS=%I64x/%x/%x\n", cylinders, 255, 63)); + } else + if(LunExt->opt_GeomType == GEOM_UNIATA) { + while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.SectorsPerTrack < 0x80)) { + cylinders /= 2; + KdPrint2((PRINT_PREFIX "cylinders /= 2\n")); + deviceExtension->FullIdentifyData.SectorsPerTrack *= 2; + deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *= 2; + } + while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.NumberOfHeads < 0x80)) { + cylinders /= 2; + KdPrint2((PRINT_PREFIX "cylinders /= 2 (2)\n")); + deviceExtension->FullIdentifyData.NumberOfHeads *= 2; + deviceExtension->FullIdentifyData.NumberOfCurrentHeads *= 2; + } + while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.SectorsPerTrack < 0x8000)) { + cylinders /= 2; + KdPrint2((PRINT_PREFIX "cylinders /= 2 (3)\n")); + deviceExtension->FullIdentifyData.SectorsPerTrack *= 2; + deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *= 2; + } + while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.NumberOfHeads < 0x8000)) { + cylinders /= 2; + KdPrint2((PRINT_PREFIX "cylinders /= 2 (4)\n")); + deviceExtension->FullIdentifyData.NumberOfHeads *= 2; + deviceExtension->FullIdentifyData.NumberOfCurrentHeads *= 2; + } + KdPrint2((PRINT_PREFIX "Use GEOM_UNIATA, CHS=%I64x/%x/%x\n", cylinders, + deviceExtension->FullIdentifyData.NumberOfCurrentHeads, + deviceExtension->FullIdentifyData.CurrentSectorsPerTrack)); + } + if(!cylinders) { + KdPrint2((PRINT_PREFIX "cylinders = tmp_cylinders (%x = %x)\n", cylinders, tmp_cylinders)); + cylinders = tmp_cylinders; + } + deviceExtension->FullIdentifyData.NumberOfCurrentCylinders = + deviceExtension->FullIdentifyData.NumberOfCylinders = (USHORT)cylinders; + +skip_lba_staff: + + KdPrint2((PRINT_PREFIX "Geometry: C %#x (%#x)\n", + deviceExtension->FullIdentifyData.NumberOfCylinders, + deviceExtension->FullIdentifyData.NumberOfCurrentCylinders + )); + KdPrint2((PRINT_PREFIX "Geometry: H %#x (%#x)\n", + deviceExtension->FullIdentifyData.NumberOfHeads, + deviceExtension->FullIdentifyData.NumberOfCurrentHeads + )); + KdPrint2((PRINT_PREFIX "Geometry: S %#x (%#x)\n", + deviceExtension->FullIdentifyData.SectorsPerTrack, + deviceExtension->FullIdentifyData.CurrentSectorsPerTrack + )); + + if(NumOfSectors) + LunExt->NumOfSectors = NumOfSectors; +/* if(deviceExtension->FullIdentifyData.MajorRevision && + deviceExtension->FullIdentifyData.DoubleWordIo) { + LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED; + }*/ + } + + ScsiPortMoveMemory(&LunExt->IdentifyData, + &deviceExtension->FullIdentifyData,sizeof(IDENTIFY_DATA2)); + + InitBadBlocks(LunExt); + + if ((LunExt->IdentifyData.DrqType & ATAPI_DRQT_INTR) && + (Command != IDE_COMMAND_IDENTIFY)) { + + // This device interrupts with the assertion of DRQ after receiving + // Atapi Packet Command + LunExt->DeviceFlags |= DFLAGS_INT_DRQ; + KdPrint2((PRINT_PREFIX "IssueIdentify: Device interrupts on assertion of DRQ.\n")); + + } else { + KdPrint2((PRINT_PREFIX "IssueIdentify: Device does not interrupt on assertion of DRQ.\n")); + } + + if(Command != IDE_COMMAND_IDENTIFY) { + // ATAPI branch + if(LunExt->IdentifyData.DeviceType == ATAPI_TYPE_TAPE) { + // This is a tape. + LunExt->DeviceFlags |= DFLAGS_TAPE_DEVICE; + KdPrint2((PRINT_PREFIX "IssueIdentify: Device is a tape drive.\n")); + } else + if(LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM || + LunExt->IdentifyData.DeviceType == ATAPI_TYPE_OPTICAL) { + KdPrint2((PRINT_PREFIX "IssueIdentify: Device is CD/Optical drive.\n")); + // set CD default costs + LunExt->RwSwitchCost = REORDER_COST_SWITCH_RW_CD; + LunExt->RwSwitchMCost = REORDER_MCOST_SWITCH_RW_CD; + LunExt->SeekBackMCost = REORDER_MCOST_SEEK_BACK_CD; + statusByte = WaitForDrq(chan); + } else { + KdPrint2((PRINT_PREFIX "IssueIdentify: ATAPI drive type %#x.\n", + LunExt->IdentifyData.DeviceType)); + } + } else { + KdPrint2((PRINT_PREFIX "IssueIdentify: hard drive.\n")); + } + + GetBaseStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX "IssueIdentify: final Status on exit (%#x)\n", statusByte)); + return TRUE; + +} // end IssueIdentify() + + +/*++ + +Routine Description: + Set drive parameters using the IDENTIFY data. + +Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + DeviceNumber - Indicates which device. + +Return Value: + TRUE if all goes well. + +--*/ +BOOLEAN +SetDriveParameters( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PIDENTIFY_DATA2 identifyData = &deviceExtension->lun[(lChannel * 2) + DeviceNumber].IdentifyData; +// ULONG i; + UCHAR statusByte; + UCHAR errorByte; + + if(deviceExtension->lun[(lChannel * 2) + DeviceNumber].DeviceFlags & + (DFLAGS_LBA_ENABLED | DFLAGS_ORIG_GEOMETRY)) + return TRUE; + + KdPrint2((PRINT_PREFIX "SetDriveParameters: Number of heads %#x\n", identifyData->NumberOfHeads)); + KdPrint2((PRINT_PREFIX "SetDriveParameters: Sectors per track %#x\n", identifyData->SectorsPerTrack)); + + // Send SET PARAMETER command. + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, + IDE_COMMAND_SET_DRIVE_PARAMETERS, 0, + (identifyData->NumberOfHeads - 1), 0, + (UCHAR)identifyData->SectorsPerTrack, 0, ATA_WAIT_IDLE); + + statusByte = UniataIsIdle(deviceExtension, statusByte); + if(statusByte & IDE_STATUS_ERROR) { + errorByte = AtapiReadPort1(&deviceExtension->chan[lChannel], IDX_IO1_i_Error); + KdPrint2((PRINT_PREFIX "SetDriveParameters: Error bit set. Status %#x, error %#x\n", + errorByte, statusByte)); + return FALSE; + } + + if(statusByte == IDE_STATUS_IDLE) { + return TRUE; + } + + return FALSE; + +} // end SetDriveParameters() + + +/*++ + +Routine Description: + Reset IDE controller and/or Atapi device. + +Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + +Return Value: + Nothing. + + +--*/ +BOOLEAN +DDKAPI +AtapiResetController( + IN PVOID HwDeviceExtension, + IN ULONG PathId + ) +{ + KdPrint2((PRINT_PREFIX "AtapiResetController()\n")); + return AtapiResetController__(HwDeviceExtension, PathId, RESET_COMPLETE_ALL); +} // end AtapiResetController() + + +BOOLEAN +AtapiResetController__( + IN PVOID HwDeviceExtension, + IN ULONG PathId, + IN BOOLEAN CompleteType + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG numberChannels = deviceExtension->NumberChannels; + PHW_CHANNEL chan = NULL; + ULONG i,j; + ULONG max_ldev; + UCHAR statusByte; + PSCSI_REQUEST_BLOCK CurSrb; + ULONG ChannelCtrlFlags; + UCHAR dma_status = 0; + + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + ULONG VendorID = deviceExtension->DevID & 0xffff; + ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff; + //ULONG RevID = deviceExtension->RevID; + ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + UCHAR tmp8; + UCHAR tmp16; + + KdPrint2((PRINT_PREFIX "AtapiResetController: Reset IDE %#x/%#x @ %#x\n", VendorID, DeviceID, slotNumber)); + + if(!deviceExtension->simplexOnly) { + // we shall reset both channels on SimplexOnly devices, + // It's not worth doing so on normal controllers + j = PathId; + numberChannels = j+1; + } else { + j=0; + numberChannels = deviceExtension->NumberChannels; + } + + for (; j < numberChannels; j++) { + + KdPrint2((PRINT_PREFIX "AtapiResetController: Reset channel %d\n", j)); + chan = &deviceExtension->chan[j]; + KdPrint2((PRINT_PREFIX " CompleteType %#x\n", CompleteType)); + max_ldev = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2; + if(CompleteType != RESET_COMPLETE_NONE) { +#ifndef UNIATA_CORE + while(CurSrb = UniataGetCurRequest(chan)) { + + PATA_REQ AtaReq = (PATA_REQ)(CurSrb->SrbExtension); + + KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x\n", CurSrb)); + // Check and see if we are processing an internal srb + if (AtaReq->OriginalSrb) { + KdPrint2((PRINT_PREFIX " restore original SRB %#x\n", AtaReq->OriginalSrb)); + AtaReq->Srb = AtaReq->OriginalSrb; + AtaReq->OriginalSrb = NULL; + // NOTE: internal SRB doesn't get to SRB queue !!! + CurSrb = AtaReq->Srb; + } + + // Remove current request from queue + UniataRemoveRequest(chan, CurSrb); + + // Check if request is in progress. + ASSERT(AtaReq->Srb == CurSrb); + if (CurSrb) { + // Complete outstanding request with SRB_STATUS_BUS_RESET. + UCHAR PathId = CurSrb->PathId; + UCHAR TargetId = CurSrb->TargetId; + UCHAR Lun = CurSrb->Lun; + + CurSrb->SrbStatus = ((CompleteType == RESET_COMPLETE_ALL) ? SRB_STATUS_BUS_RESET : SRB_STATUS_ABORTED) | SRB_STATUS_AUTOSENSE_VALID; + CurSrb->ScsiStatus = SCSISTAT_CHECK_CONDITION; + + if (CurSrb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)CurSrb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + if(CompleteType == RESET_COMPLETE_ALL) { + KdPrint2((PRINT_PREFIX "AtapiResetController: report SCSI_SENSE_UNIT_ATTENTION + SCSI_ADSENSE_BUS_RESET\n")); + senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; + senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_BUS_RESET; + senseBuffer->AdditionalSenseCodeQualifier = SCSI_SENSEQ_SCSI_BUS; + } else { + KdPrint2((PRINT_PREFIX "AtapiResetController: report SCSI_SENSE_ABORTED_COMMAND\n")); + senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + } + } + + // Clear request tracking fields. + AtaReq->WordsLeft = 0; + AtaReq->DataBuffer = NULL; + + ScsiPortNotification(RequestComplete, + deviceExtension, + CurSrb); + + // Indicate ready for next request. + ScsiPortNotification(NextLuRequest, + deviceExtension, + PathId, + TargetId, + Lun); + } + if(CompleteType != RESET_COMPLETE_ALL) + break; + } // end while() +#endif //UNIATA_CORE + } // end if (!CompleteType != RESET_COMPLETE_NONE) + + // Save control flags + ChannelCtrlFlags = chan->ChannelCtrlFlags; + // Clear expecting interrupt flag. + chan->ExpectingInterrupt = FALSE; + chan->RDP = FALSE; + chan->ChannelCtrlFlags = 0; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + // Reset controller + KdPrint2((PRINT_PREFIX " disable intr (0)\n")); + AtapiDisableInterrupts(deviceExtension, j); + KdPrint2((PRINT_PREFIX " done\n")); + switch(VendorID) { + case ATA_INTEL_ID: { + ULONG mask; + ULONG timeout; + if(!(ChipFlags & UNIATA_SATA)) + goto default_reset; + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + goto default_reset; + } + + /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */ + if(ChipFlags & UNIATA_AHCI) { + mask = 0x0005 << j; + } else { + /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */ + GetPciConfig1(0x90, tmp8); + if(tmp8 & 0x04) { + mask = 0x0003; + } else { + mask = 0x0001 << j; + } + } + ChangePciConfig2(0x92, a & ~mask); + AtapiStallExecution(10); + ChangePciConfig2(0x92, a | mask); + timeout = 100; + while (timeout--) { + AtapiStallExecution(10000); + GetPciConfig2(0x92, tmp16); + if ((tmp16 & (mask << 4)) == (mask << 4)) { + AtapiStallExecution(10000); + break; + } + } + break; } + case ATA_SIS_ID: + case ATA_NVIDIA_ID: { + KdPrint2((PRINT_PREFIX " SIS/nVidia\n")); + if(!(ChipFlags & UNIATA_SATA)) + goto default_reset; + break; } + case ATA_SILICON_IMAGE_ID: { + ULONG offset; + ULONG Channel = deviceExtension->Channel + j; + if(!(ChipFlags & UNIATA_SATA)) + goto default_reset; + offset = ((Channel & 1) << 7) + ((Channel & 2) << 8); + /* disable PHY state change interrupt */ + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + offset, 0); + + UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT); + + /* reset controller part for this channel */ + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x48, + AtapiReadPortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x48) | (0xc0 >> Channel)); + AtapiStallExecution(1000); + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x48, + AtapiReadPortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x48) & ~(0xc0 >> Channel)); + + + break; } + case ATA_PROMISE_ID: { + break; } + default: + if(ChipFlags & UNIATA_SATA) { + KdPrint2((PRINT_PREFIX " SATA generic reset\n")); + UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT); + } +default_reset: + KdPrint2((PRINT_PREFIX " send reset\n")); + AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS | + IDE_DC_RESET_CONTROLLER ); + KdPrint2((PRINT_PREFIX " wait a little\n")); + AtapiStallExecution(10000); + // Disable interrupts + KdPrint2((PRINT_PREFIX " disable intr\n")); + AtapiDisableInterrupts(deviceExtension, j); + KdPrint2((PRINT_PREFIX " re-enable intr\n")); + AtapiEnableInterrupts(deviceExtension, j); + KdPrint2((PRINT_PREFIX " wait a little (2)\n")); + AtapiStallExecution(100000); + KdPrint2((PRINT_PREFIX " done\n")); + + break; + } + + //if(!(ChipFlags & UNIATA_SATA)) { + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + // Reset DMA engine if active + KdPrint2((PRINT_PREFIX " check DMA engine\n")); + dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel); + KdPrint2((PRINT_PREFIX " DMA status %#x\n", dma_status)); + if((ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) || + (dma_status & BM_STATUS_INTR)) { + AtapiDmaDone(HwDeviceExtension, 0, j, NULL); + } + } + + // all these shall be performed inside AtapiHwInitialize__() ? +#if 1 + KdPrint2((PRINT_PREFIX " process connected devices\n")); + // Do special processing for ATAPI and IDE disk devices. + for (i = 0; i < max_ldev; i++) { + + // Check if device present. + if (!(deviceExtension->lun[i + (j * 2)].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + //if(!CheckDevice(HwDeviceExtension, i, j, FALSE)) + if(!UniataAnybodyHome(HwDeviceExtension, j, i)) { + continue; + } + if(!CheckDevice(HwDeviceExtension, j, i, TRUE)) { + continue; + } + } else { + if(!UniataAnybodyHome(HwDeviceExtension, j, i)) { + KdPrint2((PRINT_PREFIX " device have gone\n")); + deviceExtension->lun[i + (j * 2)].DeviceFlags &= ~DFLAGS_DEVICE_PRESENT; + } + } + + SelectDrive(chan, i); + AtapiStallExecution(10); + statusByte = WaitOnBusyLong(chan); + statusByte = UniataIsIdle(deviceExtension, statusByte); + if(statusByte == 0xff) { + KdPrint2((PRINT_PREFIX + "no drive, status %#x\n", + statusByte)); + deviceExtension->lun[i + (j * 2)].DeviceFlags = 0; + } else + // Check for ATAPI disk. + if (deviceExtension->lun[i + (j * 2)].DeviceFlags & DFLAGS_ATAPI_DEVICE) { + // Issue soft reset and issue identify. + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX "AtapiResetController: Status before Atapi reset (%#x).\n", + statusByte)); + + AtapiDisableInterrupts(deviceExtension, j); + AtapiSoftReset(chan, i); + AtapiEnableInterrupts(deviceExtension, j); + + GetStatus(chan, statusByte); + + if(statusByte == IDE_STATUS_SUCCESS) { + + IssueIdentify(HwDeviceExtension, + i, j, + IDE_COMMAND_ATAPI_IDENTIFY, FALSE); + } else { + + KdPrint2((PRINT_PREFIX + "AtapiResetController: Status after soft reset %#x\n", + statusByte)); + } + GetBaseStatus(chan, statusByte); + + } else { + // Issue identify and reinit after channel reset. + + if (statusByte != IDE_STATUS_IDLE && + statusByte != IDE_STATUS_SUCCESS && + statusByte != IDE_STATUS_DRDY) { +// result2 = FALSE; + KdPrint2((PRINT_PREFIX "AtapiResetController: IdeHardReset failed\n")); + } else + if(!IssueIdentify(HwDeviceExtension, + i, j, + IDE_COMMAND_IDENTIFY, FALSE)) { +// result2 = FALSE; + KdPrint2((PRINT_PREFIX "AtapiResetController: IDE IssueIdentify failed\n")); + } else + // Set disk geometry parameters. + if (!SetDriveParameters(HwDeviceExtension, i, j)) { + KdPrint2((PRINT_PREFIX "AtapiResetController: SetDriveParameters failed\n")); + } + GetBaseStatus(chan, statusByte); + } + // force DMA mode reinit + deviceExtension->lun[i + (j * 2)].DeviceFlags |= DFLAGS_REINIT_DMA; + } +#endif //0 + + // Enable interrupts, note, the we can have here recursive disable + AtapiStallExecution(10); + KdPrint2((PRINT_PREFIX "AtapiResetController: deviceExtension->chan[%d].DisableIntr %d -> 1\n", + j, + chan->DisableIntr)); + AtapiEnableInterrupts(deviceExtension, j); + + // Call the HwInitialize routine to setup multi-block. + AtapiHwInitialize__(deviceExtension, j); + } + ScsiPortNotification(NextRequest, deviceExtension, NULL); + + return TRUE; + +} // end AtapiResetController__() + + +/*++ + +Routine Description: + This routine maps ATAPI and IDE errors to specific SRB statuses. + +Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + Srb - IO request packet + +Return Value: + SRB status + +--*/ +ULONG +MapError( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG lChannel = GET_CHANNEL(Srb); + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); +// ULONG i; + UCHAR errorByte; + UCHAR srbStatus; + UCHAR scsiStatus; + ULONG ldev = GET_LDEV(Srb); + + // Read the error register. + + errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error); + KdPrint2((PRINT_PREFIX + "MapError: Error register is %#x\n", + errorByte)); + + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) { + + switch (errorByte >> 4) { + case SCSI_SENSE_NO_SENSE: + + KdPrint2((PRINT_PREFIX + "ATAPI: No sense information\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_RECOVERED_ERROR: + + KdPrint2((PRINT_PREFIX + "ATAPI: Recovered error\n")); + scsiStatus = 0; + srbStatus = SRB_STATUS_SUCCESS; + break; + + case SCSI_SENSE_NOT_READY: + + KdPrint2((PRINT_PREFIX + "ATAPI: Device not ready\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_MEDIUM_ERROR: + + KdPrint2((PRINT_PREFIX + "ATAPI: Media error\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_HARDWARE_ERROR: + + KdPrint2((PRINT_PREFIX + "ATAPI: Hardware error\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_ILLEGAL_REQUEST: + + KdPrint2((PRINT_PREFIX + "ATAPI: Illegal request\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_UNIT_ATTENTION: + + KdPrint2((PRINT_PREFIX + "ATAPI: Unit attention\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_DATA_PROTECT: + + KdPrint2((PRINT_PREFIX + "ATAPI: Data protect\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_BLANK_CHECK: + + KdPrint2((PRINT_PREFIX + "ATAPI: Blank check\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + case SCSI_SENSE_ABORTED_COMMAND: + KdPrint2((PRINT_PREFIX + "Atapi: Command Aborted\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + break; + + default: + + KdPrint2((PRINT_PREFIX + "ATAPI: Invalid sense information\n")); + scsiStatus = 0; + srbStatus = SRB_STATUS_ERROR; + break; + } + + } else { + + scsiStatus = 0; + + // Save errorByte,to be used by SCSIOP_REQUEST_SENSE. + chan->ReturningMediaStatus = errorByte; + + if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) { + KdPrint2((PRINT_PREFIX + "IDE: Media change\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; + senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + } else if (errorByte & IDE_ERROR_COMMAND_ABORTED) { + KdPrint2((PRINT_PREFIX + "IDE: Command abort\n")); + srbStatus = SRB_STATUS_ABORTED; + scsiStatus = SCSISTAT_CHECK_CONDITION; + + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + deviceExtension->lun[ldev].ErrorCount++; + + } else if (errorByte & IDE_ERROR_END_OF_MEDIA) { + + KdPrint2((PRINT_PREFIX + "IDE: End of media\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; + senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIA_STATE; + senseBuffer->AdditionalSenseCodeQualifier = SCSI_SENSEQ_END_OF_MEDIUM; + senseBuffer->EndOfMedia = 1; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){ + deviceExtension->lun[ldev].ErrorCount++; + } + + } else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) { + + KdPrint2((PRINT_PREFIX + "IDE: Illegal length\n")); + srbStatus = SRB_STATUS_INVALID_REQUEST; + + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST; + senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_VALUE; + senseBuffer->AdditionalSenseCodeQualifier = SCSI_SENSEQ_PARAM_INVALID_VALUE; + senseBuffer->IncorrectLength = 1; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + } else if (errorByte & IDE_ERROR_BAD_BLOCK) { + + KdPrint2((PRINT_PREFIX + "IDE: Bad block\n")); + srbStatus = SRB_STATUS_ERROR; + scsiStatus = SCSISTAT_CHECK_CONDITION; + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + } else if (errorByte & IDE_ERROR_ID_NOT_FOUND) { + + KdPrint2((PRINT_PREFIX + "IDE: Id not found\n")); + srbStatus = SRB_STATUS_ERROR; + scsiStatus = SCSISTAT_CHECK_CONDITION; + + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + deviceExtension->lun[ldev].ErrorCount++; + + } else if (errorByte & IDE_ERROR_MEDIA_CHANGE) { + + KdPrint2((PRINT_PREFIX + "IDE: Media change\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; + senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + } else if (errorByte & IDE_ERROR_DATA_ERROR) { + + KdPrint2((PRINT_PREFIX + "IDE: Data error\n")); + scsiStatus = SCSISTAT_CHECK_CONDITION; + srbStatus = SRB_STATUS_ERROR; + + if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){ + deviceExtension->lun[ldev].ErrorCount++; + } + + // Build sense buffer + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + srbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + } + + if (deviceExtension->lun[ldev].ErrorCount >= MAX_ERRORS) { +// deviceExtension->DWordIO = FALSE; + + KdPrint2((PRINT_PREFIX + "MapError: ErrorCount >= MAX_ERRORS\n")); + + deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_DWORDIO_ENABLED; + deviceExtension->lun[ldev].MaximumBlockXfer = 0; + BrutePoint(); + + KdPrint2((PRINT_PREFIX + "MapError: Disabling 32-bit PIO and Multi-sector IOs\n")); + + // Log the error. + KdPrint2((PRINT_PREFIX + "ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d)\n", + HwDeviceExtension, + Srb, + Srb->PathId, + Srb->TargetId, + Srb->Lun, + SP_BAD_FW_WARNING, + 4 + )); + ScsiPortLogError( HwDeviceExtension, + Srb, + Srb->PathId, + Srb->TargetId, + Srb->Lun, + SP_BAD_FW_WARNING, + 4); + + // Reprogram to not use Multi-sector. + UCHAR statusByte; + + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT && + !(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + + statusByte = AtaCommand(deviceExtension, ldev & 0x1, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY); + + // Check for errors. Reset the value to 0 (disable MultiBlock) if the + // command was aborted. + if (statusByte & IDE_STATUS_ERROR) { + + // Read the error register. + errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error); + + KdPrint2((PRINT_PREFIX "MapError: Error setting multiple mode. Status %#x, error byte %#x\n", + statusByte, + errorByte)); + + // Adjust the devExt. value, if necessary. + deviceExtension->lun[ldev].MaximumBlockXfer = 0; + BrutePoint(); + + } + } + } + } + + // Set SCSI status to indicate a check condition. + Srb->ScsiStatus = scsiStatus; + + return srbStatus; + +} // end MapError() + + +/*++ + +Routine Description: + +Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + +Return Value: + TRUE - if initialization successful. + FALSE - if initialization unsuccessful. + +--*/ +BOOLEAN +DDKAPI +AtapiHwInitialize( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG numberChannels = deviceExtension->NumberChannels; + ULONG c; + + KdPrint2((PRINT_PREFIX "AtapiHwInitialize: (base)\n")); + + /* do extra chipset specific setups */ + AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED); +/* + if(deviceExtension->Isr2DevObj && (deviceExtension->HwFlags & UNIATA_SATA)) { + KdPrint2((PRINT_PREFIX " enable ISR2 to catch unexpected interrupts\n")); + BMList[deviceExtension->DevIndex].Isr2Enable = TRUE; + } +*/ + for (c = 0; c < numberChannels; c++) { + AtapiHwInitialize__(deviceExtension, c); + } + KdPrint2((PRINT_PREFIX "AtapiHwInitialize: (base) done\n")); + return TRUE; +} // end AtapiHwInitialize() + +VOID +AtapiHwInitialize__( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG lChannel + ) +{ + ULONG i; + UCHAR statusByte, errorByte; + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); + PHW_LU_EXTENSION LunExt; +// ULONG tmp32; + ULONG PreferedMode = 0xffffffff; + + AtapiChipInit(deviceExtension, DEVNUM_NOT_SPECIFIED, lChannel); + FindDevices(deviceExtension, FALSE, lChannel); + + for (i = lChannel*2; i < (lChannel+1)*2; i++) { + + KdPrint2((PRINT_PREFIX "AtapiHwInitialize: lChannel %#x\n", lChannel)); + + LunExt = &(deviceExtension->lun[i]); + // skip empty slots + if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + continue; + } + + AtapiDisableInterrupts(deviceExtension, lChannel); + AtapiStallExecution(1); + + if (!(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + + KdPrint2((PRINT_PREFIX "AtapiHwInitialize: IDE branch\n")); + // Enable media status notification + IdeMediaStatus(TRUE,deviceExtension,(UCHAR)i); + + // If supported, setup Multi-block transfers. + if (LunExt->MaximumBlockXfer) { + + statusByte = AtaCommand(deviceExtension, i & 1, lChannel, + IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, + LunExt->MaximumBlockXfer, 0, ATA_WAIT_BASE_READY); + + // Check for errors. Reset the value to 0 (disable MultiBlock) if the + // command was aborted. + if (statusByte & IDE_STATUS_ERROR) { + + // Read the error register. + errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error); + + KdPrint2((PRINT_PREFIX "AtapiHwInitialize: Error setting multiple mode. Status %#x, error byte %#x\n", + statusByte, + errorByte)); + + // Adjust the devExt. value, if necessary. + LunExt->MaximumBlockXfer = 0; + + } else { + KdPrint2((PRINT_PREFIX + "AtapiHwInitialize: Using Multiblock on Device %d. Blocks / int - %d\n", + i, + LunExt->MaximumBlockXfer)); + } + } + + if(LunExt->IdentifyData.MajorRevision) { + + if(LunExt->opt_ReadCacheEnable) { + KdPrint2((PRINT_PREFIX " Try Enable Read Cache\n")); + // If supported, setup read/write cacheing + statusByte = AtaCommand(deviceExtension, i & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_BASE_READY); + + // Check for errors. + if (statusByte & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX + "AtapiHwInitialize: Enable read/write cacheing on Device %d failed\n", + i)); + LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED; + } else { + LunExt->DeviceFlags |= DFLAGS_RCACHE_ENABLED; + } + } else { + KdPrint2((PRINT_PREFIX " Disable Read Cache\n")); + statusByte = AtaCommand(deviceExtension, i & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_DIS_RCACHE, ATA_WAIT_BASE_READY); + LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED; + } + if(LunExt->opt_WriteCacheEnable) { + KdPrint2((PRINT_PREFIX " Try Enable Write Cache\n")); + // If supported & allowed, setup write cacheing + statusByte = AtaCommand(deviceExtension, i & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY); + // Check for errors. + if (statusByte & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX + "AtapiHwInitialize: Enable write cacheing on Device %d failed\n", + i)); + LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED; + } else { + LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED; + } + } else { + KdPrint2((PRINT_PREFIX " Disable Write Cache\n")); + statusByte = AtaCommand(deviceExtension, i & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY); + LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED; + } + } + + } else if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)){ + + ULONG j; + BOOLEAN isSanyo = FALSE; + CCHAR vendorId[26]; + + KdPrint2((PRINT_PREFIX "AtapiHwInitialize: ATAPI/Changer branch\n")); + + // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc. + for (j = 0; j < 26; j += 2) { + + // Build a buffer based on the identify data. + MOV_DW_SWP(vendorId[j], ((PUCHAR)LunExt->IdentifyData.ModelNumber)[j]); + } + + if (!AtapiStringCmp (vendorId, "CD-ROM CDR", 11)) { + + // Inquiry string for older model had a '-', newer is '_' + if (vendorId[12] == 'C') { + + // Torisan changer. Set the bit. This will be used in several places + // acting like 1) a multi-lun device and 2) building the 'special' TUR's. + LunExt->DeviceFlags |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER); + LunExt->DiscsPresent = 3; + isSanyo = TRUE; + } + } + } + + PreferedMode = LunExt->opt_MaxTransferMode; + if(PreferedMode == 0xffffffff) { + KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", chan->MaxTransferMode)); + PreferedMode = chan->MaxTransferMode; + } + + if(LunExt->opt_PreferedTransferMode != 0xffffffff) { + KdPrint2((PRINT_PREFIX "PreferedTransferMode: %#x\n", PreferedMode)); + PreferedMode = min(LunExt->opt_PreferedTransferMode, PreferedMode); + } + + KdPrint2((PRINT_PREFIX " try mode %#x\n", PreferedMode)); + LunExt->OrigTransferMode = + LunExt->LimitedTransferMode = + LunExt->TransferMode = + (CHAR)PreferedMode; + + AtapiDmaInit__(deviceExtension, i); + + LunExt->OrigTransferMode = + LunExt->LimitedTransferMode = + LunExt->TransferMode; + KdPrint2((PRINT_PREFIX "Using %#x mode\n", LunExt->TransferMode)); + + // We need to get our device ready for action before + // returning from this function + + // According to the atapi spec 2.5 or 2.6, an atapi device + // clears its status BSY bit when it is ready for atapi commands. + // However, some devices (Panasonic SQ-TC500N) are still + // not ready even when the status BSY is clear. They don't react + // to atapi commands. + // + // Since there is really no other indication that tells us + // the drive is really ready for action. We are going to check BSY + // is clear and then just wait for an arbitrary amount of time! + // + if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) { + ULONG waitCount; + + // have to get out of the loop sometime! + // 10000 * 100us = 1000,000us = 1000ms = 1s + waitCount = 10000; + GetStatus(chan, statusByte); + while ((statusByte & IDE_STATUS_BUSY) && waitCount) { + + KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x\n)", statusByte)); + // Wait for Busy to drop. + AtapiStallExecution(100); + GetStatus(chan, statusByte); + waitCount--; + } + + // 5000 * 100us = 500,000us = 500ms = 0.5s + waitCount = 5000; + do { + AtapiStallExecution(100); + } while (waitCount--); + } + GetBaseStatus(chan, statusByte); + AtapiEnableInterrupts(deviceExtension, lChannel); + AtapiStallExecution(10); + } + + return; + +} // end AtapiHwInitialize() + + +#ifndef UNIATA_CORE + +VOID +AtapiHwInitializeChanger( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG ldev = GET_LDEV(Srb); + + if (MechanismStatus) { + deviceExtension->lun[ldev].DiscsPresent = MechanismStatus->NumberAvailableSlots; + if (deviceExtension->lun[ldev].DiscsPresent > 1) { + deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_ATAPI_CHANGER; + } + } + return; +} // end AtapiHwInitializeChanger() + + +/*++ + +Routine Description: + This routine will parse the string for a match on the keyword, then + calculate the value for the keyword and return it to the caller. + +Arguments: + String - The ASCII string to parse. + KeyWord - The keyword for the value desired. + +Return Values: + Zero if value not found + Value converted from ASCII to binary. + +--*/ +ULONG +AtapiParseArgumentString( + IN PCHAR String, + IN PCHAR KeyWord + ) +{ + PCHAR cptr; + PCHAR kptr; + ULONG value; + ULONG stringLength = 0; + ULONG keyWordLength = 0; + ULONG index; + + if (!String) { + return 0; + } + if (!KeyWord) { + return 0; + } + + // Calculate the string length and lower case all characters. + cptr = String; + while (*cptr) { + if (*cptr >= 'A' && *cptr <= 'Z') { + *cptr = *cptr + ('a' - 'A'); + } + cptr++; + stringLength++; + } + + // Calculate the keyword length and lower case all characters. + cptr = KeyWord; + while (*cptr) { + + if (*cptr >= 'A' && *cptr <= 'Z') { + *cptr = *cptr + ('a' - 'A'); + } + cptr++; + keyWordLength++; + } + + if (keyWordLength > stringLength) { + + // Can't possibly have a match. + return 0; + } + + // Now setup and start the compare. + cptr = String; + +ContinueSearch: + + // The input string may start with white space. Skip it. + while (*cptr == ' ' || *cptr == '\t') { + cptr++; + } + + if (*cptr == '\0') { + // end of string. + return 0; + } + + kptr = KeyWord; + while (*cptr++ == *kptr++) { + + if (*(cptr - 1) == '\0') { + // end of string + return 0; + } + } + + if (*(kptr - 1) == '\0') { + + // May have a match backup and check for blank or equals. + cptr--; + while (*cptr == ' ' || *cptr == '\t') { + cptr++; + } + + // Found a match. Make sure there is an equals. + if (*cptr != '=') { + + // Not a match so move to the next semicolon. + while (*cptr) { + if (*cptr++ == ';') { + goto ContinueSearch; + } + } + return 0; + } + // Skip the equals sign. + cptr++; + + // Skip white space. + while ((*cptr == ' ') || (*cptr == '\t')) { + cptr++; + } + + if (*cptr == '\0') { + // Early end of string, return not found + return 0; + } + + if (*cptr == ';') { + // This isn't it either. + cptr++; + goto ContinueSearch; + } + + value = 0; + if ((*cptr == '0') && (*(cptr + 1) == 'x')) { + // Value is in Hex. Skip the "0x" + cptr += 2; + for (index = 0; *(cptr + index); index++) { + + if (*(cptr + index) == ' ' || + *(cptr + index) == '\t' || + *(cptr + index) == ';') { + break; + } + + if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) { + value = (16 * value) + (*(cptr + index) - '0'); + } else { + if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) { + value = (16 * value) + (*(cptr + index) - 'a' + 10); + } else { + // Syntax error, return not found. + return 0; + } + } + } + } else { + + // Value is in Decimal. + for (index = 0; *(cptr + index); index++) { + + if (*(cptr + index) == ' ' || + *(cptr + index) == '\t' || + *(cptr + index) == ';') { + break; + } + + if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) { + value = (10 * value) + (*(cptr + index) - '0'); + } else { + + // Syntax error return not found. + return 0; + } + } + } + + return value; + } else { + + // Not a match check for ';' to continue search. + while (*cptr) { + if (*cptr++ == ';') { + goto ContinueSearch; + } + } + + return 0; + } +} // end AtapiParseArgumentString()_ + +/* + Timer callback +*/ +VOID +AtapiCallBack__( + IN PVOID HwDeviceExtension, + IN UCHAR lChannel + ) +{ + + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); + ULONG c, _c; + + PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan); + UCHAR statusByte; + + KdPrint2((PRINT_PREFIX "AtapiCallBack:\n")); + // If the last command was DSC restrictive, see if it's set. If so, the device is + // ready for a new request. Otherwise, reset the timer and come back to here later. + + // If ISR decided to wait for BUSY or DRQ in DPC, we shall also get here. + // In this case chan->ExpectingInterrupt == TRUE, but interrupts are disabled, thus, + // we shall have no problem with interrupt handler. + if (!srb || chan->ExpectingInterrupt) { + KdPrint2((PRINT_PREFIX "AtapiCallBack: Calling ISR directly due to BUSY\n")); + chan->DpcState = DPC_STATE_TIMER; + if(!AtapiInterrupt__(HwDeviceExtension, lChannel)) { + InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); + KdPrint2((PRINT_PREFIX "AtapiCallBack: What's fucking this ???!!!\n")); + } + goto ReturnCallback; + } + +#if DBG + if (!IS_RDP((srb->Cdb[0]))) { + KdPrint2((PRINT_PREFIX "AtapiCallBack: Invalid CDB marked as RDP - %#x\n", srb->Cdb[0])); + } +#endif + if(!(chan->RDP)) { + goto ReturnEnableIntr; + } + GetStatus(chan, statusByte); + if (statusByte & IDE_STATUS_DSC) { + + UCHAR PathId = srb->PathId; + UCHAR TargetId = srb->TargetId; + UCHAR Lun = srb->Lun; + + KdPrint2((PRINT_PREFIX "AtapiCallBack: Found DSC for RDP - %#x\n", srb->Cdb[0])); + AtapiDmaDBSync(chan, srb); + UniataRemoveRequest(chan, srb); + ScsiPortNotification(RequestComplete, deviceExtension, srb); + // Clear current SRB. + if(!deviceExtension->simplexOnly) { + srb = UniataGetCurRequest(chan); + } else { + srb = NULL; + } + chan->RDP = FALSE; + + // Ask for next request. + ScsiPortNotification(NextLuRequest, + deviceExtension, + PathId, + TargetId, + Lun); + ScsiPortNotification(NextRequest, deviceExtension, NULL); + + if(srb) { + AtapiStartIo__(HwDeviceExtension, srb, FALSE); + } + + } else { + KdPrint2((PRINT_PREFIX "AtapiCallBack: Requesting another timer for Op %#x\n", + srb->Cdb[0])); + + AtapiQueueTimerDpc(HwDeviceExtension, lChannel, + AtapiCallBack_X, + 1000); + + goto ReturnCallback; + } + +ReturnEnableIntr: + + if(CrNtInterlockedExchangeAdd(&(chan->DisableIntr), 0)) { + KdPrint2((PRINT_PREFIX "AtapiCallBack: CallDisableInterrupts\n")); + //ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); +#ifdef UNIATA_USE_XXableInterrupts + chan->ChannelCtrlFlags |= CTRFLAGS_ENABLE_INTR_REQ; + // must be called on DISPATCH_LEVEL + ScsiPortNotification(CallDisableInterrupts, HwDeviceExtension, + AtapiEnableInterrupts__); +#else + AtapiEnableInterrupts(HwDeviceExtension, lChannel); + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + // Will raise IRQL to DIRQL + AtapiQueueTimerDpc(HwDeviceExtension, lChannel, + AtapiEnableInterrupts__, + 1); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Timer DPC inited\n")); +#endif // UNIATA_USE_XXableInterrupts + } else { + //ASSERT(!deviceExtension->simplexOnly); + } + +ReturnCallback: + + // Check other channel + // In simplex mode no interrupts must appear on other channels + for(_c=0; _cNumberChannels-1; _c++) { + c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels; + + chan = &(deviceExtension->chan[c]); + + if((ULONG)CrNtInterlockedCompareExchange((PVOID*)&(chan->CheckIntr), + (PVOID)CHECK_INTR_ACTIVE, + (PVOID)CHECK_INTR_DETECTED) == CHECK_INTR_DETECTED) { + //ASSERT(!deviceExtension->simplexOnly); + chan->DpcState = DPC_STATE_ISR; + if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) { + InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); + } + } + } + KdPrint2((PRINT_PREFIX "AtapiCallBack: return\n")); + return; + +} // end AtapiCallBack__() + +VOID +AtapiCallBack_X( + IN PVOID HwDeviceExtension + ) +{ + AtapiCallBack__(HwDeviceExtension, (UCHAR)((PHW_DEVICE_EXTENSION)HwDeviceExtension)->ActiveDpcChan); +} + +#endif //UNIATA_CORE + +/*++ + +Routine Description: + + This is the interrupt service routine for ATAPI IDE miniport driver. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + +Return Value: + + TRUE if expecting an interrupt. + +--*/ +BOOLEAN +DDKAPI +AtapiInterrupt( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG c, _c; + BOOLEAN status = FALSE; + ULONG c_state; + ULONG i_res; + ULONG pass; + BOOLEAN checked[AHCI_MAX_PORT]; + + KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID)); + + for(_c=0; _cNumberChannels; _c++) { + checked[_c] = FALSE; + } +// fc = +// atapiDev = (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE; + for(pass=0; pass<2; pass++) { + for(_c=0; _cNumberChannels; _c++) { + + c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels; + //non_empty_chan = (deviceExtension->lun[c*2].DeviceFlags | deviceExtension->lun[c*2+1].DeviceFlags) + // & DFLAGS_DEVICE_PRESENT; + + if(checked[c]) + continue; + + // check non-empty and execting interrupt channels first + if(!pass && !deviceExtension->chan[c].ExpectingInterrupt) + continue; + + checked[c] = TRUE; + + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c)); + + if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): disabled INTR on ch %d\n", c)); + continue; + } + // lock channel. Wait, while 2nd ISR checks interrupt on this channel + do { + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): try lock\n")); + // c_state = deviceExtension->chan[c].CheckIntr; + // if (deviceExtension->chan[c].CheckIntr == CHECK_INTR_DETECTED) { + // deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE; + // } + c_state = (ULONG)CrNtInterlockedCompareExchange((PVOID*)&(deviceExtension->chan[c].CheckIntr), + (PVOID)CHECK_INTR_ACTIVE, + (PVOID)CHECK_INTR_DETECTED); + if(c_state == CHECK_INTR_IDLE) { + // c_state = deviceExtension->chan[c].CheckIntr; + // if (deviceExtension->chan[c].CheckIntr == CHECK_INTR_IDLE) { + // deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE + // } + c_state = (ULONG)CrNtInterlockedCompareExchange((PVOID*)&(deviceExtension->chan[c].CheckIntr), + (PVOID)CHECK_INTR_ACTIVE, + (PVOID)CHECK_INTR_IDLE); + } + } while(c_state == CHECK_INTR_CHECK); + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): locked\n")); + // check if already serviced + if(c_state == CHECK_INTR_ACTIVE) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): CHECK_INTR_ACTIVE\n")); + continue; + } + + if((c_state == CHECK_INTR_DETECTED) || + (i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c))) { + + if(i_res == 2) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): Catch unexpected\n")); + InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE); + return TRUE; + } + // disable interrupts on other channel of legacy mode + // ISA-bridged onboard controller + if(deviceExtension->simplexOnly /*|| + ((WinVer_Id() > WinVer_NT) && BMList[deviceExtension->DevIndex].MasterDev)*/) { + AtapiDisableInterrupts(deviceExtension, !c); + } + + deviceExtension->chan[c].DpcState = DPC_STATE_ISR; + if(AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) { + deviceExtension->LastInterruptedChannel = (UCHAR)c; + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): return status TRUE\n")); + status = TRUE; + } else { + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): set CHECK_INTR_IDLE\n")); + InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE); + } + + // re-enable interrupts on other channel + if(deviceExtension->simplexOnly /*|| + ((WinVer_Id() > WinVer_NT) && BMList[deviceExtension->DevIndex].MasterDev)*/) { + AtapiEnableInterrupts(deviceExtension, !c); + } + + } else { + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): set CHECK_INTR_IDLE (2)\n")); + InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE); + } + + } + } + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): exit with status %#x\n", status)); + if(status) { + deviceExtension->FirstChannelToCheck++; + if(deviceExtension->FirstChannelToCheck >= deviceExtension->NumberChannels) + deviceExtension->FirstChannelToCheck = 0; + } + return status; +} // end AtapiInterrupt() + +//ULONG i2c = 0; +#ifndef UNIATA_CORE + +BOOLEAN +AtapiInterrupt2( + IN PKINTERRUPT Interrupt, + IN PVOID Isr2HwDeviceExtension + ) +{ + + PISR2_DEVICE_EXTENSION Isr2DeviceExtension = (PISR2_DEVICE_EXTENSION)Isr2HwDeviceExtension; + PHW_DEVICE_EXTENSION deviceExtension = Isr2DeviceExtension->HwDeviceExtension; + ULONG c; + BOOLEAN status = FALSE; + ULONG c_count = 0; + ULONG i_res; + + if(!BMList[deviceExtension->DevIndex].Isr2Enable) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: NOT ACTIVE cntrlr %#x chan %#x\n",deviceExtension->DevIndex, deviceExtension->Channel)); + return FALSE; + } + + for(c=0; cNumberChannels; c++) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c)); + + if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: disabled INTR\n")); + continue; + } + + if((ULONG)CrNtInterlockedCompareExchange((PVOID*)&(deviceExtension->chan[c].CheckIntr), + (PVOID)CHECK_INTR_CHECK, + (PVOID)CHECK_INTR_IDLE) != CHECK_INTR_IDLE) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !CHECK_INTR_IDLE\n")); + // hunt on unexpected intr (Some devices generate double interrupts, + // some controllers (at least CMD649) interrupt twice with small delay. + // If interrupts are disabled, they queue interrupt and re-issue it later, + // when we do not expect it. + continue; + } + + c_count++; + if(i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c)) { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: intr\n")); + if(i_res == 2) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: Catch unexpected\n")); + InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE); + return TRUE; + } + + status = TRUE; + InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_DETECTED); + } else { + InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE); + } + } + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: status %d, c_count %d\n", status, c_count)); + if(status && (c_count != deviceExtension->NumberChannels)) { + // there is an active ISR/DPC for one channel, but + // we have an interrupt from another one + // Lets inform current ISR/DPC about new interrupt + InterlockedExchange(&(deviceExtension->ReCheckIntr), CHECK_INTR_DETECTED); + } else { + status = FALSE; + } + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: return %d\n", status)); + return status; + +} // end AtapiInterrupt2() + +RETTYPE_XXableInterrupts +DDKAPI +AtapiInterruptDpc( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG c; + + for(c=0; cNumberChannels; c++) { + KdPrint2((PRINT_PREFIX "AtapiInterruptDpc: %#x\n",c)); + + if(!(deviceExtension->chan[c].ChannelCtrlFlags & CTRFLAGS_DPC_REQ)) { + + if((ULONG)CrNtInterlockedCompareExchange((PVOID*)&(deviceExtension->chan[c].CheckIntr), + (PVOID)CHECK_INTR_ACTIVE, + (PVOID)CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) { + continue; + } + + } else { + deviceExtension->chan[c].ChannelCtrlFlags &= ~CTRFLAGS_DPC_REQ; + } +/* + if(OldReqState != REQ_STATE_DPC_INTR_REQ) { + AtapiDisableInterrupts(deviceExtension, lChannel); + } +*/ + deviceExtension->chan[c].DpcState = DPC_STATE_DPC; + if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) { + InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE); + } + } + return RETVAL_XXableInterrupts; +} // end AtapiInterruptDpc() + + +RETTYPE_XXableInterrupts +DDKAPI +AtapiEnableInterrupts__( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts__():\n")); + ULONG c; + PHW_CHANNEL chan = NULL; + + for(c=0; cNumberChannels; c++) { + KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts__(2): %#x\n",c)); + chan = &(deviceExtension->chan[c]); + + if(chan->ChannelCtrlFlags & CTRFLAGS_ENABLE_INTR_REQ) { + // enable intrs on requested channel + chan->ChannelCtrlFlags &= ~CTRFLAGS_ENABLE_INTR_REQ; + AtapiEnableInterrupts(HwDeviceExtension, c); + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + // check if current or other channel(s) interrupted + //AtapiInterrupt(HwDeviceExtension); + + if(deviceExtension->simplexOnly) { + break; + } + } else { + // check if other channel(s) interrupted + // must do nothing in simplex mode + if((ULONG)CrNtInterlockedCompareExchange((PVOID*)&(chan->CheckIntr), + (PVOID)CHECK_INTR_ACTIVE, + (PVOID)CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) { + continue; + } + //ASSERT(!deviceExtension->simplexOnly); + chan->DpcState = DPC_STATE_ISR; + if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) { + InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); + } + } + } + // In simplex mode next command must be sent to device here + if(deviceExtension->simplexOnly && chan) { + PSCSI_REQUEST_BLOCK srb; + chan = UniataGetNextChannel(chan); + if(chan) { + srb = UniataGetCurRequest(chan); + } else { + srb = NULL; + } + if(srb) { + AtapiStartIo__(HwDeviceExtension, srb, FALSE); + } + } + + return RETVAL_XXableInterrupts; + +} // end AtapiEnableInterrupts__() + +#endif //UNIATA_CORE + + +VOID +AtapiEnableInterrupts( + IN PVOID HwDeviceExtension, + IN ULONG c + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, deviceExtension->chan[c].DisableIntr)); + if(c >= deviceExtension->NumberChannels) { + return; + } + if(!InterlockedDecrement(&deviceExtension->chan[c].DisableIntr)) { + AtapiWritePort1(&deviceExtension->chan[c], IDX_IO2_o_Control, + IDE_DC_A_4BIT ); + deviceExtension->chan[c].ChannelCtrlFlags &= ~CTRFLAGS_INTR_DISABLED; + } else { + AtapiWritePort1(&deviceExtension->chan[c], IDX_IO2_o_Control, + IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ ); + } + return; +} // end AtapiEnableInterrupts() + +VOID +AtapiDisableInterrupts( + IN PVOID HwDeviceExtension, + IN ULONG c + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: %d\n",c, deviceExtension->chan[c].DisableIntr)); + // mark channel as busy + if(c >= deviceExtension->NumberChannels) { + return; + } + if(InterlockedIncrement(&deviceExtension->chan[c].DisableIntr)) { + AtapiWritePort1(&deviceExtension->chan[c], IDX_IO2_o_Control, + IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ ); + deviceExtension->chan[c].ChannelCtrlFlags |= CTRFLAGS_INTR_DISABLED; + } + + return; +} // end AtapiDisableInterrupts() + + +/* + Check hardware for interrupt state + */ +BOOLEAN +AtapiCheckInterrupt__( + IN PVOID HwDeviceExtension, + IN UCHAR c // logical channel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[c]); + + ULONG VendorID = deviceExtension->DevID & 0xffff; + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + + ULONG status; + ULONG pr_status; + UCHAR dma_status = 0; + UCHAR reg8 = 0; + UCHAR reg32 = 0; + UCHAR statusByte; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + UCHAR Channel; + UCHAR lChannel; + BOOLEAN DmaTransfer = FALSE; + BOOLEAN OurInterrupt = FALSE; + ULONG k; + UCHAR interruptReason; + BOOLEAN EarlyIntr = FALSE; + + KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__:\n")); + + lChannel = c; + Channel = (UCHAR)(deviceExtension->Channel + lChannel); + + if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) { + DmaTransfer = TRUE; + KdPrint2((PRINT_PREFIX " cntrlr %#x:%#x, lch %#x DmaTransfer = TRUE\n", deviceExtension->DevIndex, + deviceExtension->Channel + c, c)); + } else { + KdPrint2((PRINT_PREFIX " cntrlr %#x:%#x, lch %#x DmaTransfer = FALSE\n", deviceExtension->DevIndex, + deviceExtension->Channel + c, c)); + dma_status = GetDmaStatus(deviceExtension, lChannel); + KdPrint2((PRINT_PREFIX " DMA status %#x\n", dma_status)); + } + + // do controller-specific interrupt servicing staff + if(deviceExtension->UnknownDev) { + KdPrint2((PRINT_PREFIX " UnknownDev\n")); + goto check_unknown; + } + + // Attention ! + // We can catch (BM_STATUS_ACTIVE + BM_STATUS_INTR) when operation is actually completed + // Such behavior was observed with Intel ICH-xxx chips + // This condition shall also be treated as 'our interrupt' because of BM_STATUS_INTR flag + + switch(VendorID) { + + case ATA_PROMISE_ID: { + switch(ChipType) { + case PROLD: + case PRNEW: + status = AtapiReadPortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x1c); + if (!DmaTransfer) + break; + if (!(status & + ((Channel) ? 0x00004000 : 0x00000400))) { + KdPrint2((PRINT_PREFIX " Promise old/new unexpected\n")); + return FALSE; + } + break; + case PRTX: + AtapiWritePort1(chan, IDX_BM_DeviceSpecific0, 0x0b); + status = AtapiReadPort1(chan, IDX_BM_DeviceSpecific1); + if (!DmaTransfer) + break; + if(!(status & 0x20)) { + KdPrint2((PRINT_PREFIX " Promise tx unexpected\n")); + return FALSE; + } + break; + case PRMIO: + status = AtapiReadPortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x0040); + if(ChipFlags & PRSATA) { + pr_status = AtapiReadPortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x006c); + AtapiWritePortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x006c, pr_status & 0x000000ff); + } + if(pr_status & (0x11 << Channel)) { + // TODO: reset channel + KdPrint2((PRINT_PREFIX " Promise mio unexpected + reset req\n")); + return FALSE; + } + if(!(status & (0x01 << Channel))) { + KdPrint2((PRINT_PREFIX " Promise mio unexpected\n")); + return FALSE; + } + AtapiWritePort4(chan, IDX_BM_DeviceSpecific0, 0x00000001); + break; + } + break; } + case ATA_NVIDIA_ID: { + if(!(ChipFlags & UNIATA_SATA)) + break; + + KdPrint2((PRINT_PREFIX "NVIDIA\n")); + + ULONG offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010; + ULONG shift = Channel << ((ChipFlags & NVQ) ? 4 : 2); + + /* get and clear interrupt status */ + if(ChipFlags & NVQ) { + pr_status = AtapiReadPortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs); + AtapiWritePortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0fUL << shift) | 0x00f000f0); + } else { + pr_status = AtapiReadPortEx1(chan, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs); + AtapiWritePortEx1(chan, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0f << shift)); + } + KdPrint2((PRINT_PREFIX " pr_status %x\n", pr_status)); + + /* check for and handle connect events */ + if(((pr_status & (0x0cUL << shift)) == (0x04UL << shift)) ) { + UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH); + } + /* check for and handle disconnect events */ + if((pr_status & (0x08UL << shift)) && + !((pr_status & (0x04UL << shift) && + AtapiReadPort4(chan, IDX_SATA_SStatus))) ) { + UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH); + } + /* do we have any device action ? */ + if(!(pr_status & (0x01UL << shift))) { + KdPrint2((PRINT_PREFIX " nVidia unexpected\n")); + if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) { + OurInterrupt = 2; + } else { + return FALSE; + } + } + + break; } + case ATA_ATI_ID: + KdPrint2((PRINT_PREFIX "ATI\n")); + if(ChipType == SIIMIO) { + // fall to SiI + } else { + break; + } + case ATA_SILICON_IMAGE_ID: + + if(ChipType == SIIMIO) { + + reg32 = AtapiReadPort1(chan, IDX_BM_DeviceSpecific0); + KdPrint2((PRINT_PREFIX " Sii DS0 %x\n", reg32)); + if(reg32 == 0xffffffff) { + KdPrint2((PRINT_PREFIX " Sii mio unexpected\n")); + return FALSE; + } + if(!(reg32 & (BM_DS0_SII_DMA_SATA_IRQ | BM_DS0_SII_DMA_COMPLETE | BM_DS0_SII_IRQ | BM_DS0_SII_DMA_ENABLE | BM_DS0_SII_DMA_ERROR))) { + KdPrint2((PRINT_PREFIX " Sii mio unexpected (2)\n")); + return FALSE; + } + + if(ChipFlags & UNIATA_SATA) { + if(reg32 & (BM_DS0_SII_DMA_SATA_IRQ | BM_DS0_SII_IRQ)) { + + /* SIEN doesn't mask SATA IRQs on some 3112s. Those + * controllers continue to assert IRQ as long as + * SError bits are pending. Clear SError immediately. + */ + if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) { + OurInterrupt = 2; + } + } + } + + if (!DmaTransfer) + break; + if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) { + KdPrint2((PRINT_PREFIX " Sii mio unexpected (3)\n")); + return OurInterrupt; + } + AtapiWritePort1(chan, IDX_BM_Status, dma_status & ~BM_STATUS_ERR); + goto skip_dma_stat_check; + + } else { + if(!(deviceExtension->HwFlags & SIIINTR)) + break; + GetPciConfig1(0x71, reg8); + KdPrint2((PRINT_PREFIX " 0x71 = %#x\n", reg8)); + if (!(reg8 & + (Channel ? 0x08 : 0x04))) { + return FALSE; + } + if (!DmaTransfer) { + KdPrint2((PRINT_PREFIX " cmd our\n")); + OurInterrupt = 2; + } + SetPciConfig1(0x71, (Channel ? 0x08 : 0x04)); + } + break; + + case ATA_ACARD_ID: + if (!DmaTransfer) + break; + //dma_status = GetDmaStatus(deviceExtension, lChannel); + if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) { + KdPrint2((PRINT_PREFIX " Acard unexpected\n")); + return FALSE; + } + AtapiWritePort1(chan, IDX_BM_Status, dma_status | BM_STATUS_INTR); + AtapiStallExecution(1); + AtapiWritePort1(chan, IDX_BM_Command, + AtapiReadPort1(chan, IDX_BM_Command) & ~BM_COMMAND_START_STOP); + goto skip_dma_stat_check; + default: + if(deviceExtension->BaseIoAddressSATA_0.Addr && + (ChipFlags & UNIATA_SATA)) { + if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) { + OurInterrupt = 2; + } + } + } +check_unknown: + KdPrint2((PRINT_PREFIX " perform generic check\n")); + if (DmaTransfer) { + if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) { + KdPrint2((PRINT_PREFIX " DmaTransfer + !BM_STATUS_INTR (%x)\n", dma_status)); + if(dma_status & BM_STATUS_ERR) { + KdPrint2((PRINT_PREFIX " DmaTransfer + BM_STATUS_ERR -> our\n")); + OurInterrupt = 2; + } else { + KdPrint2((PRINT_PREFIX " getting status...\n")); + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX " status %#x\n", statusByte)); + if(statusByte & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX " IDE_STATUS_ERROR -> our\n", statusByte)); + OurInterrupt = 2; + } else { + return FALSE; + } + } + } + } else { + if(dma_status & BM_STATUS_INTR) { + // bullshit, we have DMA interrupt, but had never initiate DMA operation + KdPrint2((PRINT_PREFIX " clear unexpected DMA intr\n")); + AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL); + // catch it ! + OurInterrupt = 2; + } + } +skip_dma_stat_check: + if(!(ChipFlags & UNIATA_SATA)) { + AtapiStallExecution(1); + } + + /* if drive is busy it didn't interrupt */ + /* the exception is DCS + BSY state of ATAPI dvices */ + KdPrint2((PRINT_PREFIX " getting status...\n")); + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX " status %#x\n", statusByte)); + if (statusByte == 0xff) { + // interrupt from empty controller ? + } else + if (statusByte & IDE_STATUS_BUSY) { + if(!chan->ExpectingInterrupt) { + KdPrint2((PRINT_PREFIX " unexpected intr + BUSY\n")); + return OurInterrupt; + } + + if(deviceExtension->lun[c*2 + chan->cur_cdev].DeviceFlags & DFLAGS_ATAPI_DEVICE) { + KdPrint2((PRINT_PREFIX " ATAPI additional check\n")); + } else { + KdPrint2((PRINT_PREFIX " expecting intr + BUSY (3), non ATAPI\n")); + return FALSE; + } + if(statusByte != (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) { + KdPrint2((PRINT_PREFIX " unexpected status, seems it is not our\n")); + return FALSE; + } + + EarlyIntr = TRUE; + + if(dma_status & BM_STATUS_INTR) { + KdPrint2((PRINT_PREFIX " our interrupt with BSY set, try wait in ISR or post to DPC\n")); + /* clear interrupt and get status */ + GetBaseStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX " base status %#x\n", statusByte)); + return TRUE; + } + + if(g_WaitBusyInISR) { + for(k=20; k; k--) { + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte)); + KdPrint2((PRINT_PREFIX " Error reg (%#x)\n", + AtapiReadPort1(chan, IDX_IO1_i_Error))); + if (!(statusByte & IDE_STATUS_BUSY)) { + KdPrint2((PRINT_PREFIX " expecting intr + cleared BUSY\n")); + break; + } + break; + //AtapiStallExecution(25); + } + if (statusByte & IDE_STATUS_BUSY) { + KdPrint2((PRINT_PREFIX " still BUSY, seems it is not our\n")); + return FALSE; + } + } + + } + + /* clear interrupt and get status */ + GetBaseStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX " base status %#x\n", statusByte)); + if (statusByte == 0xff) { + // interrupt from empty controller ? + } else + if(!(statusByte & (IDE_STATUS_DRQ | IDE_STATUS_DRDY))) { + KdPrint2((PRINT_PREFIX " no DRQ/DRDY set\n")); + return OurInterrupt; + } + +#ifndef UNIATA_PIO_ONLY + if(DmaTransfer) { + if(!EarlyIntr || g_WaitBusyInISR) { + dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/); + } else { + PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan); + PATA_REQ AtaReq = srb ? (PATA_REQ)(srb->SrbExtension) : NULL; + + //ASSERT(AtaReq); + + KdPrint2((PRINT_PREFIX " set REQ_STATE_EARLY_INTR.\n")); + if(AtaReq) { + AtaReq->ReqState = REQ_STATE_EARLY_INTR; + } + } + } +#endif // + + if (!(chan->ExpectingInterrupt)) { + + KdPrint2((PRINT_PREFIX " Unexpected interrupt.\n")); + + if(deviceExtension->lun[c*2 + chan->cur_cdev * 2].DeviceFlags & DFLAGS_ATAPI_DEVICE) { + KdPrint2((PRINT_PREFIX " ATAPI additional check\n")); + } else { + KdPrint2((PRINT_PREFIX " OurInterrupt = %d\n", OurInterrupt)); + return OurInterrupt; + } + interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3); + KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__: ATAPI int reason %x\n", interruptReason)); + return OurInterrupt; + } + //ASSERT(!chan->queue_depth || chan->cur_req); + + KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__: exit with TRUE\n")); + return TRUE; + +} // end AtapiCheckInterrupt__() + + +BOOLEAN +AtapiInterrupt__( + IN PVOID HwDeviceExtension, + IN UCHAR c + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[c]); + // Get current Srb + PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan); + PATA_REQ AtaReq = srb ? (PATA_REQ)(srb->SrbExtension) : NULL; + + ULONG wordCount = 0, wordsThisInterrupt = DEV_BSIZE/2; + ULONG status; + UCHAR dma_status = 0; + ULONG i; + ULONG k; + UCHAR statusByte,interruptReason; + + BOOLEAN atapiDev = FALSE; + + UCHAR Channel; + UCHAR lChannel; + UCHAR DeviceNumber; + BOOLEAN DmaTransfer = FALSE; + UCHAR error = 0; + ULONG TimerValue = 1000; +#ifdef UNIATA_USE_XXableInterrupts + BOOLEAN InDpc = (KeGetCurrentIrql() == DISPATCH_LEVEL); +#else + BOOLEAN InDpc = (chan->DpcState != DPC_STATE_ISR); +#endif // UNIATA_USE_XXableInterrupts + BOOLEAN UseDpc = deviceExtension->UseDpc; +// BOOLEAN RestoreUseDpc = FALSE; + BOOLEAN DataOverrun = FALSE; + BOOLEAN NoStartIo = TRUE; + + KdPrint2((PRINT_PREFIX "AtapiInterrupt:\n")); + if(InDpc) { + KdPrint2((PRINT_PREFIX " InDpc = TRUE\n")); + //ASSERT((chan->ChannelCtrlFlags & CTRFLAGS_INTR_DISABLED)); + } + + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR OldReqState = REQ_STATE_NONE; + ULONG ldev; + PHW_LU_EXTENSION LunExt; + + lChannel = c; + Channel = (UCHAR)(deviceExtension->Channel + lChannel); + + KdPrint2((PRINT_PREFIX " cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c)); + + if((chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) || + (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ) { + DmaTransfer = TRUE; + KdPrint2((PRINT_PREFIX " DmaTransfer = TRUE\n")); + } + + if (srb) { + PathId = srb->PathId; + TargetId = srb->TargetId; + Lun = srb->Lun; + } else { + PathId = (UCHAR)c; + TargetId = + Lun = 0; + goto enqueue_next_req; + } + + ldev = GET_LDEV2(PathId, TargetId, Lun); + DeviceNumber = (UCHAR)(ldev & 1); + LunExt = &(deviceExtension->lun[ldev]); + atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE; + KdPrint2((PRINT_PREFIX " dev_type %s\n", atapiDev ? "ATAPI" : "IDE")); + + // check if we are in ISR DPC + if(InDpc) { + KdPrint2((PRINT_PREFIX " InDpc -> CTRFLAGS_INTR_DISABLED\n")); + goto ServiceInterrupt; + } + + if (DmaTransfer) { + dma_status = GetDmaStatus(deviceExtension, lChannel); + } + + if (!(chan->ExpectingInterrupt)) { + + KdPrint2((PRINT_PREFIX " Unexpected interrupt for this channel.\n")); + return FALSE; + } + + // change request state + if(AtaReq) { + OldReqState = AtaReq->ReqState; + AtaReq->ReqState = REQ_STATE_PROCESSING_INTR; + KdPrint2((PRINT_PREFIX " OldReqState = %x\n", OldReqState)); + } + + // We don't want using DPC for fast operations, like + // DMA completion, sending CDB, short ATAPI transfers, etc. + // !!!! BUT !!!! + // We MUST use DPC, because of interprocessor synchronization + // on multiprocessor platforms + + if(DmaTransfer) + goto ServiceInterrupt; + + switch(OldReqState) { + case REQ_STATE_ATAPI_EXPECTING_CMD_INTR: + case REQ_STATE_ATAPI_EXPECTING_DATA_INTR: + case REQ_STATE_DPC_WAIT_BUSY0: + case REQ_STATE_DPC_WAIT_BUSY1: + KdPrint2((PRINT_PREFIX " continue service interrupt\n")); + goto ServiceInterrupt; + case REQ_STATE_ATAPI_DO_NOTHING_INTR: + KdPrint2((PRINT_PREFIX " do nothing on interrupt\n")); + return TRUE; + } + + if(!DmaTransfer && !atapiDev) { + KdPrint2((PRINT_PREFIX " service PIO HDD\n")); + UseDpc = FALSE; + } + +#ifndef UNIATA_CORE + + if(!UseDpc) + goto ServiceInterrupt; + +#ifdef UNIATA_USE_XXableInterrupts + if(InDpc) { + KdPrint2((PRINT_PREFIX " Unexpected InDpc\n")); + ASSERT(FALSE); + // shall never get here + TimerValue = 1; + goto CallTimerDpc; + } + + KdPrint2((PRINT_PREFIX " this is direct DPC call on DRQL\n")); + if(AtaReq) { + AtaReq->ReqState = REQ_STATE_DPC_INTR_REQ; + KdPrint2((PRINT_PREFIX " ReqState -> REQ_STATE_DPC_INTR_REQ\n")); + } else { + KdPrint2((PRINT_PREFIX " DPC without AtaReq!!!\n")); + } +#else + KdPrint2((PRINT_PREFIX "call service interrupt\n")); + goto ServiceInterrupt; +#endif // UNIATA_USE_XXableInterrupts + +PostToDpc: + + // Attention !!! + // AtapiInterruptDpc() is called on DISPATCH_LEVEL + // We always get here when are called from timer callback, which is invoked on DRQL. + // It is intended to lower IRQL and let other interrupts to be serviced while we are waiting for BUSY release + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: start DPC init...\n")); + // disable interrupts for this channel, + // but avoid recursion and double-disable + if(OldReqState != REQ_STATE_DPC_WAIT_BUSY1) { + AtapiDisableInterrupts(deviceExtension, lChannel); + } + // go to ISR DPC + chan->ChannelCtrlFlags |= CTRFLAGS_DPC_REQ; + +#ifdef UNIATA_USE_XXableInterrupts + // Will lower IRQL to DISPATCH_LEVEL + ScsiPortNotification(CallEnableInterrupts, HwDeviceExtension, + /*c ?*/ AtapiInterruptDpc/*_1 : AtapiInterruptDpc_0*/); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: DPC inited\n")); +#else + // Will raise IRQL to DIRQL + AtapiQueueTimerDpc(HwDeviceExtension, c, + AtapiInterruptDpc, + TimerValue); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Timer DPC inited\n")); +#endif // UNIATA_USE_XXableInterrupts + return TRUE; + +#ifndef UNIATA_CORE +CallTimerDpc: + AtaReq->ReqState = REQ_STATE_PROCESSING_INTR; +CallTimerDpc2: + // Will raise IRQL to DIRQL + AtapiQueueTimerDpc(HwDeviceExtension, c, + AtapiCallBack_X, + TimerValue); + return TRUE; +#endif //UNIATA_CORE + +ServiceInterrupt: + + if(AtaReq && InDpc) { + switch(AtaReq->ReqState) { + case REQ_STATE_DPC_WAIT_DRQ0: + goto PIO_wait_DRQ0; + case REQ_STATE_DPC_WAIT_BUSY: + goto PIO_wait_busy; + case REQ_STATE_DPC_WAIT_DRQ: + goto PIO_wait_DRQ; + case REQ_STATE_DPC_WAIT_DRQ_ERR: + goto continue_err; + case REQ_STATE_DPC_WAIT_BUSY0: + case REQ_STATE_DPC_WAIT_BUSY1: + // continue normal execution + break; + } + } +#else +ServiceInterrupt: +#endif //UNIATA_CORE + + // make additional delay for old devices (if we are not in DPC) + if((!LunExt->IdentifyData.MajorRevision || (deviceExtension->lun[DeviceNumber].TransferMode < ATA_PIO4)) + && + !InDpc && + !atapiDev && + !(deviceExtension->HwFlags & UNIATA_SATA) + ) { + KdPrint2((PRINT_PREFIX " additional delay 10us for old devices\n")); + AtapiStallExecution(10); + } + + /* clear interrupt and get status */ + GetBaseStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Entered with status (%#x)\n", statusByte)); + + if(!UseDpc) { + KdPrint2((PRINT_PREFIX " operate like in DPC\n")); + InDpc = TRUE; + } + + if (!atapiDev) { + // IDE + if (statusByte & IDE_STATUS_BUSY) { + if (deviceExtension->DriverMustPoll) { + // Crashdump is polling and we got caught with busy asserted. + // Just go away, and we will be polled again shortly. + KdPrint2((PRINT_PREFIX " Hit BUSY while polling during crashdump.\n")); + goto ReturnEnableIntr; + } +try_dpc_wait: + // Ensure BUSY is non-asserted. + // make a very small idle before falling to DPC + k = (InDpc && UseDpc) ? 1000 : 2; + + for (i = 0; i < k; i++) { + + GetBaseStatus(chan, statusByte); + if (!(statusByte & IDE_STATUS_BUSY)) { + break; + } + AtapiStallExecution(10); + } + + if (!InDpc && UseDpc && i == 2) { + + KdPrint2((PRINT_PREFIX " BUSY on entry. Status %#x, Base IO %#x\n", statusByte)); + + TimerValue = 50; + AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0; + +#ifndef UNIATA_CORE + goto PostToDpc; +#else UNIATA_CORE + AtapiStallExecution(TimerValue); + goto ServiceInterrupt; +#endif //UNIATA_CORE + } else + if (InDpc && i == k) { + // reset the controller. + KdPrint2((PRINT_PREFIX + " Resetting due to BUSY on entry - %#x.\n", + statusByte)); + goto IntrPrepareResetController; + } + } + } else { + // ATAPI + if(!LunExt->IdentifyData.MajorRevision && + InDpc && + !atapiDev && + !(deviceExtension->HwFlags & UNIATA_SATA) + ) { + KdPrint2((PRINT_PREFIX " additional delay 10us for old devices (2)\n")); + AtapiStallExecution(10); + } + if (statusByte & IDE_STATUS_BUSY) { + //if(chan->ChannelCtrlFlags & CTRFLAGS_DSC_BSY) { + KdPrint2((PRINT_PREFIX " BUSY on ATAPI device, waiting\n")); + for(k=20; k; k--) { + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte)); + KdPrint2((PRINT_PREFIX " Error reg (%#x)\n", + AtapiReadPort1(chan, IDX_IO1_i_Error))); + if (!(statusByte & IDE_STATUS_BUSY)) { + KdPrint2((PRINT_PREFIX " expecting intr + cleared BUSY\n")); + break; + } + if(k <= 18) { + KdPrint2((PRINT_PREFIX " too long wait -> DPC\n")); + if(!InDpc) { + KdPrint2((PRINT_PREFIX " too long wait: ISR -> DPC\n")); + TimerValue = 100; + AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0; + } else { + KdPrint2((PRINT_PREFIX " too long wait: DPC -> DPC\n")); + TimerValue = 1000; + AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY1; + } +#ifndef UNIATA_CORE + goto CallTimerDpc2; +#else UNIATA_CORE + AtapiStallExecution(TimerValue); +#endif //UNIATA_CORE + } + + AtapiStallExecution(10); + } + if (statusByte & IDE_STATUS_BUSY) { + KdPrint2((PRINT_PREFIX " expecting intr + BUSY (2), try DPC wait\n")); + goto try_dpc_wait; + } + } + } + + if(AtaReq && DmaTransfer) { + switch(OldReqState) { + case REQ_STATE_EARLY_INTR: + case REQ_STATE_DPC_WAIT_BUSY0: + + if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: DMA still active\n")); + dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/); + } + break; + } + } + +//retry_check: + // Check for error conditions. + if ((statusByte & IDE_STATUS_ERROR) || + (dma_status & BM_STATUS_ERR)) { + + error = AtapiReadPort1(chan, IDX_IO1_i_Error); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Error %#x\n", error)); +/* + if(error & IDE_STATUS_CORRECTED_ERROR) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: (corrected)\n")); + statusByte &= ~IDE_STATUS_ERROR; + goto retry_check; + } +*/ + if(AtaReq) { + KdPrint2((PRINT_PREFIX " Bad Lba %#I64x\n", AtaReq->lba)); + } else { + KdPrint2((PRINT_PREFIX " Bad Lba unknown\n")); + } + + KdPrint2((PRINT_PREFIX " wait ready after error\n")); + + if(!atapiDev) { + AtapiStallExecution(100); + } else { + AtapiStallExecution(10); + } +continue_err: + + KdPrint2((PRINT_PREFIX " Intr on DRQ %x\n", + LunExt->DeviceFlags & DFLAGS_INT_DRQ)); + + for (k = atapiDev ? 0 : 200; k; k--) { + GetStatus(chan, statusByte); + if (!(statusByte & IDE_STATUS_DRQ)) { + AtapiStallExecution(50); + } else { + break; + } + } + + if (!atapiDev) { + /* if this is a UDMA CRC error, reinject request */ + + AtaReq->retry++; + if(AtaReq->retry < MAX_RETRIES) { +#ifdef IO_STATISTICS + chan->lun[DeviceNumber]->ModeErrorCount[AtaReq->retry]++; +#endif //IO_STATISTICS + if(DmaTransfer /*&& + (error & IDE_ERROR_ICRC)*/) { + if(AtaReq->retry < MAX_RETRIES) { +//fallback_pio: + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE; +// LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE; + AtaReq->ReqState = REQ_STATE_QUEUED; + goto reenqueue_req; + } + } else { + if(!(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE)) { + AtaReq->retry++; + } + KdPrint2((PRINT_PREFIX "Errors in PIO mode\n")); + } + } + } else { + interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: ATAPI Error, int reason %x\n", interruptReason)); + } + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Error\n")); + if (srb->Cdb[0] != SCSIOP_REQUEST_SENSE) { + // Fail this request. + status = SRB_STATUS_ERROR; + goto CompleteRequest; + } else { + KdPrint2((PRINT_PREFIX " continue with SCSIOP_REQUEST_SENSE\n")); + } +#ifdef IO_STATISTICS + } else + if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE_LBA48) { + KdPrint2((PRINT_PREFIX "DMA doesn't work right with LBA48\n")); + deviceExtension->HbaCtrlFlags |= HBAFLAGS_DMA_DISABLED_LBA48; + } else + if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE) { + KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n")); + chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry]++; + if(chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->IoCount/3) { + deviceExtension->lun[DeviceNumber].LimitedTransferMode = + deviceExtension->lun[DeviceNumber].TransferMode; + } +#endif //IO_STATISTICS + } +#ifdef IO_STATISTICS + chan->lun[DeviceNumber]->IoCount++; +#endif //IO_STATISTICS + +continue_PIO: + + // check reason for this interrupt. + if (atapiDev) { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: ATAPI branch\n")); + // ATAPI branch + + interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason)); + if(DmaTransfer) { + wordsThisInterrupt = DEV_BSIZE/2*512; + } else { + wordsThisInterrupt = DEV_BSIZE; + } + + } else { + + // ATA branch + + if(DmaTransfer) { + // simulate DRQ for DMA transfers + statusByte |= IDE_STATUS_DRQ; + } + if (statusByte & IDE_STATUS_DRQ) { + + if(DmaTransfer) { + wordsThisInterrupt = DEV_BSIZE/2*512; + } else + if (LunExt->MaximumBlockXfer) { + wordsThisInterrupt = DEV_BSIZE/2 * LunExt->MaximumBlockXfer; + } + + if (srb->SrbFlags & SRB_FLAGS_DATA_IN) { + + interruptReason = 0x2; + + } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) { + interruptReason = 0x0; + + } else { + status = SRB_STATUS_ERROR; + goto CompleteRequest; + } + + } else if (statusByte & IDE_STATUS_BUSY) { + + //AtapiEnableInterrupts(deviceExtension, lChannel); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: return FALSE on ATA IDE_STATUS_BUSY\n")); + return FALSE; + + } else { + + if (AtaReq->WordsLeft) { + + // Funky behaviour seen with PCI IDE (not all, just one). +PIO_wait_DRQ0: + // The ISR hits with DRQ low, but comes up later. + for (k = 0; k < 5000; k++) { + GetStatus(chan, statusByte); + if (statusByte & IDE_STATUS_DRQ) { + break; + } + if(!InDpc) { + // goto DPC + AtaReq->ReqState = REQ_STATE_DPC_WAIT_DRQ0; + TimerValue = 100; + KdPrint2((PRINT_PREFIX "AtapiInterrupt: go to DPC (drq0)\n")); +#ifndef UNIATA_CORE + goto PostToDpc; +#else UNIATA_CORE + AtapiStallExecution(TimerValue); + goto ServiceInterrupt; +#endif //UNIATA_CORE + } + AtapiStallExecution(100); + } + if (k == 5000) { + // reset the controller. + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Resetting due to DRQ not up. Status %#x\n", + statusByte)); +IntrPrepareResetController: + AtapiResetController__(HwDeviceExtension, lChannel, RESET_COMPLETE_CURRENT); + goto ReturnEnableIntr; + + } else { + interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 : 0x0; + } + + } else { + // Command complete - verify, write, or the SMART enable/disable. + // Also get_media_status + interruptReason = 0x3; + } + } + } + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: i-reason=%d, status=%#x\n", interruptReason, statusByte)); + if (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) { + // Write the packet. + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Writing Atapi packet.\n")); + // Send CDB to device. + WriteBuffer(chan, (PUSHORT)srb->Cdb, 6, 0); + AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; + + if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: AtapiDmaStart().\n")); + AtapiDmaStart(HwDeviceExtension, ldev & 1, lChannel, srb); + } + + goto ReturnEnableIntr; + + } else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) { + + // Write the data. + if (atapiDev) { + + // Pick up bytes to transfer and convert to words. + wordCount = + AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow); + + wordCount |= + AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8; + + // Covert bytes to words. + wordCount >>= 1; + KdPrint2((PRINT_PREFIX "AtapiInterrupt: get W wordCount %#x\n", wordCount)); + + if (wordCount != AtaReq->WordsLeft) { + KdPrint2((PRINT_PREFIX + "AtapiInterrupt: %d words requested; %d words xferred\n", + AtaReq->WordsLeft, + wordCount)); + } + + // Verify this makes sense. + if (wordCount > AtaReq->WordsLeft) { + wordCount = AtaReq->WordsLeft; + KdPrint2((PRINT_PREFIX + "AtapiInterrupt: Write underrun\n")); + DataOverrun = TRUE; + } + + } else { + + // IDE path. Check if words left is at least DEV_BSIZE/2 = 256. + if (AtaReq->WordsLeft < wordsThisInterrupt) { + + // Transfer only words requested. + wordCount = AtaReq->WordsLeft; + + } else { + + // Transfer next block. + wordCount = wordsThisInterrupt; + } + } + + if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) { + //ASSERT(AtaReq->WordsLeft == wordCount); + AtaReq->WordsLeft = 0; + status = SRB_STATUS_SUCCESS; + chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; + goto CompleteRequest; + } + // Ensure that this is a write command. + if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) { + + KdPrint2((PRINT_PREFIX + "AtapiInterrupt: Write interrupt\n")); + + statusByte = WaitOnBusy(chan); + + if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) { + + WriteBuffer(chan, + AtaReq->DataBuffer, + wordCount, + UniataGetPioTiming(LunExt)); + } else { + + WriteBuffer2(chan, + (PULONG)(AtaReq->DataBuffer), + wordCount / 2, + UniataGetPioTiming(LunExt)); + } + } else { + + KdPrint2((PRINT_PREFIX + "AtapiInterrupt: Int reason %#x, but srb is for a write %#x.\n", + interruptReason, + srb)); + + // Fail this request. + status = SRB_STATUS_ERROR; + goto CompleteRequest; + } + + // Advance data buffer pointer and bytes left. + AtaReq->DataBuffer += wordCount; + AtaReq->WordsLeft -= wordCount; + + if (atapiDev) { + AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; + } + + goto ReturnEnableIntr; + + } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) { + + + if (atapiDev) { + + // Pick up bytes to transfer and convert to words. + wordCount = + AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) | + (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8); + + // Covert bytes to words. + wordCount >>= 1; + KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount)); + + if (wordCount != AtaReq->WordsLeft) { + KdPrint2((PRINT_PREFIX + "AtapiInterrupt: %d words requested; %d words xferred\n", + AtaReq->WordsLeft, + wordCount)); + } + + // Verify this makes sense. + if (wordCount > AtaReq->WordsLeft) { + wordCount = AtaReq->WordsLeft; + DataOverrun = TRUE; + } + + } else { + + // Check if words left is at least 256. + if (AtaReq->WordsLeft < wordsThisInterrupt) { + + // Transfer only words requested. + wordCount = AtaReq->WordsLeft; + + } else { + + // Transfer next block. + wordCount = wordsThisInterrupt; + } + } + + if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) { + //ASSERT(AtaReq->WordsLeft == wordCount); + AtaReq->WordsLeft = 0; + status = SRB_STATUS_SUCCESS; + chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; + goto CompleteRequest; + } + // Ensure that this is a read command. + if (srb->SrbFlags & SRB_FLAGS_DATA_IN) { + +/* KdPrint2(( + "AtapiInterrupt: Read interrupt\n"));*/ + + statusByte = WaitOnBusy(chan); + + if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) { + KdPrint2((PRINT_PREFIX + "IdeIntr: Read %#x words\n", wordCount)); + + ReadBuffer(chan, + AtaReq->DataBuffer, + wordCount, + UniataGetPioTiming(LunExt)); + KdPrint2(("IdeIntr: PIO Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x\n", AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)-1) )); + //KdDump(AtaReq->DataBuffer, wordCount*2); + + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte)); + + if(DataOverrun) { + KdPrint2((PRINT_PREFIX " DataOverrun\n")); + AtapiSuckPort2(chan); + } + + } else { + KdPrint2((PRINT_PREFIX + "IdeIntr: Read %#x Dwords\n", wordCount/2)); + + ReadBuffer2(chan, + (PULONG)(AtaReq->DataBuffer), + wordCount / 2, + UniataGetPioTiming(LunExt)); + } + } else { + + KdPrint2((PRINT_PREFIX + "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n", + interruptReason, + srb)); + + // Fail this request. + status = SRB_STATUS_ERROR; + goto CompleteRequest; + } + + // Advance data buffer pointer and bytes left. + AtaReq->DataBuffer += wordCount; + AtaReq->WordsLeft -= wordCount; + + // Check for read command complete. + if (AtaReq->WordsLeft == 0) { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: all transferred, AtaReq->WordsLeft == 0\n")); + if (atapiDev) { + + // Work around to make many atapi devices return correct sector size + // of 2048. Also certain devices will have sector count == 0x00, check + // for that also. + if ((srb->Cdb[0] == SCSIOP_READ_CAPACITY) && + (LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM)) { + + AtaReq->DataBuffer -= wordCount; + if (AtaReq->DataBuffer[0] == 0x00) { + + *((ULONG *) &(AtaReq->DataBuffer[0])) = 0xFFFFFF7F; + + } + + *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000; + AtaReq->DataBuffer += wordCount; + } + } else { + + /* + // Completion for IDE drives. + if (AtaReq->WordsLeft) { + status = SRB_STATUS_DATA_OVERRUN; + } else { + status = SRB_STATUS_SUCCESS; + } + + goto CompleteRequest; + */ + status = SRB_STATUS_SUCCESS; + goto CompleteRequest; + + } + } else { + if (atapiDev) { + AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; + } + } + + goto ReturnEnableIntr; + + } else if (interruptReason == 0x3 && !(statusByte & IDE_STATUS_DRQ)) { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: interruptReason = CompleteRequest\n")); + // Command complete. + if(DmaTransfer) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was DmaTransfer\n")); + AtaReq->WordsLeft = 0; + } + if (AtaReq->WordsLeft) { + status = SRB_STATUS_DATA_OVERRUN; + } else { + status = SRB_STATUS_SUCCESS; + } + +#ifdef UNIATA_DUMP_ATAPI + if(srb && + srb->SrbFlags & SRB_FLAGS_DATA_IN) { + UCHAR ScsiCommand; + PCDB Cdb; + PCHAR CdbData; + PCHAR ModeSelectData; + ULONG CdbDataLen; + PSCSI_REQUEST_BLOCK Srb = srb; + + Cdb = (PCDB)(Srb->Cdb); + ScsiCommand = Cdb->CDB6.OperationCode; + CdbData = (PCHAR)(Srb->DataBuffer); + CdbDataLen = Srb->DataTransferLength; + + if(CdbDataLen > 0x1000) { + CdbDataLen = 0x1000; + } + + KdPrint(("--\n")); + KdPrint2(("VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID)); + KdPrint2(("P:T:D=%d:%d:%d\n", + Srb->PathId, + Srb->TargetId, + Srb->Lun)); + KdPrint(("Complete SCSI Command %2.2x\n", ScsiCommand)); + KdDump(Cdb, 16); + + if(ScsiCommand == SCSIOP_MODE_SENSE) { + KdPrint(("ModeSense 6\n")); + PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData; + ModeSelectData = CdbData+4; + KdDump(CdbData, CdbDataLen); + } else + if(ScsiCommand == SCSIOP_MODE_SENSE10) { + KdPrint(("ModeSense 10\n")); + PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData; + ModeSelectData = CdbData+8; + KdDump(CdbData, CdbDataLen); + } else { + if(srb->SrbFlags & SRB_FLAGS_DATA_IN) { + KdPrint(("Read buffer from device:\n")); + KdDump(CdbData, CdbDataLen); + } + } + KdPrint(("--\n")); + } +#endif //UNIATA_DUMP_ATAPI + +CompleteRequest: + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest\n")); + // Check and see if we are processing our secret (mechanism status/request sense) srb + if (AtaReq->OriginalSrb) { + + ULONG srbStatus; + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: OriginalSrb != NULL\n")); + if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: SCSIOP_MECHANISM_STATUS status %#x\n", status)); + if (status == SRB_STATUS_SUCCESS) { + // Bingo!! + AtapiHwInitializeChanger (HwDeviceExtension, + srb, + (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer); + + // Get ready to issue the original srb + srb = AtaReq->Srb = AtaReq->OriginalSrb; + AtaReq->OriginalSrb = NULL; + + } else { + // failed! Get the sense key and maybe try again + srb = AtaReq->Srb = BuildRequestSenseSrb ( + HwDeviceExtension, + AtaReq->OriginalSrb); + } +/* + // do not enable interrupts in DPC, do not waste time, do it now! + if(UseDpc && chan->DisableIntr) { + AtapiEnableInterrupts(HwDeviceExtension, c); + UseDpc = FALSE; + RestoreUseDpc = TRUE; + } +*/ + srbStatus = AtapiSendCommand(HwDeviceExtension, srb, CMD_ACTION_ALL); + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: chan->ExpectingInterrupt %d (1)\n", chan->ExpectingInterrupt)); + + if (srbStatus == SRB_STATUS_PENDING) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: send orig SRB_STATUS_PENDING (1)\n")); + goto ReturnEnableIntr; + } +/* + if(RestoreUseDpc) { + // restore state on error + UseDpc = TRUE; + AtapiDisableInterrupts(HwDeviceExtension, c); + } +*/ + + } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE) + + PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer; + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: ATAPI command status %#x\n", status)); + if (status == SRB_STATUS_DATA_OVERRUN) { + // Check to see if we at least get mininum number of bytes + if ((srb->DataTransferLength - AtaReq->WordsLeft) > + (offsetof (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) { + status = SRB_STATUS_SUCCESS; + } + } + + if (status == SRB_STATUS_SUCCESS) { +#ifndef UNIATA_CORE + if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) && + chan->MechStatusRetryCount) { + + // The sense key doesn't say the last request is illegal, so try again + chan->MechStatusRetryCount--; + srb = AtaReq->Srb = BuildMechanismStatusSrb ( + HwDeviceExtension, + AtaReq->OriginalSrb); + } else { + + // last request was illegal. No point trying again + AtapiHwInitializeChanger (HwDeviceExtension, + srb, + (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); + + // Get ready to issue the original srb + srb = AtaReq->Srb = AtaReq->OriginalSrb; + AtaReq->OriginalSrb = NULL; + } +#endif //UNIATA_CORE +/* + // do not enable interrupts in DPC, do not waste time, do it now! + if(UseDpc && chan->DisableIntr) { + AtapiEnableInterrupts(HwDeviceExtension, c); + UseDpc = FALSE; + RestoreUseDpc = TRUE; + } +*/ + srbStatus = AtapiSendCommand(HwDeviceExtension, srb, CMD_ACTION_ALL); + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: chan->ExpectingInterrupt %d (2)\n", chan->ExpectingInterrupt)); + + if (srbStatus == SRB_STATUS_PENDING) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: send orig SRB_STATUS_PENDING (2)\n")); + goto ReturnEnableIntr; + } +/* + if(RestoreUseDpc) { + // restore state on error + UseDpc = TRUE; + AtapiDisableInterrupts(HwDeviceExtension, c); + } +*/ + } + } + + // If we get here, it means AtapiSendCommand() has failed + // Can't recover. Pretend the original srb has failed and complete it. + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Error. complete OriginalSrb\n")); + + if (AtaReq->OriginalSrb) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiHwInitializeChanger()\n")); + AtapiHwInitializeChanger (HwDeviceExtension, + srb, + (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); + srb = AtaReq->Srb = AtaReq->OriginalSrb; + AtaReq->OriginalSrb = NULL; + } + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: chan->ExpectingInterrupt %d (3)\n", chan->ExpectingInterrupt)); + + // fake an error and read no data + status = SRB_STATUS_ERROR; + srb->ScsiStatus = 0; + AtaReq->DataBuffer = (PUSHORT)(srb->DataBuffer); + AtaReq->WordsLeft = srb->DataTransferLength; + chan->RDP = FALSE; + + } else if (status == SRB_STATUS_ERROR) { + + // Map error to specific SRB status and handle request sense. + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Error. Begin mapping...\n")); + status = MapError(deviceExtension, + srb); + + chan->RDP = FALSE; + + } else if(!DmaTransfer) { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO completion\n")); +PIO_wait_busy: + KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO completion, wait BUSY\n")); + // Wait for busy to drop. + for (i = 0; i < 5*30; i++) { + GetStatus(chan, statusByte); + if (!(statusByte & IDE_STATUS_BUSY)) { + break; + } + if(!InDpc) { + // goto DPC + AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY; + TimerValue = 200; + KdPrint2((PRINT_PREFIX "AtapiInterrupt: go to DPC (busy)\n")); +#ifndef UNIATA_CORE + goto PostToDpc; +#else UNIATA_CORE + AtapiStallExecution(TimerValue); + goto ServiceInterrupt; +#endif //UNIATA_CORE + } + AtapiStallExecution(100); + } + + if (i == 5*30) { + + // reset the controller. + KdPrint2((PRINT_PREFIX + "AtapiInterrupt: Resetting due to BSY still up - %#x.\n", + statusByte)); + goto IntrPrepareResetController; + } + // Check to see if DRQ is still up. + if(statusByte & IDE_STATUS_DRQ) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: DRQ...\n")); + if(srb) { + if(srb->SrbFlags & SRB_FLAGS_DATA_IN) { + KdPrint2((PRINT_PREFIX "srb %x data in\n", srb)); + } else { + KdPrint2((PRINT_PREFIX "srb %x data out\n", srb)); + } + } else { + KdPrint2((PRINT_PREFIX "srb NULL\n")); + } + if(AtaReq) { + KdPrint2((PRINT_PREFIX "AtaReq %x AtaReq->WordsLeft=%x\n", AtaReq, AtaReq->WordsLeft)); + } else { + KdPrint2((PRINT_PREFIX "AtaReq NULL\n")); + } + if(AtaReq && AtaReq->WordsLeft /*&& + !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))*/) { + KdPrint2((PRINT_PREFIX "DRQ+AtaReq->WordsLeft -> next portion\n")); + goto continue_PIO; + } + } + //if (atapiDev && (statusByte & IDE_STATUS_DRQ)) {} + //if ((statusByte & IDE_STATUS_DRQ)) {} + if((statusByte & IDE_STATUS_DRQ) && + (LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED)) ) { + +PIO_wait_DRQ: + KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO_wait_DRQ\n")); + for (i = 0; i < 200; i++) { + GetStatus(chan, statusByte); + if (!(statusByte & IDE_STATUS_DRQ)) { + break; + } + if(!InDpc) { + // goto DPC + KdPrint2((PRINT_PREFIX "AtapiInterrupt: go to DPC (drq)\n")); + AtaReq->ReqState = REQ_STATE_DPC_WAIT_DRQ; + TimerValue = 100; +#ifndef UNIATA_CORE + goto PostToDpc; +#else UNIATA_CORE + AtapiStallExecution(TimerValue); + goto ServiceInterrupt; +#endif //UNIATA_CORE + } + AtapiStallExecution(100); + } + + if (i == 200) { + // reset the controller. + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Resetting due to DRQ still up - %#x\n", + statusByte)); + goto IntrPrepareResetController; + } + } + if(atapiDev) { + KdPrint2(("IdeIntr: ATAPI Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x, len %#x\n", + AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)(-1)), srb->DataTransferLength )); + //KdDump(srb->DataBuffer, srb->DataTransferLength); + } + if(!AtapiDmaPioSync(HwDeviceExtension, srb, (PUCHAR)(srb->DataBuffer), srb->DataTransferLength)) { + KdPrint2(("IdeIntr: Can't sync DMA and PIO buffers\n")); + } + } + + // Clear interrupt expecting flag. + chan->ExpectingInterrupt = FALSE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + // Sanity check that there is a current request. + if (srb != NULL) { + // Set status in SRB. + srb->SrbStatus = (UCHAR)status; + + // Check for underflow. + if (AtaReq->WordsLeft) { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Check for underflow, AtaReq->WordsLeft %x\n", AtaReq->WordsLeft)); + // Subtract out residual words and update if filemark hit, + // setmark hit , end of data, end of media... + if (!(LunExt->DeviceFlags & DFLAGS_TAPE_DEVICE)) { + if (status == SRB_STATUS_DATA_OVERRUN) { + srb->DataTransferLength -= AtaReq->WordsLeft; + } else { + srb->DataTransferLength = 0; + } + } else { + srb->DataTransferLength -= AtaReq->WordsLeft; + } + } + + if (srb->Function != SRB_FUNCTION_IO_CONTROL) { + +CompleteRDP: + // Indicate command complete. + if (!(chan->RDP)) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: RequestComplete\n")); +IntrCompleteReq: + + if (status == SRB_STATUS_SUCCESS && + srb->SenseInfoBuffer && + srb->SenseInfoBufferLength >= sizeof(SENSE_DATA)) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)srb->SenseInfoBuffer; + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: set AutoSense\n")); + senseBuffer->ErrorCode = 0; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = 0; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + AtapiDmaDBSync(chan, srb); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: remove srb %#x, status %x\n", srb, status)); + UniataRemoveRequest(chan, srb); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: RequestComplete, srb %#x\n", srb)); + ScsiPortNotification(RequestComplete, + deviceExtension, + srb); + } + } else { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: IOCTL completion\n")); + PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); + + if (status != SRB_STATUS_SUCCESS) { + error = AtapiReadPort1(chan, IDX_IO1_i_Error); + KdPrint2((PRINT_PREFIX "AtapiInterrupt: error %#x\n", error)); + } + + // Build the SMART status block depending upon the completion status. + cmdOutParameters->cBufferSize = wordCount; + cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0; + cmdOutParameters->DriverStatus.bIDEError = error; + + // If the sub-command is return smart status, jam the value from cylinder low and high, into the + // data buffer. + if (chan->SmartCommand == RETURN_SMART_STATUS) { + cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS; + cmdOutParameters->bBuffer[1] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason); + cmdOutParameters->bBuffer[2] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Unused1); + cmdOutParameters->bBuffer[3] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow); + cmdOutParameters->bBuffer[4] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh); + cmdOutParameters->bBuffer[5] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_DriveSelect); + cmdOutParameters->bBuffer[6] = SMART_CMD; + cmdOutParameters->cBufferSize = 8; + } + + // Indicate command complete. + goto IntrCompleteReq; + } + + } else { + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: No SRB!\n")); + } + + if (chan->RDP) { + // Check DSC + for (i = 0; i < 5; i++) { + GetStatus(chan, statusByte); + if(!(statusByte & IDE_STATUS_BUSY)) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: RDP + cleared BUSY\n")); + chan->RDP = FALSE; + goto CompleteRDP; + } else + if (statusByte & IDE_STATUS_DSC) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Clear RDP\n")); + chan->RDP = FALSE; + goto CompleteRDP; + } + AtapiStallExecution(50); + } + } + // RDP can be cleared since previous check + if (chan->RDP) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: RequestTimerCall 2000\n")); + + TimerValue = 2000; +#ifndef UNIATA_CORE + goto CallTimerDpc; +#else UNIATA_CORE + AtapiStallExecution(TimerValue); + goto ServiceInterrupt; +#endif //UNIATA_CORE + } + +// ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); +enqueue_next_req: + // Get next request + srb = UniataGetCurRequest(chan); + +reenqueue_req: + +#ifndef UNIATA_CORE + KdPrint2((PRINT_PREFIX "AtapiInterrupt: NextRequest, srb=%#x\n",srb)); + if(!srb) { + ScsiPortNotification(NextRequest, + deviceExtension, + NULL); + } else { + ScsiPortNotification(NextLuRequest, + deviceExtension, + PathId, + TargetId, + Lun); + // in simplex mode next command must NOT be sent here + if(!deviceExtension->simplexOnly) { + AtapiStartIo__(HwDeviceExtension, srb, FALSE); + } + } + // Try to get SRB fron any non-empty queue (later) + if(deviceExtension->simplexOnly) { + NoStartIo = FALSE; + } +#endif //UNIATA_CORE + + goto ReturnEnableIntr; + + } else { + + // Unexpected int. Catch it + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Unexpected ATAPI interrupt. InterruptReason %#x. Status %#x.\n", + interruptReason, + statusByte)); + + } + +ReturnEnableIntr: + + KdPrint2((PRINT_PREFIX "AtapiInterrupt: ReturnEnableIntr\n",srb)); + if(UseDpc) { + if(CrNtInterlockedExchangeAdd(&(chan->DisableIntr), 0)) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiEnableInterrupts__()\n")); +#ifdef UNIATA_USE_XXableInterrupts + //ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + chan->ChannelCtrlFlags |= CTRFLAGS_ENABLE_INTR_REQ; + // must be called on DISPATCH_LEVEL + ScsiPortNotification(CallDisableInterrupts, HwDeviceExtension, + AtapiEnableInterrupts__); +#else + AtapiEnableInterrupts(HwDeviceExtension, c); + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + // Will raise IRQL to DIRQL +#ifndef UNIATA_CORE + AtapiQueueTimerDpc(HwDeviceExtension, lChannel, + AtapiEnableInterrupts__, + 1); +#endif // UNIATA_CORE + KdPrint2((PRINT_PREFIX "AtapiInterrupt: Timer DPC inited\n")); +#endif // UNIATA_USE_XXableInterrupts + } + } + + InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); + // in simplex mode next command must be sent here if + // DPC is not used + KdPrint2((PRINT_PREFIX "AtapiInterrupt: exiting, UseDpc=%d, NoStartIo=%d\n", UseDpc, NoStartIo)); + +#ifndef UNIATA_CORE + if(!UseDpc && /*deviceExtension->simplexOnly &&*/ !NoStartIo) { + chan = UniataGetNextChannel(chan); + if(chan) { + srb = UniataGetCurRequest(chan); + } else { + srb = NULL; + } + KdPrint2((PRINT_PREFIX "AtapiInterrupt: run srb %x\n", srb)); + if(srb) { + AtapiStartIo__(HwDeviceExtension, srb, FALSE); + } + } +#endif //UNIATA_CORE + return TRUE; + +} // end AtapiInterrupt__() + +#ifndef UNIATA_CORE + +/*++ + +Routine Description: + + This routine handles SMART enable, disable, read attributes and threshold commands. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + Srb - IO request packet + +Return Value: + + SRB status + +--*/ +ULONG +IdeSendSmartCommand( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG c = GET_CHANNEL(Srb); + PHW_CHANNEL chan = &(deviceExtension->chan[c]); + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); + SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); + PIDEREGS regs = &cmdInParameters.irDriveRegs; +// ULONG i; + UCHAR statusByte,targetId; + + + if (regs->bCommandReg != SMART_CMD) { + KdPrint2((PRINT_PREFIX + "IdeSendSmartCommand: bCommandReg != SMART_CMD\n")); + return SRB_STATUS_INVALID_REQUEST; + } + + targetId = cmdInParameters.bDriveNumber; + + //TODO optimize this check + if ((!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) || + (deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + + return SRB_STATUS_SELECTION_TIMEOUT; + } + + chan->SmartCommand = regs->bFeaturesReg; + + // Determine which of the commands to carry out. + switch(regs->bFeaturesReg) { + case READ_ATTRIBUTES: + case READ_THRESHOLDS: + + statusByte = WaitOnBusy(chan); + + if (statusByte & IDE_STATUS_BUSY) { + KdPrint2((PRINT_PREFIX + "IdeSendSmartCommand: Returning BUSY status\n")); + return SRB_STATUS_BUSY; + } + + // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same). + RtlZeroMemory(cmdOutParameters, sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1); + + // Set data buffer pointer and words left. + AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer; + AtaReq->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2; + + statusByte = AtaCommand(deviceExtension, targetId & 0x1, c, + regs->bCommandReg, + (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8), + 0, + regs->bSectorNumberReg, + regs->bSectorCountReg, + regs->bFeaturesReg, + ATA_IMMEDIATE); + + if(!(statusByte & IDE_STATUS_ERROR)) { + // Wait for interrupt. + return SRB_STATUS_PENDING; + } + return SRB_STATUS_ERROR; + + case ENABLE_SMART: + case DISABLE_SMART: + case RETURN_SMART_STATUS: + case ENABLE_DISABLE_AUTOSAVE: + case EXECUTE_OFFLINE_DIAGS: + case SAVE_ATTRIBUTE_VALUES: + + statusByte = WaitOnBusy(chan); + + if (statusByte & IDE_STATUS_BUSY) { + KdPrint2((PRINT_PREFIX + "IdeSendSmartCommand: Returning BUSY status\n")); + return SRB_STATUS_BUSY; + } + + // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same). + RtlZeroMemory(cmdOutParameters, sizeof(SENDCMDOUTPARAMS) - 1); + + // Set data buffer pointer and indicate no data transfer. + AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer; + AtaReq->WordsLeft = 0; + + statusByte = AtaCommand(deviceExtension, targetId & 0x1, c, + regs->bCommandReg, + (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8), + 0, + regs->bSectorNumberReg, + regs->bSectorCountReg, + regs->bFeaturesReg, + ATA_IMMEDIATE); + + if(!(statusByte & IDE_STATUS_ERROR)) { + // Wait for interrupt. + return SRB_STATUS_PENDING; + } + return SRB_STATUS_ERROR; + } // end switch(regs->bFeaturesReg) + + return SRB_STATUS_INVALID_REQUEST; + +} // end IdeSendSmartCommand() + +#endif //UNIATA_CORE + +ULONGLONG +UniAtaCalculateLBARegs( + PHW_LU_EXTENSION LunExt, + ULONG startingSector + ) +{ + UCHAR drvSelect,sectorNumber; + USHORT cylinder; + ULONG tmp; + + if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) { + return startingSector; + } + tmp = LunExt->IdentifyData.SectorsPerTrack * + LunExt->IdentifyData.NumberOfHeads; + if(!tmp) { + KdPrint2((PRINT_PREFIX "UniAtaCalculateLBARegs: 0-sized\n")); + cylinder = 0; + drvSelect = 0; + sectorNumber = 1; + } else { + cylinder = (USHORT)(startingSector / tmp); + drvSelect = (UCHAR)((startingSector % tmp) / LunExt->IdentifyData.SectorsPerTrack); + sectorNumber = (UCHAR)(startingSector % LunExt->IdentifyData.SectorsPerTrack) + 1; + } + + return (ULONG)(sectorNumber&0xff) | (((ULONG)cylinder&0xffff)<<8) | (((ULONG)drvSelect&0xf)<<24); +} // end UniAtaCalculateLBARegs() + +ULONGLONG +UniAtaCalculateLBARegsBack( + PHW_LU_EXTENSION LunExt, + ULONGLONG lba + ) +{ + ULONG drvSelect,sectorNumber; + ULONG cylinder; + ULONG tmp; + + if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) { + return lba; + } + tmp = LunExt->IdentifyData.SectorsPerTrack * + LunExt->IdentifyData.NumberOfHeads; + + cylinder = (USHORT)((lba >> 8) & 0xffff); + drvSelect = (UCHAR)((lba >> 24) & 0xf); + sectorNumber = (UCHAR)(lba & 0xff); + + lba = sectorNumber-1 + + (drvSelect*LunExt->IdentifyData.SectorsPerTrack) + + (cylinder*tmp); + + return lba; +} // end UniAtaCalculateLBARegsBack() + + +/*++ + +Routine Description: + + This routine handles IDE read and writes. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + Srb - IO request packet + +Return Value: + + SRB status + +--*/ +ULONG +IdeReadWrite( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN ULONG CmdAction + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + UCHAR lChannel = GET_CHANNEL(Srb); + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); + PHW_LU_EXTENSION LunExt; + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + ULONG ldev = GET_LDEV(Srb); + UCHAR DeviceNumber = (UCHAR)(ldev & 1); + ULONG startingSector; + ULONG wordCount; + UCHAR statusByte,statusByte2; + UCHAR cmd; + ULONGLONG lba; + BOOLEAN use_dma = FALSE; + + AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD; + LunExt = &deviceExtension->lun[ldev]; + + if((CmdAction & CMD_ACTION_PREPARE) && + (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) { + + // Set data buffer pointer and words left. + AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer; + + MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks); + //ASSERT(Srb->DataTransferLength == AtaReq->bcount * DEV_BSIZE); + AtaReq->WordsLeft = min(Srb->DataTransferLength, + AtaReq->bcount * DEV_BSIZE) / 2; + + // Set up 1st block. + MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA); + + KdPrint2((PRINT_PREFIX "IdeReadWrite (REQ): Starting sector is %#x, Number of WORDS %#x, DevSize %#x\n", + startingSector, + AtaReq->WordsLeft, + AtaReq->bcount)); + + lba = UniAtaCalculateLBARegs(LunExt, startingSector); + AtaReq->lba = lba; + + // assume best case here + // we cannot reinit Dma until previous request is completed + if ((LunExt->LimitedTransferMode >= ATA_DMA)) { + use_dma = TRUE; + // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success + if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb, + (PUCHAR)(AtaReq->DataBuffer), + ((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1)))) { + use_dma = FALSE; + } + } + AtaReq->ReqState = REQ_STATE_READY_TO_TRANSFER; + } else { // exec_only + KdPrint2((PRINT_PREFIX "IdeReadWrite (ExecOnly): \n")); + lba = AtaReq->lba; + + if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) { + use_dma = TRUE; + } + } + if(!(CmdAction & CMD_ACTION_EXEC)) { + return SRB_STATUS_PENDING; + } + + // if this is queued request, reinit DMA and check + // if DMA mode is still available + AtapiDmaReinit(deviceExtension, ldev, AtaReq); + if (/*EnableDma &&*/ + (LunExt->TransferMode >= ATA_DMA)) { + use_dma = TRUE; + } else { + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + use_dma = FALSE; + } + + // Check if write request. + if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { + + // Prepare read command. + if(use_dma) { + cmd = IDE_COMMAND_READ_DMA; + } else + if(LunExt->MaximumBlockXfer) { + cmd = IDE_COMMAND_READ_MULTIPLE; + } else { + cmd = IDE_COMMAND_READ; + } + } else { + + // Prepare write command. + if (use_dma) { + wordCount = Srb->DataTransferLength/2; + cmd = IDE_COMMAND_WRITE_DMA; + } else + if (LunExt->MaximumBlockXfer) { + wordCount = DEV_BSIZE/2 * LunExt->MaximumBlockXfer; + + if (AtaReq->WordsLeft < wordCount) { + // Transfer only words requested. + wordCount = AtaReq->WordsLeft; + } + cmd = IDE_COMMAND_WRITE_MULTIPLE; + + } else { + wordCount = DEV_BSIZE/2; + cmd = IDE_COMMAND_WRITE; + } + } + + if(use_dma) { + chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION; + } else { + chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; + } + + // Send IO command. + KdPrint2((PRINT_PREFIX "IdeReadWrite: Lba %#I64x, Count %#x(%#x)\n", lba, ((Srb->DataTransferLength + 0x1FF) / 0x200), + ((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE))); + + if ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) || + use_dma) { + statusByte2 = AtaCommand48(deviceExtension, DeviceNumber, lChannel, + cmd, lba, + (UCHAR)((Srb->DataTransferLength + DEV_BSIZE-1) / DEV_BSIZE), +// (UCHAR)((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE), + 0, ATA_IMMEDIATE); + GetStatus(chan, statusByte2); + if(statusByte2 & IDE_STATUS_ERROR) { + statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error); + KdPrint2((PRINT_PREFIX "IdeReadWrite: status %#x, error %#x\n", statusByte2, statusByte)); + return SRB_STATUS_ERROR; + } + if(use_dma) { + AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb); + } + return SRB_STATUS_PENDING; + } + + statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel, + cmd, lba, + (UCHAR)((Srb->DataTransferLength + DEV_BSIZE-1) / DEV_BSIZE), +// (UCHAR)((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE), + 0, ATA_WAIT_INTR); + + if (!(statusByte & IDE_STATUS_DRQ)) { + + KdPrint2((PRINT_PREFIX + "IdeReadWrite: DRQ never asserted (%#x)\n", + statusByte)); + + AtaReq->WordsLeft = 0; + + // Clear interrupt expecting flag. + chan->ExpectingInterrupt = FALSE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + // Clear current SRB. + UniataRemoveRequest(chan, Srb); + + return SRB_STATUS_TIMEOUT; + } + + chan->ExpectingInterrupt = TRUE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + // Write next DEV_BSIZE/2*N words. + if (!(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED)) { + KdPrint2((PRINT_PREFIX + "IdeReadWrite: Write %#x words\n", wordCount)); + + WriteBuffer(chan, + AtaReq->DataBuffer, + wordCount, + UniataGetPioTiming(LunExt)); + + } else { + + KdPrint2((PRINT_PREFIX + "IdeReadWrite: Write %#x Dwords\n", wordCount/2)); + + WriteBuffer2(chan, + (PULONG)(AtaReq->DataBuffer), + wordCount / 2, + UniataGetPioTiming(LunExt)); + } + + // Adjust buffer address and words left count. + AtaReq->WordsLeft -= wordCount; + AtaReq->DataBuffer += wordCount; + + // Wait for interrupt. + return SRB_STATUS_PENDING; + +} // end IdeReadWrite() + +#ifndef UNIATA_CORE + +/*++ + +Routine Description: + This routine handles IDE Verify. + +Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + Srb - IO request packet + ` +Return Value: + SRB status + +--*/ +ULONG +IdeVerify( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + UCHAR lChannel = GET_CHANNEL(Srb); + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + PHW_LU_EXTENSION LunExt; + ULONG ldev = GET_LDEV(Srb); + UCHAR statusByte; + ULONG startingSector; + ULONG sectors; + ULONG endSector; + USHORT sectorCount; + ULONGLONG lba; + + LunExt = &deviceExtension->lun[ldev]; + // Drive has these number sectors. + if(!(sectors = (ULONG)(LunExt->NumOfSectors))) { + sectors = LunExt->IdentifyData.SectorsPerTrack * + LunExt->IdentifyData.NumberOfHeads * + LunExt->IdentifyData.NumberOfCylinders; + } + + KdPrint2((PRINT_PREFIX + "IdeVerify: Total sectors %#x\n", + sectors)); + + // Get starting sector number from CDB. + MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA); + MOV_DW_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks); + + KdPrint2((PRINT_PREFIX + "IdeVerify: Starting sector %#x. Number of blocks %#x\n", + startingSector, + sectorCount)); + + endSector = startingSector + sectorCount; + + KdPrint2((PRINT_PREFIX + "IdeVerify: Ending sector %#x\n", + endSector)); + + if (endSector > sectors) { + + // Too big, round down. + KdPrint2((PRINT_PREFIX + "IdeVerify: Truncating request to %#x blocks\n", + sectors - startingSector - 1)); + + sectorCount = (USHORT)(sectors - startingSector - 1); + + } else { + + // Set up sector count register. Round up to next block. + if (sectorCount > 0xFF) { + sectorCount = (USHORT)0xFF; + } + } + + // Set data buffer pointer and words left. + AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer; + AtaReq->WordsLeft = Srb->DataTransferLength / 2; + + // Indicate expecting an interrupt. + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + lba = UniAtaCalculateLBARegs(LunExt, startingSector); + + statusByte = AtaCommand48(deviceExtension, ldev & 0x01, GET_CHANNEL(Srb), + IDE_COMMAND_VERIFY, lba, + sectorCount, + 0, ATA_IMMEDIATE); + + if(!(statusByte & IDE_STATUS_ERROR)) { + // Wait for interrupt. + return SRB_STATUS_PENDING; + } + return SRB_STATUS_ERROR; + +} // end IdeVerify() + +#endif //UNIATA_CORE + +/*++ + +Routine Description: + Send ATAPI packet command to device. + +Arguments: + HwDeviceExtension - HBA miniport driver's adapter data storage + Srb - IO request packet + +Return Value: + +--*/ +ULONG +AtapiSendCommand( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN ULONG CmdAction + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + UCHAR lChannel = GET_CHANNEL(Srb); + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + ULONG ldev = GET_LDEV(Srb); + ULONG i; + ULONG flags; + UCHAR statusByte,byteCountLow,byteCountHigh; + BOOLEAN use_dma = FALSE; + BOOLEAN dma_reinited = FALSE; + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: req state %#x\n", AtaReq->ReqState)); + if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER) + AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER; + +#ifdef UNIATA_DUMP_ATAPI + if(CmdAction & CMD_ACTION_PREPARE) { + UCHAR ScsiCommand; + PCDB Cdb; + PCHAR CdbData; + PCHAR ModeSelectData; + ULONG CdbDataLen; + + Cdb = (PCDB)(Srb->Cdb); + ScsiCommand = Cdb->CDB6.OperationCode; + CdbData = (PCHAR)(Srb->DataBuffer); + CdbDataLen = Srb->DataTransferLength; + + if(CdbDataLen > 0x1000) { + CdbDataLen = 0x1000; + } + + KdPrint(("--\n")); + KdPrint2(("VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID)); + KdPrint2(("P:T:D=%d:%d:%d\n", + Srb->PathId, + Srb->TargetId, + Srb->Lun)); + KdPrint(("SCSI Command %2.2x\n", ScsiCommand)); + KdDump(Cdb, 16); + + if(ScsiCommand == SCSIOP_WRITE_CD) { + KdPrint(("Write10, LBA %2.2x%2.2x%2.2x%2.2x\n", + Cdb->WRITE_CD.LBA[0], + Cdb->WRITE_CD.LBA[1], + Cdb->WRITE_CD.LBA[2], + Cdb->WRITE_CD.LBA[3] + )); + } else + if(ScsiCommand == SCSIOP_WRITE12) { + KdPrint(("Write12, LBA %2.2x%2.2x%2.2x%2.2x\n", + Cdb->CDB12READWRITE.LBA[0], + Cdb->CDB12READWRITE.LBA[1], + Cdb->CDB12READWRITE.LBA[2], + Cdb->CDB12READWRITE.LBA[3] + )); + } else + if(ScsiCommand == SCSIOP_MODE_SELECT) { + KdPrint(("ModeSelect 6\n")); + PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData; + ModeSelectData = CdbData+4; + KdDump(CdbData, CdbDataLen); + } else + if(ScsiCommand == SCSIOP_MODE_SELECT10) { + KdPrint(("ModeSelect 10\n")); + PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData; + ModeSelectData = CdbData+8; + KdDump(CdbData, CdbDataLen); + } else { + if(Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { + KdPrint(("Send buffer to device:\n")); + KdDump(CdbData, CdbDataLen); + } + } + KdPrint(("--\n")); + } +#endif //UNIATA_DUMP_ATAPI + + + if(CmdAction == CMD_ACTION_PREPARE) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE\n")); + switch (Srb->Cdb[0]) { + case SCSIOP_READ: + case SCSIOP_WRITE: + case SCSIOP_READ12: + case SCSIOP_WRITE12: + // all right + break; + default: + KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY\n")); + return SRB_STATUS_BUSY; + } + // + if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_CHANGER_INITED) && + !AtaReq->OriginalSrb) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY (2)\n")); + return SRB_STATUS_BUSY; + } + } + + if((CmdAction & CMD_ACTION_PREPARE) && + (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) { + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x\n", Srb->Cdb[0])); + // Set data buffer pointer and words left. + AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer; + AtaReq->WordsLeft = Srb->DataTransferLength / 2; + AtaReq->TransferLength = Srb->DataTransferLength; + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + + // check if reorderable + switch(Srb->Cdb[0]) { + case SCSIOP_READ12: + case SCSIOP_WRITE12: + + MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks); + goto GetLba; + + case SCSIOP_READ: + case SCSIOP_WRITE: + + MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks); +GetLba: + MOV_DD_SWP(AtaReq->lba, ((PCDB)Srb->Cdb)->CDB10.LBA); + + AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD; + AtaReq->Flags &= ~REQ_FLAG_RW_MASK; + AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_WRITE12) ? + REQ_FLAG_WRITE : REQ_FLAG_READ; + break; + } + + // check if DMA read/write + if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE, no DMA setup\n")); + } else + if(AtaReq->TransferLength) { + // try use DMA + switch(Srb->Cdb[0]) { + case SCSIOP_WRITE: + case SCSIOP_WRITE12: + if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_RO) + break; + /* FALLTHROUGH */ + case SCSIOP_READ: + case SCSIOP_READ12: + + if(deviceExtension->opt_AtapiDmaReadWrite) { +call_dma_setup: + if(AtapiDmaSetup(HwDeviceExtension, ldev & 1, lChannel, Srb, + (PUCHAR)(AtaReq->DataBuffer), + Srb->DataTransferLength + /*((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1))*/ + )) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma\n")); + use_dma = TRUE; + } + } + break; + case SCSIOP_READ_CD: + if(deviceExtension->opt_AtapiDmaRawRead) + goto call_dma_setup; + break; + default: + + if(deviceExtension->opt_AtapiDmaControlCmd) { + if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) { + // read operation + use_dma = TRUE; + } else { + // write operation + if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_RO) { + KdPrint2((PRINT_PREFIX "dma RO\n")); + use_dma = FALSE; + } else { + use_dma = TRUE; + } + } + } + break; + } + // try setup DMA + if(use_dma) { + if(!AtapiDmaSetup(HwDeviceExtension, ldev & 1, lChannel, Srb, + (PUCHAR)(AtaReq->DataBuffer), + Srb->DataTransferLength)) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: no dma\n")); + use_dma = FALSE; + } else { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma\n")); + } + } + } else { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer, no DMA setup\n")); + } + + } else { + if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) { + // if this is queued request, reinit DMA and check + // if DMA mode is still available + KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit() (1)\n")); + AtapiDmaReinit(deviceExtension, ldev, AtaReq); + if (/*EnableDma &&*/ + (deviceExtension->lun[ldev].TransferMode >= ATA_DMA)) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (2)\n")); + use_dma = TRUE; + } else { + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + KdPrint2((PRINT_PREFIX "AtapiSendCommand: no dma (2)\n")); + use_dma = FALSE; + } + dma_reinited = TRUE; + } + } + + if(!(CmdAction & CMD_ACTION_EXEC)) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: !CMD_ACTION_EXEC => SRB_STATUS_PENDING\n")); + return SRB_STATUS_PENDING; + } + KdPrint2((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma)); + if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) { + KdPrint2((PRINT_PREFIX " REQ_FLAG_DMA_OPERATION\n")); + } + + if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE -> no dma setup (2)\n")); + use_dma = FALSE; + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + //AtapiDmaReinit(deviceExtension, ldev, AtaReq); + } if(AtaReq->TransferLength) { + if(!dma_reinited) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n")); + AtapiDmaReinit(deviceExtension, ldev, AtaReq); + if (/*EnableDma &&*/ + (deviceExtension->lun[ldev].TransferMode >= ATA_DMA)) { + use_dma = TRUE; + } else { + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + use_dma = FALSE; + } + } + } else { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer\n")); + use_dma = FALSE; + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + if(!deviceExtension->opt_AtapiDmaZeroTransfer) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit() to PIO\n")); + AtapiDmaReinit(deviceExtension, ldev, AtaReq); + } + } + KdPrint2((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma)); + if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) { + KdPrint2((PRINT_PREFIX " REQ_FLAG_DMA_OPERATION\n")); + } + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_EXEC\n")); + +#ifndef UNIATA_CORE + // We need to know how many platters our atapi cd-rom device might have. + // Before anyone tries to send a srb to our target for the first time, + // we must "secretly" send down a separate mechanism status srb in order to + // initialize our device extension changer data. That's how we know how + // many platters our target has. + + if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_CHANGER_INITED) && + !AtaReq->OriginalSrb) { + + ULONG srbStatus; + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: BuildMechanismStatusSrb()\n")); + // Set this flag now. If the device hangs on the mech. status + // command, we will not have the chance to set it. + deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_CHANGER_INITED; + + chan->MechStatusRetryCount = 3; + AtaReq->OriginalSrb = Srb; + AtaReq->Srb = BuildMechanismStatusSrb ( + HwDeviceExtension, + Srb); + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiSendCommand recursive\n")); + srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL); + if (srbStatus == SRB_STATUS_PENDING) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_PENDING (2)\n")); + return srbStatus; + } else { + AtaReq->Srb = AtaReq->OriginalSrb; + AtaReq->OriginalSrb = NULL; + KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiHwInitializeChanger()\n")); + AtapiHwInitializeChanger (HwDeviceExtension, Srb, + (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL); + // fall out + } + } +#endif //UNIATA_CORE + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Command %#x to TargetId %d lun %d\n", + Srb->Cdb[0], Srb->TargetId, Srb->Lun)); + + // Make sure command is to ATAPI device. + flags = deviceExtension->lun[ldev].DeviceFlags; + if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) { + if ((Srb->Lun) > (deviceExtension->lun[ldev].DiscsPresent - 1)) { + + // Indicate no device found at this address. + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + return SRB_STATUS_SELECTION_TIMEOUT; + } + } else if (Srb->Lun > 0) { + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + return SRB_STATUS_SELECTION_TIMEOUT; + } + + if (!(flags & DFLAGS_ATAPI_DEVICE)) { + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + return SRB_STATUS_SELECTION_TIMEOUT; + } + + // Select device 0 or 1. + SelectDrive(chan, ldev & 0x1); + + // Verify that controller is ready for next command. + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Entered with status %#x\n", statusByte)); + + if (statusByte == 0xff) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: bad status 0xff on entry\n")); + goto make_reset; + } + if (statusByte & IDE_STATUS_BUSY) { + if(statusByte & IDE_STATUS_DSC) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: DSC on entry (%#x), try exec\n", statusByte)); + } + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Device busy (%#x)\n", statusByte)); + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + return SRB_STATUS_BUSY; + } + if (statusByte & IDE_STATUS_ERROR) { + if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) { + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Error on entry: (%#x)\n", statusByte)); + // Read the error reg. to clear it and fail this request. + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + return MapError(deviceExtension, Srb); + } else { + KdPrint2((PRINT_PREFIX " continue with SCSIOP_REQUEST_SENSE\n", statusByte)); + } + } + // If a tape drive doesn't have DSC set and the last command is restrictive, don't send + // the next command. See discussion of Restrictive Delayed Process commands in QIC-157. + if ((!(statusByte & IDE_STATUS_DSC)) && + (flags & (DFLAGS_TAPE_DEVICE | DFLAGS_ATAPI_DEVICE)) && chan->RDP) { + + AtapiStallExecution(200); + KdPrint2((PRINT_PREFIX "AtapiSendCommand: DSC not set. %#x => SRB_STATUS_PENDING\n",statusByte)); + AtaReq->ReqState = REQ_STATE_QUEUED; + return SRB_STATUS_PENDING; + } + + if (IS_RDP(Srb->Cdb[0])) { + chan->RDP = TRUE; + KdPrint2((PRINT_PREFIX "AtapiSendCommand: %#x mapped as DSC restrictive\n", Srb->Cdb[0])); + } else { + chan->RDP = FALSE; + } + if (statusByte & IDE_STATUS_DRQ) { + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Entered with status (%#x). Attempting to recover.\n", + statusByte)); + // Try to drain the data that one preliminary device thinks that it has + // to transfer. Hopefully this random assertion of DRQ will not be present + // in production devices. + for (i = 0; i < 0x10000; i++) { + GetStatus(chan, statusByte); + if (statusByte & IDE_STATUS_DRQ) { + AtapiReadPort2(chan, IDX_IO1_i_Data); + } else { + break; + } + } + + if (i == 0x10000) { +make_reset: + KdPrint2((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted.Status (%#x)\n", statusByte)); + + AtapiDisableInterrupts(deviceExtension, lChannel); + + AtapiSoftReset(chan, ldev & 1); + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Issued soft reset to Atapi device. \n")); + // Re-initialize Atapi device. + IssueIdentify(HwDeviceExtension, ldev & 1, GET_CHANNEL(Srb), + IDE_COMMAND_ATAPI_IDENTIFY, FALSE); + // Inform the port driver that the bus has been reset. + ScsiPortNotification(ResetDetected, HwDeviceExtension, 0); + // Clean up device extension fields that AtapiStartIo won't. + chan->ExpectingInterrupt = FALSE; + chan->RDP = FALSE; + InterlockedExchange(&(deviceExtension->chan[GET_CHANNEL(Srb)].CheckIntr), + CHECK_INTR_IDLE); + + AtapiEnableInterrupts(deviceExtension, lChannel); + + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + return SRB_STATUS_BUS_RESET; + + } + } + + if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) { + // As the cdrom driver sets the LUN field in the cdb, it must be removed. + Srb->Cdb[1] &= ~0xE0; + if ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY) && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) { + // Torisan changer. TUR's are overloaded to be platter switches. + Srb->Cdb[7] = Srb->Lun; + } + } + + // SETUP DMA !!!!! + + if(use_dma) { + chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION; + } else { + chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; + } + + statusByte = WaitOnBusy(chan); + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Entry Status (%#x)\n", + statusByte)); + + AtapiWritePort1(chan, IDX_IO1_o_Feature, + use_dma ? ATA_F_DMA : 0); + + // Write transfer byte count to registers. + byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF); + byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8); + + if (Srb->DataTransferLength >= 0x10000) { + byteCountLow = byteCountHigh = 0xFF; + } + + AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountLow, byteCountLow); + AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh, byteCountHigh); + + if (flags & DFLAGS_INT_DRQ) { + + // This device interrupts when ready to receive the packet. + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Wait for int. to send packet. Status (%#x)\n", + statusByte)); + + chan->ExpectingInterrupt = TRUE; + AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_CMD_INTR; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + // Write ATAPI packet command. + AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET); + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING\n")); + return SRB_STATUS_PENDING; + + } else { + + // This device quickly sets DRQ when ready to receive the packet. + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Poll for int. to send packet. Status (%#x)\n", + statusByte)); + + chan->ExpectingInterrupt = TRUE; + AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + + AtapiDisableInterrupts(deviceExtension, lChannel); + + // Write ATAPI packet command. + AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET); + + // Wait for DRQ. + WaitOnBusy(chan); + statusByte = WaitForDrq(chan); + + // Need to read status register and clear interrupt (if any) + GetBaseStatus(chan, statusByte); + + if (!(statusByte & IDE_STATUS_DRQ)) { + + AtapiEnableInterrupts(deviceExtension, lChannel); + KdPrint2((PRINT_PREFIX "AtapiSendCommand: DRQ never asserted (%#x)\n", statusByte)); + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + return SRB_STATUS_ERROR; + } + } + + GetStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX "AtapiSendCommand: status (%#x)\n", statusByte)); + + // Send CDB to device. + statusByte = WaitOnBaseBusy(chan); + + // Indicate expecting an interrupt and wait for it. + chan->ExpectingInterrupt = TRUE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; + + GetBaseStatus(chan, statusByte); + + AtapiEnableInterrupts(deviceExtension, lChannel); + + WriteBuffer(chan, + (PUSHORT)Srb->Cdb, + 6, + 0); + + if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) { + AtapiDmaStart(HwDeviceExtension, ldev & 1, lChannel, Srb); + } + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: ExpectingInterrupt (%#x)\n", chan->ExpectingInterrupt)); + + KdPrint2((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (3)\n")); + return SRB_STATUS_PENDING; + +} // end AtapiSendCommand() + + +#ifndef UNIATA_CORE + +/*++ + +Routine Description: + Program ATA registers for IDE disk transfer. + +Arguments: + HwDeviceExtension - ATAPI driver storage. + Srb - System request block. + +Return Value: + SRB status (pending if all goes well). + +--*/ + +#ifdef _DEBUG +ULONG check_point = 0; +#define SetCheckPoint(cp) { check_point = (cp) ; } +#else +#define SetCheckPoint(cp) +#endif + +ULONG +IdeSendCommand( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN ULONG CmdAction + ) +{ + SetCheckPoint(1); + KdPrint2((PRINT_PREFIX "** Ide: Command: entryway\n")); + SetCheckPoint(2); + + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + SetCheckPoint(3); + UCHAR lChannel; + PHW_CHANNEL chan; + PCDB cdb; + + SetCheckPoint(4); + + UCHAR statusByte,errorByte; + ULONG status; + ULONG i; + PMODE_PARAMETER_HEADER modeData; + ULONG ldev; + PATA_REQ AtaReq; + SetCheckPoint(5); + //ULONG __ebp__ = 0; + + SetCheckPoint(0x20); + KdPrint2((PRINT_PREFIX "** Ide: Command:\n\n")); +/* __asm { + mov eax,ebp + mov __ebp__, eax + }*/ + /*KdPrint2((PRINT_PREFIX "** Ide: Command EBP %#x, pCdb %#x, cmd %#x\n", + __ebp__, &(Srb->Cdb[0]), Srb->Cdb[0])); + KdPrint2((PRINT_PREFIX "** Ide: Command %s\n", + (CmdAction == CMD_ACTION_PREPARE) ? "Prep " : "")); + KdPrint2((PRINT_PREFIX "** Ide: Command Srb %#x\n", + Srb)); + KdPrint2((PRINT_PREFIX "** Ide: Command SrbExt %#x\n", + Srb->SrbExtension)); + KdPrint2((PRINT_PREFIX "** Ide: Command to device %d\n", + Srb->TargetId));*/ + + SetCheckPoint(0x30); + AtaReq = (PATA_REQ)(Srb->SrbExtension); + + KdPrint2((PRINT_PREFIX "** Ide: Command &AtaReq %#x\n", + &AtaReq)); + KdPrint2((PRINT_PREFIX "** Ide: Command AtaReq %#x\n", + AtaReq)); + KdPrint2((PRINT_PREFIX "** --- **\n")); + + lChannel = GET_CHANNEL(Srb); + chan = &(deviceExtension->chan[lChannel]); + ldev = GET_LDEV(Srb); + + SetCheckPoint(0x40); + if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER) + AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER; + + if(CmdAction == CMD_ACTION_PREPARE) { + switch (Srb->Cdb[0]) { + //case SCSIOP_INQUIRY: // now it requires device access + case SCSIOP_READ_CAPACITY: + case SCSIOP_READ: + case SCSIOP_WRITE: + case SCSIOP_REQUEST_SENSE: + // all right + KdPrint2((PRINT_PREFIX "** Ide: Command continue prep\n")); + SetCheckPoint(50); + break; + default: + SetCheckPoint(0); + KdPrint2((PRINT_PREFIX "** Ide: Command break prep\n")); + return SRB_STATUS_BUSY; + } + } + + SetCheckPoint(0x100 | Srb->Cdb[0]); + switch (Srb->Cdb[0]) { + case SCSIOP_INQUIRY: + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_INQUIRY PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + // Filter out all TIDs but 0 and 1 since this is an IDE interface + // which support up to two devices. + if ((Srb->Lun != 0) || + (Srb->PathId >= deviceExtension->NumberChannels) || + (Srb->TargetId > 2) /*|| + (!deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)*/) { + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_INQUIRY rejected\n")); + // Indicate no device found at this address. + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + + } else { + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_INQUIRY ok\n")); + PINQUIRYDATA inquiryData = (PINQUIRYDATA)(Srb->DataBuffer); + PIDENTIFY_DATA2 identifyData = &(deviceExtension->lun[ldev].IdentifyData); + + if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + + if(!CheckDevice(HwDeviceExtension, lChannel, ldev & 1, FALSE)) { + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_INQUIRY rejected (2)\n")); + // Indicate no device found at this address. + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + } else { + if(!UniataAnybodyHome(HwDeviceExtension, lChannel, ldev & 1)) { + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_INQUIRY device have gone\n")); + // Indicate no device found at this address. + deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_DEVICE_PRESENT; + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + } + + // Zero INQUIRY data structure. + RtlZeroMemory((PCHAR)(Srb->DataBuffer), Srb->DataTransferLength); + + // Standard IDE interface only supports disks. + inquiryData->DeviceType = DIRECT_ACCESS_DEVICE; + + // Set the removable bit, if applicable. + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE) { + KdPrint2((PRINT_PREFIX + "RemovableMedia\n")); + inquiryData->RemovableMedia = 1; + } + // Set the Relative Addressing (LBA) bit, if applicable. + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) { + inquiryData->RelativeAddressing = 1; + KdPrint2((PRINT_PREFIX + "RelativeAddressing\n")); + } + // Set the CommandQueue bit + inquiryData->CommandQueue = 1; + + // Fill in vendor identification fields. + for (i = 0; i < 24; i += 2) { + MOV_DW_SWP(inquiryData->VendorId[i], ((PUCHAR)identifyData->ModelNumber)[i]); + } +/* + // Initialize unused portion of product id. + for (i = 0; i < 4; i++) { + inquiryData->ProductId[12+i] = ' '; + } +*/ + // Move firmware revision from IDENTIFY data to + // product revision in INQUIRY data. + for (i = 0; i < 4; i += 2) { + MOV_DW_SWP(inquiryData->ProductRevisionLevel[i], ((PUCHAR)identifyData->FirmwareRevision)[i]); + } + + status = SRB_STATUS_SUCCESS; + } + + break; + + case SCSIOP_MODE_SENSE: + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_MODE_SENSE PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + // This is used to determine if the media is write-protected. + // Since IDE does not support mode sense then we will modify just the portion we need + // so the higher level driver can determine if media is protected. + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { + + SelectDrive(chan, ldev & 0x1); + AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS); + statusByte = WaitOnBusy(chan); + + if (!(statusByte & IDE_STATUS_ERROR)){ + + // no error occured return success, media is not protected + chan->ExpectingInterrupt = FALSE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + status = SRB_STATUS_SUCCESS; + + } else { + + // error occured, handle it locally, clear interrupt + errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error); + + GetBaseStatus(chan, statusByte); + chan->ExpectingInterrupt = FALSE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + status = SRB_STATUS_SUCCESS; + + if (errorByte & IDE_ERROR_DATA_ERROR) { + + //media is write-protected, set bit in mode sense buffer + modeData = (PMODE_PARAMETER_HEADER)Srb->DataBuffer; + + Srb->DataTransferLength = sizeof(MODE_PARAMETER_HEADER); + modeData->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT; + } + } + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_INVALID_REQUEST; + } + break; + + case SCSIOP_TEST_UNIT_READY: + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_TEST_UNIT_READY PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { + + // Select device 0 or 1. + SelectDrive(chan, ldev & 0x1); + AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS); + + // Wait for busy. If media has not changed, return success + statusByte = WaitOnBusy(chan); + + if (!(statusByte & IDE_STATUS_ERROR)){ + chan->ExpectingInterrupt = FALSE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + status = SRB_STATUS_SUCCESS; + } else { + errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error); + if (errorByte == IDE_ERROR_DATA_ERROR){ + + // Special case: If current media is write-protected, + // the 0xDA command will always fail since the write-protect bit + // is sticky,so we can ignore this error + GetBaseStatus(chan, statusByte); + chan->ExpectingInterrupt = FALSE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + status = SRB_STATUS_SUCCESS; + + } else { + + // Request sense buffer to be build + chan->ExpectingInterrupt = TRUE; + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); + status = SRB_STATUS_PENDING; + } + } + } else { + status = SRB_STATUS_SUCCESS; + } + + break; + + case SCSIOP_READ_CAPACITY: + + KdPrint2((PRINT_PREFIX + "** IdeSendCommand: SCSIOP_READ_CAPACITY PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + // Claim 512 byte blocks (big-endian). + //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000; + i = DEV_BSIZE; + MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock, i ); + + // Calculate last sector. + if(!(i = (ULONG)deviceExtension->lun[ldev].NumOfSectors)) { + i = deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack * + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads * + deviceExtension->lun[ldev].IdentifyData.NumberOfCylinders; + } + i--; + + //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress = + // (((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) | + // (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3]; + + MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress, i ); + + KdPrint2((PRINT_PREFIX + "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x\n", + Srb->TargetId, + deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack, + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads, + deviceExtension->lun[ldev].IdentifyData.NumberOfCylinders)); + + + status = SRB_STATUS_SUCCESS; + break; + + case SCSIOP_VERIFY: + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_VERIFY PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + status = IdeVerify(HwDeviceExtension,Srb); + + break; + + case SCSIOP_READ: + case SCSIOP_WRITE: + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_READ/SCSIOP_WRITE PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + AtaReq->Flags &= ~REQ_FLAG_RW_MASK; + AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE) ? REQ_FLAG_WRITE : REQ_FLAG_READ; + status = IdeReadWrite(HwDeviceExtension, + Srb, CmdAction); + break; + + case SCSIOP_START_STOP_UNIT: + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + //Determine what type of operation we should perform + cdb = (PCDB)Srb->Cdb; + + if (cdb->START_STOP.LoadEject == 1){ + + statusByte = WaitOnBaseBusy(chan); + // Eject media, + // first select device 0 or 1. + SelectDrive(chan, ldev & 0x1); + AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT); + } + status = SRB_STATUS_SUCCESS; + break; + + case SCSIOP_MEDIUM_REMOVAL: + + cdb = (PCDB)Srb->Cdb; + + statusByte = WaitOnBaseBusy(chan); + + SelectDrive(chan, ldev & 0x1); + if (cdb->MEDIA_REMOVAL.Prevent == TRUE) { + AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_LOCK); + } else { + AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_UNLOCK); + } + status = SRB_STATUS_SUCCESS; + break; + + // Note: I don't implement this, because NTFS driver too often issues this command + // It causes awful performance degrade. However, if somebody wants, I will implement + // SCSIOP_FLUSH_BUFFER/SCSIOP_SYNCHRONIZE_CACHE optionally. + +#if 0 + case SCSIOP_FLUSH_BUFFER: + case SCSIOP_SYNCHRONIZE_CACHE: + + SelectDrive(chan, ldev & 0x1); + AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_FLUSH_CACHE); + status = SRB_STATUS_SUCCESS; +// status = SRB_STATUS_PENDING; + statusByte = WaitOnBusy(chan); + break; +#endif + + case SCSIOP_REQUEST_SENSE: + // this function makes sense buffers to report the results + // of the original GET_MEDIA_STATUS command + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_REQUEST_SENSE PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { + status = IdeBuildSenseBuffer(HwDeviceExtension,Srb); + break; + } + status = SRB_STATUS_INVALID_REQUEST; + break; + + // ATA_PASSTHORUGH + case SCSIOP_ATA_PASSTHROUGH: + { + PIDEREGS_EX regs; + BOOLEAN use_dma = FALSE; + ULONG to_lim; + + regs = (PIDEREGS_EX) &(Srb->Cdb[2]); + + lChannel = Srb->TargetId >> 1; + + regs->bDriveHeadReg &= 0x0f; + regs->bDriveHeadReg |= (UCHAR) (((Srb->TargetId & 0x1) << 4) | 0xA0); + + if((regs->bReserved & 1) == 0) { // execute ATA command + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->PathId, Srb->Lun, Srb->TargetId)); + + + AtapiDisableInterrupts(deviceExtension, lChannel); + + if(AtaCommandFlags[regs->bCommandReg] & ATA_CMD_FLAG_DMA) { + if((chan->lun[Srb->TargetId & 0x1]->LimitedTransferMode >= ATA_DMA)) { + use_dma = TRUE; + // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success + if(!AtapiDmaSetup(HwDeviceExtension, Srb->TargetId & 0x1, lChannel, Srb, + (PUCHAR)(Srb->DataBuffer), + ((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1)))) { + use_dma = FALSE; + } + } + } + + AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, regs->bDriveHeadReg); + AtapiStallExecution(10); + + if((regs->bReserved & ATA_FLAGS_48BIT_COMMAND) == 0) { // execute ATA command + AtapiWritePort1(chan, IDX_IO1_o_Feature, regs->bFeaturesReg); + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, regs->bSectorCountReg); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, regs->bSectorNumberReg); + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, regs->bCylLowReg); + AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighReg); + } else { + AtapiWritePort1(chan, IDX_IO1_o_Feature, regs->bFeaturesRegH); + AtapiWritePort1(chan, IDX_IO1_o_Feature, regs->bFeaturesReg); + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, regs->bSectorCountRegH); + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, regs->bSectorCountReg); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, regs->bSectorNumberRegH); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, regs->bSectorNumberReg); + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, regs->bCylLowRegH); + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, regs->bCylLowReg); + AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighRegH); + AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighReg); + } + AtapiWritePort1(chan, IDX_IO1_o_Command, regs->bCommandReg); + + if(use_dma) { + GetBaseStatus(chan, statusByte); + if(statusByte & IDE_STATUS_ERROR) { + goto passthrough_err; + } + AtapiDmaStart(HwDeviceExtension, (Srb->TargetId & 0x1), lChannel, Srb); + } + + ScsiPortStallExecution(1); // wait for busy to be set + + if(regs->bReserved & UNIATA_SPTI_EX_SPEC_TO) { + to_lim = Srb->TimeOutValue; + } else { + if(Srb->TimeOutValue <= 2) { + to_lim = Srb->TimeOutValue*900; + } else { + to_lim = (Srb->TimeOutValue*999) - 500; + } + } + for(i=0; i= to_lim) { + //if(regs->bReserved & UNIATA_SPTI_EX_FREEZE_TO) { + //} + AtapiResetController__(HwDeviceExtension, lChannel, RESET_COMPLETE_NONE); + goto passthrough_err; + } + + if(use_dma) { + AtapiCheckInterrupt__(deviceExtension, (UCHAR)lChannel); + } + AtapiDmaDone(deviceExtension, (Srb->TargetId & 0x1), lChannel, NULL); + GetBaseStatus(chan, statusByte); + + if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) { + AtapiSuckPort2(chan); +passthrough_err: + if (Srb->SenseInfoBuffer) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID; + Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION; + } + status = SRB_STATUS_ERROR; + } else { + + if(!use_dma) { + if (statusByte & IDE_STATUS_DRQ) { + if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) { + ReadBuffer(chan, + (PUSHORT) Srb->DataBuffer, + Srb->DataTransferLength / 2, + 0); + } else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) { + WriteBuffer(chan, + (PUSHORT) Srb->DataBuffer, + Srb->DataTransferLength / 2, + 0); + } + } + } + status = SRB_STATUS_SUCCESS; + } + + AtapiEnableInterrupts(deviceExtension, lChannel); + + } else { // read task register + + regs = (PIDEREGS_EX) Srb->DataBuffer; + + regs->bDriveHeadReg = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect); + + if((regs->bReserved & ATA_FLAGS_48BIT_COMMAND) == 0) { // execute ATA command + regs->bFeaturesReg = AtapiReadPort1(chan, IDX_IO1_i_Error); + regs->bSectorCountReg = AtapiReadPort1(chan, IDX_IO1_i_BlockCount); + regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber); + regs->bCylLowReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + regs->bCylHighReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + } else { + regs->bFeaturesReg = AtapiReadPort1(chan, IDX_IO1_i_Error); + regs->bFeaturesRegH = AtapiReadPort1(chan, IDX_IO1_i_Error); + regs->bSectorCountReg = AtapiReadPort1(chan, IDX_IO1_i_BlockCount); + regs->bSectorCountRegH = AtapiReadPort1(chan, IDX_IO1_i_BlockCount); + regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber); + regs->bSectorNumberRegH= AtapiReadPort1(chan, IDX_IO1_i_BlockNumber); + regs->bCylLowReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + regs->bCylLowRegH = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + regs->bCylHighReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + regs->bCylHighRegH = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + } + regs->bCommandReg = AtapiReadPort1(chan, IDX_IO1_i_Status); + status = SRB_STATUS_SUCCESS; + } + break; + } + + default: + + KdPrint2((PRINT_PREFIX + "IdeSendCommand: Unsupported command %#x\n", + Srb->Cdb[0])); + + status = SRB_STATUS_INVALID_REQUEST; + + } // end switch + + if(status == SRB_STATUS_PENDING) { + KdPrint2((PRINT_PREFIX "IdeSendCommand: SRB_STATUS_PENDING\n")); + if(CmdAction & CMD_ACTION_EXEC) { + KdPrint2((PRINT_PREFIX "IdeSendCommand: REQ_STATE_EXPECTING_INTR\n")); + AtaReq->ReqState = REQ_STATE_EXPECTING_INTR; + } + } else { + KdPrint2((PRINT_PREFIX "IdeSendCommand: REQ_STATE_TRANSFER_COMPLETE\n")); + AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE; + } + + return status; + +} // end IdeSendCommand() + + +/*++ + +Routine Description: + Enables disables media status notification + +Arguments: + HwDeviceExtension - ATAPI driver storage. + +--*/ +VOID +IdeMediaStatus( + BOOLEAN EnableMSN, + IN PVOID HwDeviceExtension, + UCHAR ldev + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan; + UCHAR lChannel = ldev >> 1; + UCHAR statusByte,errorByte; + + chan = &(deviceExtension->chan[lChannel]); + + if (EnableMSN == TRUE){ + + // If supported enable Media Status Notification support + if ((deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE)) { + + // enable + statusByte = AtaCommand(deviceExtension, ldev & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_ENAB_MEDIASTAT, ATA_WAIT_BASE_READY); + + if (statusByte & IDE_STATUS_ERROR) { + // Read the error register. + errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error); + + KdPrint2((PRINT_PREFIX + "IdeMediaStatus: Error enabling media status. Status %#x, error byte %#x\n", + statusByte, + errorByte)); + } else { + deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_MEDIA_STATUS_ENABLED; + KdPrint2((PRINT_PREFIX "IdeMediaStatus: Media Status Notification Supported\n")); + chan->ReturningMediaStatus = 0; + + } + + } + } else { // end if EnableMSN == TRUE + + // disable if previously enabled + if ((deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)) { + + statusByte = AtaCommand(deviceExtension, ldev & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_DIS_MEDIASTAT, ATA_WAIT_BASE_READY); + deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_MEDIA_STATUS_ENABLED; + } + + + } + + +} // end IdeMediaStatus() + + +/*++ + +Routine Description: + + Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS + command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE. +Arguments: + + HwDeviceExtension - ATAPI driver storage. + Srb - System request block. + +Return Value: + + SRB status (ALWAYS SUCCESS). + +--*/ +ULONG +IdeBuildSenseBuffer( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; +// ULONG status; + PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->DataBuffer; + UCHAR ReturningMediaStatus = deviceExtension->chan[GET_CHANNEL(Srb)].ReturningMediaStatus; + + if (senseBuffer){ + + if(ReturningMediaStatus & IDE_ERROR_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 = 0; + } else if(ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE_REQ) { + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION; + senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED; + senseBuffer->AdditionalSenseCodeQualifier = 0; + } else if(ReturningMediaStatus & IDE_ERROR_END_OF_MEDIA) { + + 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; + } else if(ReturningMediaStatus & IDE_ERROR_DATA_ERROR) { + + senseBuffer->ErrorCode = 0x70; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_DATA_PROTECT; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + } + return SRB_STATUS_SUCCESS; + } + return SRB_STATUS_ERROR; + +}// End of IdeBuildSenseBuffer + +VOID +UniataUserDeviceReset( + PHW_DEVICE_EXTENSION deviceExtension, + PHW_LU_EXTENSION LunExt, + ULONG PathId, + ULONG ldev + ) +{ + AtapiDisableInterrupts(deviceExtension, PathId); + if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) { + KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset ATAPI\n")); + AtapiSoftReset(&(deviceExtension->chan[PathId]), ldev & 1); + } else { + KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset IDE -> reset entire channel\n")); + AtapiResetController__(deviceExtension, PathId, RESET_COMPLETE_NONE); + } + LunExt->DeviceFlags |= DFLAGS_REINIT_DMA; // force PIO/DMA reinit + AtapiEnableInterrupts(deviceExtension, PathId); + return; +} // end UniataUserDeviceReset() + +BOOLEAN +UniataNeedQueueing( + PHW_DEVICE_EXTENSION deviceExtension, + PHW_CHANNEL chan, + BOOLEAN TopLevel + ) +{ + BOOLEAN PostReq = FALSE; + if(TopLevel) { + if(chan->queue_depth > 0) { +#if 0 + if(atapiDev && + ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY)/* || + (Srb->Cdb[0] == SCSIOP_REQUEST_SENSE)*/) ) { + KdPrint2((PRINT_PREFIX "spec: SCSIOP_TEST_UNIT_READY\n")); + //PostReq = FALSE; + status = SRB_STATUS_BUSY; + goto skip_exec; + } else { + PostReq = TRUE; + } +#else + PostReq = TRUE; +#endif + } else + if(deviceExtension->simplexOnly && deviceExtension->queue_depth > 0) { + PostReq = TRUE; + } + } + return PostReq; +} // end UniataNeedQueueing() + +/*++ + +Routine Description: + + This routine is called from the SCSI port driver synchronized + with the kernel to start an IO request. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + Srb - IO request packet + +Return Value: + + TRUE + +--*/ +BOOLEAN +DDKAPI +AtapiStartIo( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + return AtapiStartIo__(HwDeviceExtension, Srb, TRUE); +} // end AtapiStartIo() + +BOOLEAN +AtapiStartIo__( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN BOOLEAN TopLevel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + UCHAR lChannel; + PHW_CHANNEL chan; + ULONG status; + ULONG ldev; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + PATA_REQ AtaReq; + PSCSI_REQUEST_BLOCK tmpSrb; + BOOLEAN PostReq = FALSE; + BOOLEAN atapiDev; + + if(deviceExtension->Isr2DevObj && !BMList[deviceExtension->DevIndex].Isr2Enable) { + KdPrint2((PRINT_PREFIX "Isr2Enable -> 1\n")); + BMList[deviceExtension->DevIndex].Isr2Enable = TRUE; + } +// deviceExtension->QueueNewIrql = max(deviceExtension->QueueNewIrql, KeGetCurrentIrql()); + +/* KeBugCheckEx(0xc000000e, + (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun), + Srb->Function, + TopLevel, 0x80000001); +*/ + if(TopLevel && Srb && Srb->SrbExtension) { + KdPrint2((PRINT_PREFIX "TopLevel\n")); + RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ)); + } + + do { + + lChannel = GET_CHANNEL(Srb); + chan = &(deviceExtension->chan[lChannel]); + ldev = GET_LDEV(Srb); + + //ASSERT(deviceExtension); + //ASSERT(chan); + + KdPrint2((PRINT_PREFIX + "** AtapiStartIo: Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId)); + KdPrint2((PRINT_PREFIX " VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID)); + + if(GET_CDEV(Srb) >= 2 || + ldev >= deviceExtension->NumberChannels*2 || + lChannel >= deviceExtension->NumberChannels || + Srb->Lun) { + + if(lChannel >= deviceExtension->NumberChannels) { + chan = NULL; + } + +reject_srb: + //if(!CheckDevice(HwDeviceExtension, lChannel, ldev & 1, FALSE)) { + KdPrint2((PRINT_PREFIX + "AtapiStartIo: SRB rejected\n")); + // Indicate no device found at this address. + KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n")); + status = SRB_STATUS_SELECTION_TIMEOUT; + goto complete_req; + //} + } + + atapiDev = (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE; + +#ifdef _DEBUG + if(!(chan->lun[ldev & 1])) { + PrintNtConsole("de = %#x, chan = %#x , dev %#x, nchan %#x\n", + deviceExtension, + chan, ldev & 1, + deviceExtension->NumberChannels); + PrintNtConsole("lchan = %#x, ldev %#x, cdev %#x, lun0 %#x\n", + lChannel, ldev, GET_CDEV(Srb), deviceExtension->chan[0].lun[0]); + PrintNtConsole("Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n", + Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId); +/* + int i; + for(i=0; i<1000; i++) { + AtapiStallExecution(3*1000); + } +*/ + goto reject_srb; + } +#endif //_DEBUG + //ASSERT(chan->lun[ldev & 1]); + + // Determine which function. + switch (Srb->Function) { + + case SRB_FUNCTION_EXECUTE_SCSI: + + if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + if(Srb->Cdb[0] == SCSIOP_ATA_PASSTHROUGH) { + // let passthrough go + } else + if(Srb->Cdb[0] == SCSIOP_INQUIRY) { + // let INQUIRY go + } else { + + //if(!CheckDevice(HwDeviceExtension, lChannel, ldev & 1, FALSE)) { + KdPrint2((PRINT_PREFIX + "AtapiStartIo: EXECUTE_SCSI rejected (2)\n")); + // Indicate no device found at this address. + KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n")); + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + //} + } + } +/* + __try { + if(Srb->DataTransferLength) { + UCHAR a; + a = ((PUCHAR)(Srb->DataBuffer))[0]; + g_foo += a; + } + } __except(EXCEPTION_EXECUTE_HANDLER) { + KdPrint2((PRINT_PREFIX + "AtapiStartIo: Bad data buffer -> EXECUTE_SCSI rejected\n")); + // Indicate no device found at this address. + KdPrint2((PRINT_PREFIX "SRB_STATUS_ERROR\n")); + status = SRB_STATUS_ERROR; + KdPrint2((PRINT_PREFIX " *** Exception...\n")); + ASSERT(FALSE); + break; + } +*/ + PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel); + + if(PostReq) { + + KdPrint2((PRINT_PREFIX "Non-empty queue\n")); + if (atapiDev && + (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)) { + KdPrint2((PRINT_PREFIX "Try ATAPI prepare\n")); + + status = AtapiSendCommand(HwDeviceExtension, Srb, CMD_ACTION_PREPARE); + } else { + KdPrint2((PRINT_PREFIX "Try IDE prepare\n")); + status = IdeSendCommand(HwDeviceExtension, Srb, CMD_ACTION_PREPARE); + } + /*KeBugCheckEx(0xc000000e, + (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun), + Srb->Function, + status, 0x80000001);*/ + if(status == SRB_STATUS_BUSY) + status = SRB_STATUS_PENDING; + // Insert requests AFTER they have been initialized on + // CMD_ACTION_PREPARE stage + // we should not check TopLevel here (it is always TRUE) + //ASSERT(chan->lun[GET_LDEV(Srb) & 1]); + UniataQueueRequest(chan, Srb); + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth)); + + } else { + // Send command to device. + KdPrint2((PRINT_PREFIX "Send to device\n")); + if(TopLevel) { + KdPrint2((PRINT_PREFIX "TopLevel (2), srb %#x\n", Srb)); + AtaReq = (PATA_REQ)(Srb->SrbExtension); + KdPrint2((PRINT_PREFIX "TopLevel (3), AtaReq %#x\n", AtaReq)); + //ASSERT(!AtaReq->Flags); + //ASSERT(chan->lun[GET_LDEV(Srb) & 1]); + UniataQueueRequest(chan, Srb); +// AtaReq = (PATA_REQ)(Srb->SrbExtension); + //ASSERT(!AtaReq->Flags); + AtaReq->ReqState = REQ_STATE_QUEUED; + //ASSERT(!AtaReq->Flags); + } + + if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + if(Srb->Cdb[0] == SCSIOP_INQUIRY) { + if(UniataAnybodyHome(deviceExtension, chan->lChannel, ldev & 1)) { + if(!CheckDevice(HwDeviceExtension, chan->lChannel, ldev & 1, TRUE)) { + goto reject_srb; + } + } + if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + goto reject_srb; + } + } else + if(Srb->Cdb[0] == SCSIOP_ATA_PASSTHROUGH) { + // allow + } else { + goto reject_srb; + } + } + + if(atapiDev && + (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)) { + KdPrint2((PRINT_PREFIX "Try ATAPI send\n")); + status = AtapiSendCommand(HwDeviceExtension, Srb, CMD_ACTION_ALL); + } else { + KdPrint2((PRINT_PREFIX "Try IDE send\n")); +/* { + ULONG __ebp__ = 0; + ULONG __esp__ = 0; + + KdPrint2((PRINT_PREFIX "** before IdeSendCommand:\n")); + __asm { + mov eax,ebp + mov __ebp__, eax + mov eax,esp + mov __esp__, eax + } + KdPrint2((PRINT_PREFIX "** before Ide: EBP:%#x ESP:%#x\n", __ebp__, __esp__)); + }*/ + status = IdeSendCommand(HwDeviceExtension, Srb, CMD_ACTION_ALL); + } +/* KeBugCheckEx(0xc000000e, + (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun), + Srb->Function, + status, 0x80000002);*/ + + } +//skip_exec: + TopLevel = FALSE; + + break; + + case SRB_FUNCTION_ABORT_COMMAND: + + tmpSrb = ScsiPortGetSrb(HwDeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun, + Srb->QueueTag); + // Verify that SRB to abort is still outstanding. + if((tmpSrb != Srb->NextSrb) || + !chan->queue_depth) { + + KdPrint2((PRINT_PREFIX "AtapiStartIo: SRB to abort already completed\n")); + + // Complete abort SRB. + status = SRB_STATUS_ABORT_FAILED; + break; + } + + AtaReq = (PATA_REQ)(tmpSrb->SrbExtension); + if(AtaReq->ReqState > REQ_STATE_READY_TO_TRANSFER) { + if (!AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_CURRENT)) { + KdPrint2((PRINT_PREFIX "AtapiStartIo: Abort command failed\n")); + // Log reset failure. + KdPrint2((PRINT_PREFIX + "ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d)\n", + HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8 + )); + ScsiPortLogError(HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8); + status = SRB_STATUS_ERROR; + + } else { + status = SRB_STATUS_SUCCESS; + } + } else { + KdPrint2((PRINT_PREFIX "AtapiInterrupt: remove aborted srb %#x\n", tmpSrb)); + if (tmpSrb->SenseInfoBuffer && + tmpSrb->SenseInfoBufferLength >= sizeof(SENSE_DATA)) { + + PSENSE_DATA senseBuffer = (PSENSE_DATA)tmpSrb->SenseInfoBuffer; + + senseBuffer->ErrorCode = 0; + senseBuffer->Valid = 1; + senseBuffer->AdditionalSenseLength = 0xb; + senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND; + senseBuffer->AdditionalSenseCode = 0; + senseBuffer->AdditionalSenseCodeQualifier = 0; + + tmpSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + AtapiDmaDBSync(chan, tmpSrb); + UniataRemoveRequest(chan, tmpSrb); + // Indicate command complete. + ScsiPortNotification(RequestComplete, + deviceExtension, + tmpSrb); + status = SRB_STATUS_SUCCESS; + } + break; + + // Abort function indicates that a request timed out. + // Call reset routine. Card will only be reset if + // status indicates something is wrong. + // Fall through to reset code. + + case SRB_FUNCTION_RESET_DEVICE: + case SRB_FUNCTION_RESET_LOGICAL_UNIT: + + // Reset single device. + // For now we support only Lun=0 + + // Note: reset is immediate command, it cannot be queued since it is usually used to + // revert not- responding device to operational state + KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset device request received\n")); + UniataUserDeviceReset(deviceExtension, &(deviceExtension->lun[ldev]), lChannel, ldev); + status = SRB_STATUS_SUCCESS; + break; + + case SRB_FUNCTION_RESET_BUS: + + // Reset Atapi and SCSI bus. + + // Note: reset is immediate command, it cannot be queued since it is usually used to + // revert not- responding device to operational state + KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset bus request received\n")); + if (!AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_ALL)) { + KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset bus failed\n")); + // Log reset failure. + KdPrint2((PRINT_PREFIX + "ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d) - (2)\n", + HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8 + )); + ScsiPortLogError(HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8); + status = SRB_STATUS_ERROR; + + } else { + status = SRB_STATUS_SUCCESS; + } + + break; + + case SRB_FUNCTION_SHUTDOWN: + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown\n")); + if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - no such device\n")); + } + if(atapiDev) { + // FLUSH ATAPI device - do nothing + KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - ATAPI device\n")); + } else { + // FLUSH IDE/ATA device + KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - IDE device\n")); + AtapiDisableInterrupts(deviceExtension, lChannel); + status = AtaCommand(deviceExtension, ldev & 1, GET_CHANNEL(Srb), + IDE_COMMAND_FLUSH_CACHE, 0, 0, 0, 0, 0, ATA_WAIT_IDLE); + // If supported & allowed, reset write cacheing + if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_WCACHE_ENABLED) { + + // Disable write cache + status = AtaCommand(deviceExtension, ldev & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY); + // Check for errors. + if (status & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX + "AtapiHwInitialize: Disable write cacheing on Device %d failed\n", + ldev)); + } + deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_WCACHE_ENABLED; + + // Re-enable write cache + status = AtaCommand(deviceExtension, ldev & 1, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY); + // Check for errors. + if (status & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX + "AtapiHwInitialize: Enable write cacheing on Device %d failed\n", + ldev)); + deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_WCACHE_ENABLED; + } else { + deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_WCACHE_ENABLED; + } + } + + AtapiEnableInterrupts(deviceExtension, lChannel); + } + status = SRB_STATUS_SUCCESS; + + break; + + case SRB_FUNCTION_FLUSH: + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Flush (do nothing)\n")); + status = SRB_STATUS_SUCCESS; + break; + + /* case SRB_FUNCTION_SHUTDOWN: + case SRB_FUNCTION_FLUSH: + + // Flush device's cache. + KdPrint2((PRINT_PREFIX "AtapiStartIo: Device flush received\n")); + + if (chan->CurrentSrb) { + + KdPrint2((PRINT_PREFIX "AtapiStartIo (SRB_FUNCTION_FLUSH): Already have a request!\n")); + Srb->SrbStatus = SRB_STATUS_BUSY; + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + return FALSE; + } + + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) { + status = SRB_STATUS_SUCCESS; + } else { + status = AtaCommand(deviceExtension, ldev & 1, GET_CHANNEL(Srb), + IDE_COMMAND_FLUSH_CACHE, 0, 0, 0, 0, 0, ATA_WAIT_INTR); + if (status & IDE_STATUS_DRQ) { + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_SELECTION_TIMEOUT; + } + } + break;*/ + + case SRB_FUNCTION_IO_CONTROL: { + + ULONG len; + + KdPrint2((PRINT_PREFIX "AtapiStartIo: SRB_FUNCTION_IO_CONTROL\n")); + + len = Srb->DataTransferLength; + + if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) { + + switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) { + case IOCTL_SCSI_MINIPORT_SMART_VERSION: { + + PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); + UCHAR deviceNumber; + + KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n")); + + // Version and revision per SMART 1.03 + + versionParameters->bVersion = 1; + versionParameters->bRevision = 1; + versionParameters->bReserved = 0; + + // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands. + versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD); + + // This is done because of how the IOCTL_SCSI_MINIPORT + // determines 'targetid's'. Disk.sys places the real target id value + // in the DeviceMap field. Once we do some parameter checking, the value passed + // back to the application will be determined. + + deviceNumber = versionParameters->bIDEDeviceMap; + + if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT) || + atapiDev) { + + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + + // NOTE: This will only set the bit + // corresponding to this drive's target id. + // The bit mask is as follows: + // + // -Sec Pri + // S M S M + // 3 2 1 0 + + if (deviceExtension->NumberChannels == 1) { + if (chan->PrimaryAddress) { + deviceNumber = 1 << ldev; + } else { + deviceNumber = 4 << ldev; + } + } else { + deviceNumber = 1 << ldev; + } + + versionParameters->bIDEDeviceMap = deviceNumber; + + status = SRB_STATUS_SUCCESS; + break; + } + + case IOCTL_SCSI_MINIPORT_IDENTIFY: { + + PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); + SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL)); + UCHAR targetId; + + KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY\n")); + // Extract the target. + targetId = cmdInParameters.bDriveNumber; + KdPrint2((PRINT_PREFIX "targetId %d\n", targetId)); + if((targetId >= deviceExtension->NumberChannels*2) || + !(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { + KdPrint2((PRINT_PREFIX "Error: xxx_ID_CMD for non-existant device\n")); + status = SRB_STATUS_SELECTION_TIMEOUT; + break; + } + + switch(cmdInParameters.irDriveRegs.bCommandReg) { + case ID_CMD: + if((deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + KdPrint2((PRINT_PREFIX "Error: ID_CMD for ATAPI\n")); + status = SRB_STATUS_INVALID_REQUEST; + break; + } + /* FALL THROUGH */ + case ATAPI_ID_CMD: + + if(!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE) && + (cmdInParameters.irDriveRegs.bCommandReg == ATAPI_ID_CMD)) { + KdPrint2((PRINT_PREFIX "Error: ATAPI_ID_CMD for non-ATAPI\n")); + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + len = min(len, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE); + // Zero the output buffer + RtlZeroMemory(cmdOutParameters, len); +/* for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1); i++) { + ((PUCHAR)cmdOutParameters)[i] = 0; + }*/ + + // Build status block. + cmdOutParameters->cBufferSize = min(IDENTIFY_BUFFER_SIZE, len - sizeof(SENDCMDOUTPARAMS) + 1); + cmdOutParameters->DriverStatus.bDriverError = 0; + cmdOutParameters->DriverStatus.bIDEError = 0; + + // Extract the identify data from the device extension. + ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->lun[targetId].IdentifyData, + cmdOutParameters->cBufferSize); + + KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY Ok\n")); + + status = SRB_STATUS_SUCCESS; + + break; + default: + KdPrint2((PRINT_PREFIX "AtapiStartIo: not supported ID code %x\n", + cmdInParameters.irDriveRegs.bCommandReg)); + status = SRB_STATUS_INVALID_REQUEST; + break; + } + break; + } + + case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS: + case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS: + case IOCTL_SCSI_MINIPORT_ENABLE_SMART: + case IOCTL_SCSI_MINIPORT_DISABLE_SMART: + case IOCTL_SCSI_MINIPORT_RETURN_STATUS: + case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE: + case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES: + case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS: + + PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel); + + if(PostReq || TopLevel) { + UniataQueueRequest(chan, Srb); + AtaReq = (PATA_REQ)(Srb->SrbExtension); + AtaReq->ReqState = REQ_STATE_QUEUED; + } + + if(PostReq) { + + KdPrint2((PRINT_PREFIX "Non-empty queue (SMART)\n")); + status = SRB_STATUS_PENDING; + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth)); + } else { + + status = IdeSendSmartCommand(HwDeviceExtension,Srb); + } + break; + + default : + KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n", + ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode )); + status = SRB_STATUS_INVALID_REQUEST; + break; + + } + } else + if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"-UNIATA-", sizeof("-UNIATA-")-1)) { + + PUNIATA_CTL AtaCtl = (PUNIATA_CTL)(Srb->DataBuffer); + ULONG ldev = GET_LDEV2(AtaCtl->addr.PathId, AtaCtl->addr.TargetId, 0); + PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]); + BOOLEAN bad_ldev; + ULONG i; + //chan = &(deviceExtension->chan[lChannel]); + + if(AtaCtl->addr.Lun || + ldev >= deviceExtension->NumberChannels*2 || + AtaCtl->addr.PathId > deviceExtension->NumberChannels) { + + bad_ldev = TRUE; + LunExt = NULL; + + } else { + bad_ldev = FALSE; + LunExt = &(deviceExtension->lun[ldev]); + } + + KdPrint2((PRINT_PREFIX "AtapiStartIo: -UNIATA- %#x, ldev %#x\n", AtaCtl->hdr.ControlCode, ldev)); + + /* check for valid LUN */ + switch (AtaCtl->hdr.ControlCode) { + case IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES: + case IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE: + case IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE: + case IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE: + case IOCTL_SCSI_MINIPORT_UNIATA_RESETBB: + case IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE: + if(bad_ldev) { + KdPrint2((PRINT_PREFIX + "AtapiStartIo: bad_ldev -> IOCTL SRB rejected\n")); + // Indicate no device found at this address. + goto reject_srb; + } + } + + /* check if queueing is necessary */ + switch (AtaCtl->hdr.ControlCode) { + case IOCTL_SCSI_MINIPORT_UNIATA_RESETBB: + if(!LunExt->nBadBlocks) { + break; + } + goto uata_ctl_queue; + case IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE: + if(!AtaCtl->SetMode.ApplyImmediately) { + break; + } + goto uata_ctl_queue; + case IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES: + //case IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE: reset must be processed immediately +uata_ctl_queue: + KdPrint2((PRINT_PREFIX "put to queue (UNIATA)\n")); + PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel); + + if(PostReq || TopLevel) { + UniataQueueRequest(chan, Srb); + AtaReq = (PATA_REQ)(Srb->SrbExtension); + AtaReq->ReqState = REQ_STATE_QUEUED; + } + if(PostReq) { + KdPrint2((PRINT_PREFIX "Non-empty queue (UNIATA)\n")); + status = SRB_STATUS_PENDING; + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth)); + goto complete_req; + } + } + + /* process request */ + switch (AtaCtl->hdr.ControlCode) { + case IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES: + + KdPrint2((PRINT_PREFIX "AtapiStartIo: rescan bus\n")); + + for(i=0; iFindDelDev.WaitForPhysicalLink && i<30; i++) { + AtapiStallExecution(1000 * 1000); + } + + FindDevices(HwDeviceExtension, FALSE, AtaCtl->addr.PathId); + status = SRB_STATUS_SUCCESS; + + break; + + case IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE: { + + KdPrint2((PRINT_PREFIX "AtapiStartIo: remove %#x:%#x\n", AtaCtl->addr.PathId, AtaCtl->addr.TargetId)); + + deviceExtension->lun[ldev].DeviceFlags = 0; + + for(i=0; iFindDelDev.WaitForPhysicalLink && i<30; i++) { + AtapiStallExecution(1000 * 1000); + } + + status = SRB_STATUS_SUCCESS; + break; + } + case IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE: { + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Set transfer mode\n")); + + if(AtaCtl->SetMode.OrigMode != -1) { + LunExt->OrigTransferMode = (UCHAR)(AtaCtl->SetMode.OrigMode); + } + if(AtaCtl->SetMode.MaxMode != -1) { + LunExt->LimitedTransferMode = (UCHAR)(AtaCtl->SetMode.MaxMode); + if(LunExt->LimitedTransferMode > + LunExt->OrigTransferMode) { + // check for incorrect value + LunExt->LimitedTransferMode = + LunExt->OrigTransferMode; + } + } + LunExt->TransferMode = LunExt->OrigTransferMode; + + LunExt->DeviceFlags |= DFLAGS_REINIT_DMA; // force PIO/DMA reinit + if(AtaCtl->SetMode.ApplyImmediately) { + AtapiDmaInit__(deviceExtension, ldev); + } +/* deviceExtension->lun[ldev].TransferMode = + deviceExtension->lun[ldev].LimitedTransferMode = (UCHAR)(setTransferMode->Mode);*/ + status = SRB_STATUS_SUCCESS; + break; + } + case IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE: { + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Get transfer mode\n")); + + AtaCtl->GetMode.OrigMode = LunExt->OrigTransferMode; + AtaCtl->GetMode.MaxMode = LunExt->LimitedTransferMode; + AtaCtl->GetMode.CurrentMode = LunExt->TransferMode; + + status = SRB_STATUS_SUCCESS; + break; + } + case IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO: { + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Get adapter info\n")); + + AtaCtl->AdapterInfo.HeaderLength = offsetof(ADAPTERINFO, Chan); + + if(len < AtaCtl->AdapterInfo.HeaderLength + sizeof(AtaCtl->AdapterInfo.Chan)) { + KdPrint2((PRINT_PREFIX "AtapiStartIo: Buffer too small: %#x < %#x\n", len, + AtaCtl->AdapterInfo.HeaderLength + sizeof(AtaCtl->AdapterInfo.Chan))); + status = SRB_STATUS_DATA_OVERRUN; + break; + } + + AtaCtl->AdapterInfo.DevID = deviceExtension->DevID; + AtaCtl->AdapterInfo.RevID = deviceExtension->RevID; + AtaCtl->AdapterInfo.slotNumber = deviceExtension->slotNumber; + AtaCtl->AdapterInfo.SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + AtaCtl->AdapterInfo.DevIndex = deviceExtension->DevIndex; + AtaCtl->AdapterInfo.Channel = deviceExtension->Channel; + AtaCtl->AdapterInfo.HbaCtrlFlags = deviceExtension->HbaCtrlFlags; + AtaCtl->AdapterInfo.simplexOnly= deviceExtension->simplexOnly; + AtaCtl->AdapterInfo.MemIo = FALSE;/*deviceExtension->MemIo;*/ + AtaCtl->AdapterInfo.UnknownDev = deviceExtension->UnknownDev; + AtaCtl->AdapterInfo.MasterDev = deviceExtension->MasterDev; + AtaCtl->AdapterInfo.MaxTransferMode = deviceExtension->MaxTransferMode; + AtaCtl->AdapterInfo.HwFlags = deviceExtension->HwFlags; + AtaCtl->AdapterInfo.OrigAdapterInterfaceType = deviceExtension->OrigAdapterInterfaceType; + AtaCtl->AdapterInfo.BusInterruptLevel = deviceExtension->BusInterruptLevel; + AtaCtl->AdapterInfo.InterruptMode = deviceExtension->InterruptMode; + AtaCtl->AdapterInfo.BusInterruptVector = deviceExtension->BusInterruptVector; + AtaCtl->AdapterInfo.NumberChannels = deviceExtension->NumberChannels; + + AtaCtl->AdapterInfo.ChanInfoValid = FALSE; + + RtlZeroMemory(&AtaCtl->AdapterInfo.Chan, sizeof(AtaCtl->AdapterInfo.Chan)); + + status = SRB_STATUS_SUCCESS; + break; + } + case IOCTL_SCSI_MINIPORT_UNIATA_RESETBB: { + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Forget BB list\n")); + + ForgetBadBlocks(LunExt); + + status = SRB_STATUS_SUCCESS; + break; + } + case IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE: { + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset device\n")); + + UniataUserDeviceReset(deviceExtension, LunExt, AtaCtl->addr.PathId, ldev); + + status = SRB_STATUS_SUCCESS; + break; + } + default : + KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for -UNIATA- signature\n", + AtaCtl->hdr.ControlCode )); + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + } else { + KdPrint2((PRINT_PREFIX "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s or %s\n", + ((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature, + "SCSIDISK", "-UNIATA-")); + + status = SRB_STATUS_INVALID_REQUEST; + break; + } + + break; + } // end SRB_FUNCTION_IO_CONTROL + default: + + KdPrint2((PRINT_PREFIX "AtapiStartIo: Unknown IOCTL\n")); + // Indicate unsupported command. + status = SRB_STATUS_INVALID_REQUEST; + +// break; + + } // end switch + +complete_req: + + PathId = Srb->PathId; + TargetId = Srb->TargetId; + Lun = Srb->Lun; + + if (status != SRB_STATUS_PENDING) { + + KdPrint2((PRINT_PREFIX + "AtapiStartIo: Srb %#x complete with status %#x\n", + Srb, + status)); + + // Set status in SRB. + Srb->SrbStatus = (UCHAR)status; + + AtapiDmaDBSync(chan, Srb); + UniataRemoveRequest(chan, Srb); + // Indicate command complete. + ScsiPortNotification(RequestComplete, + deviceExtension, + Srb); + + // Remove current Srb & get next one + if(Srb = UniataGetCurRequest(chan)) { + AtaReq = (PATA_REQ)(Srb->SrbExtension); + if(AtaReq->ReqState > REQ_STATE_QUEUED) { + // current request is under precessing, thus + // we should do nothing here + Srb = NULL; + } + } + if(!chan) { + //ASSERT(TopLevel); + } + } + KdPrint2((PRINT_PREFIX "AtapiStartIo: next Srb %x\n", Srb)); + + } while (Srb && (status != SRB_STATUS_PENDING)); + + KdPrint2((PRINT_PREFIX "AtapiStartIo: query PORT for next request\n")); + // Indicate ready for next request. + ScsiPortNotification(NextRequest, + deviceExtension, + NULL); + + ScsiPortNotification(NextLuRequest, + deviceExtension, + PathId, + TargetId, + Lun); + + return TRUE; + +} // end AtapiStartIo__() + + +void +UniataInitAtaCommands() +{ + int i; + UCHAR command; + UCHAR flags; + + for(i=0, command=0; i<256; i++, command++) { + + switch(command) { + case IDE_COMMAND_READ_DMA48: + case IDE_COMMAND_READ_DMA_Q48: + case IDE_COMMAND_READ_STREAM_DMA48: + case IDE_COMMAND_READ_STREAM48: + case IDE_COMMAND_WRITE_DMA48: + case IDE_COMMAND_WRITE_DMA_Q48: + case IDE_COMMAND_READ_DMA_Q: + case IDE_COMMAND_READ_DMA: + case IDE_COMMAND_WRITE_DMA: + case IDE_COMMAND_WRITE_DMA_Q: + case IDE_COMMAND_WRITE_STREAM_DMA48: + case IDE_COMMAND_WRITE_STREAM48: + case IDE_COMMAND_WRITE_FUA_DMA48: + case IDE_COMMAND_WRITE_FUA_DMA_Q48: + case IDE_COMMAND_READ_LOG_DMA48: + case IDE_COMMAND_WRITE_LOG_DMA48: + case IDE_COMMAND_TRUSTED_RCV_DMA: + case IDE_COMMAND_TRUSTED_SEND_DMA: + flags |= ATA_CMD_FLAG_DMA; + } + + switch(command) { + case IDE_COMMAND_READ48: + case IDE_COMMAND_READ_DMA48: + case IDE_COMMAND_READ_DMA_Q48: + case IDE_COMMAND_READ_MUL48: + case IDE_COMMAND_READ_STREAM_DMA48: + case IDE_COMMAND_READ_STREAM48: + case IDE_COMMAND_WRITE48: + case IDE_COMMAND_WRITE_DMA48: + case IDE_COMMAND_WRITE_DMA_Q48: + case IDE_COMMAND_WRITE_MUL48: + case IDE_COMMAND_WRITE_STREAM_DMA48: + case IDE_COMMAND_WRITE_STREAM48: + case IDE_COMMAND_WRITE_FUA_DMA48: + case IDE_COMMAND_WRITE_FUA_DMA_Q48: + case IDE_COMMAND_WRITE_MUL_FUA48: + case IDE_COMMAND_FLUSH_CACHE48: + case IDE_COMMAND_VERIFY48: + + flags |= ATA_CMD_FLAG_48; + /* FALL THROUGH */ + + case IDE_COMMAND_READ: + case IDE_COMMAND_READ_MULTIPLE: + case IDE_COMMAND_READ_DMA: + case IDE_COMMAND_READ_DMA_Q: + case IDE_COMMAND_WRITE: + case IDE_COMMAND_WRITE_MULTIPLE: + case IDE_COMMAND_WRITE_DMA: + case IDE_COMMAND_WRITE_DMA_Q: + case IDE_COMMAND_FLUSH_CACHE: + case IDE_COMMAND_VERIFY: + + flags |= ATA_CMD_FLAG_LBAIOsupp; + } + + flags |= ATA_CMD_FLAG_48supp; + + switch (command) { + case IDE_COMMAND_READ: + command = IDE_COMMAND_READ48; break; + case IDE_COMMAND_READ_MULTIPLE: + command = IDE_COMMAND_READ_MUL48; break; + case IDE_COMMAND_READ_DMA: + command = IDE_COMMAND_READ_DMA48; break; + case IDE_COMMAND_READ_DMA_Q: + command = IDE_COMMAND_READ_DMA_Q48; break; + case IDE_COMMAND_WRITE: + command = IDE_COMMAND_WRITE48; break; + case IDE_COMMAND_WRITE_MULTIPLE: + command = IDE_COMMAND_WRITE_MUL48; break; + case IDE_COMMAND_WRITE_DMA: + command = IDE_COMMAND_WRITE_DMA48; break; + case IDE_COMMAND_WRITE_DMA_Q: + command = IDE_COMMAND_WRITE_DMA_Q48; break; + case IDE_COMMAND_FLUSH_CACHE: + command = IDE_COMMAND_FLUSH_CACHE48; break; + case IDE_COMMAND_READ_NATIVE_SIZE: + // command = IDE_COMMAND_READ_NATIVE_SIZE48; break; + case IDE_COMMAND_SET_NATIVE_SIZE: + command = IDE_COMMAND_SET_NATIVE_SIZE48; break; + case IDE_COMMAND_VERIFY: + command = IDE_COMMAND_VERIFY48; break; + default: + flags &= ~ATA_CMD_FLAG_48supp; + } + + AtaCommands48[i] = command; + AtaCommandFlags[i] = flags; + } +} // end UniataInitAtaCommands() + +/*++ + +Routine Description: + + Installable driver initialization entry point for system. + +Arguments: + + Driver Object + +Return Value: + + Status from ScsiPortInitialize() + +--*/ +extern "C" +ULONG +DDKAPI +DriverEntry( + IN PVOID DriverObject, + IN PVOID Argument2 + ) +{ + HW_INITIALIZATION_DATA_COMMON hwInitializationData; + ULONG adapterCount; + ULONG i, c, alt; + ULONG statusToReturn, newStatus; + PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2; + BOOLEAN ReEnter = FALSE; + WCHAR a; + NTSTATUS status; + + PCONFIGURATION_INFORMATION GlobalConfig = IoGetConfigurationInformation(); + BOOLEAN PrimaryClaimed = FALSE; + BOOLEAN SecondaryClaimed = FALSE; + + LARGE_INTEGER t0, t1; + + Connect_DbgPrint(); + KdPrint2((PRINT_PREFIX (PCCHAR)ver_string)); + a = (WCHAR)strlen(ver_string); + + g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0); + if(g_opt_Verbose) { + _PrintNtConsole("Universal ATA driver v 0." UNIATA_VER_STR "\n"); + } + + if(!SavedDriverObject) { + SavedDriverObject = (PDRIVER_OBJECT)DriverObject; + // we are here for the 1st time + // init CrossNT and get OS version + if(!NT_SUCCESS(status = CrNtInit(SavedDriverObject, RegistryPath))) { + KdPrint(("UniATA Init: CrNtInit failed with status %#x\n", status)); + //HalDisplayString((PUCHAR)"DbgPrnHkInitialize: CrNtInit failed\n"); + return status; + } + KdPrint(("UniATA Init: OS ver %x.%x (%d)\n", MajorVersion, MinorVersion, BuildNumber)); + + KeQuerySystemTime(&t0); + do { + KeQuerySystemTime(&t1); + } while(t0.QuadPart == t1.QuadPart); + t0=t1; + g_Perf=0; + do { + KeQuerySystemTime(&t1); + g_Perf++; + } while(t0.QuadPart == t1.QuadPart); + g_PerfDt = (ULONG)((t1.QuadPart - t0.QuadPart)/10); + KdPrint(("Performance calibration: dt=%d, counter=%I64d\n", g_PerfDt, g_Perf )); + + } else { + ReEnter = TRUE; + } + + // (re)read bad block list + InitBadBlocks(NULL); + + if(!ReEnter) { + // init ATA command translation table + UniataInitAtaCommands(); + // get registry path to settings + RtlCopyMemory(&SavedRegPath, RegistryPath, sizeof(UNICODE_STRING)); + SavedRegPath.Buffer = (PWCHAR)&SavedRegPathBuffer; + SavedRegPath.Length = min(RegistryPath->Length, 255*sizeof(WCHAR)); + SavedRegPath.MaximumLength = 255*sizeof(WCHAR); + RtlCopyMemory(SavedRegPath.Buffer, RegistryPath->Buffer, SavedRegPath.Length); + SavedRegPath.Buffer[SavedRegPath.Length/sizeof(WCHAR)] = 0; + } + + SkipRaids = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"SkipRaids", 1); + ForceSimplex = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"ForceSimplex", 0); +#ifdef _DEBUG + g_LogToDisplay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"LogToDisplay", 0); +#endif //_DEBUG + + statusToReturn = 0xffffffff; + + // Zero out structure. + RtlZeroMemory(((PCHAR)&hwInitializationData), sizeof(hwInitializationData)); + + // Set size of hwInitializationData. + hwInitializationData.comm.HwInitializationDataSize = + sizeof(hwInitializationData.comm) + +// sizeof(hwInitializationData.nt4) + + ((WinVer_Id() <= WinVer_NT) ? 0 : sizeof(hwInitializationData.w2k)); + + // Set entry points. + hwInitializationData.comm.HwInitialize = AtapiHwInitialize; + hwInitializationData.comm.HwResetBus = AtapiResetController; + hwInitializationData.comm.HwStartIo = AtapiStartIo; + hwInitializationData.comm.HwInterrupt = AtapiInterrupt; + + // Specify size of extensions. + hwInitializationData.comm.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); + hwInitializationData.comm.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION); + hwInitializationData.comm.SrbExtensionSize = sizeof(ATA_REQ); + + // Indicate PIO device. + hwInitializationData.comm.MapBuffers = TRUE; + // Set PnP-specific API + if(WinVer_Id() > WinVer_NT) { + hwInitializationData.comm.NeedPhysicalAddresses = TRUE; + hwInitializationData.w2k.HwAdapterControl = AtapiAdapterControl; + } + + KdPrint2((PRINT_PREFIX "\n\nATAPI IDE enum supported BusMaster Devices\n")); + + if(!ReEnter) { + UniataEnumBusMasterController(DriverObject, Argument2); + } + + // Look for legacy ISA-bridged PCI IDE controller (onboard) + KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for legacy ISA-bridged PCI IDE controller (onboard)\n")); + KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: BMListLen %d\n", BMListLen)); + for (i=0; i AtDiskPrimaryAddressClaimed) + PrimaryClaimed = TRUE; + if(GlobalConfig->AtDiskSecondaryAddressClaimed) + SecondaryClaimed = TRUE; + + if(g_opt_Verbose) { + _PrintNtConsole("Init standard Dual-channel PCI ATA controller:"); + } + for(alt = 0; alt < 2; alt++) { + + for(c=0; c<2; c++) { + + if(AtapiRegCheckDevValue(NULL, c, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", 0)) { + break; + } + if(c==0) { + if(PrimaryClaimed) { + KdPrint2((PRINT_PREFIX "Primary already claimed\n")); + continue; + } + } else + if(c==1) { + if(SecondaryClaimed) { + KdPrint2((PRINT_PREFIX "Secondary already claimed\n")); + continue; + } + } + + if((WinVer_Id() <= WinVer_NT)) { + // do not even try if already claimed + if(c==0) { + GlobalConfig->AtDiskPrimaryAddressClaimed = FALSE; + } else + if(c==1) { + GlobalConfig->AtDiskSecondaryAddressClaimed = FALSE; + } + } + hwInitializationData.comm.HwFindAdapter = UniataFindBusMasterController; + hwInitializationData.comm.NumberOfAccessRanges = 6; + hwInitializationData.comm.AdapterInterfaceType = Isa; + + BMList[i].channel = (UCHAR)c; + + KdPrint2((PRINT_PREFIX "Try init channel %d, method %d\n", c, alt)); + newStatus = ScsiPortInitialize(DriverObject, + Argument2, + &hwInitializationData.comm, + (PVOID)(i | (alt ? 0x80000000 : 0))); + KdPrint2((PRINT_PREFIX "Status %#x\n", newStatus)); + if (newStatus < statusToReturn) { + statusToReturn = newStatus; + } + if (newStatus == STATUS_SUCCESS) { + BMList[i].ChanInitOk |= 0x01 << c; +/* + if(BMList[i].MasterDev && (WinVer_Id() > WinVer_NT)) { + c = 1; // this will break our for() + BMList[i].ChanInitOk |= 0x01 << c; + } +*/ + } + } + if(WinVer_Id() > WinVer_NT) { + // the following doesn't work under higher OSes + KdPrint2((PRINT_PREFIX "make still one attempt\n")); + continue; + } + if(BMList[i].ChanInitOk & 0x03) { + // under NT we receive status immediately, so + // we can omit alternative init method id STATUS_SUCCESS returned + KdPrint2((PRINT_PREFIX "Ok, no more retries required\n")); + break; + } + // if (WinVer_Id() == WinVer_NT) and some error occured + // try alternative init method + } + if(g_opt_Verbose) { + if(BMList[i].ChanInitOk & 0x03) { + _PrintNtConsole(" OK\n"); + } else { + _PrintNtConsole(" failed\n"); + } + } + + } + +/* KeBugCheckEx(0xc000000e, + (i << 16) | BMList[0].ChanInitOk, + c, + newStatus, statusToReturn);*/ + + // Look for PCI IDE controller + KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for PCI IDE controller\n")); + KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: i %d, BMListLen %d\n", i, BMListLen)); + for (; i SrbExtension); + + srb = &(deviceExtension->chan[GET_CHANNEL(Srb)].InternalSrb); + + RtlZeroMemory((PCHAR) srb, sizeof(SCSI_REQUEST_BLOCK)); + + srb->PathId = (UCHAR)(Srb->PathId); + srb->TargetId = (UCHAR)(Srb->TargetId); + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->Length = sizeof(SCSI_REQUEST_BLOCK); + + // Set flags to disable synchronous negociation. + srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + + // Set timeout to 4 seconds. + srb->TimeOutValue = 4; + + srb->CdbLength = 6; + srb->DataBuffer = &(deviceExtension->chan[GET_CHANNEL(Srb)].MechStatusData); + srb->DataTransferLength = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER); + srb->SrbExtension = AtaReq; + + // Set CDB operation code. + cdb = (PCDB)srb->Cdb; + cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS; + cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER); + + return srb; +} // end BuildMechanismStatusSrb() + +#endif //UNIATA_CORE + +PSCSI_REQUEST_BLOCK +BuildRequestSenseSrb ( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PSCSI_REQUEST_BLOCK srb; + PCDB cdb; + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + + srb = &(deviceExtension->chan[GET_CHANNEL(Srb)].InternalSrb); + + RtlZeroMemory((PCHAR) srb, sizeof(SCSI_REQUEST_BLOCK)); + + srb->PathId = (UCHAR)(Srb->PathId); + srb->TargetId = (UCHAR)(Srb->TargetId); + srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + srb->Length = sizeof(SCSI_REQUEST_BLOCK); + + // Set flags to disable synchronous negociation. + srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + + // Set timeout to 2 seconds. + srb->TimeOutValue = 4; + + srb->CdbLength = 6; + srb->DataBuffer = &(deviceExtension->chan[GET_CHANNEL(Srb)].MechStatusSense); + srb->DataTransferLength = sizeof(SENSE_DATA); + srb->SrbExtension = AtaReq; + + // Set CDB operation code. + cdb = (PCDB)srb->Cdb; + cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE; + cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA); + + return srb; +} // end BuildRequestSenseSrb() + +#ifndef UNIATA_CORE + +ULONG +AtapiRegCheckDevLunValue( + IN PVOID HwDeviceExtension, + IN PWCHAR NamePrefix, + IN ULONG chan, + IN ULONG dev, + IN PWSTR Name, + IN ULONG Default + ) +{ + WCHAR namex[160]; + ULONG val = Default; + + val = AtapiRegCheckParameterValue( + HwDeviceExtension, NamePrefix, Name, val); + + if(chan != CHAN_NOT_SPECIFIED) { + swprintf(namex, L"%s\\Chan_%1.1d", NamePrefix, chan); + val = AtapiRegCheckParameterValue( + HwDeviceExtension, namex, Name, val); + if(dev != DEVNUM_NOT_SPECIFIED) { + swprintf(namex, L"%s\\Chan_%1.1d\\%s", NamePrefix, chan, (dev & 0x01) ? L"Lun_1" : L"Lun_0"); + val = AtapiRegCheckParameterValue( + HwDeviceExtension, namex, Name, val); + } + } + return val; +} // end AtapiRegCheckDevLunValue() + +ULONG +EncodeVendorStr( + OUT PWCHAR Buffer, + IN PUCHAR Str, + IN ULONG Length + ) +{ + ULONG i,j; + WCHAR a; + + for(i=0, j=0; i= 127)) { + Buffer[j] = '#'; + j++; + swprintf(Buffer+j, L"%2.2x", a); + j++; + } else { + Buffer[j] = a; + } + } + Buffer[j] = 0; + return j; +} // end EncodeVendorStr() + +ULONG +AtapiRegCheckDevValue( + IN PVOID HwDeviceExtension, + IN ULONG chan, + IN ULONG dev, + IN PWSTR Name, + IN ULONG Default + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; +// WCHAR name0[11]; +// WCHAR name1[11+4+5]; +// WCHAR name2[11+4+4+10]; +// WCHAR name3[11+4+4+5+20]; +// WCHAR name3[11+4+4+5+20+1]; + WCHAR namex[160]; + + WCHAR namev[16]; + WCHAR named[16]; + WCHAR names[20]; + + IN ULONG VendorID; + IN ULONG DeviceID; + IN ULONG SlotNumber; + + ULONG val = Default; + + KdPrint(( " Parameter %ws\n", Name)); + + if(deviceExtension) { + VendorID = deviceExtension->DevID & 0xffff; + DeviceID = (deviceExtension->DevID >> 16) & 0xffff; + SlotNumber = deviceExtension->slotNumber; + } else { + VendorID = 0xffff; + DeviceID = 0xffff; + SlotNumber = 0xffffffff; + } + + val = AtapiRegCheckDevLunValue( + HwDeviceExtension, L"Parameters", chan, dev, Name, val); + + if(deviceExtension) { + swprintf(namev, L"\\Ven_%4.4x", VendorID); + swprintf(named, L"\\Dev_%4.4x", DeviceID); + swprintf(names, L"\\Slot_%8.8x", SlotNumber); + + swprintf(namex, L"Parameters%s", namev); + val = AtapiRegCheckDevLunValue( + HwDeviceExtension, namex, chan, dev, Name, val); + + swprintf(namex, L"Parameters%s%s", namev, named); + val = AtapiRegCheckDevLunValue( + HwDeviceExtension, namex, chan, dev, Name, val); + + swprintf(namex, L"Parameters%s%s%s", namev, named, names); + val = AtapiRegCheckDevLunValue( + HwDeviceExtension, namex, chan, dev, Name, val); + } + + KdPrint(( " Parameter %ws = %#x\n", Name, val)); + return val; + +} // end AtapiRegCheckDevValue() + +/* + The user must specify that Xxx is to run on the platform + by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\ + Services\UniATA\Xxx:REG_DWORD:Zzz. + + The user can override the global setting to enable or disable Xxx on a + specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\ + CurrentControlSet\Services\UniATA\Parameters\Device\Xxx:REG_DWORD to one or zero. + + If this registry value does not exist or contains the value zero then + the timer to check for media change does not run. + + Arguments: + + RegistryPath - pointer to the unicode string inside + ...\CurrentControlSet\Services\UniATA + DeviceNumber - The number of the HBA device object + + Returns: Registry Key value + */ +ULONG +AtapiRegCheckParameterValue( + IN PVOID HwDeviceExtension, + IN PWSTR PathSuffix, + IN PWSTR Name, + IN ULONG Default + ) +{ +#define ITEMS_TO_QUERY 2 // always 1 greater than what is searched + +// PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + NTSTATUS status; + LONG zero = Default; + + RTL_QUERY_REGISTRY_TABLE parameters[ITEMS_TO_QUERY]; + +// LONG tmp = 0; + LONG doRun = Default; + + PUNICODE_STRING RegistryPath = &SavedRegPath; + + UNICODE_STRING paramPath; + + // \ -> +// KdPrint(( "AtapiCheckRegValue: %ws -> %ws\n", PathSuffix, Name)); +// KdPrint(( "AtapiCheckRegValue: RegistryPath %ws\n", RegistryPath->Buffer)); + + paramPath.Length = 0; + paramPath.MaximumLength = RegistryPath->Length + + (wcslen(PathSuffix)+2)*sizeof(WCHAR); + paramPath.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, paramPath.MaximumLength); + if(!paramPath.Buffer) { + KdPrint(("AtapiCheckRegValue: couldn't allocate paramPath\n")); + return Default; + } + + RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength); + RtlAppendUnicodeToString(¶mPath, RegistryPath->Buffer); + RtlAppendUnicodeToString(¶mPath, L"\\"); + RtlAppendUnicodeToString(¶mPath, PathSuffix); + + // Check for the Xxx value. + RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY)); + + parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + parameters[0].Name = Name; + parameters[0].EntryContext = &doRun; + parameters[0].DefaultType = REG_DWORD; + parameters[0].DefaultData = &zero; + parameters[0].DefaultLength = sizeof(ULONG); + + status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/, + paramPath.Buffer, parameters, NULL, NULL); + KdPrint(( "AtapiCheckRegValue: %ws -> %ws is %#x\n", PathSuffix, Name, doRun)); + + ExFreePool(paramPath.Buffer); + + if(!NT_SUCCESS(status)) { + doRun = Default; + } + + return doRun; + +#undef ITEMS_TO_QUERY + +} // end AtapiRegCheckParameterValue() + + +SCSI_ADAPTER_CONTROL_STATUS +DDKAPI +AtapiAdapterControl( + IN PVOID HwDeviceExtension, + IN SCSI_ADAPTER_CONTROL_TYPE ControlType, + IN PVOID Parameters + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PSCSI_SUPPORTED_CONTROL_TYPE_LIST pControlTypeList; + ULONG numberChannels = deviceExtension->NumberChannels; + ULONG c; + NTSTATUS status; + + KdPrint(( "AtapiAdapterControl: %#x\n", ControlType)); + + switch(ControlType) { + case ScsiQuerySupportedControlTypes: { + BOOLEAN supportedTypes[ScsiAdapterControlMax] = { + TRUE, // ScsiQuerySupportedControlTypes + TRUE, // ScsiStopAdapter + TRUE, // ScsiRestartAdapter + FALSE, // ScsiSetBootConfig + FALSE // ScsiSetRunningConfig + }; + + ULONG lim = ScsiAdapterControlMax; + ULONG i; + + pControlTypeList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST) Parameters; + + if(pControlTypeList->MaxControlType < lim) { + lim = pControlTypeList->MaxControlType; + } + + for(i = 0; i < lim; i++) { + pControlTypeList->SupportedTypeList[i] = supportedTypes[i]; + } + + break; + + } + case ScsiStopAdapter: { + + KdPrint(( "AtapiAdapterControl: ScsiStopAdapter\n")); + // Shut down all interrupts on the adapter. They'll get re-enabled + // by the initialization routines. + for (c = 0; c < numberChannels; c++) { + AtapiResetController(deviceExtension, c); + AtapiDisableInterrupts(deviceExtension, c); + } + status = UniataDisconnectIntr2(HwDeviceExtension); + BMList[deviceExtension->DevIndex].Isr2Enable = FALSE; + break; + } + case ScsiRestartAdapter: { + + KdPrint(( "AtapiAdapterControl: ScsiRestartAdapter\n")); + // Enable all the interrupts on the adapter while port driver call + // for power up an HBA that was shut down for power management + + AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED); + status = UniataConnectIntr2(HwDeviceExtension); + for (c = 0; c < numberChannels; c++) { + AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, c); + FindDevices(HwDeviceExtension, FALSE, c); + AtapiEnableInterrupts(deviceExtension, c); + AtapiHwInitialize__(deviceExtension, c); + } + if(deviceExtension->Isr2DevObj) { + BMList[deviceExtension->DevIndex].Isr2Enable = TRUE; + } + + break; + } + + default: { + KdPrint(( "AtapiAdapterControl: default => return ScsiAdapterControlUnsuccessful\n")); + return ScsiAdapterControlUnsuccessful; + } + } + + return ScsiAdapterControlSuccess; +} // end AtapiAdapterControl() + +#endif //UNIATA_CORE + +extern "C" +NTHALAPI +VOID +DDKAPI +HalDisplayString ( + PUCHAR String + ); + +extern "C" +VOID +_cdecl +_PrintNtConsole( + PCHAR DebugMessage, + ... + ) +{ + int len; + UCHAR dbg_print_tmp_buff[512]; +// UNICODE_STRING msgBuff; + va_list ap; + va_start(ap, DebugMessage); + + len = _vsnprintf((PCHAR)&dbg_print_tmp_buff[0], 511, DebugMessage, ap); + + dbg_print_tmp_buff[511] = 0; + + HalDisplayString(dbg_print_tmp_buff); + + va_end(ap); + +} // end PrintNtConsole() + diff --git a/reactos/drivers/storage/ide/uniata/id_badblock.cpp b/reactos/drivers/storage/ide/uniata/id_badblock.cpp new file mode 100644 index 00000000000..557d455fb6e --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_badblock.cpp @@ -0,0 +1,266 @@ +/*++ + +Copyright (C) 2006 VorontSOFT + +Module Name: + id_badblock.cpp + +Abstract: + This is the artificial badblock simulation part of the + miniport driver for ATA/ATAPI IDE controllers with Busmaster DMA support + +Author: + Nikolai Vorontsov (NickViz) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + 2006/08/03 Initial implementation. + 2006/08/06 Added registry work. + 2007/03/27 Added device serial to registry value name instead of LUN. + +--*/ + +#include "stdafx.h" + +//#define MAX_BADBLOCKS_ITEMS 512 + + + +//SBadBlockRange arrBadBlocks[MAX_BADBLOCKS_ITEMS]; +//ULONG nBadBlocks = 0; + +LIST_ENTRY BBList; +BOOLEAN BBListInited = FALSE; + +// RtlQueryRegistryValues callback function +static NTSTATUS __stdcall +BadBlockQueryRoutine( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + PSBadBlockListItem cur; + PLIST_ENTRY link; + ULONG i; + // The ValueType should be REG_SZ + // The ValueData is UNICODE string of the following format: + // "badblocks_start_from_lba badblocks_end_at_lba" + + KdPrint(( "BadBlockQueryRoutine: S/N:%S\n type %#x, len %#x\n", ValueName, ValueType, ValueLength)); + + if(!BBListInited) + return STATUS_SUCCESS; + + if((ValueType == REG_BINARY) && // STRING + ValueLength && // At least "0 0 0" + !(ValueLength % sizeof(SBadBlockRange))) // There is free space for the record + { + cur = NULL; + link = BBList.Flink; + while(link != &BBList) { + cur = CONTAINING_RECORD( link, SBadBlockListItem, List); + link = link->Flink; + if(!wcscmp(cur->SerNumStr, ValueName)) { + KdPrint(( "already loaded\n")); + if(cur->LunExt) { + cur->LunExt->nBadBlocks = 0; + cur->LunExt->arrBadBlocks = NULL; + cur->LunExt->bbListDescr = NULL; + cur->LunExt = NULL; + } + break; + } + } + + if(!cur) { + cur = (PSBadBlockListItem)ExAllocatePool(NonPagedPool, sizeof(SBadBlockListItem)); + if(!cur) + return STATUS_SUCCESS; + } else { + if(cur->arrBadBlocks) { + ExFreePool(cur->arrBadBlocks); + cur->arrBadBlocks = NULL; + } + } + cur->arrBadBlocks = (SBadBlockRange*)ExAllocatePool(NonPagedPool, ValueLength); + if(!cur->arrBadBlocks) { + ExFreePool(cur); + return STATUS_SUCCESS; + } + RtlCopyMemory(cur->arrBadBlocks, ValueData, ValueLength); + wcsncpy(cur->SerNumStr, ValueName, 127); + cur->SerNumStr[127] = 0; + cur->nBadBlocks = ValueLength/sizeof(SBadBlockRange); + cur->LunExt = NULL; + InitializeListHead(&cur->List); + InsertTailList(&BBList, &(cur->List)); + for(i=0; inBadBlocks; i++) { + KdPrint(( "BB: %I64x - %I64x\n", cur->arrBadBlocks[i].m_lbaStart, cur->arrBadBlocks[i].m_lbaEnd-1)); + } + } + return STATUS_SUCCESS; +} // end BadBlockQueryRoutine() + + +void +InitBadBlocks( + IN PHW_LU_EXTENSION LunExt + ) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; // Main record and zero filled end of array marker + WCHAR DevSerial[128]; + ULONG Length; + PLIST_ENTRY link; + PSBadBlockListItem cur; + // Read from the registry necessary badblock pairs and fill in arrBadBlocks array + // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\UniATA\Parameters\BadBlocks + + if(!LunExt) { + // init + KdPrint(( "InitBadBlocks general\n")); + if(!BBListInited) { + InitializeListHead(&BBList); + BBListInited = TRUE; + } + + QueryTable[0].QueryRoutine = BadBlockQueryRoutine; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].Name = NULL; // If Name is NULL, the QueryRoutine function + // specified for this table entry is called + // for all values associated with the current + // registry key. + QueryTable[0].EntryContext = NULL; + QueryTable[0].DefaultType = REG_NONE; + QueryTable[0].DefaultData = 0; + QueryTable[0].DefaultLength = 0; + + RtlZeroMemory(QueryTable + 1, sizeof RTL_QUERY_REGISTRY_TABLE); // EOF + + NTSTATUS status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, + L"UniATA\\Parameters\\BadBlocks", + QueryTable, 0, 0); + + KdPrint(( "InitBadBlocks returned: %#x\n", status)); + } else { + + KdPrint(( "InitBadBlocks local\n")); + Length = EncodeVendorStr(DevSerial, (PUCHAR)LunExt->IdentifyData.ModelNumber, sizeof(LunExt->IdentifyData.ModelNumber)); + DevSerial[Length] = '-'; + Length++; + Length += EncodeVendorStr(DevSerial+Length, LunExt->IdentifyData.SerialNumber, sizeof(LunExt->IdentifyData.SerialNumber)); + + KdPrint(( "LunExt %#x\n", LunExt)); + KdPrint(( "S/N:%S\n", DevSerial)); + + LunExt->nBadBlocks = 0; + LunExt->arrBadBlocks = NULL; + + link = BBList.Flink; + while(link != &BBList) { + cur = CONTAINING_RECORD( link, SBadBlockListItem, List); + link = link->Flink; + if(cur->LunExt == LunExt) { + KdPrint(( " deassociate BB list (by LunExt)\n")); + cur->LunExt->nBadBlocks = 0; + cur->LunExt->arrBadBlocks = NULL; + cur->LunExt->bbListDescr = NULL; + cur->LunExt = NULL; + } else + if(!wcscmp(cur->SerNumStr, DevSerial)) { + KdPrint(( " deassociate BB list (by Serial)\n")); + if(cur->LunExt) { + cur->LunExt->nBadBlocks = 0; + cur->LunExt->arrBadBlocks = NULL; + cur->LunExt->bbListDescr = NULL; + cur->LunExt = NULL; + } + } + } + + if(!(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + + link = BBList.Flink; + while(link != &BBList) { + cur = CONTAINING_RECORD( link, SBadBlockListItem, List); + link = link->Flink; + if(!wcscmp(cur->SerNumStr, DevSerial)) { + KdPrint(( "found BB:List\n")); + cur->LunExt = LunExt; + LunExt->arrBadBlocks = cur->arrBadBlocks; + LunExt->nBadBlocks = cur->nBadBlocks; + LunExt->bbListDescr = cur; + return; + } + } + } + } + return; +} // end InitBadBlocks() + + +void +ForgetBadBlocks( + IN PHW_LU_EXTENSION LunExt + ) +{ + if(LunExt->bbListDescr) { + LunExt->bbListDescr->LunExt = NULL; + LunExt->nBadBlocks = 0; + LunExt->arrBadBlocks = NULL; + LunExt->bbListDescr = NULL; + } +} // end ForgetBadBlocks() + +bool +CheckIfBadBlock( + IN PHW_LU_EXTENSION LunExt, +// IN UCHAR command, + IN ULONGLONG lba, + IN ULONG count + ) +{ + if (LunExt->nBadBlocks == 0) + return false; +/* + // this is checked by caller + if(!(AtaCommandFlags[command] & ATA_CMD_FLAG_LBAsupp)) { + return false; +*/ + ULONG nBadBlocks = LunExt->nBadBlocks; + SBadBlockRange* arrBadBlocks = LunExt->arrBadBlocks; + + // back transform for possibly CHS'ed LBA + lba = UniAtaCalculateLBARegsBack(LunExt, lba); + + for (ULONG i = 0; i < nBadBlocks; i++) + { + if (lba + count > arrBadBlocks->m_lbaStart && + lba < arrBadBlocks->m_lbaEnd) { + KdPrint(( "listed BB @ %I64x\n", lba)); + return true; + } + arrBadBlocks++; + } + + return false; + +} // end CheckIfBadBlock() diff --git a/reactos/drivers/storage/ide/uniata/id_dma.cpp b/reactos/drivers/storage/ide/uniata/id_dma.cpp new file mode 100644 index 00000000000..aadcf0a75b6 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_dma.cpp @@ -0,0 +1,1980 @@ +/*++ + +Copyright (c) 2002-2007 Alexander A. Telyatnikov (Alter) + +Module Name: + id_dma.cpp + +Abstract: + This is the miniport driver for ATAPI IDE controllers + With Busmaster DMA support + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + + This module is a port from FreeBSD 4.3-6.1 ATA driver (ata-dma.c, ata-chipset.c) by + Søren Schmidt, Copyright (c) 1998-2007 + + Changed defaulting-to-generic-PIO/DMA policy + Added PIO settings for VIA + Optimized VIA/AMD/nVidia init part + Optimized Promise TX2 init part + Optimized Intel init part + by Alex A. Telyatnikov (Alter) (c) 2002-2007 + + +--*/ + +#include "stdafx.h" + +static const ULONG valid_udma[7] = {0,0,2,0,4,5,6}; + +static const CHAR retry_Wdma[MAX_RETRIES+1] = {2, 2, 2,-1,-1,-1}; +static const CHAR retry_Udma[MAX_RETRIES+1] = {6, 2,-1,-1,-1,-1}; + +PHYSICAL_ADDRESS ph4gb = {0xFFFFFFFF, 0}; + +VOID +cyrix_timing ( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ); + +VOID +promise_timing ( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ); + +VOID +hpt_timing ( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ); + +VOID +via82c_timing ( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ); + +ULONG +hpt_cable80( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG channel // physical channel number (0-1) + ); + +#define ATAPI_DEVICE(de, ldev) (de->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) + +ULONG +AtapiVirtToPhysAddr_( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN PUCHAR data, + IN PULONG count, + OUT PULONG ph_addru + ) +{ + PHYSICAL_ADDRESS ph_addr; + ULONG addr; + + ph_addr = MmGetPhysicalAddress(data); + if(!ph_addru && ph_addr.HighPart) { + // do so until we add 64bit address support + // or some workaround + *count = 0; + return -1; + } + + (*ph_addru) = ph_addr.HighPart; + //addr = ScsiPortConvertPhysicalAddressToUlong(ph_addr); + addr = ph_addr.LowPart; + if(!addr && !ph_addr.HighPart) { + *count = 0; + return 0; + } + if(!Srb) { + *count = sizeof(BM_DMA_ENTRY)*ATA_DMA_ENTRIES; + } else { + *count = PAGE_SIZE - (addr & (PAGE_SIZE-1)); + } + return addr; +} // end AtapiVirtToPhysAddr_() + +VOID +AtapiDmaAlloc( + IN PVOID HwDeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN ULONG lChannel // logical channel, + ) +{ +#ifdef USE_OWN_DMA + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); + ULONG c = lChannel; + ULONG i; + ULONG ph_addru; + + deviceExtension->chan[c].CopyDmaBuffer = FALSE; + + if(!deviceExtension->Host64 && (WinVer_Id() > WinVer_NT)) { + KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: allocate tmp buffers below 4Gb\n")); + chan->DB_PRD = MmAllocateContiguousMemory(sizeof(((PATA_REQ)NULL)->dma_tab), ph4gb); + if(chan->DB_PRD) { + chan->DB_PRD_PhAddr = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)(chan->DB_PRD), &i, &ph_addru); + if(!chan->DB_PRD_PhAddr || !i || ((LONG)(chan->DB_PRD_PhAddr) == -1)) { + KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: No DB PRD BASE\n" )); + chan->DB_PRD = NULL; + chan->DB_PRD_PhAddr = 0; + return; + } + if(ph_addru) { + KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: No DB PRD below 4Gb\n" )); + goto err_1; + } + } + chan->DB_IO = MmAllocateContiguousMemory(deviceExtension->MaximumDmaTransferLength, ph4gb); + if(chan->DB_IO) { + chan->DB_IO_PhAddr = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)(chan->DB_IO), &i, &ph_addru); + if(!chan->DB_IO_PhAddr || !i || ((LONG)(chan->DB_IO_PhAddr) == -1)) { + KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: No DB IO BASE\n" )); +err_1: + MmFreeContiguousMemory(chan->DB_PRD); + chan->DB_PRD = NULL; + chan->DB_PRD_PhAddr = 0; + chan->DB_IO = NULL; + chan->DB_IO_PhAddr = 0; + return; + } + if(ph_addru) { + KdPrint2((PRINT_PREFIX "AtapiDmaAlloc: No DB IO below 4Gb\n" )); + MmFreeContiguousMemory(chan->DB_IO); + goto err_1; + } + } + } +#endif //USE_OWN_DMA + + return; +} // end AtapiDmaAlloc() + +BOOLEAN +AtapiDmaSetup( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + IN PSCSI_REQUEST_BLOCK Srb, + IN PUCHAR data, + IN ULONG count + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG dma_count, dma_base, dma_baseu; + ULONG i; + PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + BOOLEAN use_DB_IO = FALSE; + ULONG orig_count = count; + + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: mode %#x\n", deviceExtension->lun[lChannel*2+DeviceNumber].TransferMode )); + if(deviceExtension->lun[lChannel*2+DeviceNumber].TransferMode < ATA_DMA) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: Not DMA mode, assume this is just preparation\n" )); + //return FALSE; + } + if(!count) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: count=0\n" )); + return FALSE; + } + if(count > deviceExtension->MaximumDmaTransferLength) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: deviceExtension->MaximumDmaTransferLength > count\n" )); + return FALSE; + } + if((ULONG)data & deviceExtension->AlignmentMask) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: unaligned data: %#x (%#x)\n", data, deviceExtension->AlignmentMask)); + return FALSE; + } + + // NOTE: This code is intended for 32-bit capable controllers only. + // 64-bit capable controllers shall be handled separately. + dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)&(AtaReq->dma_tab) /*chan->dma_tab*/, &i, &dma_baseu); + if(dma_baseu) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: SRB built-in PRD above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base)); + dma_base = chan->DB_PRD_PhAddr; + AtaReq->Flags |= REQ_FLAG_DMA_DBUF_PRD; + i = 1; + } else + if(!dma_base || !i || ((LONG)(dma_base) == -1)) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: No BASE\n" )); + return FALSE; + } + AtaReq->dma_base = dma_base; + + dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, Srb, data, &dma_count, &dma_baseu); + if(dma_baseu) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: 1st block of buffer above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base)); +retry_DB_IO: + use_DB_IO = TRUE; + dma_base = chan->DB_IO_PhAddr; + data = (PUCHAR)(chan->DB_IO); + } else + if(!dma_count || ((LONG)(dma_base) == -1)) { + AtaReq->dma_base = NULL; + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: No 1st block\n" )); + return FALSE; + } + + dma_count = min(count, (PAGE_SIZE - ((ULONG)data & PAGE_MASK))); + data += dma_count; + count -= dma_count; + i = 0; + + while (count) { + AtaReq->dma_tab[i].base = dma_base; + AtaReq->dma_tab[i].count = (dma_count & 0xffff); + i++; + if (i >= ATA_DMA_ENTRIES) { + AtaReq->dma_base = NULL; + KdPrint2((PRINT_PREFIX "too many segments in DMA table\n" )); + return FALSE; + } + dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, Srb, data, &dma_count, &dma_baseu); + if(dma_baseu) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: block of buffer above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base)); + if(use_DB_IO) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: *ERROR* special buffer above 4Gb: %8.8x%8.8x\n", dma_baseu, dma_base)); + return FALSE; + } + count = orig_count; + goto retry_DB_IO; + } else + if(!dma_count || !dma_base || ((LONG)(dma_base) == -1)) { + AtaReq->dma_base = NULL; + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: No NEXT block\n" )); + return FALSE; + } + + dma_count = min(count, PAGE_SIZE); + data += min(count, PAGE_SIZE); + count -= min(count, PAGE_SIZE); + } + AtaReq->dma_tab[i].base = dma_base; + AtaReq->dma_tab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT; + + if(use_DB_IO) { + AtaReq->Flags |= REQ_FLAG_DMA_DBUF; + } + AtaReq->Flags |= REQ_FLAG_DMA_OPERATION; + + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: OK\n" )); + return TRUE; + +} // end AtapiDmaSetup() + +BOOLEAN +AtapiDmaPioSync( + PVOID HwDeviceExtension, + PSCSI_REQUEST_BLOCK Srb, + PUCHAR data, + ULONG count + ) +{ +#ifndef USE_OWN_DMA + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG dma_base; + PUCHAR DmaBuffer; + ULONG dma_count; + ULONG len; + PATA_REQ AtaReq; + + // This must never be called after DMA operation !!! + KdPrint2((PRINT_PREFIX "AtapiDmaPioSync: data %#x, len %#x\n", data, count)); + + if(!Srb) { + KdPrint2((PRINT_PREFIX "AtapiDmaPioSync: !Srb\n" )); + return FALSE; + } + + AtaReq = (PATA_REQ)(Srb->SrbExtension); + + // do nothing on PCI (This can be changed. We cannot guarantee, + // that CommonBuffer will always point to User's buffer, + // however, this usually happens on PCI-32) + if(deviceExtension->OrigAdapterInterfaceType == PCIBus) { + return TRUE; + } + // do nothing for DMA + if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) { + return TRUE; + } + + if(!data) { + KdPrint2((PRINT_PREFIX "AtapiDmaPioSync: !data\n" )); + return FALSE; + } + + while(count) { + dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, Srb, data, &dma_count); + if(!dma_base) { + KdPrint2((PRINT_PREFIX "AtapiDmaPioSync: !dma_base for data %#x\n", data)); + return FALSE; + } + DmaBuffer = (PUCHAR)ScsiPortGetVirtualAddress(HwDeviceExtension, + ScsiPortConvertUlongToPhysicalAddress(dma_base)); + if(!DmaBuffer) { + KdPrint2((PRINT_PREFIX "AtapiDmaPioSync: !DmaBuffer for dma_base %#x\n", dma_base)); + return FALSE; + } + len = min(dma_count, count); + memcpy(DmaBuffer, data, len); + count -= len; + data += len; + } +#endif //USE_OWN_DMA + + return TRUE; +} // end AtapiDmaPioSync() + +BOOLEAN +AtapiDmaDBSync( + PHW_CHANNEL chan, + PSCSI_REQUEST_BLOCK Srb + ) +{ + PATA_REQ AtaReq; + + AtaReq = (PATA_REQ)(Srb->SrbExtension); + if((Srb->SrbFlags & SRB_FLAGS_DATA_IN) && + (AtaReq->Flags & REQ_FLAG_DMA_DBUF)) { + KdPrint2((PRINT_PREFIX " AtapiDmaDBSync is issued.\n")); + ASSERT(FALSE); + KdPrint2((PRINT_PREFIX " DBUF (Read)\n")); + RtlCopyMemory(AtaReq->DataBuffer, chan->DB_IO, + Srb->DataTransferLength); + } + return TRUE; +} // end AtapiDmaDBSync() + +VOID +AtapiDmaStart( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + //PIDE_BUSMASTER_REGISTERS BaseIoAddressBM = deviceExtension->BaseIoAddressBM[lChannel]; + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + + ULONG VendorID = deviceExtension->DevID & 0xffff; + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + + KdPrint2((PRINT_PREFIX "AtapiDmaStart: %s on %#x:%#x\n", + (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "read" : "write", + lChannel, DeviceNumber )); + + if(!AtaReq->dma_base) { + KdPrint2((PRINT_PREFIX "AtapiDmaStart: *** !AtaReq->dma_base\n")); + return; + } + if(AtaReq->Flags & REQ_FLAG_DMA_DBUF_PRD) { + KdPrint2((PRINT_PREFIX " DBUF_PRD\n")); + ASSERT(FALSE); + RtlCopyMemory(chan->DB_PRD, &(AtaReq->dma_tab), sizeof(AtaReq->dma_tab)); + } + if(!(Srb->SrbFlags & SRB_FLAGS_DATA_IN) && + (AtaReq->Flags & REQ_FLAG_DMA_DBUF)) { + KdPrint2((PRINT_PREFIX " DBUF (Write)\n")); + ASSERT(FALSE); + RtlCopyMemory(chan->DB_IO, AtaReq->DataBuffer, + Srb->DataTransferLength); + } + + // set flag + chan->ChannelCtrlFlags |= CTRFLAGS_DMA_ACTIVE; + + switch(VendorID) { + case ATA_PROMISE_ID: + if(ChipType == PRNEW) { + ULONG Channel = deviceExtension->Channel + lChannel; + if(chan->ChannelCtrlFlags & CTRFLAGS_LBA48) { + AtapiWritePortEx1(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x11, + AtapiReadPortEx1(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x11) | + (Channel ? 0x08 : 0x02)); + AtapiWritePortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),(Channel ? 0x24 : 0x20), + ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x05000000 : 0x06000000) | (Srb->DataTransferLength >> 1) + ); + } +/* + } else + if(deviceExtension->MemIo) { + // begin transaction + AtapiWritePort4(chan, + IDX_BM_Command, + (AtapiReadPort4(chan, + IDX_BM_Command) & ~0x000000c0) | + ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x00000080 : 0x000000c0) ); + return; +*/ + } + break; + } + + // set pointer to Pointer Table + AtapiWritePort4(chan, IDX_BM_PRD_Table, + AtaReq->dma_base + ); + // set transfer direction + AtapiWritePort1(chan, IDX_BM_Command, + (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? BM_COMMAND_READ : BM_COMMAND_WRITE); + // clear Error & Intr bits (writeing 1 clears bits) + // set DMA capability bit + AtapiWritePort1(chan, IDX_BM_Status, + AtapiReadPort1(chan, IDX_BM_Status) | + (BM_STATUS_INTR | BM_STATUS_ERR) /*| + (DeviceNumber ? BM_STATUS_DRIVE_1_DMA : BM_STATUS_DRIVE_0_DMA)*/); + // begin transaction + AtapiWritePort1(chan, IDX_BM_Command, + AtapiReadPort1(chan, IDX_BM_Command) | + BM_COMMAND_START_STOP); + return; + +} // end AtapiDmaStart() + +UCHAR +AtapiDmaDone( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + //PIDE_BUSMASTER_REGISTERS BaseIoAddressBM = deviceExtension->BaseIoAddressBM[lChannel]; + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + UCHAR dma_status; + + ULONG VendorID = deviceExtension->DevID & 0xffff; + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + + KdPrint2((PRINT_PREFIX "AtapiDmaDone: dev %d\n", DeviceNumber)); + + switch(VendorID) { + case ATA_PROMISE_ID: + if(ChipType == PRNEW) { + ULONG Channel = deviceExtension->Channel + lChannel; + if(chan->ChannelCtrlFlags & CTRFLAGS_LBA48) { + AtapiWritePortEx1(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x11, + AtapiReadPortEx1(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x11) & + ~(Channel ? 0x08 : 0x02)); + AtapiWritePortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0),(Channel ? 0x24 : 0x20), + 0 + ); + } +/* + } else + if(deviceExtension->MemIo) { + // end transaction + AtapiWritePort4(chan, + IDX_BM_Command, + (AtapiReadPort4(chan, + IDX_BM_Command) & ~0x00000080) ); + // clear flag + chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_ACTIVE; + return 0; +*/ + } + break; + } + + // get status + dma_status = AtapiReadPort1(chan, IDX_BM_Status) & BM_STATUS_MASK; + // end transaction + AtapiWritePort1(chan, IDX_BM_Command, + AtapiReadPort1(chan, IDX_BM_Command) & + ~BM_COMMAND_START_STOP); + // clear interrupt and error status + AtapiWritePort1(chan, IDX_BM_Status, BM_STATUS_ERR | BM_STATUS_INTR); + // clear flag + chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_ACTIVE; + + return dma_status; + +} // end AtapiDmaDone() + +VOID +AtapiDmaReinit( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG ldev, + IN PATA_REQ AtaReq + ) +{ + PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]); + CHAR apiomode; + + apiomode = (CHAR)AtaPioMode(&(LunExt->IdentifyData)); + + if(!(AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) { + KdPrint2((PRINT_PREFIX + "AtapiDmaReinit: !(AtaReq->Flags & REQ_FLAG_DMA_OPERATION), fall to PIO on Device %d\n", ldev & 1)); + goto limit_pio; + } + if(!AtaReq->dma_base) { + KdPrint2((PRINT_PREFIX + "AtapiDmaReinit: no PRD, fall to PIO on Device %d\n", ldev & 1)); + goto limit_pio; + } + + if((deviceExtension->HbaCtrlFlags & HBAFLAGS_DMA_DISABLED_LBA48) && + (AtaReq->lba >= ATA_MAX_LBA28) && + (LunExt->TransferMode > ATA_PIO5) ) { + KdPrint2((PRINT_PREFIX + "AtapiDmaReinit: FORCE_DOWNRATE on Device %d for LBA48\n", ldev & 1)); + goto limit_lba48; + } + + + if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE) { + KdPrint2((PRINT_PREFIX + "AtapiDmaReinit: FORCE_DOWNRATE on Device %d\n", ldev & 1)); + if(AtaReq->lba >= ATA_MAX_LBA28) { +limit_lba48: + LunExt->DeviceFlags |= REQ_FLAG_FORCE_DOWNRATE_LBA48; +limit_pio: + // do not make extra work if we already use PIO + KdPrint2((PRINT_PREFIX + "AtapiDmaReinit: set PIO mode on Device %d (%x -> %x)\n", ldev & 1, LunExt->TransferMode, ATA_PIO0+apiomode)); + if(/*LunExt->TransferMode >= ATA_DMA*/ + LunExt->TransferMode != ATA_PIO0+apiomode + ) { + AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1, + apiomode, + -1, + -1 ); + } + } else { + KdPrint2((PRINT_PREFIX + "AtapiDmaReinit: set MAX mode on Device %d\n", ldev & 1)); + AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1, + apiomode, + min( retry_Wdma[AtaReq->retry], + (CHAR)AtaWmode(&(LunExt->IdentifyData)) ), + min( retry_Udma[AtaReq->retry], + (CHAR)AtaUmode(&(LunExt->IdentifyData)) ) ); + } +// LunExt->DeviceFlags &= ~DFLAGS_FORCE_DOWNRATE; + } else + if(/*!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_FORCE_DOWNRATE) &&*/ + (LunExt->LimitedTransferMode > + LunExt->TransferMode) || + (LunExt->DeviceFlags & DFLAGS_REINIT_DMA)) { + // restore IO mode + KdPrint2((PRINT_PREFIX + "AtapiDmaReinit: restore IO mode on Device %d\n", ldev & 1)); + AtapiDmaInit__(deviceExtension, ldev); + } +} // end AtapiDmaReinit() + +VOID +AtapiDmaInit__( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG ldev + ) +{ + PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]); + + if(LunExt->IdentifyData.SupportDma) { + KdPrint2((PRINT_PREFIX + "AtapiDmaInit__: Set (U)DMA on Device %d\n", ldev & 1)); +/* for(i=AtaUmode(&(LunExt->IdentifyData)); i>=0; i--) { + AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1, + (CHAR)AtaPioMode(&(LunExt->IdentifyData)), + (CHAR)AtaWmode(&(LunExt->IdentifyData)), + UDMA_MODE0+(CHAR)i ); + } + for(i=AtaWmode(&(LunExt->IdentifyData)); i>=0; i--) { + AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1, + (CHAR)AtaPioMode(&(LunExt->IdentifyData)), + (CHAR)AtaWmode(&(LunExt->IdentifyData)), + UDMA_MODE0+(CHAR)i ); + }*/ + AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1, + (CHAR)AtaPioMode(&(LunExt->IdentifyData)), + (CHAR)AtaWmode(&(LunExt->IdentifyData)), + (CHAR)AtaUmode(&(LunExt->IdentifyData)) ); + } else { + KdPrint2((PRINT_PREFIX + "AtapiDmaInit__: Set PIO on Device %d\n", ldev & 1)); + AtapiDmaInit(deviceExtension, ldev & 1, ldev >> 1, + (CHAR)AtaPioMode(&(LunExt->IdentifyData)), -1, -1); + } +} // end AtapiDmaInit__() + +BOOLEAN +AtaSetTransferMode( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + IN PHW_LU_EXTENSION LunExt, + IN ULONG mode + ) +{ + KdPrint2((PRINT_PREFIX + "AtaSetTransferMode: Set %#x on Device %d/%d\n", mode, lChannel, DeviceNumber)); + LONG statusByte = 0; + CHAR apiomode; + + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, + IDE_COMMAND_SET_FEATURES, 0, 0, 0, + (UCHAR)((mode > ATA_UDMA6) ? ATA_UDMA6 : mode), ATA_C_F_SETXFER, ATA_WAIT_BASE_READY); + if(statusByte & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX " wait ready after error\n")); + if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) { + AtapiStallExecution(10); + } else { + AtapiStallExecution(100); + } + apiomode = (CHAR)AtaPioMode(&(LunExt->IdentifyData)); + if( apiomode > 0 && + (CHAR)AtaWmode(&(LunExt->IdentifyData)) > 0 && + (CHAR)AtaUmode(&(LunExt->IdentifyData)) > 0 + ) { + return FALSE; + } + if(mode > ATA_PIO2) { + return FALSE; + } + KdPrint2((PRINT_PREFIX " assume that drive doesn't support mode swithingm using PIO%d\n", apiomode)); + mode = ATA_PIO0 + apiomode; + } + //if(mode <= ATA_UDMA6) { + LunExt->TransferMode = (UCHAR)mode; + //} + return TRUE; +} // end AtaSetTransferMode() + +VOID +AtapiDmaInit( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, // logical channel, + // is always 0 except simplex-only controllers + IN CHAR apiomode, + IN CHAR wdmamode, + IN CHAR udmamode + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG Channel = deviceExtension->Channel + lChannel; + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + //LONG statusByte = 0; + ULONG dev = Channel*2 + DeviceNumber; + ULONG ldev = lChannel*2 + DeviceNumber; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + LONG i; + PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]); + + ULONG VendorID = deviceExtension->DevID & 0xffff; + //ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff; + //ULONG RevID = deviceExtension->RevID; + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + + LONG statusByte = 0; + + //UCHAR *reg_val = NULL; + + LunExt->DeviceFlags &= ~DFLAGS_REINIT_DMA; + /* set our most pessimistic default mode */ + LunExt->TransferMode = ATA_PIO; +// if(!deviceExtension->BaseIoAddressBM[lChannel]) { + if(!deviceExtension->BusMaster) { + KdPrint2((PRINT_PREFIX " !deviceExtension->BusMaster: NO DMA\n")); + wdmamode = udmamode = -1; + } + + // Limit transfer mode (controller limitation) + if((LONG)deviceExtension->MaxTransferMode >= ATA_UDMA) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: deviceExtension->MaxTransferMode >= ATA_UDMA\n")); + udmamode = min( udmamode, (CHAR)(deviceExtension->MaxTransferMode - ATA_UDMA)); + } else + if((LONG)deviceExtension->MaxTransferMode >= ATA_WDMA) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: deviceExtension->MaxTransferMode >= ATA_WDMA\n")); + udmamode = -1; + wdmamode = min( wdmamode, (CHAR)(deviceExtension->MaxTransferMode - ATA_WDMA)); + } else + if((LONG)deviceExtension->MaxTransferMode >= ATA_PIO0) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: NO DMA\n")); + wdmamode = udmamode = -1; + apiomode = min( apiomode, (CHAR)(deviceExtension->MaxTransferMode - ATA_PIO0)); + } else { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: PIO0\n")); + wdmamode = udmamode = -1; + apiomode = 0; + } + // Limit transfer mode (device limitation) + KdPrint2((PRINT_PREFIX "AtapiDmaInit: LunExt->LimitedTransferMode %#x\n", LunExt->LimitedTransferMode)); + if((LONG)LunExt->LimitedTransferMode >= ATA_UDMA) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: LunExt->MaxTransferMode >= ATA_UDMA => %#x\n", + min( udmamode, (CHAR)(LunExt->LimitedTransferMode - ATA_UDMA)) + )); + udmamode = min( udmamode, (CHAR)(LunExt->LimitedTransferMode - ATA_UDMA)); + } else + if((LONG)LunExt->LimitedTransferMode >= ATA_WDMA) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: LunExt->MaxTransferMode >= ATA_WDMA => %#x\n", + min( wdmamode, (CHAR)(LunExt->LimitedTransferMode - ATA_WDMA)) + )); + udmamode = -1; + wdmamode = min( wdmamode, (CHAR)(LunExt->LimitedTransferMode - ATA_WDMA)); + } else + if((LONG)LunExt->LimitedTransferMode >= ATA_PIO0) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: lun NO DMA\n")); + wdmamode = udmamode = -1; + apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO0)); + } else { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: lun PIO0\n")); + wdmamode = udmamode = -1; + apiomode = 0; + } + + SelectDrive(chan, DeviceNumber); + GetStatus(chan, statusByte); + // we can see here IDE_STATUS_ERROR status after previous operation + if(statusByte & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX "IDE_STATUS_ERROR detected on entry, statusByte = %#x\n", statusByte)); + //GetBaseStatus(chan, statusByte); + } + if(statusByte && UniataIsIdle(deviceExtension, statusByte & ~IDE_STATUS_ERROR) != IDE_STATUS_IDLE) { + KdPrint2((PRINT_PREFIX "Can't setup transfer mode: statusByte = %#x\n", statusByte)); + return; + } + + if(deviceExtension->UnknownDev) { + KdPrint2((PRINT_PREFIX "Unknown chip, omit Vendor/Dev checks\n")); + goto try_generic_dma; + } + + if(deviceExtension->BaseIoAddressSATA_0.Addr) { + //if(ChipFlags & UNIATA_SATA) { + /****************/ + /* SATA Generic * + /****************/ + UCHAR ModeByte; + + KdPrint2((PRINT_PREFIX "SATA Generic\n")); + if(udmamode > 5) { + if(LunExt->IdentifyData.SataCapabilities != 0x0000 && + LunExt->IdentifyData.SataCapabilities != 0xffff) { + //udmamode = min(udmamode, 6); + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_SA150)) { + return; + } + udmamode = min(udmamode, 5); + + } else { + KdPrint2((PRINT_PREFIX "SATA -> PATA adapter ?\n")); + if (udmamode > 2 && !LunExt->IdentifyData.HwResCableId) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: DMA limited to UDMA33, non-ATA66 compliant cable\n")); + udmamode = 2; + apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO0)); + } else { + udmamode = min(udmamode, 5); + } + } + } + if(udmamode >= 0) { + ModeByte = ATA_UDMA0 + udmamode; + } else + if(wdmamode >= 0) { + ModeByte = ATA_WDMA0 + wdmamode; + } else + if(apiomode >= 0) { + ModeByte = ATA_PIO0 + apiomode; + } else { + ModeByte = ATA_PIO; + } + + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ModeByte); + return; + } + if (udmamode > 2 && !LunExt->IdentifyData.HwResCableId) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: DMA limited to UDMA33, non-ATA66 compliant cable\n")); + udmamode = 2; + apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO)); + } + + KdPrint2((PRINT_PREFIX "Setup chip a:w:u=%d:%d:%d\n", + apiomode, + wdmamode, + udmamode)); + + switch(VendorID) { + case ATA_ACARD_ID: { + /*********/ + /* Acard */ + /*********/ + static const USHORT reg4a = 0xa6; + UCHAR reg = 0x40 + (UCHAR)dev; + + if(ChipType == ATPOLD) { + /* Old Acard 850 */ + static const USHORT reg4x = 0x0301; + + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA + i)) { +set_old_acard: + ChangePciConfig1(0x54, a | (0x01 << dev) | ((i+1) << (dev*2))); + SetPciConfig1(0x4a, reg4a); + SetPciConfig2(reg, reg4x); + return; + } + + } + if (wdmamode >= 2 && apiomode >= 4) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA2)) { + goto set_old_acard; + } + } + } else { + /* New Acard 86X */ + static const UCHAR reg4x = 0x31; + + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA + i)) { +set_new_acard: + ChangePciConfig2(0x44, (a & ~(0x000f << (dev * 4))) | ((i+1) << (dev*4))); + SetPciConfig1(0x4a, reg4a); + SetPciConfig1(reg, reg4x); + return; + } + + } + if (wdmamode >= 2 && apiomode >= 4) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA2)) { + goto set_new_acard; + } + } + } + /* Use GENERIC PIO */ + break; } + case ATA_ACER_LABS_ID: { + /************************/ + /* Acer Labs Inc. (ALI) */ + /************************/ + static const UCHAR ali_udma[] = {0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x0f}; + static const ULONG ali_pio[] = + { 0x006d0003, 0x00580002, 0x00440001, 0x00330001, + 0x00310001, 0x00440001}; + /* the older Aladdin doesn't support ATAPI DMA on both master & slave */ + if ((ChipFlags & ALIOLD) && + (udmamode >= 0 || wdmamode >= 0)) { + if(ATAPI_DEVICE(deviceExtension, lChannel*2) && + ATAPI_DEVICE(deviceExtension, lChannel*2 + 1)) { + // 2 devices on this channel - NO DMA + chan->MaxTransferMode = + min(chan->MaxTransferMode, ATA_PIO4); + udmamode = wdmamode = -1; + break; + } + } + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + ULONG word54; + + GetPciConfig4(0x54, word54); + word54 &= ~(0x000f000f << (dev * 4)); + word54 |= (((ali_udma[i]<<16) | 5) << (dev * 4)); + SetPciConfig4(0x54, word54); + ChangePciConfig1(0x53, a | 0x03); + SetPciConfig4(0x58 + (Channel<<2), 0x00310001); + return; + } + } + /* make sure eventual UDMA mode from the BIOS is disabled */ + ChangePciConfig2(0x56, a & ~(0x0008 << (dev * 4)) ); + if (wdmamode >= 2 && apiomode >= 4) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA2)) { + ChangePciConfig1(0x53, a | 0x03); + chan->ChannelCtrlFlags |= CTRFLAGS_DMA_RO; + return; + } + } + ChangePciConfig1(0x53, (a & ~0x01) | 0x02); + + for(i=apiomode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + i)) { + ChangePciConfig4(0x54, a & ~(0x0008000f << (dev * 4))); + SetPciConfig4(0x58 + (Channel<<2), ali_pio[i]); + return; + } + } + return; + break; } + case ATA_AMD_ID: + case ATA_NVIDIA_ID: + case ATA_VIA_ID: { + /********************/ + /* AMD, nVidia, VIA */ + /********************/ + static const UCHAR via_modes[5][7] = { + { 0xc2, 0xc1, 0xc0, 0x00, 0x00, 0x00, 0x00 }, /* ATA33 and New Chips */ + { 0xee, 0xec, 0xea, 0xe9, 0xe8, 0x00, 0x00 }, /* ATA66 */ + { 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 }, /* ATA100 */ + { 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 }, /* VIA ATA133 */ + { 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 }}; /* AMD/nVIDIA */ + static const UCHAR via_pio[] = + { 0xa8, 0x65, 0x42, 0x22, 0x20, 0x42, 0x22, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; + const UCHAR *reg_val = NULL; + UCHAR reg = 0x53-(UCHAR)dev; + + reg_val = &via_modes[ChipType][0]; + + if(VendorID == ATA_NVIDIA_ID) + reg += 0x10; + + for(i = udmamode; i>=0; i--) { + SetPciConfig1(reg-0x08, via_pio[8+i]); + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + SetPciConfig1(reg, (UCHAR)reg_val[i]); + return; + } + } + for(i = wdmamode; i>=0; i--) { + SetPciConfig1(reg-0x08, via_pio[5+i]); + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + SetPciConfig1(reg, 0x8b); + return; + } + } + /* set PIO mode timings */ + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + if((apiomode >= 0) && (ChipType != VIA133)) { + SetPciConfig1(reg-0x08, via_pio[apiomode]); + } + via82c_timing(deviceExtension, dev, ATA_PIO0 + apiomode); + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + return; + + break; } + case ATA_CYRIX_ID: { + /*********/ + /* Cyrix */ + /*********/ + ULONG cyr_piotiming[] = + { 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 }; + ULONG cyr_wdmatiming[] = { 0x00077771, 0x00012121, 0x00002020 }; + ULONG cyr_udmatiming[] = { 0x00921250, 0x00911140, 0x00911030 }; + ULONG mode_reg = 0x24+(dev << 3); + + if(apiomode >= 4) + apiomode = 4; + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + AtapiWritePortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_udmatiming[udmamode]); + return; + } + } + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + AtapiWritePortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_wdmatiming[wdmamode]); + return; + } + } + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode)) { + AtapiWritePortEx4(chan, (ULONG)(&deviceExtension->BaseIoAddressBM_0), mode_reg, cyr_piotiming[apiomode]); + return; + } + return; + + break; } + case ATA_NATIONAL_ID: { + /************/ + /* National */ + /************/ + ULONG nat_piotiming[] = + { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010, + 0x00803020, 0x20102010, 0x00100010, + 0x00100010, 0x00100010, 0x00100010 }; + ULONG nat_dmatiming[] = { 0x80077771, 0x80012121, 0x80002020 }; + ULONG nat_udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 }; + + if(apiomode >= 4) + apiomode = 4; + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + SetPciConfig4(0x44 + (dev * 8), nat_udmatiming[i]); + SetPciConfig4(0x40 + (dev * 8), nat_piotiming[i+8]); + return; + } + } + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + SetPciConfig4(0x44 + (dev * 8), nat_dmatiming[i]); + SetPciConfig4(0x40 + (dev * 8), nat_piotiming[i+5]); + return; + } + } + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode)) { + ChangePciConfig4(0x44 + (dev * 8), a | 0x80000000); + SetPciConfig4(0x40 + (dev * 8), nat_piotiming[apiomode]); + return; + } + /* Use GENERIC PIO */ + break; } + case ATA_CYPRESS_ID: + /***********/ + /* Cypress */ + /***********/ + if (wdmamode >= 2 && apiomode >= 4) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA2)) { + SetPciConfig2(Channel ? 0x4e:0x4c, 0x2020); + return; + } + } + /* Use GENERIC PIO */ + break; + case ATA_HIGHPOINT_ID: { + /********************/ + /* High Point (HPT) */ + /********************/ + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + hpt_timing(deviceExtension, dev, (UCHAR)(ATA_UDMA + i)); // ??? + return; + } + } + + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + hpt_timing(deviceExtension, dev, (UCHAR)(ATA_WDMA0+i)); + return; + } + } + /* try generic DMA, use hpt_timing() */ + if (wdmamode >= 0 && apiomode >= 4) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_DMA)) { + return; + } + } + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + hpt_timing(deviceExtension, dev, ATA_PIO0 + apiomode); + return; + break; } + case ATA_INTEL_ID: { + /*********/ + /* Intel */ + /*********/ + + BOOLEAN udma_ok = FALSE; + ULONG idx = 0; + ULONG reg40; + UCHAR reg44; + USHORT reg48; + USHORT reg4a; + USHORT reg54; + ULONG mask40 = 0; + ULONG new40 = 0; + UCHAR mask44 = 0; + UCHAR new44 = 0; + UCHAR intel_timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 }; + + if(deviceExtension->DevID == ATA_I82371FB) { + if (wdmamode >= 2 && apiomode >= 4) { + ULONG word40; + + GetPciConfig4(0x40, word40); + word40 >>= Channel * 16; + + /* Check for timing config usable for DMA on controller */ + if (!((word40 & 0x3300) == 0x2300 && + ((word40 >> ((!(DeviceNumber & 1)) ? 0 : 4)) & 1) == 1)) { + udmamode = wdmamode = -1; + break; + } + + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA2)) { + return; + } + } + break; + } + + GetPciConfig2(0x48, reg48); + if(!(ChipFlags & ICH4_FIX)) { + GetPciConfig2(0x4a, reg4a); + } + GetPciConfig2(0x54, reg54); +// if(udmamode >= 0) { + // enable the write buffer to be used in a split (ping/pong) manner. + reg54 |= 0x400; +// } else { +// reg54 &= ~0x400; +// } + +// reg40 &= ~0x00ff00ff; +// reg40 |= 0x40774077; + + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + + SetPciConfig1(0x48, reg48 | (0x0001 << dev)); + if(!(ChipFlags & ICH4_FIX)) { + SetPciConfig2(0x4a, (reg4a & ~(0x3 << (dev<<2))) | + (0x01 + !(i & 0x01)) ); + } + if(i >= 2) { + reg54 |= (0x1 << dev); + } else { + reg54 &= ~(0x1 << dev); + } + if(i >= 5) { + reg54 |= (0x1000 << dev); + } else { + reg54 &= ~(0x1000 << dev); + } + SetPciConfig2(0x54, reg54); + + udma_ok = TRUE; + idx = i+8; + if(ChipFlags & ICH4_FIX) { + return; + } + break; + } + } + + if(!udma_ok) { + SetPciConfig1(0x48, reg48 & ~(0x0001 << dev)); + if(!(ChipFlags & ICH4_FIX)) { + SetPciConfig2(0x4a, (reg4a & ~(0x3 << (dev << 2))) ); + } + SetPciConfig2(0x54, reg54 & ~(0x1001 << dev)); + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + udma_ok = TRUE; + idx = i+5; + if(ChipFlags & ICH4_FIX) { + return; + } + } + } + } + + if(!udma_ok) { + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + idx = apiomode; + } + + GetPciConfig4(0x40, reg40); + GetPciConfig1(0x44, reg44); + + mask40 = 0x000000ff; + + if(!(DeviceNumber & 1)) { + mask40 |= 0x00003300; + new40 = ((USHORT)(intel_timings[idx]) << 8); + //mask44 = 0x00; // already done on init + //new44 = 0x00; + } else { + mask44 = 0x0f; + new44 = ((intel_timings[idx] & 0x30) >> 2) | + (intel_timings[idx] & 0x03); + } + new40 |= 0x00004077; + + if (Channel) { + mask40 <<= 16; + new40 <<= 16; + mask44 <<= 4; + new44 <<= 4; + } + + SetPciConfig4(0x40, (reg40 & ~mask40) | new40); + SetPciConfig1(0x44, (reg44 & ~mask44) | new44); + + return; + break; } + case ATA_PROMISE_ID: + /***********/ + /* Promise */ + /***********/ + if(ChipType < PRTX) { + if (ATAPI_DEVICE(deviceExtension, ldev)) { + udmamode = + wdmamode = -1; + } + } + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + promise_timing(deviceExtension, dev, (UCHAR)(ATA_UDMA + i)); // ??? + return; + } + } + + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + promise_timing(deviceExtension, dev, (UCHAR)(ATA_WDMA0+i)); + return; + } + } + /* try generic DMA, use hpt_timing() */ + if (wdmamode >= 0 && apiomode >= 4) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_DMA)) { + return; + } + } + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + promise_timing(deviceExtension, dev, ATA_PIO0 + apiomode); + return; + break; + case ATA_ATI_ID: + + KdPrint2((PRINT_PREFIX "ATI\n")); + if(ChipType = SIIMIO) { + goto l_ATA_SILICON_IMAGE_ID; + } + //goto ATA_SERVERWORKS_ID; + // FALL THROUGH + + //break; } + + case ATA_SERVERWORKS_ID: { + /***************/ + /* ServerWorks */ + /***************/ +// static const ULONG udma_modes[] = { 0x70, 0x21, 0x20 }; + static const ULONG sw_dma_modes[] = { 0x70, 0x21, 0x20 }; + static const ULONG sw_pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; + USHORT reg56; + ULONG reg44; + ULONG reg40; + ULONG offset = dev ^ 0x01; + ULONG bit_offset = offset * 8; + + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + GetPciConfig2(0x56, reg56); + reg56 &= ~(0xf << (dev * 4)); + reg56 |= ((USHORT)i << (dev * 4)); + SetPciConfig2(0x56, reg56); + ChangePciConfig1(0x54, a | (0x01 << dev)); + // 44 + GetPciConfig4(0x44, reg44); + reg44 = (reg44 & ~(0xff << bit_offset)) | + (sw_dma_modes[2] << bit_offset); + SetPciConfig4(0x44, reg44); + // 40 + GetPciConfig4(0x40, reg40); + reg40 = (reg40 & ~(0xff << bit_offset)) | + (sw_pio_modes[8+i] << bit_offset); + SetPciConfig4(0x40, reg40); + return; + } + } + + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + + ChangePciConfig1(0x54, a & ~(0x01 << dev)); + // 44 + GetPciConfig4(0x44, reg44); + reg44 = (reg44 & ~(0xff << bit_offset)) | + (sw_dma_modes[wdmamode] << bit_offset); + SetPciConfig4(0x44, reg44); + // 40 + GetPciConfig4(0x40, reg40); + reg40 = (reg40 & ~(0xff << bit_offset)) | + (sw_pio_modes[5+i] << bit_offset); + SetPciConfig4(0x40, reg40); + return; + } + } + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); +// SetPciConfig4(0x44, sw_pio_modes[apiomode]); + if(VendorID == ATA_ATI_ID) { + // special case for ATI + // Seems, that PATA ATI are just re-brended ServerWorks + USHORT reg4a; + // 4a + GetPciConfig2(0x4a, reg4a); + reg4a = (reg4a & ~(0xf << (dev*4))) | + (apiomode << (dev*4)); + SetPciConfig2(0x4a, reg4a); + } + + // 40 + GetPciConfig4(0x40, reg40); + reg40 = (reg40 & ~(0xff << bit_offset)) | + (sw_pio_modes[apiomode] << bit_offset); + SetPciConfig4(0x40, reg40); + return; + break; } + case ATA_SILICON_IMAGE_ID: { +l_ATA_SILICON_IMAGE_ID: + /********************/ + /* SiliconImage/CMD */ + /********************/ + if(ChipType == SIIMIO) { + + static const UCHAR sil_modes[7] = + { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 }; + static const USHORT sil_wdma_modes[3] = + { 0x2208, 0x10c2, 0x10c1 }; + static const USHORT sil_pio_modes[6] = + { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1, 0x10c1 }; + + UCHAR ureg = 0xac + ((UCHAR)DeviceNumber * 0x02) + ((UCHAR)Channel * 0x10); + UCHAR uval; + UCHAR mreg = Channel ? 0x84 : 0x80; + UCHAR mask = DeviceNumber ? 0x30 : 0x03; + UCHAR mode; + + GetPciConfig1(ureg, uval); + GetPciConfig1(mreg, mode); + + /* enable UDMA mode */ + for(i = udmamode; i>=0; i--) { + + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + SetPciConfig1(mreg, mode | mask); + SetPciConfig1(ureg, (uval & 0x3f) | sil_modes[i]); + return; + } + } + /* enable WDMA mode */ + for(i = wdmamode; i>=0; i--) { + + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + SetPciConfig1(mreg, mode | (mask & 0x22)); + SetPciConfig2(ureg - 0x4, sil_wdma_modes[i]); + return; + } + } + /* restore PIO mode */ + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + + SetPciConfig1(mreg, mode | (mask & 0x11)); + SetPciConfig2(ureg - 0x8, sil_pio_modes[i]); + return; + + } else { + + static const UCHAR cmd_modes[2][6] = { + { 0x31, 0x21, 0x011, 0x25, 0x15, 0x05 }, + { 0xc2, 0x82, 0x042, 0x8a, 0x4a, 0x0a } }; + static const UCHAR cmd_wdma_modes[] = { 0x87, 0x32, 0x3f }; + static const UCHAR cmd_pio_modes[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f }; + ULONG treg = 0x54 + (dev < 3) ? (dev << 1) : 7; + + udmamode = min(udmamode, 5); + /* enable UDMA mode */ + for(i = udmamode; i>=0; i--) { + UCHAR umode; + + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + GetPciConfig1(Channel ? 0x7b : 0x73, umode); + umode &= ~(!(DeviceNumber & 1) ? 0x35 : 0xca); + umode |= ( cmd_modes[DeviceNumber & 1][i]); + SetPciConfig1(Channel ? 0x7b : 0x73, umode); + return; + } + } + /* make sure eventual UDMA mode from the BIOS is disabled */ + ChangePciConfig1(Channel ? 0x7b : 0x73, a & ~(!(DeviceNumber & 1) ? 0x35 : 0xca)); + + for(i = wdmamode; i>=0; i--) { + + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + SetPciConfig1(treg, cmd_wdma_modes[i]); + ChangePciConfig1(Channel ? 0x7b : 0x73, a & ~(!(DeviceNumber & 1) ? 0x35 : 0xca)); + return; + } + } + /* set PIO mode timings */ + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + + SetPciConfig1(treg, cmd_pio_modes[apiomode]); + ChangePciConfig1(Channel ? 0x7b : 0x73, a & ~(!(DeviceNumber & 1) ? 0x35 : 0xca)); + return; + + } + return; + break; } + case ATA_SIS_ID: { + /*******/ + /* SiS */ + /*******/ + PULONG sis_modes; + static const ULONG sis_modes_new133[] = + { 0x28269008, 0x0c266008, 0x04263008, 0x0c0a3008, 0x05093008, + 0x22196008, 0x0c0a3008, 0x05093008, 0x050939fc, 0x050936ac, + 0x0509347c, 0x0509325c, 0x0509323c, 0x0509322c, 0x0509321c}; + static const ULONG sis_modes_old133[] = + { 0x00cb, 0x0067, 0x0044, 0x0033, 0x0031, 0x0044, 0x0033, 0x0031, + 0x8f31, 0x8a31, 0x8731, 0x8531, 0x8331, 0x8231, 0x8131 }; + static const ULONG sis_modes_old[] = + { 0x0c0b, 0x0607, 0x0404, 0x0303, 0x0301, 0x0404, 0x0303, 0x0301, + 0xf301, 0xd301, 0xb301, 0xa301, 0x9301, 0x8301 }; + static const ULONG sis_modes_new100[] = + { 0x00cb, 0x0067, 0x0044, 0x0033, 0x0031, 0x0044, 0x0033, 0x0031, + 0x8b31, 0x8731, 0x8531, 0x8431, 0x8231, 0x8131 }; + + ULONG reg; + UCHAR reg57; + ULONG reg_size; + ULONG offs; + + switch(ChipType) { + case SIS133NEW: + sis_modes = (PULONG)(&sis_modes_new133[0]); + reg_size = 4; + GetPciConfig1(0x57, reg57); + reg = (reg57 & 0x40 ? 0x70 : 0x40) + (dev * 4); + break; + case SIS133OLD: + sis_modes = (PULONG)(&sis_modes_old133[0]); + reg_size = 2; + reg = 0x40 + (dev * 2); + break; + case SIS100NEW: + sis_modes = (PULONG)(&sis_modes_new100[0]); + reg_size = 2; + reg = 0x40 + (dev * 2); + break; + case SIS100OLD: + case SIS66: + case SIS33: + sis_modes = (PULONG)(&sis_modes_old[0]); + reg_size = 2; + reg = 0x40 + (dev * 2); + break; + } + + offs = 5+3; + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + if(reg_size == 4) { + SetPciConfig4(reg, sis_modes[offs+i]); + } else { + SetPciConfig2(reg, (USHORT)sis_modes[offs+i]); + } + return; + } + } + + offs = 5; + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + if(reg_size == 4) { + SetPciConfig4(reg, sis_modes[offs+i]); + } else { + SetPciConfig2(reg, (USHORT)sis_modes[offs+i]); + } + return; + } + } + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + if(reg_size == 4) { + SetPciConfig4(reg, sis_modes[apiomode]); + } else { + SetPciConfig2(reg, (USHORT)sis_modes[apiomode]); + } + return; + break; } + case 0x16ca: + /* Cenatek Rocket Drive controller */ + if (wdmamode >= 0 && + (AtapiReadPort1(chan, IDX_BM_Status) & + (DeviceNumber ? BM_STATUS_DRIVE_1_DMA : BM_STATUS_DRIVE_0_DMA))) { + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + wdmamode); + } else { + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + } + return; + case ATA_ITE_ID: { /* ITE IDE controller */ + + if(ChipType == ITE_33) { + int a_speed = 3 << (dev * 4); + int u_flag = 1 << dev; + int u_speed = 0; + int pio = 1; + UCHAR reg48, reg4a; + USHORT drive_enables; + ULONG drive_timing; + + GetPciConfig1(0x48, reg48); + GetPciConfig1(0x4a, reg4a); + + /* + * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec + * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA + * transfers on some drives, even though both numbers meet the minimum + * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively. + * So the faster times are just commented out here. The good news is + * that the slower cycle time has very little affect on transfer + * performance. + */ + + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + SetPciConfig1(0x48, reg48 | u_flag); + reg4a &= ~a_speed; + SetPciConfig1(0x4a, reg4a | u_speed); + pio = 4; + goto setup_drive_ite; + } + } + + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + SetPciConfig1(0x48, reg48 & ~u_flag); + SetPciConfig1(0x4a, reg4a & ~a_speed); + pio = 3; + return; + } + } + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + SetPciConfig1(0x48, reg48 & ~u_flag); + SetPciConfig1(0x4a, reg4a & ~a_speed); + + pio = apiomode; + +setup_drive_ite: + + GetPciConfig2(0x40, drive_enables); + GetPciConfig4(0x44, drive_timing); + + /* + * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 + * are being left at the default values of 8 PCI clocks (242 nsec + * for a 33 MHz clock). These can be safely shortened at higher + * PIO modes. The DIOR/DIOW pulse width and recovery times only + * apply to PIO modes, not to the DMA modes. + */ + + /* + * Enable port 0x44. The IT8172G spec is confused; it calls + * this register the "Slave IDE Timing Register", but in fact, + * it controls timing for both master and slave drives. + */ + drive_enables |= 0x4000; + + drive_enables &= (0xc000 | (0x06 << (DeviceNumber*4))); + if (pio > 1) { + /* enable prefetch and IORDY sample-point */ + drive_enables |= (0x06 << (DeviceNumber*4)); + } + + SetPciConfig2(0x40, drive_enables); + } else + if(ChipType == ITE_133) { + static const UCHAR udmatiming[] = + { 0x44, 0x42, 0x31, 0x21, 0x11, 0xa2, 0x91 }; + static const UCHAR chtiming[] = + { 0xaa, 0xa3, 0xa1, 0x33, 0x31, 0x88, 0x32, 0x31 }; + ULONG offset = (Channel<<2) + DeviceNumber; + UCHAR reg54; + + for(i=udmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) { + ChangePciConfig1(0x50, a & ~(1 << (dev + 3)) ); + SetPciConfig1(0x56 + offset, udmatiming[i]); + return; + } + } + + for(i=wdmamode; i>=0; i--) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_WDMA0 + i)) { + + ChangePciConfig1(0x50, a | (1 << (dev + 3)) ); + GetPciConfig1(0x54 + offset, reg54); + if(reg54 < chtiming[i+5]) { + SetPciConfig1(0x54 + offset, chtiming[i+5]); + } + return; + } + } + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + ChangePciConfig1(0x50, a | (1 << (dev + 3)) ); + GetPciConfig1(0x54 + offset, reg54); + if(reg54 < chtiming[i]) { + SetPciConfig1(0x54 + offset, chtiming[i]); + } + return; + } + + return; + break; } + case 0x3388: + /* HiNT Corp. VXPro II EIDE */ + if (wdmamode >= 0 && + (AtapiReadPort1(chan, IDX_BM_Status) & + (DeviceNumber ? BM_STATUS_DRIVE_1_DMA : BM_STATUS_DRIVE_0_DMA))) { + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_DMA); + } else { + AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode); + } + return; + } + +try_generic_dma: + + /* unknown controller chip */ + + /* better not try generic DMA on ATAPI devices it almost never works */ + if (ATAPI_DEVICE(deviceExtension, ldev)) { + KdPrint2((PRINT_PREFIX "ATAPI on unknown controller -> PIO\n")); + udmamode = + wdmamode = -1; + } + + /* if controller says its setup for DMA take the easy way out */ + /* the downside is we dont know what DMA mode we are in */ + if ((udmamode >= 0 || /*wdmamode > 1*/ wdmamode >= 0) && + /*deviceExtension->BaseIoAddressBM[lChannel]*/ deviceExtension->BusMaster && + (GetDmaStatus(deviceExtension, lChannel) & + (!(ldev & 1) ? + BM_STATUS_DRIVE_0_DMA : BM_STATUS_DRIVE_1_DMA))) { +// LunExt->TransferMode = ATA_DMA; +// return; + KdPrint2((PRINT_PREFIX "try DMA on unknown controller\n")); + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_DMA)) { + return; + } + } + +#if 0 + /* well, we have no support for this, but try anyways */ + if ((wdmamode >= 0 && apiomode >= 4) && deviceExtension->BaseIoAddressBM[lChannel]) { + if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_DMA/* + wdmamode*/)) { + return; + } + } +#endif + + KdPrint2((PRINT_PREFIX "try PIO%d on unknown controller\n", apiomode)); + if(!AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_PIO0 + apiomode)) { + KdPrint2((PRINT_PREFIX "fall to PIO on unknown controller\n")); + LunExt->TransferMode = ATA_PIO; + } + return; +} // end AtapiDmaInit() + + +VOID +cyrix_timing( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ) +{ +// ASSERT(dev/2 >= deviceExtension->Channel); +// PHW_CHANNEL chan = &(deviceExtension->chan[dev/2-deviceExtension->Channel]); + ULONG reg20 = 0x0000e132; + ULONG reg24 = 0x00017771; + + if(mode == ATA_PIO5) + mode = ATA_PIO4; + + switch (mode) { + case ATA_PIO0: reg20 = 0x0000e132; break; + case ATA_PIO1: reg20 = 0x00018121; break; + case ATA_PIO2: reg20 = 0x00024020; break; + case ATA_PIO3: reg20 = 0x00032010; break; + case ATA_PIO4: + case ATA_PIO5: reg20 = 0x00040010; break; + case ATA_WDMA2: reg24 = 0x00002020; break; + case ATA_UDMA2: reg24 = 0x00911030; break; + } + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressBM_0),(dev*8) + 0x20, reg20); + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressBM_0),(dev*8) + 0x24, reg24); +} // cyrix_timing() + +VOID +promise_timing( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ) +{ + PVOID HwDeviceExtension = (PVOID)deviceExtension; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + //ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + + ULONG timing = 0; + + if(mode == ATA_PIO5) + mode = ATA_PIO4; + + switch(ChipType) { + case PROLD: + switch (mode) { + default: + case ATA_PIO0: timing = 0x004ff329; break; + case ATA_PIO1: timing = 0x004fec25; break; + case ATA_PIO2: timing = 0x004fe823; break; + case ATA_PIO3: timing = 0x004fe622; break; + case ATA_PIO4: timing = 0x004fe421; break; + case ATA_WDMA0: timing = 0x004567f3; break; + case ATA_WDMA1: timing = 0x004467f3; break; + case ATA_WDMA2: timing = 0x004367f3; break; + case ATA_UDMA0: timing = 0x004367f3; break; + case ATA_UDMA1: timing = 0x004247f3; break; + case ATA_UDMA2: timing = 0x004127f3; break; + } + break; + + case PRNEW: + switch (mode) { + default: + case ATA_PIO0: timing = 0x004fff2f; break; + case ATA_PIO1: timing = 0x004ff82a; break; + case ATA_PIO2: timing = 0x004ff026; break; + case ATA_PIO3: timing = 0x004fec24; break; + case ATA_PIO4: timing = 0x004fe822; break; + case ATA_WDMA0: timing = 0x004acef6; break; + case ATA_WDMA1: timing = 0x0048cef6; break; + case ATA_WDMA2: timing = 0x0046cef6; break; + case ATA_UDMA0: timing = 0x0046cef6; break; + case ATA_UDMA1: timing = 0x00448ef6; break; + case ATA_UDMA2: timing = 0x00436ef6; break; + case ATA_UDMA3: timing = 0x00424ef6; break; + case ATA_UDMA4: timing = 0x004127f3; break; + case ATA_UDMA5: timing = 0x004127f3; break; + } + break; + default: + return; + } + SetPciConfig4(0x60 + (dev<<2), timing); +} // end promise_timing() + + +VOID +hpt_timing( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ) +{ + PVOID HwDeviceExtension = (PVOID)deviceExtension; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + //ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + + ULONG timing; + + if(mode == ATA_PIO5) + mode = ATA_PIO4; + + switch(ChipType) { + case HPT374: + + switch (mode) { /* HPT374 */ + case ATA_PIO0: timing = 0x0ac1f48a; break; + case ATA_PIO1: timing = 0x0ac1f465; break; + case ATA_PIO2: timing = 0x0a81f454; break; + case ATA_PIO3: timing = 0x0a81f443; break; + case ATA_PIO4: timing = 0x0a81f442; break; + case ATA_WDMA0: timing = 0x228082ea; break; + case ATA_WDMA1: timing = 0x22808254; break; + case ATA_WDMA2: timing = 0x22808242; break; + case ATA_UDMA0: timing = 0x121882ea; break; + case ATA_UDMA1: timing = 0x12148254; break; + case ATA_UDMA2: timing = 0x120c8242; break; + case ATA_UDMA3: timing = 0x128c8242; break; + case ATA_UDMA4: timing = 0x12ac8242; break; + case ATA_UDMA5: timing = 0x12848242; break; + case ATA_UDMA6: timing = 0x12808242; break; + default: timing = 0x0d029d5e; + } + break; + + case HPT372: + + switch (mode) { /* HPT372 */ + case ATA_PIO0: timing = 0x0d029d5e; break; + case ATA_PIO1: timing = 0x0d029d26; break; + case ATA_PIO2: timing = 0x0c829ca6; break; + case ATA_PIO3: timing = 0x0c829c84; break; + case ATA_PIO4: timing = 0x0c829c62; break; + case ATA_WDMA0: timing = 0x2c82922e; break; + case ATA_WDMA1: timing = 0x2c829266; break; + case ATA_WDMA2: timing = 0x2c829262; break; + case ATA_UDMA0: timing = 0x1c829c62; break; + case ATA_UDMA1: timing = 0x1c9a9c62; break; + case ATA_UDMA2: timing = 0x1c929c62; break; + case ATA_UDMA3: timing = 0x1c8e9c62; break; + case ATA_UDMA4: timing = 0x1c8a9c62; break; + case ATA_UDMA5: timing = 0x1c8a9c62; break; + case ATA_UDMA6: timing = 0x1c869c62; break; + default: timing = 0x0d029d5e; + } + break; + + case HPT370: + + switch (mode) { /* HPT370 */ + case ATA_PIO0: timing = 0x06914e57; break; + case ATA_PIO1: timing = 0x06914e43; break; + case ATA_PIO2: timing = 0x06514e33; break; + case ATA_PIO3: timing = 0x06514e22; break; + case ATA_PIO4: timing = 0x06514e21; break; + case ATA_WDMA0: timing = 0x26514e97; break; + case ATA_WDMA1: timing = 0x26514e33; break; + case ATA_WDMA2: timing = 0x26514e21; break; + case ATA_UDMA0: timing = 0x16514e31; break; + case ATA_UDMA1: timing = 0x164d4e31; break; + case ATA_UDMA2: timing = 0x16494e31; break; + case ATA_UDMA3: timing = 0x166d4e31; break; + case ATA_UDMA4: timing = 0x16454e31; break; + case ATA_UDMA5: timing = 0x16454e31; break; + default: timing = 0x06514e57; + } + + case HPT366: { + UCHAR reg41; + + GetPciConfig1(0x41 + (dev << 2), reg41); + + switch (reg41) { + case 0x85: /* 25Mhz */ + switch (mode) { + case ATA_PIO0: timing = 0x40d08585; break; + case ATA_PIO1: timing = 0x40d08572; break; + case ATA_PIO2: timing = 0x40ca8542; break; + case ATA_PIO3: timing = 0x40ca8532; break; + case ATA_PIO4: timing = 0x40ca8521; break; + case ATA_WDMA2: timing = 0x20ca8521; break; + case ATA_UDMA2: timing = 0x10cf8521; break; + case ATA_UDMA4: timing = 0x10c98521; break; + default: timing = 0x01208585; + } + break; + default: + case 0xa7: /* 33MHz */ + switch (mode) { + case ATA_PIO0: timing = 0x40d0a7aa; break; + case ATA_PIO1: timing = 0x40d0a7a3; break; + case ATA_PIO2: timing = 0x40d0a753; break; + case ATA_PIO3: timing = 0x40c8a742; break; + case ATA_PIO4: timing = 0x40c8a731; break; + case ATA_WDMA0: timing = 0x20c8a797; break; + case ATA_WDMA1: timing = 0x20c8a732; break; + case ATA_WDMA2: timing = 0x20c8a731; break; + case ATA_UDMA0: timing = 0x10c8a731; break; + case ATA_UDMA1: timing = 0x10cba731; break; + case ATA_UDMA2: timing = 0x10caa731; break; + case ATA_UDMA3: timing = 0x10cfa731; break; + case ATA_UDMA4: timing = 0x10c9a731; break; + default: timing = 0x0120a7a7; + } + break; + case 0xd9: /* 40Mhz */ + switch (mode) { + case ATA_PIO0: timing = 0x4018d9d9; break; + case ATA_PIO1: timing = 0x4010d9c7; break; + case ATA_PIO2: timing = 0x4010d997; break; + case ATA_PIO3: timing = 0x4010d974; break; + case ATA_PIO4: timing = 0x4008d963; break; + case ATA_WDMA2: timing = 0x2008d943; break; + case ATA_UDMA2: timing = 0x100bd943; break; + case ATA_UDMA4: timing = 0x100fd943; break; + default: timing = 0x0120d9d9; + } + } + break; } + } + + SetPciConfig4(0x40 + (dev<<2), timing); +} // end hpt_timing() + + +#define FIT(v,min,max) (((v)>(max)?(max):(v))<(min)?(min):(v)) + +VOID +via82c_timing( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG dev, // physical device number (0-3) + IN CHAR mode + ) +{ + PVOID HwDeviceExtension = (PVOID)deviceExtension; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + + USHORT T = 1000 / /* PciBusClockMHz()*/ 33; + + USHORT setup = 0; + USHORT active = 0; + USHORT recover = 0; + USHORT cycle = 0; + + UCHAR t; + + switch(mode) { + default: + case ATA_PIO0: setup = 70; active = 165; recover = 150; cycle = 600; break; + case ATA_PIO1: setup = 50; active = 125; recover = 100; cycle = 383; break; + case ATA_PIO2: setup = 30; active = 100; recover = 90; cycle = 240; break; + case ATA_PIO3: setup = 30; active = 80; recover = 70; cycle = 180; break; + case ATA_PIO4: setup = 25; active = 70; recover = 25; cycle = 120; break; + case ATA_PIO5: setup = 20; active = 50; recover = 30; cycle = 100; break; + } + + setup = (setup -1)/(T+1); + active = (active -1)/(T+1); + recover = (recover-1)/(T+1); + cycle = (cycle -1)/(T+1); + + if (active + recover < cycle) { + active += (cycle - (active + recover)) / 2; + recover = cycle - active; + } + + // Newer chips dislike this: + if(!(deviceExtension->HwFlags & VIAAST)) { + /* PIO address setup */ + GetPciConfig1(0x4c, t); + t = (t & ~(3 << ((3 - dev) << 1))) | (FIT(setup - 1, 0, 3) << ((3 - dev) << 1)); + SetPciConfig1(0x4c, t); + } + + /* PIO active & recover */ + SetPciConfig1(0x4b-dev, (FIT(active - 1, 0, 0xf) << 4) | FIT(recover - 1, 0, 0xf) ); +} // end via82c_timing() + diff --git a/reactos/drivers/storage/ide/uniata/id_init.cpp b/reactos/drivers/storage/ide/uniata/id_init.cpp new file mode 100644 index 00000000000..e591c262434 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_init.cpp @@ -0,0 +1,1830 @@ +/*++ + +Copyright (c) 2004-2007 Alexandr A. Telyatnikov (Alter) + +Module Name: + id_init.cpp + +Abstract: + This is the chip-specific init module for ATA/ATAPI IDE controllers + with Busmaster DMA and Serial ATA support + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + + Some parts of code were taken from FreeBSD 5.1-6.1 ATA driver by + Søren Schmidt, Copyright (c) 1998-2007 + added IT8172 IDE controller support from Linux + added VIA 8233/8235 fix from Linux + added 80-pin cable detection from Linux for + VIA, nVidia + added support for non-standard layout of registers + added SATA support + +--*/ + +#include "stdafx.h" + +BOOLEAN +UniataChipDetect( + IN PVOID HwDeviceExtension, + IN PPCI_COMMON_CONFIG pciData, // optional + IN ULONG DeviceNumber, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN BOOLEAN* simplexOnly + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + ULONG VendorID = deviceExtension->DevID & 0xffff; + ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff; + ULONG RevID = deviceExtension->RevID; + ULONG i, c; + BUSMASTER_CONTROLLER_INFORMATION* DevTypeInfo; + PHW_CHANNEL chan; + ULONG ChipType; + ULONG ChipFlags; + ULONG tmp32; + UCHAR tmp8; + ULONG BaseMemAddress; + ULONG BaseIoAddress1; + ULONG BaseIoAddress2; + ULONG BaseIoAddressBM; + BOOLEAN MemIo = FALSE; + + KdPrint2((PRINT_PREFIX "UniataChipDetect:\n" )); + KdPrint2((PRINT_PREFIX "HwFlags: %#x\n", deviceExtension->HwFlags)); + + i = Ata_is_dev_listed((PBUSMASTER_CONTROLLER_INFORMATION)&BusMasterAdapters[0], VendorID, 0xffff, 0, NUM_BUSMASTER_ADAPTERS); + + c = AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"ForceSimplex", 0); + if(c) { + *simplexOnly = TRUE; + } + + KdPrint2((PRINT_PREFIX "i: %#x\n", i)); + if(i != BMLIST_TERMINATOR) { + DevTypeInfo = (PBUSMASTER_CONTROLLER_INFORMATION)&BusMasterAdapters[i]; + } else { + DevTypeInfo = NULL; + deviceExtension->MaxTransferMode = deviceExtension->BaseIoAddressBM_0.Addr ? ATA_DMA : ATA_PIO4; + return FALSE; + } + + static BUSMASTER_CONTROLLER_INFORMATION const SiSAdapters[] = { + PCI_DEV_HW_SPEC_BM( 0182, 1039, 0x00, ATA_SA150, "SiS 182" , SISSATA | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 0181, 1039, 0x00, ATA_SA150, "SiS 181" , SISSATA | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 0180, 1039, 0x00, ATA_SA150, "SiS 180" , SISSATA | UNIATA_SATA), + PCI_DEV_HW_SPEC_BM( 0965, 1039, 0x00, ATA_UDMA6, "SiS 965" , SIS133NEW ), + PCI_DEV_HW_SPEC_BM( 0964, 1039, 0x00, ATA_UDMA6, "SiS 964" , SIS133NEW ), + PCI_DEV_HW_SPEC_BM( 0963, 1039, 0x00, ATA_UDMA6, "SiS 963" , SIS133NEW ), + PCI_DEV_HW_SPEC_BM( 0962, 1039, 0x00, ATA_UDMA6, "SiS 962" , SIS133NEW ), + + PCI_DEV_HW_SPEC_BM( 0745, 1039, 0x00, ATA_UDMA5, "SiS 745" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0735, 1039, 0x00, ATA_UDMA5, "SiS 735" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0733, 1039, 0x00, ATA_UDMA5, "SiS 733" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0730, 1039, 0x00, ATA_UDMA5, "SiS 730" , SIS100OLD ), + + PCI_DEV_HW_SPEC_BM( 0646, 1039, 0x00, ATA_UDMA6, "SiS 645DX", SIS133NEW ), +/* PCI_DEV_HW_SPEC_BM( 0645, 1039, 0x00, ATA_UDMA6, "SiS 645" , SIS133NEW ), +/* PCI_DEV_HW_SPEC_BM( 0640, 1039, 0x00, ATA_UDMA4, "SiS 640" , SIS_SOUTH ),*/ + PCI_DEV_HW_SPEC_BM( 0635, 1039, 0x00, ATA_UDMA5, "SiS 635" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0633, 1039, 0x00, ATA_UDMA5, "SiS 633" , SIS100NEW ), + PCI_DEV_HW_SPEC_BM( 0630, 1039, 0x00, ATA_UDMA5, "SiS 630S" , SIS100OLD ), + PCI_DEV_HW_SPEC_BM( 0630, 1039, 0x00, ATA_UDMA4, "SiS 630" , SIS66 ), + PCI_DEV_HW_SPEC_BM( 0620, 1039, 0x00, ATA_UDMA4, "SiS 620" , SIS66 ), + + PCI_DEV_HW_SPEC_BM( 0550, 1039, 0x00, ATA_UDMA5, "SiS 550" , SIS66 ), + PCI_DEV_HW_SPEC_BM( 0540, 1039, 0x00, ATA_UDMA4, "SiS 540" , SIS66 ), + PCI_DEV_HW_SPEC_BM( 0530, 1039, 0x00, ATA_UDMA4, "SiS 530" , SIS66 ), + +// PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x04, ATA_UDMA6, "SiS 962L" , SIS133OLD ), // ??? +// PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x00, ATA_UDMA6, "SiS 961" , SIS133OLD ), + + PCI_DEV_HW_SPEC_BM( 5517, 1039, 0x00, ATA_UDMA5, "SiS 961" , SIS100NEW | SIS_BASE ), + PCI_DEV_HW_SPEC_BM( 5518, 1039, 0x00, ATA_UDMA6, "SiS 962/3", SIS133NEW | SIS_BASE ), + PCI_DEV_HW_SPEC_BM( 5513, 1039, 0xc2, ATA_UDMA2, "SiS 5513" , SIS33 | SIS_BASE ), + PCI_DEV_HW_SPEC_BM( 5513, 1039, 0x00, ATA_WDMA2, "SiS 5513" , SIS33 | SIS_BASE ), + PCI_DEV_HW_SPEC_BM( 0601, 1039, 0x00, ATA_UDMA2, "SiS 5513" , SIS33 | SIS_BASE ), + PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR , NULL , BMLIST_TERMINATOR ) + }; + + static BUSMASTER_CONTROLLER_INFORMATION const ViaAdapters[] = { + PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x41, ATA_UDMA2, "VIA 82C586B", VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x40, ATA_UDMA2, "VIA 82C586B", VIA33 | VIAPRQ ), + PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x02, ATA_UDMA2, "VIA 82C586B", VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0586, 1106, 0x00, ATA_WDMA2, "VIA 82C586" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0596, 1106, 0x12, ATA_UDMA4, "VIA 82C596B", VIA66 | VIACLK ), + PCI_DEV_HW_SPEC_BM( 0596, 1106, 0x00, ATA_UDMA2, "VIA 82C596" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 0686, 1106, 0x40, ATA_UDMA5, "VIA 82C686B", VIA100 | VIABUG ), + PCI_DEV_HW_SPEC_BM( 0686, 1106, 0x10, ATA_UDMA4, "VIA 82C686A", VIA66 | VIACLK ), + PCI_DEV_HW_SPEC_BM( 0686, 1106, 0x00, ATA_UDMA2, "VIA 82C686" , VIA33 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 8231, 1106, 0x00, ATA_UDMA5, "VIA 8231" , VIA100 | VIABUG ), + PCI_DEV_HW_SPEC_BM( 3074, 1106, 0x00, ATA_UDMA5, "VIA 8233" , VIA100 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 3109, 1106, 0x00, ATA_UDMA5, "VIA 8233C" , VIA100 | 0x00 ), + PCI_DEV_HW_SPEC_BM( 3147, 1106, 0x00, ATA_UDMA6, "VIA 8233A" , VIA133 | VIAAST ), + PCI_DEV_HW_SPEC_BM( 3177, 1106, 0x00, ATA_UDMA6, "VIA 8235" , VIA133 | VIAAST ), + PCI_DEV_HW_SPEC_BM( 3227, 1106, 0x00, ATA_UDMA6, "VIA 8237" , VIA133 | VIAAST ), + PCI_DEV_HW_SPEC_BM( 3349, 1106, 0x00, ATA_UDMA6, "VIA 8237" , VIA133 | VIAAST ), + PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR , NULL , BMLIST_TERMINATOR ) + }; + + static BUSMASTER_CONTROLLER_INFORMATION const ViaSouthAdapters[] = { + PCI_DEV_HW_SPEC_BM( 3112, 1106, 0x00, -1, "VIA 8361", VIASOUTH ), + PCI_DEV_HW_SPEC_BM( 0305, 1106, 0x00, -1, "VIA 8363", VIASOUTH ), + PCI_DEV_HW_SPEC_BM( 0391, 1106, 0x00, -1, "VIA 8371", VIASOUTH ), + PCI_DEV_HW_SPEC_BM( 3102, 1106, 0x00, -1, "VIA 8662", VIASOUTH ), + PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, BMLIST_TERMINATOR, NULL , BMLIST_TERMINATOR ) + }; + + KdPrint2((PRINT_PREFIX "VendorID/DeviceID/Rev %#x/%#x/%#x\n", VendorID, DeviceID, RevID)); + + switch(VendorID) { + + case ATA_SIS_ID: + KdPrint2((PRINT_PREFIX "ATA_SIS_ID\n")); + DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION*)&SiSAdapters[0]; + i = AtapiFindListedDev(DevTypeInfo, -1, HwDeviceExtension, SystemIoBusNumber, -1, NULL); + goto for_ugly_chips; + + case ATA_VIA_ID: + KdPrint2((PRINT_PREFIX "ATA_VIA_ID\n")); + // New chips have own DeviceId + if(deviceExtension->DevID != ATA_VIA82C571) + break; + // Old chips have same DeviceId, we can distinguish between them + // only by SouthBridge DeviceId + DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION*)&ViaSouthAdapters[0]; + i = AtapiFindListedDev(DevTypeInfo, -1, HwDeviceExtension, SystemIoBusNumber, slotNumber, NULL); + if(i != -1) { + KdPrint2((PRINT_PREFIX "VIASOUTH\n")); + deviceExtension->HwFlags |= VIASOUTH; + } + DevTypeInfo = (BUSMASTER_CONTROLLER_INFORMATION*)&ViaAdapters[0]; + i = AtapiFindListedDev(DevTypeInfo, -1, HwDeviceExtension, SystemIoBusNumber, slotNumber, NULL); + goto for_ugly_chips; + + default: + + // do nothing + break; + +#if 0 + KdPrint2((PRINT_PREFIX "Default\n")); + + deviceExtension->MaxTransferMode = deviceExtension->BaseIoAddressBM_0 ? ATA_DMA : ATA_PIO4; + /* do extra chipset specific setups */ + switch(deviceExtension->DevID) { + + //case ATA_CYPRESS_ID: + case 0xc6931080: /* 82c693 ATA controller */ + deviceExtension->MaxTransferMode = ATA_WDMA2; + break; + + case 0x000116ca: /* Cenatek Rocket Drive controller */ + deviceExtension->MaxTransferMode = ATA_WDMA2; + break; + +/* case ATA_CYRIX_ID: + DevTypeInfo = &CyrixAdapters[0]; + break;*/ + case 0x01021078: /* Cyrix 5530 ATA33 controller */ + deviceExtension->MaxTransferMode = ATA_UDMA2; + break; + + case 0x06401095: /* CMD 640 known bad, no DMA */ + case 0x06011039: + *simplexOnly = TRUE; + + /* FALLTHROUGH */ + + case 0x10001042: /* RZ 100? known bad, no DMA */ + case 0x10011042: + + if(deviceExtension->BaseIoAddressBM_0) + ScsiPortFreeDeviceBase(HwDeviceExtension, + deviceExtension->BaseIoAddressBM_0); + + deviceExtension->BaseIoAddressBM_0 = 0; + deviceExtension->BusMaster = FALSE; + deviceExtension->MaxTransferMode = ATA_PIO4; + break; + + case 0x81721283: /* IT8172 IDE controller */ + deviceExtension->MaxTransferMode = ATA_UDMA2; + *simplexOnly = TRUE; + break; + + default: + return FALSE; + } + return TRUE; +#endif + } + + i = Ata_is_dev_listed(DevTypeInfo, VendorID, DeviceID, RevID, -1); +for_ugly_chips: + KdPrint2((PRINT_PREFIX "i: %#x\n", i)); + if(i == -1) { + return FALSE; + } + deviceExtension->MaxTransferMode = DevTypeInfo[i].MaxTransferMode; + deviceExtension->HwFlags |= DevTypeInfo[i].RaidFlags; + + KdPrint2((PRINT_PREFIX "HwFlags: %#x\n", deviceExtension->HwFlags)); + + tmp32 = AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"HwFlagsOverride", deviceExtension->HwFlags); + KdPrint2((PRINT_PREFIX "HwFlagsOverride: %#x\n", tmp32)); + deviceExtension->HwFlags = tmp32; + + tmp32 = AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"HwFlagsAdd", 0); + KdPrint2((PRINT_PREFIX "HwFlagsAdd: %#x\n", tmp32)); + deviceExtension->HwFlags |= tmp32; + + KdPrint2((PRINT_PREFIX "HwFlags (final): %#x\n", deviceExtension->HwFlags)); + if(deviceExtension->HwFlags & UNIATA_SIMPLEX_ONLY) { + KdPrint2((PRINT_PREFIX "UNIATA_SIMPLEX_ONLY\n" )); + *simplexOnly = TRUE; + } + + KdPrint2((PRINT_PREFIX "MaxTransferMode: %#x\n", deviceExtension->MaxTransferMode)); + tmp32 = AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxTransferMode", deviceExtension->MaxTransferMode); + if(tmp32 != 0xffffffff) { + KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", deviceExtension->MaxTransferMode)); + deviceExtension->MaxTransferMode = tmp32; + } + + if(deviceExtension->MaxTransferMode >= ATA_SA150) { + deviceExtension->HwFlags |= UNIATA_SATA; + } + + ConfigInfo->MaximumTransferLength = DEV_BSIZE*256; + deviceExtension->MaximumDmaTransferLength = ConfigInfo->MaximumTransferLength; + + ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + + switch(VendorID) { + case ATA_ACER_LABS_ID: + switch(deviceExtension->DevID) { + case 0x528710b9: + case 0x528810b9: + deviceExtension->NumberChannels = 4; + } + if(ChipFlags & UNIATA_SATA) { + deviceExtension->AltRegMap = TRUE; // inform generic resource allocator + BaseIoAddress1 = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 0, 0, 0x10); + BaseIoAddress2 = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 1, 0, 0x10); + BaseIoAddressBM = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 4, 0, deviceExtension->NumberChannels*sizeof(IDE_BUSMASTER_REGISTERS)); + for(c=0; cNumberChannels; c++) { + ULONG unit01 = (c & 1); + ULONG unit10 = (c & 2); + chan = &deviceExtension->chan[c]; + + for (i=0; i<=IDX_IO1_SZ; i++) { + chan->RegTranslation[IDX_IO1+i].Addr = BaseIoAddress1 + i + (unit10 ? 8 : 0); + } + chan->RegTranslation[IDX_IO2_AltStatus].Addr = BaseIoAddress2 + 2 + (unit10 ? 4 : 0); + UniataInitSyncBaseIO(chan); + + for (i=0; i<=IDX_BM_IO_SZ; i++) { + chan->RegTranslation[IDX_BM_IO+i].Addr = BaseIoAddressBM + i + (c * sizeof(IDE_BUSMASTER_REGISTERS)); + } + + // SATA not supported yet + + //chan->RegTranslation[IDX_BM_Command] = BaseMemAddress + 0x260 + offs7; + //chan->RegTranslation[IDX_BM_PRD_Table] = BaseMemAddress + 0x244 + offs7; + //chan->RegTranslation[IDX_BM_DeviceSpecific0] = BaseMemAddress + (c << 2); + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + } + break; + case ATA_NVIDIA_ID: + if(ChipFlags & UNIATA_SATA) { + KdPrint2((PRINT_PREFIX "NVIDIA SATA\n")); + BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 5, 0, ((ChipFlags & NV4OFF) ? 0x400 : 0) + 0x40*2); + KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress)); + if((*ConfigInfo->AccessRanges)[5].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->BaseIoAddressSATA_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo; + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + + chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + (c << 6); + chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + 4 + (c << 6); + chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + 8 + (c << 6); + chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + } + break; + case ATA_PROMISE_ID: + + if(ChipType != PRMIO) { + break; + } + deviceExtension->NumberChannels = 4; + if(!pciData) { + break; + } + deviceExtension->AltRegMap = TRUE; // inform generic resource allocator + BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 4, 0, 0x4000); + KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress)); + if((*ConfigInfo->AccessRanges)[4].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->BaseIoAddressBM_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressBM_0.MemIo = MemIo; + for(c=0; cNumberChannels; c++) { + + ULONG offs12, offs7; + + chan = &deviceExtension->chan[c]; + + offs12 = c << 12; + offs7 = c << 7; + + for (i=0; i<=IDX_IO1_SZ; i++) { + chan->RegTranslation[IDX_IO1+i].Addr = BaseMemAddress + 0x200 + (i << 2) + offs12; + chan->RegTranslation[IDX_IO1+i].MemIo = MemIo; + } + chan->RegTranslation[IDX_IO2_AltStatus].Addr = BaseMemAddress + 0x238 + offs7; + chan->RegTranslation[IDX_IO2_AltStatus].MemIo = MemIo; + + UniataInitSyncBaseIO(chan); + + chan->RegTranslation[IDX_BM_Command].Addr = BaseMemAddress + 0x260 + offs7; + chan->RegTranslation[IDX_BM_Command].MemIo = MemIo; + chan->RegTranslation[IDX_BM_PRD_Table].Addr = BaseMemAddress + 0x244 + offs7; + chan->RegTranslation[IDX_BM_PRD_Table].MemIo = MemIo; + chan->RegTranslation[IDX_BM_DeviceSpecific0].Addr = BaseMemAddress + (c << 2); + chan->RegTranslation[IDX_BM_DeviceSpecific0].MemIo = MemIo; + } + break; + + case ATA_ATI_ID: + KdPrint2((PRINT_PREFIX "ATI\n")); + case ATA_SILICON_IMAGE_ID: { + + if(ChipFlags & SIIBUG) { + } + if(ChipType != SIIMIO) { + break; + } + if(!pciData) { + break; + } + + if(VendorID == ATA_SILICON_IMAGE_ID) { + KdPrint2((PRINT_PREFIX "New SII\n")); + } else { + KdPrint2((PRINT_PREFIX "ATI SATA\n")); + } + //if(deviceExtension->HwFlags & SII4CH) { + deviceExtension->AltRegMap = TRUE; // inform generic resource allocator + //} + BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 5, 0, 0x800); + KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress)); + if((*ConfigInfo->AccessRanges)[5].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->BaseIoAddressSATA_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo; + if(deviceExtension->HwFlags & SII4CH) { + deviceExtension->NumberChannels = 4; + } + + for(c=0; cNumberChannels; c++) { + ULONG unit01 = (c & 1); + ULONG unit10 = (c & 2); + + chan = &deviceExtension->chan[c]; + + if(deviceExtension->AltRegMap) { + for (i=0; i<=IDX_IO1_SZ; i++) { + chan->RegTranslation[IDX_IO1+i].Addr = BaseMemAddress + 0x80 + i + (unit01 << 6) + (unit10 << 8); + chan->RegTranslation[IDX_IO1+i].MemIo = MemIo; + } + chan->RegTranslation[IDX_IO2_AltStatus].Addr = BaseMemAddress + 0x8a + (unit01 << 6) + (unit10 << 8); + chan->RegTranslation[IDX_IO2_AltStatus].MemIo = MemIo; + UniataInitSyncBaseIO(chan); + + chan->RegTranslation[IDX_BM_Command].Addr = BaseMemAddress + 0x00 + (unit01 << 3) + (unit10 << 8); + chan->RegTranslation[IDX_BM_Command].MemIo = MemIo; + chan->RegTranslation[IDX_BM_Status].Addr = BaseMemAddress + 0x02 + (unit01 << 3) + (unit10 << 8); + chan->RegTranslation[IDX_BM_Status].MemIo = MemIo; + chan->RegTranslation[IDX_BM_PRD_Table].Addr = BaseMemAddress + 0x04 + (unit01 << 3) + (unit10 << 8); + chan->RegTranslation[IDX_BM_PRD_Table].MemIo = MemIo; + //chan->RegTranslation[IDX_BM_DeviceSpecific0].Addr = BaseMemAddress + 0xa1 + (unit01 << 6) + (unit10 << 8); + //chan->RegTranslation[IDX_BM_DeviceSpecific0].MemIo = MemIo; + chan->RegTranslation[IDX_BM_DeviceSpecific0].Addr = BaseMemAddress + 0x10 + (unit01 << 3) + (unit10 << 8); + chan->RegTranslation[IDX_BM_DeviceSpecific0].MemIo = MemIo; + chan->RegTranslation[IDX_BM_DeviceSpecific1].Addr = BaseMemAddress + 0x40 + (unit01 << 2) + (unit10 << 8); + chan->RegTranslation[IDX_BM_DeviceSpecific1].MemIo = MemIo; + } + + if(ChipFlags & UNIATA_SATA) { + chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + 0x104 + (unit01 << 7) + (unit10 << 8); + chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + 0x108 + (unit01 << 7) + (unit10 << 8); + chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + 0x100 + (unit01 << 7) + (unit10 << 8); + chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + } + break; } + + case ATA_SERVERWORKS_ID: { + + if(ChipType != SWKSMIO) { + break; + } + if(!pciData) { + break; + } + + KdPrint2((PRINT_PREFIX "ServerWorks\n")); + + deviceExtension->AltRegMap = TRUE; // inform generic resource allocator + BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 5, 0, 0x400); + KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress)); + if((*ConfigInfo->AccessRanges)[5].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->BaseIoAddressSATA_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo; + + for(c=0; cNumberChannels; c++) { + ULONG offs = c*0x100; + + chan = &deviceExtension->chan[c]; + for (i=0; i<=IDX_IO1_SZ; i++) { + chan->RegTranslation[IDX_IO1+i].Addr = BaseMemAddress + offs + i*4; + chan->RegTranslation[IDX_IO1+i].MemIo = MemIo; + } + chan->RegTranslation[IDX_IO2_AltStatus].Addr = BaseMemAddress + offs + 0x20; + chan->RegTranslation[IDX_IO2_AltStatus].MemIo = MemIo; + UniataInitSyncBaseIO(chan); + + chan->RegTranslation[IDX_BM_Command].Addr = BaseMemAddress + offs + 0x30; + chan->RegTranslation[IDX_BM_Command].MemIo = MemIo; + chan->RegTranslation[IDX_BM_Status].Addr = BaseMemAddress + offs + 0x32; + chan->RegTranslation[IDX_BM_Status].MemIo = MemIo; + chan->RegTranslation[IDX_BM_PRD_Table].Addr = BaseMemAddress + offs + 0x34; + chan->RegTranslation[IDX_BM_PRD_Table].MemIo = MemIo; + + chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + offs + 0x40; + chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + offs + 0x44; + chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + offs + 0x48; + chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + break; } + + case ATA_SIS_ID: { + //if(ChipType != SIS_SOUTH) { + BOOLEAN SIS_182=FALSE; + + if(!(ChipFlags & SIS_BASE)) { + KdPrint2((PRINT_PREFIX "Found SIS_SOUTH\n")); + //PrintNtConsole("Found SIS_SOUTH\n"); + break; + } + // Make some additional checks + KdPrint2((PRINT_PREFIX "ChipType == SIS_BASE\n")); + ChangePciConfig1(0x57, (a & 0x7f)); + GetPciConfig4(0x00, tmp32); + if(tmp32 == ATA_SIS5518) { + ChipType = SIS133NEW; + deviceExtension->HwFlags = (deviceExtension->HwFlags & ~CHIPTYPE_MASK) | SIS133NEW; + deviceExtension->MaxTransferMode = ATA_UDMA6; + KdPrint2((PRINT_PREFIX "UniataChipDetect: SiS 962/963 DMA %#x controller\n", deviceExtension->MaxTransferMode)); + //PrintNtConsole("UniataChipDetect: SiS 962/963 DMA %#x controller\n", deviceExtension->MaxTransferMode); + // Restore device ID + ChangePciConfig1(0x57, (a | 0x80)); + } else { + static BUSMASTER_CONTROLLER_INFORMATION const SiSSouthAdapters[] = { + PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x10, -1, "SiS 961", 0 ), +// PCI_DEV_HW_SPEC_BM( 0008, 1039, 0x00, -1, "SiS 961", 0 ), + PCI_DEV_HW_SPEC_BM( ffff, ffff, 0xff, -1, NULL , -1 ) + }; + // Save settings + GetPciConfig1(0x4a, tmp8); + ChangePciConfig1(0x4a, (a | 0x10)); + if(tmp32 == ATA_SIS5513 || + tmp32 == ATA_SIS5517) { + i = AtapiFindListedDev((BUSMASTER_CONTROLLER_INFORMATION*)&SiSSouthAdapters[0], + -1, HwDeviceExtension, SystemIoBusNumber, -1, NULL); + if(i != -1) { + deviceExtension->HwFlags = (deviceExtension->HwFlags & ~CHIPTYPE_MASK) | SIS133OLD; + //deviceExtension->MaxTransferMode = ATA_UDMA6; + deviceExtension->MaxTransferMode = SiSSouthAdapters[i].MaxTransferMode; + if(SiSSouthAdapters[i].RaidFlags & UNIATA_SATA) { + deviceExtension->HwFlags |= UNIATA_SATA; + if(SiSSouthAdapters[i].nDeviceId == 0x01182) { + SIS_182 = TRUE; + } + } + } else { + // SiS-South not found + if(tmp32 == ATA_SIS5517) { + deviceExtension->HwFlags = (deviceExtension->HwFlags & ~CHIPTYPE_MASK) | SIS100NEW; + deviceExtension->MaxTransferMode = ATA_UDMA5; + } else { + // generic SiS33 + KdPrint2((PRINT_PREFIX "Generic SiS DMA\n")); + } + } + } + // Restore settings + SetPciConfig1(0x4a, tmp8); + KdPrint2((PRINT_PREFIX "UniataChipDetect: SiS 961 DMA %#x controller\n", deviceExtension->MaxTransferMode)); + //PrintNtConsole("UniataChipDetect: SiS 961 DMA %#x controller\n", deviceExtension->MaxTransferMode); + if(deviceExtension->HwFlags & UNIATA_SATA) { + KdPrint2((PRINT_PREFIX "SiS SATA\n")); + + BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 5, 0, 0x400); + KdPrint2((PRINT_PREFIX "BaseMemAddress %x\n", BaseMemAddress)); + if((*ConfigInfo->AccessRanges)[5].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->BaseIoAddressSATA_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo; + + for(c=0; cNumberChannels; c++) { + ULONG offs = c << (SIS_182 ? 5 : 6); + + chan = &deviceExtension->chan[c]; + chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + 0 + offs; + chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + 4 + offs; + chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + 8 + offs; + chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + } + } + //ChangePciConfig1(0x57, (a | 0x80)); + break; } + + case ATA_VIA_ID: { + + if(ChipFlags & UNIATA_SATA) { + + ULONG IoSize = 0; + + switch(DeviceID) { + case 3149: // VIA 6420 + IoSize = 0x80; + break; + case 3249: // VIA 6421 + IoSize = 0x40; + break; + } + if(IoSize) { + /*deviceExtension->*/BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 5, 0, IoSize * deviceExtension->NumberChannels); + if((*ConfigInfo->AccessRanges)[5].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->BaseIoAddressSATA_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo; + } + if(/*deviceExtension->*/BaseMemAddress) { + KdPrint2((PRINT_PREFIX "UniataChipDetect: BAR5 %x\n", /*deviceExtension->*/BaseMemAddress)); + if(ChipFlags & VIABAR) { + + ULONG BaseIoAddressBM_0; + ULONG BaseIo; + + KdPrint2((PRINT_PREFIX "UniataChipDetect: VIABAR\n")); + /*deviceExtension->*/BaseIoAddressBM_0 = /*(PIDE_BUSMASTER_REGISTERS)*/ + AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, 4, 0, + sizeof(IDE_BUSMASTER_REGISTERS)*deviceExtension->NumberChannels); + deviceExtension->AltRegMap = TRUE; // inform generic resource allocator + for(c=0; cNumberChannels; c++) { + + chan = &deviceExtension->chan[c]; + + BaseIo = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, c, 0, 0x80); + + for (i=0; i<=IDX_IO1_SZ; i++) { + chan->RegTranslation[IDX_IO1+i].Addr = BaseIo + i; + } + chan->RegTranslation[IDX_IO2_AltStatus].Addr = BaseIo + sizeof(IDE_REGISTERS_1) + 2 + FIELD_OFFSET(IDE_REGISTERS_2, AltStatus ); + UniataInitSyncBaseIO(chan); + + for (i=0; i<=IDX_BM_IO_SZ; i++) { + chan->RegTranslation[IDX_BM_IO+i].Addr = BaseIoAddressBM_0 + sizeof(IDE_BUSMASTER_REGISTERS)*c + i; + } + chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + (c * IoSize); + chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + 4 + (c * IoSize); + chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + 8 + (c * IoSize); + chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + } + } + } + break; } + case ATA_INTEL_ID: { + + if(!(ChipFlags & UNIATA_SATA)) { + break; + } + + /* the intel 31244 needs special care if in DPA mode */ + if(DeviceID == 3200 && // Intel 31244 + pciData->SubClass != PCI_DEV_SUBCLASS_IDE) { + + KdPrint2((PRINT_PREFIX "UniataChipDetect: Intel 31244, DPA mode\n")); + BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + 0, 0, 0x0c00); + if((*ConfigInfo->AccessRanges)[0].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->AltRegMap = TRUE; // inform generic resource allocator + deviceExtension->BaseIoAddressSATA_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo; + + for(c=0; cNumberChannels; c++) { + ULONG offs = 0x200 + c*0x200; + + chan = &deviceExtension->chan[c]; + for (i=0; i<=IDX_IO1_SZ; i++) { + chan->RegTranslation[IDX_IO1+i].MemIo = MemIo; + chan->RegTranslation[IDX_IO1_o+i].MemIo = MemIo; + } + + chan->RegTranslation[IDX_IO1_i_Data ].Addr = BaseMemAddress + 0x00 + offs; + chan->RegTranslation[IDX_IO1_i_Error ].Addr = BaseMemAddress + 0x04 + offs; + chan->RegTranslation[IDX_IO1_i_BlockCount ].Addr = BaseMemAddress + 0x08 + offs; + chan->RegTranslation[IDX_IO1_i_BlockNumber ].Addr = BaseMemAddress + 0x0c + offs; + chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr = BaseMemAddress + 0x10 + offs; + chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr = BaseMemAddress + 0x14 + offs; + chan->RegTranslation[IDX_IO1_i_DriveSelect ].Addr = BaseMemAddress + 0x18 + offs; + chan->RegTranslation[IDX_IO1_i_Status ].Addr = BaseMemAddress + 0x1c + offs; + + UniataInitSyncBaseIO(chan); + + chan->RegTranslation[IDX_IO1_o_Command ].Addr = BaseMemAddress + 0x1d + offs; + chan->RegTranslation[IDX_IO1_o_Feature ].Addr = BaseMemAddress + 0x06 + offs; + chan->RegTranslation[IDX_IO2_o_Control ].Addr = BaseMemAddress + 0x29 + offs; + + chan->RegTranslation[IDX_IO2_AltStatus].Addr = BaseMemAddress + 0x28 + offs; + chan->RegTranslation[IDX_IO2_AltStatus].MemIo = MemIo; + + chan->RegTranslation[IDX_BM_Command].Addr = BaseMemAddress + offs + 0x70; + chan->RegTranslation[IDX_BM_Command].MemIo = MemIo; + chan->RegTranslation[IDX_BM_Status].Addr = BaseMemAddress + offs + 0x72; + chan->RegTranslation[IDX_BM_Status].MemIo = MemIo; + chan->RegTranslation[IDX_BM_PRD_Table].Addr = BaseMemAddress + offs + 0x74; + chan->RegTranslation[IDX_BM_PRD_Table].MemIo = MemIo; + + chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + 0x100 + offs; + chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + 0x104 + offs; + chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + 0x108 + offs; + chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + + break; + } + /* SATA parts can be either compat or AHCI */ + if(ChipFlags & UNIATA_AHCI) { + + GetPciConfig1(0x90, tmp8); + if(tmp8 & 0xc0) { + KdPrint2((PRINT_PREFIX "AHCI not supported yet\n")); + return FALSE; + } + deviceExtension->HwFlags &= ~UNIATA_AHCI; + } +#if 0 + if(ChipFlags & UNIATA_SATA) { + //BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, + // 0, 0, 0x0c00); + BaseMemAddress = NULL; // HACK-HACK + if(!BaseMemAddress) { + KdPrint2((PRINT_PREFIX "Intel: no SATA I/O space, operate in PATA Compatible mode\n")); + deviceExtension->HwFlags &= ~UNIATA_SATA; + break; + } + if((*ConfigInfo->AccessRanges)[0].RangeInMemory) { + KdPrint2((PRINT_PREFIX "MemIo\n")); + MemIo = TRUE; + } + deviceExtension->BaseIoAddressSATA_0.Addr = BaseMemAddress; + deviceExtension->BaseIoAddressSATA_0.MemIo = MemIo; + } +#endif + break; } + case 0x1078: + /* Cyrix 5530 ATA33 controller */ + if(deviceExtension->DevID == 0x01021078) { + ConfigInfo->AlignmentMask = 0x0f; + deviceExtension->MaximumDmaTransferLength = 63*1024; + } + break; + } + + return TRUE; + +} // end UniataChipDetect() + + +/* + Do some 'magic staff' for VIA SouthBridge + This will prevent data losses +*/ +VOID +AtapiViaSouthBridgeFixup( + IN PVOID HwDeviceExtension, + IN BUS_DATA_TYPE BusDataType, + IN ULONG SystemIoBusNumber, + IN ULONG slotNumber + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PCI_COMMON_CONFIG pciData; + ULONG funcNumber; + ULONG busDataRead; + + ULONG VendorID; + ULONG DeviceID; + PCI_SLOT_NUMBER slotData; + ULONG dev_id; + BOOLEAN found = FALSE; + + slotData.u.AsULONG = slotNumber; + for(funcNumber = 0; funcNumber < PCI_MAX_FUNCTION; funcNumber++) { + + slotData.u.bits.FunctionNumber = funcNumber; + + busDataRead = ScsiPortGetBusData(HwDeviceExtension, + PCIConfiguration, + SystemIoBusNumber, + slotData.u.AsULONG, + &pciData, + PCI_COMMON_HDR_LENGTH); + + if (busDataRead < PCI_COMMON_HDR_LENGTH) { + continue; + } + + VendorID = pciData.VendorID; + DeviceID = pciData.DeviceID; + dev_id = (VendorID | (DeviceID << 16)); + + if (dev_id == 0x03051106 || /* VIA VT8363 */ + dev_id == 0x03911106 || /* VIA VT8371 */ + dev_id == 0x31021106 || /* VIA VT8662 */ + dev_id == 0x31121106) { /* VIA VT8361 */ + UCHAR reg76; + + GetPciConfig1(0x76, reg76); + + if ((reg76 & 0xf0) != 0xd0) { + SetPciConfig1(0x75, 0x80); + SetPciConfig1(0x76, (reg76 & 0x0f) | 0xd0); + } + found = TRUE; + break; + } + } + if(!found) { + deviceExtension->HwFlags &= ~VIABUG; + } +} // end AtapiViaSouthBridgeFixup() + +/* + Do some 'magic staff' for ROSB SouthBridge + This will prevent data losses +*/ +VOID +AtapiRosbSouthBridgeFixup( + IN PVOID HwDeviceExtension, + IN BUS_DATA_TYPE BusDataType, + IN ULONG SystemIoBusNumber, + IN ULONG slotNumber + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PCI_COMMON_CONFIG pciData; + ULONG funcNumber; + ULONG busDataRead; + + ULONG VendorID; + ULONG DeviceID; + PCI_SLOT_NUMBER slotData; + ULONG dev_id; +// BOOLEAN found = FALSE; + + /* locate the ISA part in the southbridge and enable UDMA33 */ + slotData.u.AsULONG = slotNumber; + for(funcNumber = 0; funcNumber < PCI_MAX_FUNCTION; funcNumber++) { + + slotData.u.bits.FunctionNumber = funcNumber; + + busDataRead = ScsiPortGetBusData(HwDeviceExtension, + PCIConfiguration, + SystemIoBusNumber, + slotData.u.AsULONG, + &pciData, + PCI_COMMON_HDR_LENGTH); + + if (busDataRead < PCI_COMMON_HDR_LENGTH) { + continue; + } + + VendorID = pciData.VendorID; + DeviceID = pciData.DeviceID; + dev_id = (VendorID | (DeviceID << 16)); + + if (dev_id == ATA_ROSB4_ISA) { /* VIA VT8361 */ + ChangePciConfig4(0x64, ((a & ~0x00002000) | 0x00004000)); + break; + } + } +} // end AtapiRosbSouthBridgeFixup() + +/* + Do some 'magic staff' for ROSB SouthBridge + This will prevent data losses +*/ +VOID +AtapiAliSouthBridgeFixup( + IN PVOID HwDeviceExtension, + IN BUS_DATA_TYPE BusDataType, + IN ULONG SystemIoBusNumber, + IN ULONG slotNumber, + IN ULONG c + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PCI_COMMON_CONFIG pciData; + ULONG funcNumber; + ULONG busDataRead; + + ULONG VendorID; + ULONG DeviceID; + PCI_SLOT_NUMBER slotData; + ULONG dev_id; +// BOOLEAN found = FALSE; + + /* workaround for datacorruption bug found on at least SUN Blade-100 + * find the ISA function on the southbridge and disable then enable + * the ATA channel tristate buffer */ + slotData.u.AsULONG = slotNumber; + for(funcNumber = 0; funcNumber < PCI_MAX_FUNCTION; funcNumber++) { + + slotData.u.bits.FunctionNumber = funcNumber; + + busDataRead = ScsiPortGetBusData(HwDeviceExtension, + PCIConfiguration, + SystemIoBusNumber, + slotData.u.AsULONG, + &pciData, + PCI_COMMON_HDR_LENGTH); + + if (busDataRead < PCI_COMMON_HDR_LENGTH) { + continue; + } + + VendorID = pciData.VendorID; + DeviceID = pciData.DeviceID; + dev_id = (VendorID | (DeviceID << 16)); + + if (dev_id == ATA_ALI_1533) { /* SOUTH */ + ChangePciConfig1(0x58, (a & ~(0x04 << c))); + ChangePciConfig1(0x58, (a | (0x04 << c))); + break; + } + } +} // end AtapiRosbSouthBridgeFixup() + +ULONG +hpt_cable80( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG channel // physical channel number (0-1) + ) +{ + PVOID HwDeviceExtension = (PVOID)deviceExtension; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + + UCHAR reg, val, res; + PCI_SLOT_NUMBER slotData; + + slotData.u.AsULONG = deviceExtension->slotNumber; + + if(ChipType == HPT374 && slotData.u.bits.FunctionNumber == 1) { + reg = channel ? 0x57 : 0x53; + GetPciConfig1(reg, val); + SetPciConfig1(reg, val | 0x80); + } + else { + reg = 0x5b; + GetPciConfig1(reg, val); + SetPciConfig1(reg, val & 0xfe); + } + GetPciConfig1(0x5a, res); + res = res & (channel ? 0x01 : 0x02); + SetPciConfig1(reg, val); + return !res; +} // end hpt_cable80() + + +ULONG +via_cable80( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG channel // physical channel number (0-1) + ) +{ + PVOID HwDeviceExtension = (PVOID)deviceExtension; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + + ULONG reg50; + ULONG a; + ULONG i, j; + BOOLEAN res; + + GetPciConfig1(0x50, reg50); + + switch(ChipType) { + case VIA133: + a = 8; + break; + case VIA100: + a = 4; + break; + case VIA66: + a = 2; + break; + default: + return false; + } + + res = FALSE; + for (j=0; j>=2; i -= 8) { + i = (3-(channel*2+j))*8; + if (((reg50 >> (i & 16)) & 8) && + ((reg50 >> i) & 0x20) && + (((reg50 >> i) & 7) < a)) { + + res |= TRUE; //(1 << (1 - (i >> 4))); + } + } + return res; + +} // end via_cable80() + +VOID +UniAtaReadLunConfig( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN ULONG channel, // physical channel + IN ULONG ldev + ) +{ + ULONG tmp32; + PHW_CHANNEL chan; + PHW_LU_EXTENSION LunExt; + ULONG c; + + c = channel - deviceExtension->Channel; // logical channel + + chan = &deviceExtension->chan[c]; + ldev &= 0x01; + LunExt = &(deviceExtension->lun[c*2+ldev]); + + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"ReadCacheEnable", 1); + LunExt->opt_ReadCacheEnable = tmp32 ? TRUE : FALSE; + + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"WriteCacheEnable", 1); + LunExt->opt_WriteCacheEnable = tmp32 ? TRUE : FALSE; + + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"MaxTransferMode", chan->MaxTransferMode); + LunExt->opt_MaxTransferMode = tmp32; + + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"PreferedTransferMode", 0xffffffff); + LunExt->opt_PreferedTransferMode = tmp32; + + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, ldev, L"GeomType", 0xffffffff); + if(tmp32 > 2) { + tmp32 = 0xffffffff; + } + LunExt->opt_GeomType = tmp32; + + return; +} // end UniAtaReadLunConfig() + +BOOLEAN +AtapiReadChipConfig( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG channel // physical channel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan; + ULONG tmp32; + ULONG c; // logical channel (for Compatible Mode controllers) + + KdPrint2((PRINT_PREFIX "AtapiReadChipConfig: devExt %#x\n", deviceExtension )); + ASSERT(deviceExtension); + + if(channel != CHAN_NOT_SPECIFIED) { + c = channel - deviceExtension->Channel; // logical channel (for Compatible Mode controllers) + } else { + c = CHAN_NOT_SPECIFIED; + } + + KdPrint2((PRINT_PREFIX "AtapiReadChipConfig: dev %#x, ph chan %d\n", DeviceNumber, channel )); + + if(channel == CHAN_NOT_SPECIFIED) { + if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"ForceSimplex", FALSE)) { + deviceExtension->simplexOnly = TRUE; + } + deviceExtension->opt_AtapiDmaZeroTransfer = FALSE; + deviceExtension->opt_AtapiDmaControlCmd = FALSE; + deviceExtension->opt_AtapiDmaRawRead = TRUE; + deviceExtension->opt_AtapiDmaReadWrite = TRUE; + } + + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + chan->MaxTransferMode = deviceExtension->MaxTransferMode; + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DEVNUM_NOT_SPECIFIED, L"MaxTransferMode", chan->MaxTransferMode); + if(tmp32 != 0xffffffff) { + KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", chan->MaxTransferMode)); + chan->MaxTransferMode = tmp32; + } + //UniAtaReadLunConfig(deviceExtension, c, 0); + //UniAtaReadLunConfig(deviceExtension, c, 1); + } + + deviceExtension->opt_AtapiDmaZeroTransfer = + AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaZeroTransfer", deviceExtension->opt_AtapiDmaZeroTransfer) ? + TRUE : FALSE; + + deviceExtension->opt_AtapiDmaControlCmd = + AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaControlCmd", deviceExtension->opt_AtapiDmaControlCmd) ? + TRUE : FALSE; + + deviceExtension->opt_AtapiDmaRawRead = + AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead", deviceExtension->opt_AtapiDmaRawRead) ? + TRUE : FALSE; + + deviceExtension->opt_AtapiDmaReadWrite = + AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaReadWrite", deviceExtension->opt_AtapiDmaReadWrite) ? + TRUE : FALSE; + + } else { + chan = &deviceExtension->chan[c]; + chan->MaxTransferMode = deviceExtension->MaxTransferMode; + tmp32 = AtapiRegCheckDevValue(deviceExtension, c, DEVNUM_NOT_SPECIFIED, L"MaxTransferMode", chan->MaxTransferMode); + if(tmp32 != 0xffffffff) { + KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", chan->MaxTransferMode)); + chan->MaxTransferMode = tmp32; + } + tmp32 = AtapiRegCheckDevValue(deviceExtension, c, DEVNUM_NOT_SPECIFIED, L"ReorderEnable", TRUE); + chan->UseReorder = tmp32 ? TRUE : FALSE; + + UniAtaReadLunConfig(deviceExtension, channel, 0); + UniAtaReadLunConfig(deviceExtension, channel, 1); + } + + return TRUE; +} // end AtapiReadChipConfig() + +BOOLEAN +AtapiChipInit( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG channel // physical channel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG slotNumber = deviceExtension->slotNumber; + ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; + ULONG VendorID = deviceExtension->DevID & 0xffff; + ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff; + ULONG RevID = deviceExtension->RevID; +// ULONG i; +// BUSMASTER_CONTROLLER_INFORMATION* DevTypeInfo; + ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; + ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + PHW_CHANNEL chan; + UCHAR tmp8; + USHORT tmp16; + ULONG tmp32; + ULONG c; // logical channel (for Compatible Mode controllers) + //ULONG BaseIoAddress; + + if(channel != CHAN_NOT_SPECIFIED) { + c = channel - deviceExtension->Channel; // logical channel (for Compatible Mode controllers) + } else { + c = CHAN_NOT_SPECIFIED; + } + + KdPrint2((PRINT_PREFIX "AtapiChipInit: dev %#x, ph chan %d\n", DeviceNumber, channel )); + + KdPrint2((PRINT_PREFIX "HwFlags: %#x\n", deviceExtension->HwFlags)); + KdPrint2((PRINT_PREFIX "VendorID/DeviceID/Rev %#x/%#x/%#x\n", VendorID, DeviceID, RevID)); + + if(deviceExtension->UnknownDev) { + KdPrint2((PRINT_PREFIX " Unknown chip, exiting\n" )); + //return TRUE; + VendorID = 0xffffffff; + } + + switch(VendorID) { +// case ATA_ACARD_ID: +// break; + case ATA_ACER_LABS_ID: + if(ChipFlags & UNIATA_SATA) { + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + /* the southbridge might need the data corruption fix */ + if(RevID == 0xc2 || RevID == 0xc3) { + AtapiAliSouthBridgeFixup(HwDeviceExtension, PCIConfiguration, + SystemIoBusNumber, slotNumber, c); + } + } + /* enable PCI interrupt */ + ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400)); + } + } else + if(ChipFlags & ALINEW) { + if(c == CHAN_NOT_SPECIFIED) { + /* use device interrupt as byte count end */ + ChangePciConfig1(0x4a, (a | 0x20)); + /* enable cable detection and UDMA support on newer chips */ + ChangePciConfig1(0x4b, (a | 0x09)); + + /* enable ATAPI UDMA mode */ + ChangePciConfig1(0x53, (a | 0x01)); + } + } else { + if(c == CHAN_NOT_SPECIFIED) { + /* deactivate the ATAPI FIFO and enable ATAPI UDMA */ + ChangePciConfig1(0x53, (a | 0x03)); + // ATAPI DMA R/O + for(c=0; cNumberChannels; c++) { + deviceExtension->chan[c].ChannelCtrlFlags |= CTRFLAGS_DMA_RO; + } + } else { + // ATAPI DMA R/O + deviceExtension->chan[c].ChannelCtrlFlags |= CTRFLAGS_DMA_RO; + } + } + break; + case ATA_AMD_ID: + if(c == CHAN_NOT_SPECIFIED) { + /* set prefetch, postwrite */ + if(ChipFlags & AMDBUG) { + ChangePciConfig1(0x41, (a & 0x0f)); + } else { + ChangePciConfig1(0x41, (a | 0xf0)); + } + } + if(deviceExtension->MaxTransferMode < ATA_UDMA2) + break; + // check 80-pin cable + if(ChipFlags & AMDCABLE) { + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + GetPciConfig1(0x42, tmp8); + if(!(tmp8 & (1 << channel))) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + GetPciConfig1(0x42, tmp8); + if(!(tmp8 & (1 << channel))) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } + break; + case ATA_HIGHPOINT_ID: + + if(c == CHAN_NOT_SPECIFIED) { + + if(ChipFlags & HPTOLD) { + /* turn off interrupt prediction */ + ChangePciConfig1(0x51, (a & ~0x80)); + } else { + /* turn off interrupt prediction */ + ChangePciConfig1(0x51, (a & ~0x03)); + ChangePciConfig1(0x55, (a & ~0x03)); + /* turn on interrupts */ + ChangePciConfig1(0x5a, (a & ~0x10)); + /* set clocks etc */ + if(ChipType < HPT372) { + SetPciConfig1(0x5b, 0x22); + } else { + ChangePciConfig1(0x5b, ((a & 0x01) | 0x20)); + } + } + + // check 80-pin cable + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + if(!hpt_cable80(deviceExtension, channel)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + // check 80-pin cable + chan = &deviceExtension->chan[c]; + if(!hpt_cable80(deviceExtension, channel)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + break; + case ATA_INTEL_ID: { + USHORT reg54; + if(ChipFlags & UNIATA_SATA) { + if(c != CHAN_NOT_SPECIFIED) + break; +#if 0 + /* force all ports active "the legacy way" */ + ChangePciConfig2(0x92, (a | 0x0f)); + /* enable PCI interrupt */ + ChangePciConfig2(/*PCIR_COMMAND*/0x04, (a & ~0x0400)); + + if(!(ChipFlags & UNIATA_AHCI)) { + /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */ + GetPciConfig1(0x90, tmp8); + if(!(tmp8 & 0x04)) { + /* XXX SOS should be in intel_allocate if we grow it */ + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + deviceExtension->chan[c].ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + } else { + deviceExtension->chan[c].ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + } + } +#else + /* enable PCI interrupt */ + ChangePciConfig2(/*PCIR_COMMAND*/0x04, (a & ~0x0400)); +#endif + break; + } + if(deviceExtension->MaxTransferMode < ATA_UDMA2) + break; + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + GetPciConfig2(0x54, reg54); + if( ((reg54 >> (channel*2)) & 30) != 30) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + GetPciConfig2(0x54, reg54); + if( ((reg54 >> (channel*2)) & 30) != 30) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + break; } + case ATA_NVIDIA_ID: { + if(ChipFlags & UNIATA_SATA) { + if(c == CHAN_NOT_SPECIFIED) { + ULONG offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010; + /* enable control access */ + ChangePciConfig1(0x50, (a | 0x04)); + KdPrint2((PRINT_PREFIX "BaseIoAddressSATA_0=%x\n", deviceExtension->BaseIoAddressSATA_0.Addr)); + if(ChipFlags & NVQ) { + /* clear interrupt status */ + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs, 0x00ff00ff); + /* enable device and PHY state change interrupts */ + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs+4, 0x000d000d); + /* disable NCQ support */ + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),0x0400, + AtapiReadPortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),0x0400) & 0xfffffff9); + } else { + /* clear interrupt status */ + AtapiWritePortEx1(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs, 0xff); + /* enable device and PHY state change interrupts */ + AtapiWritePortEx1(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),offs+1, 0xdd); + } + /* enable PCI interrupt */ + ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400)); + } else { + //UniataSataPhyEnable(HwDeviceExtension, c); + } + } else { + UCHAR reg52; + + // check 80-pin cable + if(c == CHAN_NOT_SPECIFIED) { + + /* set prefetch, postwrite */ + ChangePciConfig1(0x51, (a & 0x0f)); + + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + GetPciConfig1(0x52, reg52); + if( !((reg52 >> (channel*2)) & 0x01)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + GetPciConfig1(0x52, reg52); + if( !((reg52 >> (channel*2)) & 0x01)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } + break; } + case ATA_PROMISE_ID: { + USHORT Reg50; + switch(ChipType) { + case PRNEW: + /* setup clocks */ + if(c == CHAN_NOT_SPECIFIED) { +// ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | 0x0a); + AtapiWritePortEx1(NULL, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x11, + AtapiReadPortEx1(NULL, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x11) | 0x0a ); + } + /* FALLTHROUGH */ + case PROLD: + /* enable burst mode */ +// ATA_OUTB(ctlr->r_res1, 0x1f, ATA_INB(ctlr->r_res1, 0x1f) | 0x01); + if(c == CHAN_NOT_SPECIFIED) { + AtapiWritePortEx1(NULL, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x1f, + AtapiReadPortEx1(NULL, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x1f) | 0x01 ); + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + GetPciConfig2(0x50, Reg50); + if(Reg50 & (1 << (channel+10))) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + GetPciConfig2(0x50, Reg50); + if(Reg50 & (1 << (channel+10))) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + break; + case PRTX: + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + AtapiWritePort1(chan, IDX_BM_DeviceSpecific0, 0x0b); + if(AtapiReadPort1(chan, IDX_BM_DeviceSpecific1) & 0x04) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + AtapiWritePort1(chan, IDX_BM_DeviceSpecific0, 0x0b); + if(AtapiReadPort1(chan, IDX_BM_DeviceSpecific1) & 0x04) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + break; + case PRMIO: + if(c == CHAN_NOT_SPECIFIED) { + if(ChipFlags & PRSATA) { + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressBM_0),0x6c, 0x000000ff); + } + for(c=0; c<4; c++) { + chan = &deviceExtension->chan[c]; + AtapiWritePort4(chan, IDX_BM_Command, + (AtapiReadPort4(chan, IDX_BM_Command) & ~0x00000f8f) | channel ); + AtapiWritePort4(chan, IDX_BM_DeviceSpecific0, 0x00000001); + if(chan->MaxTransferMode < ATA_SA150 && + (AtapiReadPort4(chan, IDX_BM_Command) & 0x01000000)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + AtapiWritePort4(chan, IDX_BM_Command, + (AtapiReadPort4(chan, IDX_BM_Command) & ~0x00000f8f) | channel ); + AtapiWritePort4(chan, IDX_BM_DeviceSpecific0, 0x00000001); + if(chan->MaxTransferMode < ATA_SA150 && + (AtapiReadPort4(chan, IDX_BM_Command) & 0x01000000)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + break; + } + break; } + case ATA_SERVERWORKS_ID: + if(c == CHAN_NOT_SPECIFIED) { + if(ChipType == SWKS33) { + AtapiRosbSouthBridgeFixup(HwDeviceExtension, PCIConfiguration, + SystemIoBusNumber, slotNumber); + } else { + ChangePciConfig1(0x5a, ((a & ~0x40) | ((ChipType == SWKS100) ? 0x03 : 0x02))); + } + } + break; + case ATA_ATI_ID: + if(ChipType == SIIMIO) { + KdPrint2((PRINT_PREFIX "ATI New\n")); + // fall to SiI + } else { + KdPrint2((PRINT_PREFIX "ATI\n")); + break; + } + case ATA_SILICON_IMAGE_ID: + /* if(ChipFlags & SIIENINTR) { + SetPciConfig1(0x71, 0x01); + }*/ + switch(ChipType) { + case SIIMIO: { + + KdPrint2((PRINT_PREFIX "SII\n")); + UCHAR Reg79; + + if(c == CHAN_NOT_SPECIFIED) { + if(ChipFlags & SIISETCLK) { + KdPrint2((PRINT_PREFIX "SIISETCLK\n")); + GetPciConfig1(0x8a, tmp8); + if ((tmp8 & 0x30) != 0x10) + ChangePciConfig1(0x8a, (a & 0xcf | 0x10)); + GetPciConfig1(0x8a, tmp8); + if ((tmp8 & 0x30) != 0x10) { + KdPrint2((PRINT_PREFIX "Sil 0680 could not set ATA133 clock\n")); + deviceExtension->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA5); + } + } + } + if(deviceExtension->MaxTransferMode < ATA_SA150) { + KdPrint2((PRINT_PREFIX "Check UDMA66 cable\n")); + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + GetPciConfig2(0x79, Reg79); + if(Reg79 & (channel ? 0x02 : 0x01)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + GetPciConfig2(0x79, Reg79); + if(Reg79 & (channel ? 0x02 : 0x01)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + ULONG unit01 = (c & 1); + ULONG unit10 = (c & 2); + /* enable/disable PHY state change interrupt */ + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + unit01 = (c & 1); + unit10 = (c & 2); + if(ChipFlags & SIINOSATAIRQ) { + KdPrint2((PRINT_PREFIX "Disable broken SATA intr on c=%x\n", c)); + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),0); + } + } + } else { + if(ChipFlags & SIINOSATAIRQ) { + KdPrint2((PRINT_PREFIX "Disable broken SATA intr on c=%x\n", c)); + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),0); + } else { + KdPrint2((PRINT_PREFIX "Enable SATA intr on c=%x\n", c)); + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16)); + } + } + } + if(c == CHAN_NOT_SPECIFIED) { + /* enable interrupt as BIOS might not */ + ChangePciConfig1(0x8a, (a & 0x3f)); + // Enable 3rd and 4th channels + if (ChipFlags & SII4CH) { + KdPrint2((PRINT_PREFIX "SII4CH\n")); + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),0x0200, 0x00000002); + } + } else { + chan = &deviceExtension->chan[c]; + /* dont block interrupts */ + //ChangePciConfig4(0x48, (a & ~0x03c00000)); + tmp32 = AtapiReadPortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),0x48); + AtapiWritePortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),0x48, (1 << 22) << c); + // flush + tmp32 = AtapiReadPortEx4(NULL, (ULONG)(&deviceExtension->BaseIoAddressSATA_0),0x48); + + /* Initialize FIFO PCI bus arbitration */ + GetPciConfig1(offsetof(PCI_COMMON_CONFIG, CacheLineSize), tmp8); + if(tmp8) { + KdPrint2((PRINT_PREFIX "SII: CacheLine=%d\n", tmp32)); + tmp8 = (tmp8/8)+1; + AtapiWritePort2(chan, IDX_BM_DeviceSpecific1, ((USHORT)tmp8) << 8 | tmp8); + } else { + KdPrint2((PRINT_PREFIX "SII: CacheLine=0 !!!\n")); + } + } + break; } + + case SIICMD: { + + KdPrint2((PRINT_PREFIX "SII_CMD\n")); + if(c == CHAN_NOT_SPECIFIED) { + /* Setup interrupts. */ + SetPciConfig1(0x71, 0x01); + + /* GetPciConfig1(0x8a, tmp8); + tmp8 &= ~(0x30); + SetPciConfig1(0x71, tmp8);*/ + + /* Use MEMORY READ LINE for reads. + * NOTE: Although not mentioned in the PCI0646U specs, + * these bits are write only and won't be read + * back as set or not. The PCI0646U2 specs clarify + * this point. + */ + /* tmp8 |= 0x02; + SetPciConfig1(0x71, tmp8); + */ + /* Set reasonable active/recovery/address-setup values. */ + SetPciConfig1(0x53, 0x40); + SetPciConfig1(0x54, 0x3f); + SetPciConfig1(0x55, 0x40); + SetPciConfig1(0x56, 0x3f); + SetPciConfig1(0x57, 0x1c); + SetPciConfig1(0x58, 0x3f); + SetPciConfig1(0x5b, 0x3f); + } + + break; } + } + break; + case ATA_SIS_ID: + if(c == CHAN_NOT_SPECIFIED) { + switch(ChipType) { + case SIS33: + break; + case SIS66: + case SIS100OLD: + ChangePciConfig1(0x52, (a & ~0x04)); + break; + case SIS100NEW: + case SIS133OLD: + ChangePciConfig1(0x49, (a & ~0x01)); + break; + case SIS133NEW: + ChangePciConfig2(0x50, (a | 0x0008)); + ChangePciConfig2(0x52, (a | 0x0008)); + break; + case SISSATA: + ChangePciConfig2(0x04, (a & ~0x0400)); + } + } + if(ChipType == SIS133NEW) { + USHORT tmp16; + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + GetPciConfig2(channel ? 0x52 : 0x50, tmp16); + if(tmp16 & 0x8000) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + GetPciConfig2(channel ? 0x52 : 0x50, tmp16); + if(tmp16 & 0x8000) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + GetPciConfig1(48, tmp8); + if(tmp8 & (0x10 << channel)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + GetPciConfig1(48, tmp8); + if(tmp8 & (0x10 << channel)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } + break; + case ATA_VIA_ID: + + if(c == CHAN_NOT_SPECIFIED) { + /* prepare for ATA-66 on the 82C686a and 82C596b */ + if(ChipFlags & VIACLK) { + ChangePciConfig4(0x50, (a | 0x030b030b)); + } + // no init for SATA + if(ChipFlags & UNIATA_SATA) { + /* enable PCI interrupt */ + ChangePciConfig2(/*PCIR_COMMAND*/0x04, (a & ~0x0400)); + break; + } + } + // check 80-pin cable + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + if(!via_cable80(deviceExtension, channel)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + if(!via_cable80(deviceExtension, channel)) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + + if(c == CHAN_NOT_SPECIFIED) { + /* the southbridge might need the data corruption fix */ + if(ChipFlags & VIABUG) { + AtapiViaSouthBridgeFixup(HwDeviceExtension, PCIConfiguration, + SystemIoBusNumber, slotNumber); + } + /* set prefetch, postwrite */ + if(ChipType != VIA133) { + ChangePciConfig1(0x41, (a | 0xf0)); + } + + /* set fifo configuration half'n'half */ + ChangePciConfig1(0x43, ((a & ((ChipFlags & VIAPRQ) ? 0x80 : 0x90)) | 0x2a)); + + /* set status register read retry */ + ChangePciConfig1(0x44, (a | 0x08)); + + /* set DMA read & end-of-sector fifo flush */ + ChangePciConfig1(0x46, ((a & 0x0c) | 0xf0)); + + /* set sector size */ + SetPciConfig2(0x60, DEV_BSIZE); + SetPciConfig2(0x68, DEV_BSIZE); + } + + break; + + case ATA_ITE_ID: + // Old chip + if(ChipType == ITE_33) + break; + if(c == CHAN_NOT_SPECIFIED) { + /* set PCI mode and 66Mhz reference clock */ + ChangePciConfig1(0x50, a & ~0x83); + + /* set default active & recover timings */ + SetPciConfig1(0x54, 0x31); + SetPciConfig1(0x56, 0x31); + } + + GetPciConfig2(0x40, tmp16); + // check 80-pin cable + if(c == CHAN_NOT_SPECIFIED) { + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + if(!(tmp16 & (channel ? 0x08 : 0x04))) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + } else { + chan = &deviceExtension->chan[c]; + if(!(tmp16 & (channel ? 0x08 : 0x04))) { + chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2); + } + } + + break; + } + + return TRUE; +} // end AtapiChipInit() + +VOID +UniataInitMapBM( + IN PHW_DEVICE_EXTENSION deviceExtension, + IN PIDE_BUSMASTER_REGISTERS BaseIoAddressBM_0, + IN BOOLEAN MemIo + ) +{ + PHW_CHANNEL chan; + ULONG c; + ULONG i; + + if(!BaseIoAddressBM_0) { + MemIo = FALSE; + } + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + for (i=0; iRegTranslation[IDX_BM_IO+i].Addr = BaseIoAddressBM_0 ? ((ULONG)BaseIoAddressBM_0 + i) : 0; + chan->RegTranslation[IDX_BM_IO+i].MemIo = MemIo; + } + if(BaseIoAddressBM_0) { + BaseIoAddressBM_0++; + } + } +} // end UniataInitMapBM() + +VOID +UniataInitMapBase( + IN PHW_CHANNEL chan, + IN PIDE_REGISTERS_1 BaseIoAddress1, + IN PIDE_REGISTERS_2 BaseIoAddress2 + ) +{ + ULONG i; + + for (i=0; iRegTranslation[IDX_IO1+i].Addr = BaseIoAddress1 ? ((ULONG)BaseIoAddress1 + i) : 0; + chan->RegTranslation[IDX_IO1+i].MemIo = FALSE; + } + for (i=0; iRegTranslation[IDX_IO2+i].Addr = BaseIoAddress2 ? ((ULONG)BaseIoAddress2 + i) : 0; + chan->RegTranslation[IDX_IO2+i].MemIo = FALSE; + } + UniataInitSyncBaseIO(chan); +} // end UniataInitMapBase() + +VOID +UniataInitSyncBaseIO( + IN PHW_CHANNEL chan + ) +{ + RtlCopyMemory(&chan->RegTranslation[IDX_IO1_o], &chan->RegTranslation[IDX_IO1], IDX_IO1_SZ*sizeof(chan->RegTranslation[0])); + RtlCopyMemory(&chan->RegTranslation[IDX_IO2_o], &chan->RegTranslation[IDX_IO2], IDX_IO2_SZ*sizeof(chan->RegTranslation[0])); +} // end UniataInitSyncBaseIO() diff --git a/reactos/drivers/storage/ide/uniata/id_probe.cpp b/reactos/drivers/storage/ide/uniata/id_probe.cpp new file mode 100644 index 00000000000..a49ba497b79 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_probe.cpp @@ -0,0 +1,2500 @@ +/*++ + +Copyright (c) 2002-2007 Alexandr A. Telyatnikov (Alter) + +Module Name: + id_probe.cpp + +Abstract: + This module scans PCI and ISA buses for IDE controllers + and determines their Busmaster DMA capabilities + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + + Some parts of hardware-specific code were taken from FreeBSD 4.3-6.1 ATA driver by + Søren Schmidt, Copyright (c) 1998-2007 + + Some parts of device detection code were taken from from standard ATAPI.SYS from NT4 DDK by + Mike Glass (MGlass) + Chuck Park (ChuckP) + + Device search/init algorithm is completly rewritten by + Alter, Copyright (c) 2002-2004 + + Fixes for Native/Compatible modes of onboard IDE controller by + Vitaliy Vorobyov, deathsoft@yandex.ru (c) 2004 + +--*/ + +#include "stdafx.h" + +PBUSMASTER_CONTROLLER_INFORMATION BMList = NULL; +ULONG BMListLen = 0; + +BOOLEAN FirstMasterOk = FALSE; + +#ifndef UNIATA_CORE + +UCHAR pciBuffer[256]; +ULONG maxPciBus = 16; + +PDRIVER_OBJECT SavedDriverObject = NULL; + +// local routines + +ULONG +UniataEnumBusMasterController__( +/* IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again*/ + ); + +VOID +AtapiDoNothing(VOID) +{ + ULONG i = 0; + return; +} // end AtapiDoNothing() + +#endif //UNIATA_CORE + +/* + Get PCI address by ConfigInfo and RID +*/ +ULONG +AtapiGetIoRange( + IN PVOID HwDeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN PPCI_COMMON_CONFIG pciData, + IN ULONG SystemIoBusNumber, + IN ULONG rid, //range id + IN ULONG offset, + IN ULONG length + ) +{ + ULONG io_start = 0; + KdPrint2((PRINT_PREFIX " AtapiGetIoRange:\n")); + + if(ConfigInfo->NumberOfAccessRanges <= rid) + return 0; + + KdPrint2((PRINT_PREFIX " AtapiGetIoRange: rid %#x, start %#x, offs %#x, len %#x, mem %#x\n", + rid, + ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[rid].RangeStart), + offset, + length, + (*ConfigInfo->AccessRanges)[rid].RangeInMemory + )); + + if((*ConfigInfo->AccessRanges)[rid].RangeInMemory) { + io_start = + // Get the system physical address for this IO range. + ((ULONG)ScsiPortGetDeviceBase(HwDeviceExtension, + PCIBus /*ConfigInfo->AdapterInterfaceType*/, + SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/, + ScsiPortConvertUlongToPhysicalAddress( + (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[rid].RangeStart) & + ~0x07/*PCI_ADDRESS_IOMASK*/) + offset + ), + length, + (BOOLEAN)!(*ConfigInfo->AccessRanges)[rid].RangeInMemory) + ); + + KdPrint2((PRINT_PREFIX " AtapiGetIoRange: %#x\n", io_start)); + // if(io_start > offset) { + return io_start; + // } + } + + io_start = (pciData->u.type0.BaseAddresses[rid] & ~0x07/*PCI_ADDRESS_IOMASK*/) + offset; + // if(pciData->u.type0.BaseAddresses[rid] != 0) ;) + if(io_start > offset) { + if(/*(WinVer_Id() <= WinVer_NT) &&*/ offset && rid == 4) { + // MS atapi.sys does so for BusMaster controllers + (*ConfigInfo->AccessRanges)[rid+1].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(io_start); + (*ConfigInfo->AccessRanges)[rid+1].RangeLength = length; + } else { + (*ConfigInfo->AccessRanges)[rid].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(io_start); + (*ConfigInfo->AccessRanges)[rid].RangeLength = length; + } + } else { + io_start = 0; + } + KdPrint2((PRINT_PREFIX " AtapiGetIoRange: (2) %#x\n", io_start)); + return io_start; + +} // end AtapiGetIoRange() + +#ifndef UNIATA_CORE + +/* + Do nothing, but build list of supported IDE controllers + It is a hack, ScsiPort architecture assumes, that DriverEntry + can support only KNOWN Vendor/Device combinations. + Thus, we build list here. Later will pretend that always knew + about found devices. + + We shall initiate ISA device init, but callback will use + Hal routines directly in order to scan PCI bus. +*/ +VOID +UniataEnumBusMasterController( + IN PVOID DriverObject, + PVOID Argument2 + ) +{ + UniataEnumBusMasterController__(); + +} // end UniataEnumBusMasterController() + + +/* + Device initializaton callback + Builds PCI device list using Hal routines (not ScsiPort wrappers) +*/ +ULONG +UniataEnumBusMasterController__( + ) +{ +// PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PVOID HwDeviceExtension; + PHW_DEVICE_EXTENSION deviceExtension = NULL; + PCI_SLOT_NUMBER slotData; + PCI_COMMON_CONFIG pciData; + ULONG busNumber; + ULONG slotNumber; + ULONG funcNumber; + BOOLEAN no_buses = FALSE; + BOOLEAN no_ranges = FALSE; + ULONG busDataRead; +// BOOLEAN SimplexOnly; + + UCHAR vendorString[5]; + UCHAR deviceString[5]; + PUCHAR vendorStrPtr; + PUCHAR deviceStrPtr; + + UCHAR BaseClass; // (ro) + UCHAR SubClass; // (ro) + ULONG VendorID; + ULONG DeviceID; + ULONG dev_id; + + ULONG i; + ULONG pass=0; + + ULONG RaidFlags; + + BOOLEAN found; + BOOLEAN known; + + UCHAR IrqForCompat = 10; + + vendorStrPtr = vendorString; + deviceStrPtr = deviceString; + slotData.u.AsULONG = 0; + + HwDeviceExtension = + deviceExtension = (PHW_DEVICE_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(HW_DEVICE_EXTENSION)); + if(!deviceExtension) { + return(SP_RETURN_NOT_FOUND); + } + RtlZeroMemory(deviceExtension, sizeof(HW_DEVICE_EXTENSION)); + + for(pass=0; pass<3; pass++) { + for(busNumber=0 ;busNumberslotNumber = slotData.u.AsULONG; + deviceExtension->SystemIoBusNumber = busNumber; + deviceExtension->DevID = dev_id; + deviceExtension->RevID = pciData.RevisionID; + } + + found = (BOOLEAN)AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"Include", 0); + if(!found) { + KdPrint2((PRINT_PREFIX "No force include, check exclude\n")); + found = !AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"Exclude", 0); + if(!found) { + KdPrint2((PRINT_PREFIX "Device excluded\n")); + continue; + } + } + + //known = UniataChipDetect(HwDeviceExtension, NULL, -1, ConfigInfo, &SimplexOnly); + i = Ata_is_dev_listed((PBUSMASTER_CONTROLLER_INFORMATION)&BusMasterAdapters[0], VendorID, DeviceID, 0, NUM_BUSMASTER_ADAPTERS); + + known = (i != -1); + if(known) { + RaidFlags = BusMasterAdapters[i].RaidFlags; + if((RaidFlags & UNIATA_RAID_CONTROLLER) && + SkipRaids) { + KdPrint2((PRINT_PREFIX "Skip RAID\n")); + continue; + } + found = TRUE; + } else { + RaidFlags = 0; + } + + switch(SubClass) { + case PCI_DEV_SUBCLASS_IDE: + case PCI_DEV_SUBCLASS_RAID: + case PCI_DEV_SUBCLASS_ATA: + case PCI_DEV_SUBCLASS_SATA: + break; + default: + KdPrint2((PRINT_PREFIX "Subclass not supported\n")); + continue; + } + + switch(dev_id) { + /* additional checks for some supported chipsets */ + case 0xc6931080: + if (SubClass != PCI_DEV_SUBCLASS_IDE) + found = FALSE; + break; + + /* unknown chipsets, try generic DMA if it seems possible */ + default: + KdPrint2((PRINT_PREFIX "Default device\n")); + if(Ata_is_supported_dev(&pciData)) + found = TRUE; + break; + } + + if(found) { + + KdPrint2((PRINT_PREFIX "found, pass %d\n", pass)); + + KdPrint2((PRINT_PREFIX "InterruptPin = %#x\n", pciData.u.type0.InterruptPin)); + KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine)); + + if(!pass && known) { + // Enable Busmastering, IO-space and Mem-space + KdPrint2((PRINT_PREFIX "Enabling Mem/Io spaces and busmastering...\n")); + KdPrint2((PRINT_PREFIX "Initial pciData.Command = %#x\n", pciData.Command)); + for(i=0; i<3; i++) { + switch(i) { + case 0: + KdPrint2((PRINT_PREFIX "PCI_ENABLE_IO_SPACE\n")); + pciData.Command |= PCI_ENABLE_IO_SPACE; + break; + case 1: + KdPrint2((PRINT_PREFIX "PCI_ENABLE_MEMORY_SPACE\n")); + pciData.Command |= PCI_ENABLE_MEMORY_SPACE; + break; + case 2: + KdPrint2((PRINT_PREFIX "PCI_ENABLE_BUS_MASTER\n")); + pciData.Command |= PCI_ENABLE_BUS_MASTER; + break; + } + HalSetBusDataByOffset( PCIConfiguration, busNumber, slotData.u.AsULONG, + &(pciData.Command), + offsetof(PCI_COMMON_CONFIG, Command), + sizeof(pciData.Command)); + KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine)); + + // reread config space + busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, + &pciData, PCI_COMMON_HDR_LENGTH); + KdPrint2((PRINT_PREFIX "New pciData.Command = %#x\n", pciData.Command)); + } + KdPrint2((PRINT_PREFIX "Final pciData.Command = %#x\n", pciData.Command)); + } + // validate Mem/Io ranges + no_ranges = TRUE; + for(i=0; i 31*/ || + (IrqForCompat == 0xff)) { + IrqForCompat = 0x0b; + KdPrint2((PRINT_PREFIX "default to IRQ 11\n")); + } + + //ChangePciConfig1(0x09, a | PCI_IDE_PROGIF_NATIVE_ALL); // ProgIf + pciData.ProgIf |= PCI_IDE_PROGIF_NATIVE_ALL; + HalSetBusDataByOffset( PCIConfiguration, busNumber, slotData.u.AsULONG, + &(pciData.ProgIf), + offsetof(PCI_COMMON_CONFIG, ProgIf), + sizeof(pciData.ProgIf)); + + // reread config space + busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, + &pciData, PCI_COMMON_HDR_LENGTH); + // check if the device have switched to Native Mode + if(IsMasterDev(&pciData)) { + KdPrint2((PRINT_PREFIX "Can't switch to native mode\n")); + } else { + KdPrint2((PRINT_PREFIX "switched to native mode\n")); + KdPrint2((PRINT_PREFIX "InterruptPin = %#x\n", pciData.u.type0.InterruptPin)); + KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine)); + // check if IRQ is assigned to device + if(!(pciData.u.type0.InterruptLine) || + (pciData.u.type0.InterruptLine == 0xff)) { + KdPrint2((PRINT_PREFIX "assign interrupt for device\n")); + pciData.u.type0.InterruptLine = IrqForCompat; + HalSetBusDataByOffset( PCIConfiguration, busNumber, slotData.u.AsULONG, + &(pciData.u.type0.InterruptLine), + offsetof(PCI_COMMON_CONFIG, u.type0.InterruptLine), + sizeof(pciData.u.type0.InterruptLine)); + } else { + KdPrint2((PRINT_PREFIX "Auto-assigned interrupt line %#x\n", + pciData.u.type0.InterruptLine)); + IrqForCompat = pciData.u.type0.InterruptLine; + } + KdPrint2((PRINT_PREFIX "reread config space\n")); + // reread config space + busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, + &pciData, PCI_COMMON_HDR_LENGTH); + KdPrint2((PRINT_PREFIX "busDataRead = %#x\n", busDataRead)); + KdPrint2((PRINT_PREFIX "reread InterruptLine = %#x\n", pciData.u.type0.InterruptLine)); + // check if we have successfully assigned IRQ to device + if((pciData.u.type0.InterruptLine != IrqForCompat) || + (pciData.u.type0.InterruptLine == 0xff) || + !pciData.u.type0.InterruptLine) { + KdPrint2((PRINT_PREFIX "can't assign interrupt for device, revert to compat mode\n")); + pciData.u.type0.InterruptLine = 0xff; + KdPrint2((PRINT_PREFIX "set IntrLine to 0xff\n")); + HalSetBusDataByOffset( PCIConfiguration, busNumber, slotData.u.AsULONG, + &(pciData.u.type0.InterruptLine), + offsetof(PCI_COMMON_CONFIG, u.type0.InterruptLine), + sizeof(pciData.u.type0.InterruptLine)); + KdPrint2((PRINT_PREFIX "clear PCI_IDE_PROGIF_NATIVE_ALL\n")); + pciData.ProgIf &= ~PCI_IDE_PROGIF_NATIVE_ALL; + HalSetBusDataByOffset( PCIConfiguration, busNumber, slotData.u.AsULONG, + &(pciData.ProgIf), + offsetof(PCI_COMMON_CONFIG, ProgIf), + sizeof(pciData.ProgIf)); + // reread config space + KdPrint2((PRINT_PREFIX "reread config space on revert\n")); + busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG, + &pciData, PCI_COMMON_HDR_LENGTH); + } else { + KdPrint2((PRINT_PREFIX "Assigned interrupt %#x for device\n", IrqForCompat)); + KdPrint2((PRINT_PREFIX "continue detection on next round\n")); + continue; + } + } + } + } else + if(pass == 2) { + if(IsMasterDev(&pciData)) + continue; + } + +/* if(known) { + RtlCopyMemory(newBMListPtr, (PVOID)&(BusMasterAdapters[i]), sizeof(BUSMASTER_CONTROLLER_INFORMATION)); + } else {*/ + sprintf((PCHAR)vendorStrPtr, "%4.4x", VendorID); + sprintf((PCHAR)deviceStrPtr, "%4.4x", DeviceID); + + RtlCopyMemory(&(newBMListPtr->VendorIdStr), (PCHAR)vendorStrPtr, 4); + RtlCopyMemory(&(newBMListPtr->DeviceIdStr), (PCHAR)deviceStrPtr, 4); + + newBMListPtr->nVendorId = VendorID; + newBMListPtr->VendorId = (PCHAR)&(newBMListPtr->VendorIdStr); + newBMListPtr->VendorIdLength = 4; + newBMListPtr->nDeviceId = DeviceID; + newBMListPtr->DeviceId = (PCHAR)&(newBMListPtr->DeviceIdStr); + newBMListPtr->DeviceIdLength = 4; + + newBMListPtr->RaidFlags = RaidFlags; +// } + newBMListPtr->slotNumber = slotData.u.AsULONG; + newBMListPtr->MasterDev = IsMasterDev(&pciData) ? 1 : 0; + newBMListPtr->busNumber = busNumber; + + KdPrint2((PRINT_PREFIX "Add to BMList\n")); + } else { + KdPrint2((PRINT_PREFIX "count: BMListLen++\n")); + } + + BMListLen++; + } + } + } + } + if(!pass) { + if(!BMListLen) + break; + BMList = (PBUSMASTER_CONTROLLER_INFORMATION)ExAllocatePool(NonPagedPool, + (BMListLen+1)*sizeof(BUSMASTER_CONTROLLER_INFORMATION)); + if(!BMList) { + BMListLen=0; + break; + } + RtlZeroMemory(BMList, (BMListLen+1)*sizeof(BUSMASTER_CONTROLLER_INFORMATION)); + no_buses = FALSE; + BMListLen=0; + } + } + if(deviceExtension) { + ExFreePool(deviceExtension); + } + return(SP_RETURN_NOT_FOUND); +} // end UniataEnumBusMasterController__() + + +/* + Wrapper for read PCI config space +*/ +ULONG +ScsiPortGetBusDataByOffset( + IN PVOID HwDeviceExtension, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + UCHAR tmp[256]; + ULONG busDataRead; + + if(Offset+Length > 256) + return 0; + + busDataRead = HalGetBusData( + //ScsiPortGetBusData(HwDeviceExtension, + BusDataType, + BusNumber, + SlotNumber, + &tmp, + Offset+Length); + if(busDataRead < Offset+Length) { + if(busDataRead < Offset) + return 0; + return (Offset+Length-busDataRead); + } + RtlCopyMemory(Buffer, tmp+Offset, Length); + return Length; +} // end ScsiPortGetBusDataByOffset() + +/* + Looks for devices from list on specified bus(es)/slot(s) + returnts its index in list. + If no matching record found, -1 is returned +*/ +ULONG +AtapiFindListedDev( + PBUSMASTER_CONTROLLER_INFORMATION BusMasterAdapters, + ULONG lim, + IN PVOID HwDeviceExtension, + IN ULONG BusNumber, + IN ULONG SlotNumber, + OUT PCI_SLOT_NUMBER* _slotData // optional + ) +{ + PCI_SLOT_NUMBER slotData; + PCI_COMMON_CONFIG pciData; + ULONG busDataRead; + + ULONG busNumber; + ULONG slotNumber; + ULONG funcNumber; + + ULONG busNumber2; + ULONG slotNumber2; + + ULONG i; + + // set start/end bus + if(BusNumber == -1) { + busNumber = 0; + busNumber2 = maxPciBus; + } else { + busNumber = BusNumber; + busNumber2 = BusNumber+1; + } + // set start/end slot + if(SlotNumber == -1) { + slotNumber = 0; + slotNumber2 = PCI_MAX_DEVICES; + } else { + slotNumber = SlotNumber; + slotNumber2 = SlotNumber+1; + } + slotData.u.AsULONG = 0; + + for( ; busNumber < busNumber2 ; busNumber++ ) { + for( ; slotNumber < slotNumber2 ; slotNumber++) { + for(funcNumber=0; funcNumber < PCI_MAX_FUNCTION ; funcNumber++) { + + slotData.u.bits.DeviceNumber = slotNumber; + slotData.u.bits.FunctionNumber = funcNumber; + + busDataRead = HalGetBusData( + //ScsiPortGetBusData(HwDeviceExtension, + PCIConfiguration, busNumber, slotData.u.AsULONG, + &pciData, PCI_COMMON_HDR_LENGTH); + // no more buses (this should not happen) + if(!busDataRead) { + continue; + } + // no device in this slot + if(busDataRead == 2) + continue; + + if(busDataRead < PCI_COMMON_HDR_LENGTH) + continue; + + i = Ata_is_dev_listed(BusMasterAdapters, pciData.VendorID, pciData.DeviceID, pciData.RevisionID, lim); + if(i != -1) { + if(_slotData) + *_slotData = slotData; + return i; + } + + }}} + return -1; +} // end AtapiFindListedDev() + +/* + Looks for device with specified Device/Vendor and Revision + on specified Bus/Slot +*/ +ULONG +AtapiFindDev( + IN PVOID HwDeviceExtension, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN ULONG dev_id, + IN ULONG RevID + ) +{ + PCI_COMMON_CONFIG pciData; + ULONG funcNumber; + ULONG busDataRead; + + ULONG VendorID; + ULONG DeviceID; + PCI_SLOT_NUMBER slotData; + + slotData.u.AsULONG = SlotNumber; + // walk through all Function Numbers + for(funcNumber = 0; funcNumber < PCI_MAX_FUNCTION; funcNumber++) { + + slotData.u.bits.FunctionNumber = funcNumber; + if(slotData.u.AsULONG == SlotNumber) + continue; + + busDataRead = HalGetBusData( + //busDataRead = ScsiPortGetBusData(HwDeviceExtension, + PCIConfiguration, + BusNumber, + slotData.u.AsULONG, + &pciData, + PCI_COMMON_HDR_LENGTH); + + if (busDataRead < PCI_COMMON_HDR_LENGTH) { + continue; + } + + VendorID = pciData.VendorID; + DeviceID = pciData.DeviceID; + + if(dev_id != (VendorID | (DeviceID << 16)) ) + continue; + if(RevID >= pciData.RevisionID) + return 1; + } + return 0; +} // end AtapiFindDev() + +#endif //UNIATA_CORE + +/*++ + +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 - Address of adapter count + BusInformation - + ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. + ConfigInfo - Configuration information structure describing HBA + Again - Indicates search for adapters to continue + +Return Value: + + ULONG + +--*/ +ULONG +UniataFindBusMasterController( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = NULL; +#ifndef UNIATA_CORE + // this buffer must be global for UNIATA_CORE build + PCI_COMMON_CONFIG pciData; +#endif UNIATA_CORE + ULONG slotNumber; + ULONG busDataRead; + ULONG SystemIoBusNumber; + + UCHAR vendorString[5]; + UCHAR deviceString[5]; + PUCHAR vendorStrPtr; + PUCHAR deviceStrPtr; + + UCHAR BaseClass; + UCHAR SubClass; + ULONG VendorID; + ULONG DeviceID; + ULONG RevID; + ULONG dev_id; + PCI_SLOT_NUMBER slotData; + + ULONG i; + ULONG channel; + ULONG c = 0; + PUCHAR ioSpace; + UCHAR statusByte; + ULONG bm_offset; + +// UCHAR tmp8; +// ULONG irq; + + BOOLEAN found = FALSE; + BOOLEAN MasterDev; + BOOLEAN simplexOnly = FALSE; + BOOLEAN skip_find_dev = FALSE; + BOOLEAN AltInit = FALSE; + + SCSI_PHYSICAL_ADDRESS IoBasePort1; + SCSI_PHYSICAL_ADDRESS IoBasePort2; + + PIDE_BUSMASTER_REGISTERS BaseIoAddressBM_0 = NULL; + PIDE_REGISTERS_1 BaseIoAddress1[IDE_MAX_CHAN]; + PIDE_REGISTERS_2 BaseIoAddress2[IDE_MAX_CHAN]; + + RtlZeroMemory(&BaseIoAddress1, sizeof(BaseIoAddress1)); + RtlZeroMemory(&BaseIoAddress2, sizeof(BaseIoAddress2)); + + NTSTATUS status; + PPORT_CONFIGURATION_INFORMATION_COMMON _ConfigInfo = + (PPORT_CONFIGURATION_INFORMATION_COMMON)ConfigInfo; + + *Again = FALSE; + + if(ForceSimplex) { + KdPrint2((PRINT_PREFIX "ForceSimplex (1)\n")); + simplexOnly = TRUE; + } + + if(InDriverEntry) { + i = (ULONG)Context; + if(i & 0x80000000) { + AltInit = TRUE; + } + i &= ~0x80000000; + channel = BMList[i].channel; + } else { + for(i=0; iSlotNumber && + BMList[i].busNumber == ConfigInfo->SystemIoBusNumber) { + break; + } + } + if(i >= BMListLen) { + KdPrint2((PRINT_PREFIX "unexpected device arrival => SP_RETURN_NOT_FOUND\n")); + return(SP_RETURN_NOT_FOUND); + } + channel = 0; + } + + bm_offset = channel ? ATA_BM_OFFSET1 : 0; + + KdPrint2((PRINT_PREFIX "UniataFindBusMasterController\n")); + + if (!deviceExtension) { + KdPrint2((PRINT_PREFIX "!deviceExtension => SP_RETURN_ERROR\n")); + return SP_RETURN_ERROR; + } + + RtlZeroMemory(deviceExtension, sizeof(HW_DEVICE_EXTENSION)); + + vendorStrPtr = vendorString; + deviceStrPtr = deviceString; + + slotNumber = BMList[i].slotNumber; + SystemIoBusNumber = BMList[i].busNumber; + + + KdPrint2((PRINT_PREFIX "AdapterInterfaceType=%#x\n",ConfigInfo->AdapterInterfaceType)); + KdPrint2((PRINT_PREFIX "IoBusNumber=%#x\n",ConfigInfo->SystemIoBusNumber)); + KdPrint2((PRINT_PREFIX "slotNumber=%#x\n",slotNumber)); + + // this buffer must be global and already filled for UNIATA_CORE build + busDataRead = HalGetBusData( + //busDataRead = ScsiPortGetBusData(HwDeviceExtension, + PCIConfiguration, + SystemIoBusNumber, + slotNumber, + &pciData, + PCI_COMMON_HDR_LENGTH); + +#ifndef UNIATA_CORE + if (busDataRead < PCI_COMMON_HDR_LENGTH) { + KdPrint2((PRINT_PREFIX "busDataRead < PCI_COMMON_HDR_LENGTH => SP_RETURN_ERROR\n")); + return SP_RETURN_ERROR; + } + + KdPrint2((PRINT_PREFIX "busDataRead\n")); + if (pciData.VendorID == PCI_INVALID_VENDORID) { + KdPrint2((PRINT_PREFIX "PCI_INVALID_VENDORID\n")); + return SP_RETURN_ERROR; + } +#endif //UNIATA_CORE + + VendorID = pciData.VendorID; + DeviceID = pciData.DeviceID; + BaseClass = pciData.BaseClass; + SubClass = pciData.SubClass; + RevID = pciData.RevisionID; + dev_id = VendorID | (DeviceID << 16); + slotData.u.AsULONG = slotNumber; + KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass )); + + deviceExtension->slotNumber = slotNumber; + deviceExtension->SystemIoBusNumber = SystemIoBusNumber; + deviceExtension->DevID = dev_id; + deviceExtension->RevID = RevID; + deviceExtension->NumberChannels = 2; // default + + _snprintf(deviceExtension->Signature, sizeof(deviceExtension->Signature), + "UATA%8.8x/%1.1x@%8.8x", dev_id, channel, slotNumber); + + if(BaseClass != PCI_DEV_CLASS_STORAGE) { + KdPrint2((PRINT_PREFIX "BaseClass != PCI_DEV_CLASS_STORAGE => SP_RETURN_NOT_FOUND\n")); + return(SP_RETURN_NOT_FOUND); + } + + KdPrint2((PRINT_PREFIX "Storage Class\n")); + + // look for known chipsets + if(VendorID != BMList[i].nVendorId || + DeviceID != BMList[i].nDeviceId) { + KdPrint2((PRINT_PREFIX "device not suitable\n")); + return(SP_RETURN_NOT_FOUND); + } + + if((BMList[i].RaidFlags & UNIATA_RAID_CONTROLLER) && + SkipRaids) { + KdPrint2((PRINT_PREFIX "RAID support disabled\n")); + return(SP_RETURN_NOT_FOUND); + } + + switch(SubClass) { + case PCI_DEV_SUBCLASS_IDE: + case PCI_DEV_SUBCLASS_RAID: + case PCI_DEV_SUBCLASS_ATA: + case PCI_DEV_SUBCLASS_SATA: + // ok + break; + default: + KdPrint2((PRINT_PREFIX "Subclass not supported\n")); + return(SP_RETURN_NOT_FOUND); + } + + ConfigInfo->AlignmentMask = 0x00000003; + + found = UniataChipDetect(HwDeviceExtension, &pciData, i, ConfigInfo, &simplexOnly); + KdPrint2((PRINT_PREFIX "ForceSimplex = %d\n", simplexOnly)); + KdPrint2((PRINT_PREFIX "HwFlags = %x\n (0)", deviceExtension->HwFlags)); + switch(dev_id) { + /* additional checks for some supported chipsets */ + case 0xc6931080: + if (SubClass != PCI_DEV_SUBCLASS_IDE) { + KdPrint2((PRINT_PREFIX "0xc6931080, SubClass != PCI_DEV_SUBCLASS_IDE => found = FALSE\n")); + found = FALSE; + } else { + found = FALSE; + } + break; + + /* unknown chipsets, try generic DMA if it seems possible */ + default: + if (found) + break; + KdPrint2((PRINT_PREFIX "Default device\n")); + if(!Ata_is_supported_dev(&pciData)) { + KdPrint2((PRINT_PREFIX "!Ata_is_supported_dev => found = FALSE\n")); + found = FALSE; + } else { + KdPrint2((PRINT_PREFIX "Ata_is_supported_dev\n")); + found = TRUE; + } + deviceExtension->UnknownDev = TRUE; + break; + } + + KdPrint2((PRINT_PREFIX "HwFlags = %x\n (1)", deviceExtension->HwFlags)); + if(!found) { + KdPrint2((PRINT_PREFIX "!found => SP_RETURN_NOT_FOUND\n")); + return(SP_RETURN_NOT_FOUND); + } + + KdPrint2((PRINT_PREFIX "HwFlags = %x\n (2)", deviceExtension->HwFlags)); + KdPrint2((PRINT_PREFIX "found suitable device\n")); + + /***********************************************************/ + /***********************************************************/ + /***********************************************************/ + + deviceExtension->UseDpc = TRUE; + KdPrint2((PRINT_PREFIX "HwFlags = %x\n (3)", deviceExtension->HwFlags)); + if(deviceExtension->HwFlags & UNIATA_NO_DPC) { + /* CMD 649, ROSB SWK33, ICH4 */ + KdPrint2((PRINT_PREFIX "UniataFindBusMasterController: UNIATA_NO_DPC (0)\n")); + deviceExtension->UseDpc = FALSE; + } + + MasterDev = IsMasterDev(&pciData); + + if(MasterDev) { + KdPrint2((PRINT_PREFIX "MasterDev\n")); + deviceExtension->MasterDev = TRUE; + deviceExtension->NumberChannels = 1; + } + + if(MasterDev) { + if((WinVer_Id() <= WinVer_NT) && AltInit && FirstMasterOk) { + // this is the 2nd attempt to init this controller by OUR driver + KdPrint2((PRINT_PREFIX "Skip primary/secondary claiming checks\n")); + } else { + if((channel==0) && ConfigInfo->AtdiskPrimaryClaimed) { + KdPrint2((PRINT_PREFIX "Error: Primary channel already claimed by another driver\n")); + return(SP_RETURN_NOT_FOUND); + } + if((channel==1) && ConfigInfo->AtdiskSecondaryClaimed) { + KdPrint2((PRINT_PREFIX "Error: Secondary channel already claimed by another driver\n")); + return(SP_RETURN_NOT_FOUND); + } + } + } + if(deviceExtension->AltRegMap) { + KdPrint2((PRINT_PREFIX " Non-standard registers layout\n")); + if(deviceExtension->HwFlags & UNIATA_SATA) { + KdPrint2((PRINT_PREFIX "UNIATA_SATA -> IsBusMaster == TRUE\n")); + deviceExtension->BusMaster = TRUE; + } + } else { + deviceExtension->BusMaster = FALSE; + if(IsBusMaster(&pciData)) { + + KdPrint2((PRINT_PREFIX "IsBusMaster == TRUE\n")); + BaseIoAddressBM_0 = (PIDE_BUSMASTER_REGISTERS) + (AtapiGetIoRange(HwDeviceExtension, ConfigInfo, &pciData, SystemIoBusNumber, + 4, bm_offset, MasterDev ? 0x08 : 0x10/*ATA_BMIOSIZE*/)/* - bm_offset*/); //range id + if(BaseIoAddressBM_0) { + UniataInitMapBM(deviceExtension, + BaseIoAddressBM_0, + (*ConfigInfo->AccessRanges)[4].RangeInMemory ? TRUE : FALSE); + deviceExtension->BusMaster = TRUE; + deviceExtension->BaseIoAddressBM_0.Addr = (ULONG)BaseIoAddressBM_0; + if((*ConfigInfo->AccessRanges)[4].RangeInMemory) { + deviceExtension->BaseIoAddressBM_0.MemIo = TRUE; + } + } + KdPrint2((PRINT_PREFIX " BusMasterAddress (base): %#x\n", BaseIoAddressBM_0)); + } + + if(!deviceExtension->BusMaster) { + KdPrint2((PRINT_PREFIX " !BusMasterAddress -> PIO4\n")); + deviceExtension->MaxTransferMode = ATA_PIO4; + } + + if(deviceExtension->BusMaster && !MasterDev) { + KdPrint2((PRINT_PREFIX "IsBusMaster == TRUE && !MasterDev\n")); + statusByte = AtapiReadPort1(&(deviceExtension->chan[0]), IDX_BM_Status); + KdPrint2((PRINT_PREFIX " statusByte = %x\n", statusByte)); + if(statusByte == 0xff) { + KdPrint2((PRINT_PREFIX " invalid port ?\n")); +/* + if(BaseIoAddressBM_0) { + ScsiPortFreeDeviceBase(HwDeviceExtension, + BaseIoAddressBM_0); + BaseIoAddressBM_0 = NULL; + } +*/ + } else + if(statusByte & BM_STATUS_SIMPLEX_ONLY) { + KdPrint2((PRINT_PREFIX " BM_STATUS => simplexOnly\n")); + simplexOnly = TRUE; + } + } + } + + /* + * the Cypress chip is a mess, it contains two ATA functions, but + * both channels are visible on the first one. + * simply ignore the second function for now, as the right + * solution (ignoring the second channel on the first function) + * doesn't work with the crappy ATA interrupt setup on the alpha. + */ + if (dev_id == 0xc6931080 && slotData.u.bits.FunctionNumber > 1) { + KdPrint2((PRINT_PREFIX "dev_id == 0xc6931080 && FunctionNumber > 1 => exit_findbm\n")); + goto exit_findbm; + } + + /* do extra chipset specific setups */ + AtapiReadChipConfig(HwDeviceExtension, i, CHAN_NOT_SPECIFIED); + AtapiChipInit(HwDeviceExtension, i, CHAN_NOT_SPECIFIED); + + simplexOnly |= deviceExtension->simplexOnly; + deviceExtension->simplexOnly |= simplexOnly; + + KdPrint2((PRINT_PREFIX "simplexOnly = %d (2)", simplexOnly)); + + //TODO: fix hang with UseDpn=TRUE in Simplex mode + //deviceExtension->UseDpc = TRUE; + if(simplexOnly) { + KdPrint2((PRINT_PREFIX "simplexOnly => UseDpc = FALSE\n")); + deviceExtension->UseDpc = FALSE; + } + + if(simplexOnly || !MasterDev /*|| (WinVer_Id() > WinVer_NT)*/) { + if(deviceExtension->NumberChannels < 2) { + deviceExtension->NumberChannels = 2; + if(BaseIoAddressBM_0) { + UniataInitMapBM(deviceExtension, + BaseIoAddressBM_0, + (*ConfigInfo->AccessRanges)[4].RangeInMemory ? TRUE : FALSE); + } + } + } + if((channel > 0) && + (deviceExtension->NumberChannels > 1)) { + KdPrint2((PRINT_PREFIX "Error: channel > 0 && NumberChannels > 1\n")); + goto exit_findbm; + } + + // Indicate number of buses. + ConfigInfo->NumberOfBuses = (UCHAR)(deviceExtension->NumberChannels); + if(!ConfigInfo->InitiatorBusId[0]) { + ConfigInfo->InitiatorBusId[0] = (CHAR)(IoGetConfigurationInformation()->ScsiPortCount); + KdPrint2((PRINT_PREFIX "set ConfigInfo->InitiatorBusId[0] = %#x\n", ConfigInfo->InitiatorBusId[0])); + } + // Indicate four devices can be attached to the adapter + ConfigInfo->MaximumNumberOfTargets = (UCHAR)(/*deviceExtension->NumberChannels **/ 2); + + if (MasterDev) { + KdPrint2((PRINT_PREFIX "MasterDev\n")); +/* + if((WinVer_Id() > WinVer_NT) || + (deviceExtension->NumberChannels > 1)) { + + KdPrint2((PRINT_PREFIX "2 channels & 2 irq for 1 controller Win 2000+\n")); + + if (ConfigInfo->AdapterInterfaceType == MicroChannel) { + ConfigInfo->InterruptMode2 = + ConfigInfo->InterruptMode = LevelSensitive; + } else { + ConfigInfo->InterruptMode2 = + ConfigInfo->InterruptMode = Latched; + } + ConfigInfo->BusInterruptLevel = 14; + ConfigInfo->BusInterruptLevel2 = 15; + } else*/ + if(simplexOnly) { + + KdPrint2((PRINT_PREFIX "2 channels & 2 irq for 1 controller\n")); + + if (ConfigInfo->AdapterInterfaceType == MicroChannel) { + ConfigInfo->InterruptMode2 = + ConfigInfo->InterruptMode = LevelSensitive; + } else { + ConfigInfo->InterruptMode2 = + ConfigInfo->InterruptMode = Latched; + } + ConfigInfo->BusInterruptLevel = 14; + ConfigInfo->BusInterruptLevel2 = 15; + } else { + KdPrint2((PRINT_PREFIX "1 channels & 1 irq for 1 controller\n")); + if (ConfigInfo->AdapterInterfaceType == MicroChannel) { + ConfigInfo->InterruptMode = LevelSensitive; + } else { + ConfigInfo->InterruptMode = Latched; + } + ConfigInfo->BusInterruptLevel = (channel == 0 ? 14 : 15); + } + } else { + KdPrint2((PRINT_PREFIX "!MasterDev\n")); + ConfigInfo->SlotNumber = slotNumber; + ConfigInfo->SystemIoBusNumber = SystemIoBusNumber; + + /* primary and secondary channels share the same interrupt */ + if(!ConfigInfo->BusInterruptVector || + (ConfigInfo->BusInterruptVector != pciData.u.type0.InterruptLine)) { + KdPrint2((PRINT_PREFIX "patch irq line = %#x\n", pciData.u.type0.InterruptLine)); + ConfigInfo->BusInterruptVector = pciData.u.type0.InterruptLine; // set default value + if(!ConfigInfo->BusInterruptVector) { + KdPrint2((PRINT_PREFIX "patch irq line (2) = 10\n")); + ConfigInfo->BusInterruptVector = 10; + } + } + } + ConfigInfo->MultipleRequestPerLu = TRUE; + ConfigInfo->AutoRequestSense = TRUE; + ConfigInfo->TaggedQueuing = TRUE; + + if((WinVer_Id() >= WinVer_NT) || + (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4))) { + _ConfigInfo->nt4.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); + _ConfigInfo->nt4.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION); + _ConfigInfo->nt4.SrbExtensionSize = sizeof(ATA_REQ); + } + if((WinVer_Id() > WinVer_2k) || + (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4) + sizeof(_ConfigInfo->w2k))) { + _ConfigInfo->w2k.Dma64BitAddresses = 0; + _ConfigInfo->w2k.ResetTargetSupported = TRUE; + _ConfigInfo->w2k.MaximumNumberOfLogicalUnits = 2; + } + + // Save the Interrupe Mode for later use + deviceExtension->InterruptMode = ConfigInfo->InterruptMode; + deviceExtension->BusInterruptLevel = ConfigInfo->BusInterruptLevel; + deviceExtension->BusInterruptVector = ConfigInfo->BusInterruptVector; + deviceExtension->Channel = channel; + deviceExtension->DevIndex = i; + deviceExtension->OrigAdapterInterfaceType + = ConfigInfo->AdapterInterfaceType; + deviceExtension->AlignmentMask = ConfigInfo->AlignmentMask; + + found = FALSE; + + if(deviceExtension->BusMaster) { + + KdPrint2((PRINT_PREFIX "Reconstruct ConfigInfo\n")); + ConfigInfo->MapBuffers = TRUE; +#ifdef USE_OWN_DMA + ConfigInfo->NeedPhysicalAddresses = FALSE; +#else + ConfigInfo->NeedPhysicalAddresses = TRUE; +#endif //USE_OWN_DMA + if(!MasterDev) { + KdPrint2((PRINT_PREFIX "set Dma32BitAddresses\n")); + ConfigInfo->Dma32BitAddresses = TRUE; + } + + // thanks to Vitaliy Vorobyov aka deathsoft@yandex.ru for + // better solution: + + if(AltInit) { + // I'm sorry, I have to do this + // when Win doesn't + + if(ConfigInfo->AdapterInterfaceType == Isa /*&& +// InDriverEntry*/) { + KdPrint2((PRINT_PREFIX "AdapterInterfaceType Isa => PCIBus\n")); + ConfigInfo->AdapterInterfaceType = PCIBus; + } + if(ConfigInfo->AdapterInterfaceType == PCIBus /*&& +// InDriverEntry*/) { + KdPrint2((PRINT_PREFIX "AdapterInterfaceType PCIBus, update address\n")); + ConfigInfo->SlotNumber = slotNumber; + ConfigInfo->SystemIoBusNumber = SystemIoBusNumber; + } + } + +#ifndef USE_OWN_DMA + ConfigInfo->Master = TRUE; + ConfigInfo->DmaWidth = Width16Bits; +#endif //USE_OWN_DMA + ConfigInfo->CachesData = TRUE; + ConfigInfo->ScatterGather = TRUE; + } + + // Note: now we can support only 4 channels !!! + // in order to add support for multichannel controllers we must rewrite + // io-range claiming algorithm + + for (; channel < (BMList[i].channel + deviceExtension->NumberChannels); channel++, c++) { + + KdPrint2((PRINT_PREFIX "de %#x, Channel %#x\n",deviceExtension, channel)); + //PrintNtConsole("de %#x, Channel %#x, nchan %#x\n",deviceExtension, channel, deviceExtension->NumberChannels); + chan = &deviceExtension->chan[c]; + + KdPrint2((PRINT_PREFIX "chan = %#x\n", chan)); + //PrintNtConsole("chan = %#x, c=%#x\n", chan, c); + AtapiSetupLunPtrs(chan, deviceExtension, c); + + /* do extra channel-specific setups */ + AtapiReadChipConfig(HwDeviceExtension, i, channel); + //AtapiChipInit(HwDeviceExtension, i, channel); + if(deviceExtension->AltRegMap) { + KdPrint2((PRINT_PREFIX " Non-standard registers layout\n")); + } else { + // Check if the range specified is not used by another driver + if(MasterDev) { + KdPrint2((PRINT_PREFIX "set AccessRanges\n")); + (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(channel ? IO_WD2 : IO_WD1); + (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeLength = ATA_IOSIZE; + + (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart = + ScsiPortConvertUlongToPhysicalAddress((channel ? IO_WD2 : IO_WD1) + ATA_ALTOFFSET); + (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeLength = ATA_ALTIOSIZE; + + // do not claim 2nd BM io-range for Secondary channel of + // Compatible-mode controllers + if(/*(WinVer_Id() <= WinVer_NT) &&*/ !c && channel == 1) { + KdPrint2((PRINT_PREFIX "cheat ScsiPort for 2nd channel, BM io-range\n")); + (*ConfigInfo->AccessRanges)[4].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0); + (*ConfigInfo->AccessRanges)[4].RangeLength = 0; + } + } + + IoBasePort1 = (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart; + IoBasePort2 = (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart; + + if(!MasterDev) { + if(!IoBasePort1.QuadPart || !IoBasePort2.QuadPart) { + KdPrint2((PRINT_PREFIX "ScsiPortValidateRange failed (1)\n")); + continue; + } + } + + if(!ScsiPortValidateRange(HwDeviceExtension, + PCIBus /*ConfigInfo->AdapterInterfaceType*/, + SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/, + IoBasePort1, + ATA_IOSIZE, + TRUE) ) { + KdPrint2((PRINT_PREFIX "ScsiPortValidateRange failed (1)\n")); + continue; + } + + if(!ScsiPortValidateRange(HwDeviceExtension, + PCIBus /*ConfigInfo->AdapterInterfaceType*/, + SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/, + IoBasePort2, + ATA_ALTIOSIZE, + TRUE) ) { + KdPrint2((PRINT_PREFIX "ScsiPortValidateRange failed (2)\n")); + continue; + } + + KdPrint2((PRINT_PREFIX "Getting IO ranges\n")); + + // Ok, translate adresses to io-space + if(ScsiPortConvertPhysicalAddressToUlong(IoBasePort2)) { + if(!(MasterDev /* || USE_16_BIT */)) { + KdPrint2((PRINT_PREFIX "!MasterDev mode\n")); + IoBasePort2 = ScsiPortConvertUlongToPhysicalAddress( + ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) + 2); + } + } else { + KdPrint2((PRINT_PREFIX "use relative IoBasePort2\n")); + IoBasePort2 = ScsiPortConvertUlongToPhysicalAddress( + ScsiPortConvertPhysicalAddressToUlong(IoBasePort1) + ATA_PCCARD_ALTOFFSET); + } + + // Get the system physical address for this IO range. + ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension, + PCIBus /*ConfigInfo->AdapterInterfaceType*/, + SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/, + IoBasePort1, + ATA_IOSIZE, + TRUE); + KdPrint2((PRINT_PREFIX "IO range 1 %#x\n",ioSpace)); + + // Check if ioSpace accessible. + if (!ioSpace) { + KdPrint2((PRINT_PREFIX "!ioSpace\n")); + continue; + } +/* + if(deviceExtension->BusMaster) { + KdPrint2((PRINT_PREFIX "set BusMaster io-range in DO\n")); + // bm_offset already includes (channel ? ATA_BM_OFFSET1 : 0) + deviceExtension->BaseIoAddressBM[c] = (PIDE_BUSMASTER_REGISTERS) + ((ULONG)(deviceExtension->BaseIoAddressBM_0) + bm_offset + (c ? ATA_BM_OFFSET1 : 0)); + } +*/ + //deviceExtension->BaseIoAddress1[c] = (PIDE_REGISTERS_1)(ioSpace); + BaseIoAddress1[c] = (PIDE_REGISTERS_1)(ioSpace); + + // Get the system physical address for the second IO range. + ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension, + PCIBus /*ConfigInfo->AdapterInterfaceType*/, + SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/, + IoBasePort2, + ATA_ALTIOSIZE, + TRUE); + KdPrint2((PRINT_PREFIX "IO range 2 %#x\n",ioSpace)); + + BaseIoAddress2[c] = (PIDE_REGISTERS_2)(ioSpace); + if(!ioSpace) { + // Release all allocated resources + KdPrint2((PRINT_PREFIX "!deviceExtension->BaseIoAddress2\n")); + //ioSpace = (PUCHAR)BaseIoAddress1[c]; + // goto free_iospace_1; + found = FALSE; + goto exit_findbm; + } + UniataInitMapBase(chan, BaseIoAddress1[c], BaseIoAddress2[c]); + } + //ioSpace = (PUCHAR)(deviceExtension->BaseIoAddress1[c]); + + KdPrint2((PRINT_PREFIX "IDX_IO1 %x->%x(%s)\n", + IDX_IO1, + chan->RegTranslation[IDX_IO1].Addr, + chan->RegTranslation[IDX_IO1].MemIo ? "mem" : "io")); + + KdPrint2((PRINT_PREFIX "IDX_IO2 %x->%x(%s)\n", + IDX_IO2, + chan->RegTranslation[IDX_IO2].Addr, + chan->RegTranslation[IDX_IO2].MemIo ? "mem" : "io")); + + KdPrint2((PRINT_PREFIX "IDX_BM_IO %x->%x(%s)\n", + IDX_BM_IO, + chan->RegTranslation[IDX_BM_IO].Addr, + chan->RegTranslation[IDX_BM_IO].MemIo ? "mem" : "io")); + + KdPrint2((PRINT_PREFIX "IDX_SATA_IO %x->%x(%s)\n", + IDX_SATA_IO, + chan->RegTranslation[IDX_SATA_IO].Addr, + chan->RegTranslation[IDX_SATA_IO].MemIo ? "mem" : "io")); + + UniataDumpATARegs(chan); + +#ifndef UNIATA_CORE +#ifdef UNIATA_INIT_ON_PROBE +// if(deviceExtension->HwFlags & UNIATA_SATA) { +//#endif //UNIATA_INIT_ON_PROBE + KdPrint2((PRINT_PREFIX "Check drive 0\n")); + // Check master. + SelectDrive(chan, 0); + AtapiStallExecution(10); + GetBaseStatus(chan, statusByte); + skip_find_dev = FALSE; + if(!(deviceExtension->HwFlags & UNIATA_NO_SLAVE)) { + if ((statusByte & 0xf8) == 0xf8 || + (statusByte == 0xa5)) { + // Check slave. + KdPrint2((PRINT_PREFIX "Check drive 1\n")); + SelectDrive(chan, 1); + AtapiStallExecution(1); + GetBaseStatus(chan, statusByte); + if ((statusByte & 0xf8) == 0xf8 || + (statusByte == 0xa5)) { + // No controller at this base address. + KdPrint2((PRINT_PREFIX "Empty channel\n")); + skip_find_dev = TRUE; + } + } + } + + // Search for devices on this controller. + if (!skip_find_dev && + FindDevices(HwDeviceExtension, + FALSE, + c)) { + KdPrint2((PRINT_PREFIX "Found some devices\n")); + found = TRUE; + } else { + KdPrint2((PRINT_PREFIX "no devices\n")); + /* KeBugCheckEx(0xc000000e, + ScsiPortConvertPhysicalAddressToUlong(IoBasePort1), + ScsiPortConvertPhysicalAddressToUlong(IoBasePort2), + (ULONG)(deviceExtension->BaseIoAddressBM[c]), skip_find_dev);*/ + } +//#ifdef UNIATA_INIT_ON_PROBE +// } +#endif //UNIATA_INIT_ON_PROBE + found = TRUE; + + chan->PrimaryAddress = FALSE; + // Claim primary or secondary ATA IO range. + if (MasterDev) { + KdPrint2((PRINT_PREFIX "claim Compatible controller\n")); + if (channel == 0) { + KdPrint2((PRINT_PREFIX "claim Primary\n")); + ConfigInfo->AtdiskPrimaryClaimed = TRUE; + chan->PrimaryAddress = TRUE; + + FirstMasterOk = TRUE; + + } else + if (channel == 1) { + KdPrint2((PRINT_PREFIX "claim Secondary\n")); + ConfigInfo->AtdiskSecondaryClaimed = TRUE; + + FirstMasterOk = TRUE; + } + } + + AtapiDmaAlloc(HwDeviceExtension, ConfigInfo, c); +#else //UNIATA_CORE + found = TRUE; +#endif //UNIATA_CORE + } // end for(channel) + +exit_findbm: + +#ifndef UNIATA_CORE + if(!found) { + KdPrint2((PRINT_PREFIX "exit: !found\n")); + if(BaseIoAddress1[0]) + ScsiPortFreeDeviceBase(HwDeviceExtension, + BaseIoAddress1[0]); + if(BaseIoAddress2[0]) + ScsiPortFreeDeviceBase(HwDeviceExtension, + BaseIoAddress2[0]); + + if(BaseIoAddress1[1]) + ScsiPortFreeDeviceBase(HwDeviceExtension, + BaseIoAddress1[1]); + if(BaseIoAddress2[1]) + ScsiPortFreeDeviceBase(HwDeviceExtension, + BaseIoAddress2[1]); + + if(BaseIoAddressBM_0) + ScsiPortFreeDeviceBase(HwDeviceExtension, + BaseIoAddressBM_0); + + KdPrint2((PRINT_PREFIX "return SP_RETURN_NOT_FOUND\n")); + return SP_RETURN_NOT_FOUND; + } else { + + KdPrint2((PRINT_PREFIX "exit: init spinlock\n")); + //KeInitializeSpinLock(&(deviceExtension->DpcSpinLock)); + deviceExtension->ActiveDpcChan = + deviceExtension->FirstDpcChan = -1; + + BMList[i].Isr2Enable = FALSE; + + KdPrint2((PRINT_PREFIX "MasterDev=%#x, NumberChannels=%#x, Isr2DevObj=%#x\n", + MasterDev, deviceExtension->NumberChannels, BMList[i].Isr2DevObj)); + + // ConnectIntr2 should be moved to HwInitialize + status = UniataConnectIntr2(HwDeviceExtension); + + KdPrint2((PRINT_PREFIX "MasterDev=%#x, NumberChannels=%#x, Isr2DevObj=%#x\n", + MasterDev, deviceExtension->NumberChannels, BMList[i].Isr2DevObj)); + + if(!NT_SUCCESS(status)) { + KdPrint2((PRINT_PREFIX "failed\n")); + found = FALSE; + goto exit_findbm; + } + } +#endif //UNIATA_CORE + + KdPrint2((PRINT_PREFIX "return SP_RETURN_FOUND\n")); + //PrintNtConsole("return SP_RETURN_FOUND, de %#x, c0.lun0 %#x\n", deviceExtension, deviceExtension->chan[0].lun[0]); + + if(MasterDev) { + KdPrint2((PRINT_PREFIX "Attempt %d of MasterDev ok\n", AltInit)); + FirstMasterOk = TRUE; + } + + return SP_RETURN_FOUND; + +} // end UniataFindBusMasterController() + +#ifndef UNIATA_CORE +/*++ + +Routine Description: + + This function is called to initialize 2nd device object for + multichannel controllers. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + +Return Value: + + ULONG + +--*/ +NTSTATUS +UniataConnectIntr2( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG i = deviceExtension->DevIndex; + NTSTATUS status; + PISR2_DEVICE_EXTENSION Isr2DevExt; + WCHAR devname_str[32]; + UNICODE_STRING devname; + + KdPrint2((PRINT_PREFIX "Init ISR:\n")); + + if(BMList[i].Isr2DevObj) { + KdPrint2((PRINT_PREFIX "Already initialized %#x\n", BMList[i].Isr2DevObj)); + return STATUS_SUCCESS; + } + + if(!deviceExtension->MasterDev && (deviceExtension->NumberChannels > 1) && // do not touch MasterDev + !deviceExtension->simplexOnly && /* // this is unnecessary on simplex controllers + !BMList[i].Isr2DevObj*/ // handle re-init under w2k+ + /*!ForceSimplex*/ + TRUE) { + // Ok, continue... + KdPrint2((PRINT_PREFIX "Multichannel native mode, go...\n")); + } else { + KdPrint2((PRINT_PREFIX "Unnecessary\n")); + return STATUS_SUCCESS; + } + + KdPrint2((PRINT_PREFIX "Create DO\n")); + + devname.Length = + _snwprintf(devname_str, sizeof(devname_str)/sizeof(WCHAR), + L"\\Device\\uniata%d_2ch", i); + devname.Length *= sizeof(WCHAR); + devname.MaximumLength = devname.Length; + devname.Buffer = devname_str; + + KdPrint2((PRINT_PREFIX "DO name: len(%d, %d), %S\n", devname.Length, devname.MaximumLength, devname.Buffer)); + + status = IoCreateDevice(SavedDriverObject, sizeof(ISR2_DEVICE_EXTENSION), + /*NULL*/ &devname, FILE_DEVICE_UNKNOWN, + 0, FALSE, &(BMList[i].Isr2DevObj)); + + if(!NT_SUCCESS(status)) { + KdPrint2((PRINT_PREFIX "IoCreateDevice failed %#x\n")); + return status; + } + + KdPrint2((PRINT_PREFIX "HalGetInterruptVector\n")); + KdPrint2((PRINT_PREFIX " OrigAdapterInterfaceType=%d\n", deviceExtension->OrigAdapterInterfaceType)); + KdPrint2((PRINT_PREFIX " SystemIoBusNumber=%d\n", deviceExtension->SystemIoBusNumber)); + KdPrint2((PRINT_PREFIX " BusInterruptLevel=%d\n", deviceExtension->BusInterruptLevel)); + KdPrint2((PRINT_PREFIX " BusInterruptVector=%d\n", deviceExtension->BusInterruptVector)); + BMList[i].Isr2Vector = HalGetInterruptVector( + deviceExtension->OrigAdapterInterfaceType, + deviceExtension->SystemIoBusNumber, + deviceExtension->BusInterruptLevel, + deviceExtension->BusInterruptVector, + &(BMList[i].Isr2Irql), + &(BMList[i].Isr2Affinity)); + + Isr2DevExt = (PISR2_DEVICE_EXTENSION)(BMList[i].Isr2DevObj->DeviceExtension); + Isr2DevExt->HwDeviceExtension = deviceExtension; + Isr2DevExt->DevIndex = i; + + KdPrint2((PRINT_PREFIX "isr2_de %#x\n", Isr2DevExt)); + KdPrint2((PRINT_PREFIX "isr2_vector %#x\n", BMList[i].Isr2Vector)); + KdPrint2((PRINT_PREFIX "isr2_irql %#x\n", BMList[i].Isr2Irql)); + KdPrint2((PRINT_PREFIX "isr2_affinity %#x\n", BMList[i].Isr2Affinity)); + +// deviceExtension->QueueNewIrql = BMList[i].Isr2Irql; + + KdPrint2((PRINT_PREFIX "IoConnectInterrupt\n")); + status = IoConnectInterrupt( + &(BMList[i].Isr2InterruptObject), + AtapiInterrupt2, + Isr2DevExt, + NULL, + BMList[i].Isr2Vector, + BMList[i].Isr2Irql, + BMList[i].Isr2Irql, + (KINTERRUPT_MODE)(deviceExtension->InterruptMode), + TRUE, + BMList[i].Isr2Affinity, + FALSE); + + if(!NT_SUCCESS(status)) { + KdPrint2((PRINT_PREFIX "IoConnectInterrupt failed\n")); + IoDeleteDevice(BMList[i].Isr2DevObj); + BMList[i].Isr2DevObj = NULL; + BMList[i].Isr2InterruptObject = NULL; + return status; + } + + //deviceExtension->Isr2DevObj = BMList[i].Isr2DevObj; + + return status; +} // end UniataConnectIntr2() + +NTSTATUS +UniataDisconnectIntr2( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG i = deviceExtension->DevIndex; +// NTSTATUS status; + + KdPrint2((PRINT_PREFIX "Deinit ISR:\n")); + + if(!BMList[i].Isr2DevObj) { + KdPrint2((PRINT_PREFIX "Already uninitialized %#x\n")); + return STATUS_SUCCESS; + } + + IoDisconnectInterrupt(BMList[i].Isr2InterruptObject); + + BMList[i].Isr2InterruptObject = NULL; + + IoDeleteDevice(BMList[i].Isr2DevObj); + + BMList[i].Isr2DevObj = NULL; + //deviceExtension->Isr2DevObj = NULL; + + return STATUS_SUCCESS; +} // end UniataDisconnectIntr2() + +#endif //UNIATA_CORE + +/*++ + +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 - Address of adapter count + ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. + ConfigInfo - Configuration information structure describing HBA + Again - Indicates search for adapters to continue + +Return Value: + + ULONG + +--*/ +ULONG +AtapiFindController( + IN PVOID HwDeviceExtension, + IN PVOID Context, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[0]); + PULONG adapterCount = (PULONG)Context; + PUCHAR ioSpace; + ULONG i; + ULONG irq=0; + ULONG portBase; + ULONG retryCount; + BOOLEAN atapiOnly; + UCHAR statusByte; + BOOLEAN preConfig = FALSE; + // + PIDE_REGISTERS_1 BaseIoAddress1; + PIDE_REGISTERS_2 BaseIoAddress2; + + // The following table specifies the ports to be checked when searching for + // an IDE controller. A zero entry terminates the search. + static CONST ULONG AdapterAddresses[5] = {IO_WD1, IO_WD2, IO_WD1-8, IO_WD2-8, 0}; +// CONST UCHAR Channels[5] = {0, 1, 0, 1, 0}; + + // The following table specifies interrupt levels corresponding to the + // port addresses in the previous table. + static CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0}; + + KdPrint2((PRINT_PREFIX "AtapiFindController:\n")); + + if (!deviceExtension) { + return SP_RETURN_ERROR; + } + RtlZeroMemory(deviceExtension, sizeof(HW_DEVICE_EXTENSION)); + + KdPrint2((PRINT_PREFIX " assume max PIO4\n")); + deviceExtension->MaxTransferMode = ATA_PIO4; + deviceExtension->NumberChannels = 1; + +#ifndef UNIATA_CORE + + /* do extra chipset specific setups */ + AtapiReadChipConfig(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED); + AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED); + + // Check to see if this is a special configuration environment. + portBase = irq = 0; + if (ArgumentString) { + + irq = AtapiParseArgumentString(ArgumentString, "Interrupt"); + if (irq ) { + + // Both parameters must be present to proceed + portBase = AtapiParseArgumentString(ArgumentString, "BaseAddress"); + if (!portBase) { + + // Try a default search for the part. + irq = 0; + } + } + } + +#endif //UNIATA_CORE + + + // Scan though the adapter address looking for adapters. + if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) { + ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + (*ConfigInfo->AccessRanges)[0].RangeStart, + (*ConfigInfo->AccessRanges)[0].RangeLength, + (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory)); + *Again = FALSE; + // Since we have pre-configured information we only need to go through this loop once + preConfig = TRUE; + portBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart); + } + +#ifndef UNIATA_CORE + while (AdapterAddresses[*adapterCount] != 0) { +#else + do { +#endif //UNIATA_CORE + + retryCount = 4; + + for (i = 0; i < 4; i++) { + // Zero device fields to ensure that if earlier devices were found, + // but not claimed, the fields are cleared. + deviceExtension->lun[i].DeviceFlags &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE); + } + // Get the system physical address for this IO range. + + // Check if configInfo has the default information + // if not, we go and find ourselves + if (preConfig == FALSE) { + + if (portBase) { + ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + ScsiPortConvertUlongToPhysicalAddress(portBase), + 8, + TRUE); + } else { + ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]), + 8, + TRUE); + } + + }// ConfigInfo check + BaseIoAddress1 = (PIDE_REGISTERS_1)ioSpace; + + // Update the adapter count. + (*adapterCount)++; + + // Check if ioSpace accessible. + if (!ioSpace) { + KdPrint2((PRINT_PREFIX "AtapiFindController: !ioSpace\n")); + continue; + } + // check if Primary/Secondary Master IDE claimed + if((ioSpace == (PUCHAR)IO_WD1) && + (ConfigInfo->AtdiskPrimaryClaimed)) { + KdPrint2((PRINT_PREFIX "AtapiFindController: AtdiskPrimaryClaimed\n")); + goto not_found; + } else + if((ioSpace == (PUCHAR)IO_WD2) && + (ConfigInfo->AtdiskSecondaryClaimed)) { + KdPrint2((PRINT_PREFIX "AtapiFindController: AtdiskSecondaryClaimed\n")); + goto not_found; + } + + // Get the system physical address for the second IO range. + if (BaseIoAddress1) { + ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + ScsiPortConvertUlongToPhysicalAddress((ULONG)BaseIoAddress1 + ATA_ALTOFFSET), + ATA_ALTIOSIZE, + TRUE); + } + BaseIoAddress2 = (PIDE_REGISTERS_2)ioSpace; + + UniataInitMapBase(chan, BaseIoAddress1, BaseIoAddress2); + +retryIdentifier: + + // Select master. + SelectDrive(chan, 0); + + // Check if card at this address. + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, 0xAA); + + // Check if indentifier can be read back. + if ((statusByte = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)) != 0xAA) { + + KdPrint2((PRINT_PREFIX "AtapiFindController: Identifier read back from Master (%#x)\n", + statusByte)); + + statusByte = AtapiReadPort1(chan, IDX_IO2_AltStatus); + + if (statusByte & IDE_STATUS_BUSY) { + + i = 0; + + // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that + // warm boots don't clear. + do { + AtapiStallExecution(1000); + statusByte = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Status); + KdPrint2((PRINT_PREFIX + "AtapiFindController: First access to status %#x\n", + statusByte)); + } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10); + + if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) { + goto retryIdentifier; + } + } + + // Select slave. + SelectDrive(chan, 1); + + // See if slave is present. + AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, 0xAA); + + if ((statusByte = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)) != 0xAA) { + + KdPrint2((PRINT_PREFIX + "AtapiFindController: Identifier read back from Slave (%#x)\n", + statusByte)); +not_found: + // No controller at this base address. + if(BaseIoAddress1) { + ScsiPortFreeDeviceBase(HwDeviceExtension, + (PCHAR)BaseIoAddress1); + BaseIoAddress1 = NULL; + } + if(BaseIoAddress2) { + ScsiPortFreeDeviceBase(HwDeviceExtension, + (PCHAR)BaseIoAddress2); + BaseIoAddress2 = NULL; + } + continue; + } + } + + // Fill in the access array information only if default params are not in there. + if (preConfig == FALSE) { + + // An adapter has been found request another call, only if we didn't get preconfigured info. + *Again = TRUE; + + if (portBase) { + (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(portBase); + } else { + (*ConfigInfo->AccessRanges)[0].RangeStart = + ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]); + } + + (*ConfigInfo->AccessRanges)[0].RangeLength = 8; + (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; + + // Indicate the interrupt level corresponding to this IO range. + if (irq) { + ConfigInfo->BusInterruptLevel = irq; + } else { + ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1]; + } + + if (ConfigInfo->AdapterInterfaceType == MicroChannel) { + ConfigInfo->InterruptMode = LevelSensitive; + } else { + ConfigInfo->InterruptMode = Latched; + } + } + + ConfigInfo->NumberOfBuses = 1; + ConfigInfo->MaximumNumberOfTargets = 2; + + // Indicate maximum transfer length is 64k. + ConfigInfo->MaximumTransferLength = 0x10000; + deviceExtension->MaximumDmaTransferLength = ConfigInfo->MaximumTransferLength; + + KdPrint2((PRINT_PREFIX "de %#x, Channel ???\n", deviceExtension)); + //PrintNtConsole("de %#x, Channel %#x, nchan %#x\n",deviceExtension, channel, deviceExtension->NumberChannels); + + KdPrint2((PRINT_PREFIX "chan = %#x\n", chan)); + //PrintNtConsole("chan = %#x, c=%#x\n", chan, c); + chan->DeviceExtension = deviceExtension; + chan->lChannel = 0; + chan->lun[0] = &(deviceExtension->lun[0]); + chan->lun[1] = &(deviceExtension->lun[1]); + + /* do extra channel-specific setups */ + AtapiReadChipConfig(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, 0); + AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, 0); + + KdPrint2((PRINT_PREFIX + "AtapiFindController: Found IDE at %#x\n", + BaseIoAddress1)); + + // For Daytona, the atdisk driver gets the first shot at the + // primary and secondary controllers. + if (preConfig == FALSE) { + + if (*adapterCount - 1 < 2) { + + // Determine whether this driver is being initialized by the + // system or as a crash dump driver. + if (ArgumentString) { + +#ifndef UNIATA_CORE + if (AtapiParseArgumentString(ArgumentString, "dump") == 1) { + KdPrint2((PRINT_PREFIX + "AtapiFindController: Crash dump\n")); + atapiOnly = FALSE; + deviceExtension->DriverMustPoll = TRUE; + } else { + KdPrint2((PRINT_PREFIX + "AtapiFindController: Atapi Only\n")); + atapiOnly = TRUE; + deviceExtension->DriverMustPoll = FALSE; + } +#endif //UNIATA_CORE + } else { + + KdPrint2((PRINT_PREFIX + "AtapiFindController: Atapi Only (2)\n")); + atapiOnly = TRUE; + deviceExtension->DriverMustPoll = FALSE; + } + + } else { + atapiOnly = FALSE; + } + + } else { + + atapiOnly = FALSE; + deviceExtension->DriverMustPoll = FALSE; + + }// preConfig check + + // Save the Interrupe Mode for later use + deviceExtension->InterruptMode = ConfigInfo->InterruptMode; + + KdPrint2((PRINT_PREFIX + "AtapiFindController: look for devices\n")); + // Search for devices on this controller. + if (FindDevices(HwDeviceExtension, + /*atapiOnly*/ FALSE, + 0)) { + + KdPrint2((PRINT_PREFIX + "AtapiFindController: detected\n")); + // Claim primary or secondary ATA IO range. + if (portBase) { + switch (portBase) { + case IO_WD2: + ConfigInfo->AtdiskSecondaryClaimed = TRUE; + chan->PrimaryAddress = FALSE; + break; + case IO_WD1: + ConfigInfo->AtdiskPrimaryClaimed = TRUE; + chan->PrimaryAddress = TRUE; + break; + default: + break; + } + } else { + if (*adapterCount == 1) { + ConfigInfo->AtdiskPrimaryClaimed = TRUE; + chan->PrimaryAddress = TRUE; + } else if (*adapterCount == 2) { + ConfigInfo->AtdiskSecondaryClaimed = TRUE; + chan->PrimaryAddress = FALSE; + } + } + + KdPrint2((PRINT_PREFIX + "AtapiFindController: return SP_RETURN_FOUND\n")); + return(SP_RETURN_FOUND); + } +#ifndef UNIATA_CORE + } +#else + } while(FALSE); +#endif //UNIATA_CORE + + // The entire table has been searched and no adapters have been found. + // There is no need to call again and the device base can now be freed. + // Clear the adapter count for the next bus. + *Again = FALSE; + *(adapterCount) = 0; + + KdPrint2((PRINT_PREFIX + "AtapiFindController: return SP_RETURN_NOT_FOUND\n")); + return(SP_RETURN_NOT_FOUND); + +} // end AtapiFindController() + +BOOLEAN +UniataAnybodyHome( + IN PVOID HwDeviceExtension, + IN ULONG Channel, + IN ULONG deviceNumber + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[Channel]); + ULONG ldev = GET_LDEV2(Channel, deviceNumber, 0); + PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]); + + SATA_SSTATUS_REG SStatus; + UCHAR signatureLow; + + // Select the device. + SelectDrive(chan, deviceNumber); + + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + AtapiStallExecution(10); + + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, 0x55); + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, 0x55); + AtapiStallExecution(5); + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_BlockCount); + if(signatureLow != 0x55) { + KdPrint2((PRINT_PREFIX " nobody home! %#x != 0x55\n", signatureLow)); + LunExt->DeviceFlags = 0; + return FALSE; + } + + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, 0xAA); + AtapiWritePort1(chan, IDX_IO1_o_BlockCount, 0xAA); + AtapiStallExecution(5); + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_BlockCount); + if(signatureLow != 0xAA) { + KdPrint2((PRINT_PREFIX " nobody home! %#x != 0xAA\n", signatureLow)); + LunExt->DeviceFlags = 0; + return FALSE; + } + } else { + + SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus); + KdPrint2((PRINT_PREFIX "SStatus %x\n", SStatus.Reg)); + if(SStatus.DET <= SStatus_DET_Dev_NoPhy) { + KdPrint2((PRINT_PREFIX " SATA DET <= SStatus_DET_Dev_NoPhy\n")); + return FALSE; + } + if(SStatus.SPD < SStatus_SPD_Gen1) { + KdPrint2((PRINT_PREFIX " SATA SPD < SStatus_SPD_Gen1\n")); + return FALSE; + } + if(SStatus.IPM == SStatus_IPM_NoDev) { + KdPrint2((PRINT_PREFIX " SATA IPN == SStatus_IPM_NoDev\n")); + return FALSE; + } + } + + return TRUE; +} // end UniataAnybodyHome() + +ULONG +CheckDevice( + IN PVOID HwDeviceExtension, + IN ULONG Channel, + IN ULONG deviceNumber, + IN BOOLEAN ResetDev + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[Channel]); + ULONG ldev = GET_LDEV2(Channel, deviceNumber, 0); + PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]); + + UCHAR signatureLow, + signatureHigh; + UCHAR statusByte; + ULONG RetVal=0; + + KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x\n", + deviceNumber)); + if(ResetDev) { + KdPrint2((PRINT_PREFIX "CheckDevice: reset dev\n")); + + // Reset device + AtapiSoftReset(chan, deviceNumber); + + if(!UniataAnybodyHome(HwDeviceExtension, Channel, deviceNumber)) { + return 0; + } + statusByte = WaitOnBusy(chan); + + if((statusByte | IDE_STATUS_BUSY) == 0xff) { + KdPrint2((PRINT_PREFIX + "CheckDevice: bad status %x\n", statusByte)); + } else + if(statusByte != 0xff && (statusByte & IDE_STATUS_BUSY)) { + // Perform hard-reset. + KdPrint2((PRINT_PREFIX + "CheckDevice: BUSY\n")); + GetBaseStatus(chan, statusByte); + } + + if((statusByte | IDE_STATUS_BUSY) == 0xff) { + KdPrint2((PRINT_PREFIX + "CheckDevice: no dev ?\n")); + } else + if(deviceExtension->BaseIoAddressSATA_0.Addr) { + //if(deviceExtension->HwFlags & UNIATA_SATA) { + KdPrint2((PRINT_PREFIX + "CheckDevice: try enable SATA Phy\n")); + statusByte = UniataSataPhyEnable(HwDeviceExtension, Channel); + if(statusByte == 0xff) { + KdPrint2((PRINT_PREFIX "CheckDevice: status %#x (no dev)\n", statusByte)); + LunExt->DeviceFlags = 0; + return 0; + } + } + } + // Select the device. + SelectDrive(chan, deviceNumber); + + if(!UniataAnybodyHome(HwDeviceExtension, Channel, deviceNumber)) { + return 0; + } + + statusByte = WaitOnBaseBusyLong(chan); + + GetBaseStatus(chan, statusByte); + if(deviceExtension->HwFlags & UNIATA_SATA) { + UniataSataClearErr(HwDeviceExtension, Channel, UNIATA_SATA_IGNORE_CONNECT); + } + + KdPrint2((PRINT_PREFIX "CheckDevice: status %#x\n", statusByte)); + if(((statusByte | IDE_STATUS_BUSY) == 0xff) || + (statusByte & IDE_STATUS_BUSY)) { + KdPrint2((PRINT_PREFIX "CheckDevice: busy => return\n")); + LunExt->DeviceFlags = 0; + return 0; + } + + // set default costs + LunExt->RwSwitchCost = REORDER_COST_SWITCH_RW_HDD; + LunExt->RwSwitchMCost = REORDER_MCOST_SWITCH_RW_HDD; + LunExt->SeekBackMCost = REORDER_MCOST_SEEK_BACK_HDD; + + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); + signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + + if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) { + + KdPrint2((PRINT_PREFIX "CheckDevice: ATAPI signature found\n")); + // ATAPI signature found. + // Issue the ATAPI identify command if this + // is not for the crash dump utility. + + if (!deviceExtension->DriverMustPoll) { + + // Issue ATAPI packet identify command. + if (IssueIdentify(HwDeviceExtension, + deviceNumber, + Channel, + IDE_COMMAND_ATAPI_IDENTIFY, FALSE)) { + + // Indicate ATAPI device. + KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x is ATAPI\n", + deviceNumber)); + + RetVal = DFLAGS_DEVICE_PRESENT | DFLAGS_ATAPI_DEVICE; + LunExt->DeviceFlags |= (DFLAGS_DEVICE_PRESENT | DFLAGS_ATAPI_DEVICE); + + // some ATAPI devices doesn't work with DPC on CMD-649 + // and probably some other controllers + if(deviceExtension->HwFlags & UNIATA_NO_DPC_ATAPI) { + /* CMD 649, ROSB SWK33, ICH4 */ + KdPrint2((PRINT_PREFIX "CheckDevice: UNIATA_NO_DPC_ATAPI\n")); + deviceExtension->UseDpc = FALSE; + } + + GetStatus(chan, statusByte); + if (statusByte & IDE_STATUS_ERROR) { + AtapiSoftReset(chan, deviceNumber); + } + + } else { + + // Indicate no working device. + KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x not responding\n", + deviceNumber)); + + LunExt->DeviceFlags = 0; + RetVal = 0; + } + GetBaseStatus(chan, statusByte); + + } + + } else { + + KdPrint2((PRINT_PREFIX "CheckDevice: IDE device check\n")); + // Issue IDE Identify. If an Atapi device is actually present, the signature + // will be asserted, and the drive will be recognized as such. + if(deviceExtension->DWordIO) { + KdPrint2((PRINT_PREFIX " try 32bit IO\n")); + LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED; + } + if (IssueIdentify(HwDeviceExtension, + deviceNumber, + Channel, + IDE_COMMAND_IDENTIFY, FALSE)) { + + // IDE drive found. + KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x is IDE\n", + deviceNumber)); + + // Indicate IDE - not ATAPI device. + RetVal = DFLAGS_DEVICE_PRESENT; + LunExt->DeviceFlags |= DFLAGS_DEVICE_PRESENT; + LunExt->DeviceFlags &= ~DFLAGS_ATAPI_DEVICE; + } + GetBaseStatus(chan, statusByte); + } + KdPrint2((PRINT_PREFIX "CheckDevice: check status: %sfound\n", RetVal ? "" : "not ")); + return RetVal; +} // end CheckDevice() + + +/*++ + +Routine Description: + + This routine is called from AtapiFindController to identify + devices attached to an IDE controller. + +Arguments: + + HwDeviceExtension - HBA miniport driver's adapter data storage + AtapiOnly - Indicates that routine should return TRUE only if + an ATAPI device is attached to the controller. + +Return Value: + + TRUE - True if devices found. + +--*/ +BOOLEAN +FindDevices( + IN PVOID HwDeviceExtension, + IN BOOLEAN AtapiOnly, + IN ULONG Channel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &(deviceExtension->chan[Channel]); + BOOLEAN deviceResponded = FALSE, + skipSetParameters = FALSE; + ULONG waitCount = 10000; + //ULONG deviceNumber; + ULONG i; + UCHAR statusByte; + ULONG ldev; + ULONG max_ldev; + + KdPrint2((PRINT_PREFIX "FindDevices:\n")); + + // Disable interrupts + AtapiDisableInterrupts(deviceExtension, Channel); +// AtapiWritePort1(chan, IDX_IO2_o_Control,IDE_DC_DISABLE_INTERRUPTS | IDE_DC_A_4BIT ); + + // Clear expecting interrupt flag and current SRB field. + chan->ExpectingInterrupt = FALSE; +// chan->CurrentSrb = NULL; + max_ldev = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2; + KdPrint2((PRINT_PREFIX " max_ldev %d\n", max_ldev)); + + // Search for devices. + for (i = 0; i < max_ldev; i++) { + AtapiDisableInterrupts(deviceExtension, Channel); + deviceResponded |= + (CheckDevice(HwDeviceExtension, Channel, i, TRUE) != 0); + AtapiEnableInterrupts(deviceExtension, Channel); + } + + for (i = 0; i < max_ldev; i++) { + ldev = GET_LDEV2(Channel, i, 0); + + if (( deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT) && + !(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) && + !(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) && deviceResponded) { + + // This hideous hack is to deal with ESDI devices that return + // garbage geometry in the IDENTIFY data. + // This is ONLY for the crashdump environment as + // these are ESDI devices. + if (deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack == + 0x35 && + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads == + 0x07) { + + KdPrint2((PRINT_PREFIX + "FindDevices: Found nasty Compaq ESDI!\n")); + + // Change these values to something reasonable. + deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack = + 0x34; + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads = + 0x0E; + } + + if (deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack == + 0x35 && + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads == + 0x0F) { + + KdPrint2((PRINT_PREFIX + "FindDevices: Found nasty Compaq ESDI!\n")); + + // Change these values to something reasonable. + deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack = + 0x34; + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads = + 0x0F; + } + + + if (deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack == + 0x36 && + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads == + 0x07) { + + KdPrint2((PRINT_PREFIX "FindDevices: Found nasty UltraStor ESDI!\n")); + + // Change these values to something reasonable. + deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack = + 0x3F; + deviceExtension->lun[ldev].IdentifyData.NumberOfHeads = + 0x10; + skipSetParameters = TRUE; + } + + + if (skipSetParameters) + continue; + + statusByte = WaitOnBusy(chan); + + // Select the device. + SelectDrive(chan, i & 0x01); + GetStatus(chan, statusByte); + + if (statusByte & IDE_STATUS_ERROR) { + + // Reset the device. + KdPrint2((PRINT_PREFIX + "FindDevices: Resetting controller before SetDriveParameters.\n")); + + AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER ); + AtapiStallExecution(500 * 1000); + AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER); + SelectDrive(chan, i & 0x01); + + do { + // Wait for Busy to drop. + AtapiStallExecution(100); + GetStatus(chan, statusByte); + + } while ((statusByte & IDE_STATUS_BUSY) && waitCount--); + } + + statusByte = WaitOnBusy(chan); + + KdPrint2((PRINT_PREFIX + "FindDevices: Status before SetDriveParameters: (%#x) (%#x)\n", + statusByte, + AtapiReadPort1(chan, IDX_IO1_i_DriveSelect))); + + GetBaseStatus(chan, statusByte); + + // Use the IDENTIFY data to set drive parameters. + if (!SetDriveParameters(HwDeviceExtension,i,Channel)) { + + KdPrint2((PRINT_PREFIX + "FindDevices: Set drive parameters for device %d failed\n", + i)); + // Don't use this device as writes could cause corruption. + deviceExtension->lun[ldev].DeviceFlags = 0; + continue; + + } + if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE) { + + // Pick up ALL IDE removable drives that conform to Yosemite V0.2... + AtapiOnly = FALSE; + } + + // Indicate that a device was found. + if (!AtapiOnly) { + deviceResponded = TRUE; + } + } + } + +/* // Reset the controller. This is a feeble attempt to leave the ESDI + // controllers in a state that ATDISK driver will recognize them. + // The problem in ATDISK has to do with timings as it is not reproducible + // in debug. The reset should restore the controller to its poweron state + // and give the system enough time to settle. + if (!deviceResponded) { + + AtapiWritePort1(chan, IDX_IO2_o_Control,IDE_DC_RESET_CONTROLLER ); + AtapiStallExecution(50 * 1000); + AtapiWritePort1(chan, IDX_IO2_o_Control,IDE_DC_REENABLE_CONTROLLER); + } +*/ + if(deviceResponded) { + for (i = 0; i < max_ldev; i++) { + ldev = GET_LDEV2(Channel, i, 0); + + if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT) { + // Make sure some device (master is preferred) is selected on exit. + KdPrint2((PRINT_PREFIX + "FindDevices: select %d dev to clear INTR\n", i)); + SelectDrive(chan, i); + GetBaseStatus(chan, statusByte); + KdPrint2((PRINT_PREFIX + "FindDevices: statusByte=%#x\n", statusByte)); + } + } + for (i = 0; i < max_ldev; i++) { + ldev = GET_LDEV2(Channel, i, 0); + + if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT) { + // Make sure some device (master is preferred) is selected on exit. + KdPrint2((PRINT_PREFIX + "FindDevices: select %d dev on exit\n", i)); + SelectDrive(chan, i); + break; + } + } + } + + GetBaseStatus(chan, statusByte); + // Enable interrupts + AtapiEnableInterrupts(deviceExtension, Channel); +// AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_A_4BIT ); + GetBaseStatus(chan, statusByte); + + KdPrint2((PRINT_PREFIX + "FindDevices: returning %d\n", + deviceResponded)); + + return deviceResponded; + +} // end FindDevices() diff --git a/reactos/drivers/storage/ide/uniata/id_queue.cpp b/reactos/drivers/storage/ide/uniata/id_queue.cpp new file mode 100644 index 00000000000..5ec1a06e96d --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_queue.cpp @@ -0,0 +1,371 @@ +#include "stdafx.h" + +/* + Get cost of insertion Req1 before Req2 + */ +LONGLONG +UniataGetCost( + PHW_LU_EXTENSION LunExt, + IN PATA_REQ AtaReq1, + IN PATA_REQ AtaReq2 + ) +{ + BOOLEAN write1; + BOOLEAN write2; + UCHAR flags1; + UCHAR flags2; + LONGLONG cost; + // can't insert Req1 before tooooo old Req2 + if(!AtaReq2->ttl) + return REORDER_COST_TTL; + // check if reorderable + flags1 = AtaReq1->Flags; + flags2 = AtaReq2->Flags; + if(!((flags2 & flags1) & REQ_FLAG_REORDERABLE_CMD)) + return REORDER_COST_DENIED; + // if at least one Req is WRITE, target areas + // can not intersect + write1 = (flags1 & REQ_FLAG_RW_MASK) == REQ_FLAG_WRITE; + write2 = (flags2 & REQ_FLAG_RW_MASK) == REQ_FLAG_WRITE; + cost = AtaReq1->lba+AtaReq1->bcount - AtaReq2->lba; + if( write1 || write2 ) { + // check for intersection + if((AtaReq1->lba < AtaReq2->lba+AtaReq2->bcount) && + (AtaReq1->lba+AtaReq1->bcount > AtaReq2->lba)) { + // Intersection... + return REORDER_COST_INTERSECT; + } + } + if(cost < 0) { + cost *= (1-LunExt->SeekBackMCost); + } else { + cost *= (LunExt->SeekBackMCost-1); + } + if( write1 == write2 ) { + return cost; + } + return (cost * LunExt->RwSwitchMCost) + LunExt->RwSwitchCost; +} // end UniataGetCost() + +/* + Insert command to proper place of command queue + Perform reorder if necessary + */ +VOID +UniataQueueRequest( + IN PHW_CHANNEL chan, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + PATA_REQ AtaReq1; + PATA_REQ AtaReq2; + + LONGLONG best_cost; + LONGLONG new_cost; + LONGLONG new_cost1; + LONGLONG new_cost2; + PATA_REQ BestAtaReq1; + + BOOLEAN use_reorder = chan->UseReorder/*EnableReorder*/; +#ifdef QUEUE_STATISTICS + BOOLEAN reordered = FALSE; +#endif //QUEUE_STATISTICS + + PHW_LU_EXTENSION LunExt = chan->lun[GET_LDEV(Srb) & 1]; + AtaReq->Srb = Srb; + +/* +#ifdef _DEBUG + if(!LunExt) { + PrintNtConsole("q: chan = %#x, dev %#x\n", chan, GET_LDEV(Srb)); + int i; + for(i=0; i<1000; i++) { + AtapiStallExecution(5*1000); + } + return; + } +#endif //_DEBUG +*/ + // check if queue is empty + if(LunExt->queue_depth) { + AtaReq->ttl = (UCHAR)(max(LunExt->queue_depth, MIN_REQ_TTL)); + + // init loop + BestAtaReq1 = + AtaReq2 = LunExt->last_req; + + if(use_reorder && + (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE)) { + switch(Srb->QueueAction) { + case SRB_ORDERED_QUEUE_TAG_REQUEST: + use_reorder = FALSE; +#ifdef QUEUE_STATISTICS + chan->TryReorderTailCount++; +#endif //QUEUE_STATISTICS + break; + case SRB_HEAD_OF_QUEUE_TAG_REQUEST: + BestAtaReq1 = LunExt->first_req; + best_cost = -REORDER_COST_RESELECT; +#ifdef QUEUE_STATISTICS + chan->TryReorderHeadCount++; +#endif //QUEUE_STATISTICS + break; + case SRB_SIMPLE_TAG_REQUEST: + default: + best_cost = UniataGetCost(LunExt, BestAtaReq1, AtaReq); + use_reorder |= TRUE; + } + } else + if(use_reorder) { + best_cost = UniataGetCost(LunExt, BestAtaReq1, AtaReq); + } + + if(use_reorder) { + +#ifdef QUEUE_STATISTICS + chan->TryReorderCount++; +#endif //QUEUE_STATISTICS + + // walk through command queue and find the best + // place for insertion of the command + while (AtaReq1 = AtaReq2->prev_req) { + new_cost1 = UniataGetCost(LunExt, AtaReq1, AtaReq); + new_cost2 = UniataGetCost(LunExt, AtaReq, AtaReq2); + + if(new_cost1 == REORDER_COST_INTERSECT || + new_cost2 == REORDER_COST_INTERSECT) + chan->IntersectCount++; + + if(new_cost2 > REORDER_COST_RESELECT) + break; + + // for now I see nothing bad in RESELECT here + //ASSERT(new_cost1 <= REORDER_COST_RESELECT); + + new_cost = UniataGetCost(LunExt, AtaReq1, AtaReq2); + new_cost = new_cost1 + new_cost2 - new_cost; + + // check for Stop Reordering + if(new_cost > REORDER_COST_RESELECT*3) + break; + + if(new_cost < best_cost) { + best_cost = new_cost; + BestAtaReq1 = AtaReq1; +#ifdef QUEUE_STATISTICS + reordered = TRUE; +#endif //QUEUE_STATISTICS + } + AtaReq2 = AtaReq1; + } +#ifdef QUEUE_STATISTICS + if(reordered) + chan->ReorderCount++; +#endif //QUEUE_STATISTICS + } + // Insert Req between Req2 & Req1 + AtaReq2 = BestAtaReq1->next_req; + if(AtaReq2) { + AtaReq2->prev_req = AtaReq; + AtaReq->next_req = AtaReq2; + } else { + AtaReq->next_req = NULL; + LunExt->last_req = AtaReq; + } +// LunExt->last_req->next_req = AtaReq; + BestAtaReq1->next_req = AtaReq; +// AtaReq->prev_req = LunExt->last_req; + AtaReq->prev_req = BestAtaReq1; + + AtaReq1 = AtaReq; + while(AtaReq1 = AtaReq1->next_req) { + //ASSERT(AtaReq1->ttl); + AtaReq1->ttl--; + } + + } else { + // empty queue + AtaReq->ttl = 0; + AtaReq->prev_req = + AtaReq->next_req = NULL; + LunExt->first_req = + LunExt->last_req = AtaReq; + } + LunExt->queue_depth++; + chan->queue_depth++; + chan->DeviceExtension->queue_depth++; + // check if this is the 1st request in queue + if(chan->queue_depth == 1) { + chan->cur_req = LunExt->first_req; + } + +#ifdef QUEUE_STATISTICS + //ASSERT(LunExt->queue_depth); + chan->QueueStat[min(MAX_QUEUE_STAT, LunExt->queue_depth)-1]++; +#endif //QUEUE_STATISTICS +/* + ASSERT(chan->queue_depth == + (chan->lun[0]->queue_depth + chan->lun[1]->queue_depth)); + ASSERT(!chan->queue_depth || chan->cur_req); +*/ + return; +} // end UniataQueueRequest() + +/* + Remove request from queue and get next request + */ +VOID +UniataRemoveRequest( + IN PHW_CHANNEL chan, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + if(!Srb) + return; + if(!chan) + return; + + PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); + //PHW_DEVICE_EXTENSION deviceExtension = chan->DeviceExtension; + + ULONG cdev = GET_LDEV(Srb) & 1; + PHW_LU_EXTENSION LunExt = chan->lun[cdev]; + + if(!LunExt) + return; + +/* + ASSERT(chan->queue_depth == + (chan->lun[0]->queue_depth + chan->lun[1]->queue_depth)); + ASSERT(!chan->queue_depth || chan->cur_req); +*/ + // check if queue for the device is empty + if(!LunExt->queue_depth) + return; + + // check if request is under processing (busy) + if(!AtaReq->ReqState) + return; + + // remove reqest from queue + if(AtaReq->prev_req) { + AtaReq->prev_req->next_req = + AtaReq->next_req; + } else { + LunExt->first_req = AtaReq->next_req; + } + if(AtaReq->next_req) { + AtaReq->next_req->prev_req = + AtaReq->prev_req; + } else { + LunExt->last_req = AtaReq->prev_req; + } + LunExt->queue_depth--; + chan->queue_depth--; + chan->DeviceExtension->queue_depth--; + // set LastWrite flag for Lun + LunExt->last_write = ((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_WRITE); + + // get request from longest queue to balance load + if(chan->lun[0]->queue_depth * (chan->lun[0]->LunSelectWaitCount+1) > + chan->lun[1]->queue_depth * (chan->lun[1]->LunSelectWaitCount+1)) { + cdev = 0; + } else { + cdev = 1; + } +/* // prevent too long wait for actively used device + if(chan->lun[cdev ^ 1]->queue_depth && + chan->lun[cdev ^ 1]->LunSelectWaitCount >= chan->lun[cdev]->queue_depth) { + cdev = cdev ^ 1; + }*/ + // get next request for processing + chan->cur_req = chan->lun[cdev]->first_req; + chan->cur_cdev = cdev; + if(!chan->lun[cdev ^ 1]->queue_depth) { + chan->lun[cdev ^ 1]->LunSelectWaitCount=0; + } else { + chan->lun[cdev ^ 1]->LunSelectWaitCount++; + } + chan->lun[cdev]->LunSelectWaitCount=0; + +// chan->first_req->prev_req = NULL; + AtaReq->ReqState = REQ_STATE_NONE; +/* + ASSERT(chan->queue_depth == + (chan->lun[0]->queue_depth + chan->lun[1]->queue_depth)); + ASSERT(!chan->queue_depth || chan->cur_req); +*/ + return; +} // end UniataRemoveRequest() + +/* + Get currently processed request + (from head of the queue) + */ +PSCSI_REQUEST_BLOCK +UniataGetCurRequest( + IN PHW_CHANNEL chan + ) +{ +// if(!chan->lun[]->queue_depth) { + if(!chan || !chan->cur_req) { + return NULL; + } + + return chan->cur_req->Srb; +} // end UniataGetCurRequest() + +/* + Get next channel to be serviced + (used in simplex mode only) + */ +PHW_CHANNEL +UniataGetNextChannel( + IN PHW_CHANNEL chan + ) +{ + ULONG c=0, _c; + PHW_DEVICE_EXTENSION deviceExtension; + ULONG best_c; + ULONG cost_c; + + deviceExtension = chan->DeviceExtension; + + if(!deviceExtension->simplexOnly) { + return chan; + } + KdPrint2((PRINT_PREFIX "UniataGetNextChannel:\n")); + best_c = -1; + cost_c = 0; + for(_c=0; _cNumberChannels; _c++) { + c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels; + chan = &deviceExtension->chan[c]; + if(chan->queue_depth && + chan->queue_depth * (chan->ChannelSelectWaitCount+1) > + cost_c) { + best_c = c; + cost_c = chan->queue_depth * (chan->ChannelSelectWaitCount+1); + } + } + if(best_c == -1) { + KdPrint2((PRINT_PREFIX " empty queues\n")); + return NULL; + } + deviceExtension->FirstChannelToCheck = c; + for(_c=0; _cNumberChannels; _c++) { + chan = &deviceExtension->chan[_c]; + if(_c == best_c) { + chan->ChannelSelectWaitCount = 0; + continue; + } + chan->ChannelSelectWaitCount++; + if(!chan->queue_depth) { + chan->ChannelSelectWaitCount = 0; + } else { + chan->ChannelSelectWaitCount++; + } + } + KdPrint2((PRINT_PREFIX " select chan %d\n", best_c)); + return &deviceExtension->chan[best_c]; +} // end UniataGetNextChannel() diff --git a/reactos/drivers/storage/ide/uniata/id_queue.h b/reactos/drivers/storage/ide/uniata/id_queue.h new file mode 100644 index 00000000000..01548d31efb --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_queue.h @@ -0,0 +1,41 @@ +#ifndef __UNIATA_COMMAND_QUEUE_SUPPORT__H__ +#define __UNIATA_COMMAND_QUEUE_SUPPORT__H__ + +/* + Insert command to proper place of command queue + Perform reorder if necessary + */ +VOID +UniataQueueRequest( + IN PHW_CHANNEL chan, + IN PSCSI_REQUEST_BLOCK Srb + ); + +/* + Remove request from queue and get next request + */ +VOID +UniataRemoveRequest( + IN PHW_CHANNEL chan, + IN PSCSI_REQUEST_BLOCK Srb + ); + +/* + Get currently processed request + (from head of the queue) + */ +PSCSI_REQUEST_BLOCK +UniataGetCurRequest( + IN PHW_CHANNEL chan + ); + +/* + Get next channel to be serviced + (used in simplex mode only) + */ +PHW_CHANNEL +UniataGetNextChannel( + IN PHW_CHANNEL chan + ); + +#endif __UNIATA_COMMAND_QUEUE_SUPPORT__H__ \ No newline at end of file diff --git a/reactos/drivers/storage/ide/uniata/id_sata.cpp b/reactos/drivers/storage/ide/uniata/id_sata.cpp new file mode 100644 index 00000000000..0190e67eb5f --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_sata.cpp @@ -0,0 +1,289 @@ +#include "stdafx.h" + +UCHAR +UniataSataConnect( + IN PVOID HwDeviceExtension, + IN ULONG lChannel // logical channel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG Channel = deviceExtension->Channel + lChannel; + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + SATA_SSTATUS_REG SStatus; + ULONG i; +/* + UCHAR signatureLow, + signatureHigh; +*/ + UCHAR Status; + + KdPrint2((PRINT_PREFIX "UniataSataConnect:\n")); + + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + KdPrint2((PRINT_PREFIX " no I/O range\n")); + return IDE_STATUS_IDLE; + } + + /* clear SATA error register, some controllers need this */ + AtapiWritePort4(chan, IDX_SATA_SError, + AtapiReadPort4(chan, IDX_SATA_SError)); + /* wait up to 1 second for "connect well" */ + for(i=0; i<100; i++) { + SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus); + if(SStatus.SPD == SStatus_SPD_Gen1 || + SStatus.SPD == SStatus_SPD_Gen2) { + deviceExtension->lun[lChannel*2].TransferMode = ATA_SA150 + (UCHAR)(SStatus.SPD - 1); + break; + } + AtapiStallExecution(10000); + } + if(i >= 100) { + KdPrint2((PRINT_PREFIX "UniataSataConnect: SStatus %8.8x\n", SStatus.Reg)); + return 0xff; + } + /* clear SATA error register */ + AtapiWritePort4(chan, IDX_SATA_SError, + AtapiReadPort4(chan, IDX_SATA_SError)); + + Status = WaitOnBaseBusyLong(chan); + if(Status & IDE_STATUS_BUSY) { + return Status; + } +/* + signatureLow = AtapiReadPort1(chan, &deviceExtension->BaseIoAddress1[lChannel].i.CylinderLow); + signatureHigh = AtapiReadPort1(chan, &deviceExtension->baseIoAddress1[lChannel].i.CylinderHigh); + + if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) { + } +*/ + KdPrint2((PRINT_PREFIX "UniataSataConnect: OK, ATA status %x\n", Status)); + return IDE_STATUS_IDLE; +} // end UniataSataConnect() + +UCHAR +UniataSataPhyEnable( + IN PVOID HwDeviceExtension, + IN ULONG lChannel // logical channel + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + SATA_SCONTROL_REG SControl; + int loop, retry; + + KdPrint2((PRINT_PREFIX "UniataSataPhyEnable:\n")); + + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + KdPrint2((PRINT_PREFIX " no I/O range\n")); + return IDE_STATUS_IDLE; + } + + SControl.Reg = AtapiReadPort4(chan, IDX_SATA_SControl); + KdPrint2((PRINT_PREFIX "SControl %x\n", SControl.Reg)); + if(SControl.DET == SControl_DET_Idle) { + return UniataSataConnect(HwDeviceExtension, lChannel); + } + + for (retry = 0; retry < 10; retry++) { + KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry init %d\n", retry)); + for (loop = 0; loop < 10; loop++) { + SControl.Reg = 0; + SControl.DET = SControl_DET_Init; + AtapiWritePort4(chan, IDX_SATA_SControl, SControl.Reg); + AtapiStallExecution(100); + SControl.Reg = AtapiReadPort4(chan, IDX_SATA_SControl); + KdPrint2((PRINT_PREFIX " SControl %8.8%x\n", SControl.Reg)); + if(SControl.DET == SControl_DET_Init) { + break; + } + } + AtapiStallExecution(5000); + KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: retry idle %d\n", retry)); + for (loop = 0; loop < 10; loop++) { + SControl.Reg = 0; + SControl.DET = SControl_DET_DoNothing; + SControl.IPM = SControl_IPM_NoPartialSlumber; + AtapiWritePort4(chan, IDX_SATA_SControl, SControl.Reg); + AtapiStallExecution(100); + SControl.Reg = AtapiReadPort4(chan, IDX_SATA_SControl); + KdPrint2((PRINT_PREFIX " SControl %8.8%x\n", SControl.Reg)); + if(SControl.DET == SControl_DET_Idle) { + return UniataSataConnect(HwDeviceExtension, lChannel); + } + } + } + + KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: failed\n")); + return 0xff; +} // end UniataSataPhyEnable() + +BOOLEAN +UniataSataClearErr( + IN PVOID HwDeviceExtension, + IN ULONG lChannel, // logical channel + IN BOOLEAN do_connect + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK; + SATA_SSTATUS_REG SStatus; + SATA_SERROR_REG SError; + + if(deviceExtension->BaseIoAddressSATA_0.Addr) { + //if(ChipFlags & UNIATA_SATA) { + + SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus); + SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError); + + if(SStatus.Reg) { + KdPrint2((PRINT_PREFIX " SStatus %x\n", SStatus.Reg)); + } + if(SError.Reg) { + KdPrint2((PRINT_PREFIX " SError %x\n", SError.Reg)); + /* clear error bits/interrupt */ + AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg); + + if(do_connect) { + /* if we have a connection event deal with it */ + if(SError.DIAG.N) { + KdPrint2((PRINT_PREFIX " catch SATA connect/disconnect\n")); + if(SStatus.SPD >= SStatus_SPD_Gen1) { + UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH); + } else { + UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH); + } + return TRUE; + } + } + } + } + return FALSE; +} // end UniataSataClearErr() + +BOOLEAN +UniataSataEvent( + IN PVOID HwDeviceExtension, + IN ULONG lChannel, // logical channel + IN ULONG Action + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + UCHAR Status; + ULONG ldev = lChannel*2; + + if(!deviceExtension->BaseIoAddressSATA_0.Addr) { + return FALSE; + } + + switch(Action) { + case UNIATA_SATA_EVENT_ATTACH: + KdPrint2((PRINT_PREFIX " CONNECTED\n")); + Status = UniataSataConnect(HwDeviceExtension, lChannel); + KdPrint2((PRINT_PREFIX " Status %x\n", Status)); + if(Status != IDE_STATUS_IDLE) { + return FALSE; + } + CheckDevice(HwDeviceExtension, lChannel, 0 /*dev*/, FALSE); + return TRUE; + break; + case UNIATA_SATA_EVENT_DETACH: + KdPrint2((PRINT_PREFIX " DISCONNECTED\n")); + deviceExtension->lun[ldev].DeviceFlags = 0; + return TRUE; + break; + } + return FALSE; +} // end UniataSataEvent() + +BOOLEAN +UniataAhciInit( + IN PVOID HwDeviceExtension + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + ULONG version; + ULONG c; + PHW_CHANNEL chan; + ULONG offs; + ULONG BaseMemAddress; + ULONG PI; + ULONG CAP; + BOOLEAN MemIo; + + /* reset AHCI controller */ + AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC, + AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) | AHCI_GHC_HR); + AtapiStallExecution(1000000); + if(AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) & AHCI_GHC_HR) { + KdPrint2((PRINT_PREFIX " AHCI reset failed\n")); + return FALSE; + } + + /* enable AHCI mode */ + AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC, + AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) | AHCI_GHC_AE); + + CAP = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_CAP); + /* get the number of HW channels */ + deviceExtension->NumberChannels = + (CAP & AHCI_CAP_NOP_MASK)+1; + if(CAP & AHCI_CAP_S64A) { + KdPrint2((PRINT_PREFIX " AHCI 64bit\n")); + deviceExtension->Host64 = TRUE; + } + + /* clear interrupts */ + AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_IS, + AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_IS)); + + /* enable AHCI interrupts */ + AtapiWritePortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC, + AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_GHC) | AHCI_GHC_IE); + + version = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_VS); + PI = AtapiReadPortEx4(NULL, (ULONG)&deviceExtension->BaseIoAHCI_0, IDX_AHCI_PI); + KdPrint2((PRINT_PREFIX " AHCI version %x%x.%x%x controller with %d ports (mask %x) detected\n", + (version >> 24) & 0xff, (version >> 16) & 0xff, + (version >> 8) & 0xff, version & 0xff, deviceExtension->NumberChannels, PI)); + + + deviceExtension->HwFlags |= UNIATA_SATA; + deviceExtension->HwFlags |= UNIATA_AHCI; + + BaseMemAddress = deviceExtension->BaseIoAHCI_0.Addr; + MemIo = deviceExtension->BaseIoAHCI_0.MemIo; + + for(c=0; cNumberChannels; c++) { + chan = &deviceExtension->chan[c]; + offs = sizeof(IDE_AHCI_REGISTERS) + c*sizeof(IDE_AHCI_PORT_REGISTERS); + + chan->RegTranslation[IDX_IO1_i_Status ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.STS); + chan->RegTranslation[IDX_IO1_i_Status ].MemIo = MemIo; + chan->RegTranslation[IDX_IO2_AltStatus] = chan->RegTranslation[IDX_IO1_i_Status]; + chan->RegTranslation[IDX_IO1_i_Error ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, TFD.ERR); + chan->RegTranslation[IDX_IO1_i_Error ].MemIo = MemIo; + chan->RegTranslation[IDX_IO1_i_CylinderLow ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaLow); + chan->RegTranslation[IDX_IO1_i_CylinderLow ].MemIo = MemIo; + chan->RegTranslation[IDX_IO1_i_CylinderHigh].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.LbaHigh); + chan->RegTranslation[IDX_IO1_i_CylinderHigh].MemIo = MemIo; + chan->RegTranslation[IDX_IO1_i_BlockCount ].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SIG.SectorCount); + chan->RegTranslation[IDX_IO1_i_BlockCount ].MemIo = MemIo; + + UniataInitSyncBaseIO(chan); + + chan->RegTranslation[IDX_SATA_SStatus].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SSTS); + chan->RegTranslation[IDX_SATA_SStatus].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SError].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SERR); + chan->RegTranslation[IDX_SATA_SError].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SControl].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SCTL); + chan->RegTranslation[IDX_SATA_SControl].MemIo = MemIo; + chan->RegTranslation[IDX_SATA_SActive].Addr = BaseMemAddress + offs + FIELD_OFFSET(IDE_AHCI_PORT_REGISTERS, SACT); + chan->RegTranslation[IDX_SATA_SActive].MemIo = MemIo; + + chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; + } + + return TRUE; +} // end UniataAhciInit() + diff --git a/reactos/drivers/storage/ide/uniata/id_sata.h b/reactos/drivers/storage/ide/uniata/id_sata.h new file mode 100644 index 00000000000..96218899da9 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/id_sata.h @@ -0,0 +1,36 @@ +#ifndef __UNIATA_SATA__H__ +#define __UNIATA_SATA__H__ + +UCHAR +UniataSataConnect( + IN PVOID HwDeviceExtension, + IN ULONG lChannel // logical channel + ); + +UCHAR +UniataSataPhyEnable( + IN PVOID HwDeviceExtension, + IN ULONG lChannel // logical channel + ); + +#define UNIATA_SATA_DO_CONNECT TRUE +#define UNIATA_SATA_IGNORE_CONNECT FALSE + +BOOLEAN +UniataSataClearErr( + IN PVOID HwDeviceExtension, + IN ULONG lChannel, // logical channel + IN BOOLEAN do_connect + ); + +#define UNIATA_SATA_EVENT_ATTACH 0x01 +#define UNIATA_SATA_EVENT_DETACH 0x02 + +BOOLEAN +UniataSataEvent( + IN PVOID HwDeviceExtension, + IN ULONG lChannel, // logical channel + IN ULONG Action + ); + +#endif __UNIATA_SATA__H__ \ No newline at end of file diff --git a/reactos/drivers/storage/ide/uniata/idedma.def b/reactos/drivers/storage/ide/uniata/idedma.def new file mode 100644 index 00000000000..dfb97418b01 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/idedma.def @@ -0,0 +1,8 @@ +; IDEDMA.def + +NAME IDEDMA.SYS +DESCRIPTION 'IDEDMA.SYS' + +EXPORTS + + diff --git a/reactos/drivers/storage/ide/uniata/idedma.rc b/reactos/drivers/storage/ide/uniata/idedma.rc new file mode 100644 index 00000000000..878166ed757 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/idedma.rc @@ -0,0 +1,27 @@ +#include + +#include +#include "uniata_ver.h" + +#undef VERSION +#define VERSION "0." UNIATA_VER_STR +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR "AlterWare" +#define VER_FILEDESCRIPTION_STR "Universal IDE BusMaster (DMA) Miniport Driver" +#define VER_INTERNALNAME_STR "uniata.sys\0" +#define VER_ORIGINALFILENAME_STR "uniata.sys" +#define VER_LEGALCOPYRIGHT_YEARS "1999-2004" +#define VER_LEGALCOPYRIGHT_STR "Copyright \251 AlterWare" VER_LEGALCOPYRIGHT_YEARS +#undef VER_PRODUCTNAME_STR +#define VER_PRODUCTNAME_STR "UniATA" +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION 0,31,2 +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR VERSION +#undef VER_LEGALTRADEMARKS_STR + +#define VER_LANGNEUTRAL + +#include "common.ver" diff --git a/reactos/drivers/storage/ide/uniata/inc/CrNtDecl.h b/reactos/drivers/storage/ide/uniata/inc/CrNtDecl.h new file mode 100644 index 00000000000..86f5d41ec2e --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/inc/CrNtDecl.h @@ -0,0 +1,58 @@ + +#ifdef CROSSNT_DECL +#undef CROSSNT_DECL +#undef CROSSNT_DECL_EX +#endif //CROSSNT_DECL + +/***************************/ +#ifdef CROSSNT_DECL_API + +#define CROSSNT_DECL(type, dspec, name, args, callargs) \ +typedef type (dspec *ptr##name) args; \ +extern "C" ptr##name CrNt##name; \ +type dspec CrNt##name##_impl args; + +#define CROSSNT_DECL_EX(mod, type, dspec, name, args, callargs) \ +typedef type (dspec *ptr##name) args; \ +extern "C" ptr##name CrNt##name; \ +type dspec CrNt##name##_impl args; + +#endif //CROSSNT_DECL_API + +/***************************/ +#ifdef CROSSNT_DECL_STUB + +#define CROSSNT_DECL(type, dspec, name, args, callargs) \ +extern "C" ptr##name CrNt##name = NULL; \ + +#define CROSSNT_DECL_EX(mod, type, dspec, name, args, callargs) \ +extern "C" ptr##name CrNt##name = NULL; \ + +#endif //CROSSNT_DECL_STUB + +/***************************/ +#ifdef CROSSNT_INIT_STUB + +#define CROSSNT_DECL(type, dspec, name, args, callargs) \ + KdPrint(("Init " #name " cur %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = (ptr##name)CrNtGetProcAddress(g_hNtosKrnl, #name); \ + KdPrint((" GetProcAddr(NTOSKRNL.EXE," #name ") = %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = CrNt##name##_impl; \ + } \ + KdPrint((" final %\n", CrNt##name)); \ + } + +#define CROSSNT_DECL_EX(mod, type, dspec, name, args, callargs) \ + KdPrint(("Init " mod "," #name " cur %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = (ptr##name)CrNtGetProcAddress(CrNtGetModuleBase(mod), #name); \ + KdPrint((" GetProcAddr(" mod "," #name ") = %x\n", CrNt##name)); \ + if(!CrNt##name) { \ + CrNt##name = CrNt##name##_impl; \ + } \ + KdPrint((" final %x\n", CrNt##name)); \ + } + +#endif //CROSSNT_INIT_STUB diff --git a/reactos/drivers/storage/ide/uniata/inc/CrNtStubs.h b/reactos/drivers/storage/ide/uniata/inc/CrNtStubs.h new file mode 100644 index 00000000000..adb48606b9d --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/inc/CrNtStubs.h @@ -0,0 +1,109 @@ + +CROSSNT_DECL( +HANDLE,__stdcall, +PsGetCurrentProcessId,(),()) + +CROSSNT_DECL( +HANDLE,__stdcall, +PsGetCurrentThreadId,(),()) + +CROSSNT_DECL( +BOOLEAN, +__fastcall, +KeTestSpinLock,( + IN PKSPIN_LOCK SpinLock + ), + ( + SpinLock + )) + +CROSSNT_DECL( +LONG, +__fastcall, +InterlockedIncrement,( + IN OUT PLONG Addend + ), + ( + IN OUT PLONG Addend + )) + +CROSSNT_DECL( +LONG, +__fastcall, +InterlockedDecrement,( + IN OUT PLONG Addend + ), + ( + IN OUT PLONG Addend + )) + +CROSSNT_DECL( +LONG, +__fastcall, +InterlockedExchangeAdd,( + IN OUT PLONG Addend, + IN LONG Increment + ), + ( + IN OUT PLONG Addend, + IN LONG Increment + )) + +CROSSNT_DECL( +PVOID, +__fastcall, +InterlockedCompareExchange,( + IN OUT PVOID *Destination, + IN PVOID ExChange, + IN PVOID Comperand + ), + ( + IN OUT PVOID *Destination, + IN PVOID ExChange, + IN PVOID Comperand + )) + +CROSSNT_DECL_EX("HAL.DLL", +KIRQL,__stdcall, +KeRaiseIrqlToDpcLevel,(),()) + +CROSSNT_DECL_EX("HAL.DLL", +KIRQL,__stdcall, +KeRaiseIrqlToSynchLevel,(),()) + +CROSSNT_DECL_EX("NDIS.SYS", +VOID, +__stdcall, +NdisInitializeReadWriteLock,( + IN PNDIS_RW_LOCK Lock + ), + ( + Lock + )) + +CROSSNT_DECL_EX("NDIS.SYS", +VOID, +__stdcall, +NdisAcquireReadWriteLock,( + IN PNDIS_RW_LOCK Lock, + IN BOOLEAN fWrite, + IN PLOCK_STATE LockState + ), + ( + Lock, + fWrite, + LockState + )) + +CROSSNT_DECL_EX("NDIS.SYS", +VOID, +__stdcall, +NdisReleaseReadWriteLock,( + IN PNDIS_RW_LOCK Lock, + IN PLOCK_STATE LockState + ), + ( + Lock, + LockState + )) + diff --git a/reactos/drivers/storage/ide/uniata/inc/CrossNt.h b/reactos/drivers/storage/ide/uniata/inc/CrossNt.h new file mode 100644 index 00000000000..d76437350d6 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/inc/CrossNt.h @@ -0,0 +1,136 @@ +#ifndef __CROSS_VERSION_LIB_NT__H__ +#define __CROSS_VERSION_LIB_NT__H__ + +extern "C" { + +#pragma pack(push, 8) + +#if !defined(NT_INCLUDED) +#include // various NT definitions +#endif + +#include +#include +#include +#include +#include "ntddk_ex.h" +#include "tools.h" + +#include "rwlock.h" + +#ifdef CROSS_NT_INTERNAL +#include "ilock.h" +#endif //CROSS_NT_INTERNAL + +#include "misc.h" + +#pragma pack(pop) + +extern "C" +NTSTATUS +CrNtInit( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +extern "C" +PVOID +CrNtGetModuleBase( + IN PCHAR pModuleName + ); + +extern "C" +PVOID +CrNtFindModuleBaseByPtr( + IN PVOID ptrInSection, + IN PCHAR ptrExportedName + ); + +extern "C" +PVOID +CrNtGetProcAddress( + PVOID ModuleBase, + PCHAR pFunctionName + ); + +typedef BOOLEAN (__stdcall *ptrCrNtPsGetVersion)( + PULONG MajorVersion OPTIONAL, + PULONG MinorVersion OPTIONAL, + PULONG BuildNumber OPTIONAL, + PUNICODE_STRING CSDVersion OPTIONAL + ); + +extern "C" +ptrCrNtPsGetVersion CrNtPsGetVersion; + +typedef NTSTATUS (__stdcall *ptrCrNtNtQuerySystemInformation)( + IN SYSTEM_INFORMATION_CLASS SystemInfoClass, + OUT PVOID SystemInfoBuffer, + IN ULONG SystemInfoBufferSize, + OUT PULONG BytesReturned OPTIONAL + ); + +extern "C" +ptrCrNtNtQuerySystemInformation CrNtNtQuerySystemInformation; + + +extern "C" { + +extern ULONG MajorVersion; +extern ULONG MinorVersion; +extern ULONG BuildNumber; +extern ULONG SPVersion; + +extern HANDLE g_hNtosKrnl; +extern HANDLE g_hHal; + +}; + +#define WinVer_Is351 (MajorVersion==0x03) +#define WinVer_IsNT (MajorVersion==0x04) +#define WinVer_Is2k (MajorVersion==0x05 && MinorVersion==0x00) +#define WinVer_IsXP (MajorVersion==0x05 && MinorVersion==0x01) +#define WinVer_IsXPp (MajorVersion==0x05 && MinorVersion>=0x01) +#define WinVer_IsdNET (MajorVersion==0x05 && MinorVersion==0x02) +#define WinVer_IsdNETp ((MajorVersion==0x05 && MinorVersion>=0x02) || (MajorVersion>0x05)) +#define WinVer_IsVista (MajorVersion==0x06 && MinorVersion==0x00) + +#define WinVer_Id() ((MajorVersion << 8) | MinorVersion) + +#define WinVer_351 (0x0351) +#define WinVer_NT (0x0400) +#define WinVer_ROS (0x0401) +#define WinVer_2k (0x0500) +#define WinVer_XP (0x0501) +#define WinVer_dNET (0x0502) +#define WinVer_Vista (0x0600) + +#ifdef _DEBUG + +// NT3.51 doesn't export strlen() and strcmp() +// The same time, Release build doesn't depend no these functions since they are inlined + +size_t __cdecl CrNtstrlen ( + const char * str + ); + +int __cdecl CrNtstrcmp ( + const char * src, + const char * dst + ); + +#define strlen CrNtstrlen +#define strcmp CrNtstrcmp + +#endif //_DEBUG + +#define CROSSNT_DECL_API + +#include "CrNtDecl.h" +#include "CrNtStubs.h" + +#undef CROSSNT_DECL_API + +}; // end extern "C" + +#endif //__CROSS_VERSION_LIB_NT__H__ \ No newline at end of file diff --git a/reactos/drivers/storage/ide/uniata/inc/PostDbgMesg.h b/reactos/drivers/storage/ide/uniata/inc/PostDbgMesg.h new file mode 100644 index 00000000000..221cb159600 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/inc/PostDbgMesg.h @@ -0,0 +1,46 @@ +#ifndef __DBG_DUMP_TOOLS__H__ +#define __DBG_DUMP_TOOLS__H__ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +BOOLEAN +_cdecl +DbgDump_Printf( + PCHAR Format, + ... + ); + +BOOLEAN +__stdcall +DbgDump_Print( + PCHAR Msg + ); + +BOOLEAN +__stdcall +DbgDump_Printn( + PCHAR Msg, + ULONG Length + ); + +BOOLEAN +__stdcall +DbgDump_Reconnect(); + +VOID +__stdcall +DbgDump_Disconnect(); + +VOID +__stdcall +DbgDump_SetAutoReconnect( + BOOLEAN AutoReconnect + ); + +#ifdef __cplusplus +}; +#endif //__cplusplus + +#endif //__DBG_DUMP_TOOLS__H__ \ No newline at end of file diff --git a/reactos/drivers/storage/ide/uniata/inc/misc.h b/reactos/drivers/storage/ide/uniata/inc/misc.h new file mode 100644 index 00000000000..8fde91fc654 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/inc/misc.h @@ -0,0 +1,144 @@ +#ifndef __CROSSNT_MISC__H__ +#define __CROSSNT_MISC__H__ + +typedef void +(__fastcall *ptrMOV_DD_SWP)( + void* a, // ECX + void* b // EDX + ); +extern "C" ptrMOV_DD_SWP _MOV_DD_SWP; + +extern "C" +void +__fastcall +_MOV_DD_SWP_i486( + void* a, // ECX + void* b // EDX + ); + +extern "C" +void +__fastcall +_MOV_DD_SWP_i386( + void* a, // ECX + void* b // EDX + ); +#define MOV_DD_SWP(a,b) _MOV_DD_SWP(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_DW_SWP( + void* a, // ECX + void* b // EDX + ); + +#define MOV_DW_SWP(a,b) _MOV_DW_SWP(&(a),&(b)) + +/********************/ + +typedef void +(__fastcall *ptrREVERSE_DD)( + void* a // ECX + ); +extern "C" ptrREVERSE_DD _REVERSE_DD; + +void +__fastcall +_REVERSE_DD_i486( + void* a // ECX + ); + +void +__fastcall +_REVERSE_DD_i386( + void* a // ECX + ); +#define REVERSE_DD(a,b) _REVERSE_DD(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_REVERSE_DW( + void* a // ECX + ); + +#define REVERSE_DW(a) _REVERSE_DW(&(a)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_DW2DD_SWP( + void* a, // ECX + void* b // EDX + ); + +#define MOV_DW2DD_SWP(a,b) _MOV_DW2DD_SWP(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_SWP_DW2DD( + void* a, // ECX + void* b // EDX + ); + +#define MOV_SWP_DW2DD(a,b) _MOV_SWP_DW2DD(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_MOV_MSF( + void* a, // ECX + void* b // EDX + ); +#define MOV_MSF(a,b) _MOV_MSF(&(a),&(b)) + +/********************/ + +typedef void +(__fastcall *ptrMOV_MSF_SWP)( + void* a, // ECX + void* b // EDX + ); +extern "C" ptrMOV_MSF_SWP _MOV_MSF_SWP; + +extern "C" +void +__fastcall +_MOV_MSF_SWP_i486( + void* a, // ECX + void* b // EDX + ); + +extern "C" +void +__fastcall +_MOV_MSF_SWP_i386( + void* a, // ECX + void* b // EDX + ); +#define MOV_MSF_SWP(a,b) _MOV_MSF_SWP(&(a),&(b)) + +/********************/ + +extern "C" +void +__fastcall +_XCHG_DD( + void* a, // ECX + void* b // EDX + ); +#define XCHG_DD(a,b) _XCHG_DD(&(a),&(b)) + +#endif // __CROSSNT_MISC__H__ diff --git a/reactos/drivers/storage/ide/uniata/inc/rwlock.h b/reactos/drivers/storage/ide/uniata/inc/rwlock.h new file mode 100644 index 00000000000..b304781eddd --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/inc/rwlock.h @@ -0,0 +1,39 @@ +#ifndef __CROSS_NT_RWLOCK__H__ +#define __CROSS_NT_RWLOCK__H__ + +#ifndef MAXIMUM_PROCESSORS +#define MAXIMUM_PROCESSORS 32 +#endif + +typedef union _NDIS_RW_LOCK_REFCOUNT { + unsigned int RefCount; + UCHAR cacheLine[16]; // One refCount per cache line +} NDIS_RW_LOCK_REFCOUNT; + +typedef struct _NDIS_RW_LOCK { + union { + struct { + KSPIN_LOCK SpinLock; + PVOID Context; + }; + UCHAR Reserved[16]; + }; + + NDIS_RW_LOCK_REFCOUNT RefCount[MAXIMUM_PROCESSORS]; +} NDIS_RW_LOCK, *PNDIS_RW_LOCK; + +typedef struct _LOCK_STATE { + USHORT LockState; + KIRQL OldIrql; +} LOCK_STATE, *PLOCK_STATE; + +#define RWLOCK_STATE_FREE 0 +#define RWLOCK_STATE_READ_ACQUIRED 1 +#define RWLOCK_STATE_WRITE_ACQUIRED 2 +#define RWLOCK_STATE_RECURSIVE 3 +#define RWLOCK_STATE_RELEASED 0xffff + +#define RWLOCK_FOR_WRITE TRUE +#define RWLOCK_FOR_READ FALSE + +#endif __CROSS_NT_RWLOCK__H__ diff --git a/reactos/drivers/storage/ide/uniata/ntddk_ex.h b/reactos/drivers/storage/ide/uniata/ntddk_ex.h new file mode 100644 index 00000000000..a01a6b11ab2 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/ntddk_ex.h @@ -0,0 +1,571 @@ +#ifndef __NTDDK_EX__H__ +#define __NTDDK_EX__H__ + +typedef enum _SYSTEM_INFORMATION_CLASS { + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemNextEventIdInformation, + SystemEventIdsInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemPlugPlayBusInformation, + SystemDockInformation, + SystemPowerInformation, + SystemProcessorSpeedInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation +} SYSTEM_INFORMATION_CLASS; + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInfoClass, + OUT PVOID SystemInfoBuffer, + IN ULONG SystemInfoBufferSize, + OUT PULONG BytesReturned OPTIONAL +); + +NTSYSAPI +NTSTATUS +NTAPI +NtQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInfoClass, + OUT PVOID SystemInfoBuffer, + IN ULONG SystemInfoBufferSize, + OUT PULONG BytesReturned OPTIONAL +); + +typedef struct _SYSTEM_BASIC_INFORMATION { + ULONG Reserved; + ULONG TimerResolution; + ULONG PageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPageNumber; + ULONG HighestPhysicalPageNumber; + ULONG AllocationGranularity; + ULONG MinimumUserModeAddress; + ULONG MaximumUserModeAddress; + KAFFINITY ActiveProcessorsAffinityMask; + CCHAR NumberOfProcessors; +} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION; + +typedef struct _SYSTEM_MODULE_ENTRY +{ + ULONG Unused; + ULONG Always0; + PVOID ModuleBaseAddress; + ULONG ModuleSize; + ULONG Unknown; + ULONG ModuleEntryIndex; + USHORT ModuleNameLength; + USHORT ModuleNameOffset; + CHAR ModuleName [256]; +} SYSTEM_MODULE_ENTRY, * PSYSTEM_MODULE_ENTRY; + +typedef struct _SYSTEM_MODULE_INFORMATION +{ + ULONG Count; + SYSTEM_MODULE_ENTRY Module [1]; +} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; + +typedef unsigned short WORD; +typedef unsigned int BOOL; +typedef unsigned long DWORD; +typedef unsigned char BYTE; + + +typedef struct _LDR_DATA_TABLE_ENTRY { + LIST_ENTRY LoadOrder; + LIST_ENTRY MemoryOrder; + LIST_ENTRY InitializationOrder; + PVOID ModuleBaseAddress; + PVOID EntryPoint; + ULONG ModuleSize; + UNICODE_STRING FullModuleName; + UNICODE_STRING ModuleName; + ULONG Flags; + USHORT LoadCount; + USHORT TlsIndex; + union { + LIST_ENTRY Hash; + struct { + PVOID SectionPointer; + ULONG CheckSum; + }; + }; + ULONG TimeStamp; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + +typedef struct _PEB_LDR_DATA { + ULONG Length; + BOOLEAN Initialized; + HANDLE SsHandle; + LIST_ENTRY LoadOrder; + LIST_ENTRY MemoryOrder; + LIST_ENTRY InitializationOrder; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + +typedef struct _PEB_FREE_BLOCK { + struct _PEB_FREE_BLOCK *Next; + ULONG Size; +} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK; + +#define GDI_HANDLE_BUFFER_SIZE 34 + +#define TLS_MINIMUM_AVAILABLE 64 // winnt + +typedef struct _PEB { + BOOLEAN InheritedAddressSpace; // These four fields cannot change unless the + BOOLEAN ReadImageFileExecOptions; // + BOOLEAN BeingDebugged; // + BOOLEAN SpareBool; // + HANDLE Mutant; // INITIAL_PEB structure is also updated. + + PVOID ImageBaseAddress; + PPEB_LDR_DATA Ldr; + struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PVOID FastPebLockRoutine; + PVOID FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID KernelCallbackTable; + HANDLE EventLogSection; + PVOID EventLog; + PPEB_FREE_BLOCK FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[2]; // relates to TLS_MINIMUM_AVAILABLE + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID *ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + + // Useful information for LdrpInitialize + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + + // Passed up from MmCreatePeb from Session Manager registry key + + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + + // Where heap manager keeps track of all heaps created for a process + // Fields initialized by MmCreatePeb. ProcessHeaps is initialized + // to point to the first free byte after the PEB and MaximumNumberOfHeaps + // is computed from the page size used to hold the PEB, less the fixed + // size of this data structure. + + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID *ProcessHeaps; + + // + // + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + + // Following fields filled in by MmCreatePeb from system values and/or + // image header. + + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubsystem; + ULONG ImageSubsystemMajorVersion; + ULONG ImageSubsystemMinorVersion; + ULONG ImageProcessAffinityMask; + ULONG GdiHandleBuffer[GDI_HANDLE_BUFFER_SIZE]; +} PEB, *PPEB; + +// +// Gdi command batching +// + +#define GDI_BATCH_BUFFER_SIZE 310 + +typedef struct _GDI_TEB_BATCH { + ULONG Offset; + ULONG HDC; + ULONG Buffer[GDI_BATCH_BUFFER_SIZE]; +} GDI_TEB_BATCH,*PGDI_TEB_BATCH; + +// +// TEB - The thread environment block +// + +#define STATIC_UNICODE_BUFFER_LENGTH 261 +#define WIN32_CLIENT_INFO_LENGTH 31 +#define WIN32_CLIENT_INFO_SPIN_COUNT 1 + +typedef struct _TEB { + NT_TIB NtTib; + PVOID EnvironmentPointer; + CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + PVOID CsrClientThread; + PVOID Win32ThreadInfo; // PtiCurrent + ULONG Win32ClientInfo[WIN32_CLIENT_INFO_LENGTH]; // User32 Client Info + PVOID WOW32Reserved; // used by WOW + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + PVOID SystemReserved1[54]; // Used by FP emulator + PVOID Spare1; // unused + NTSTATUS ExceptionCode; // for RaiseUserException + UCHAR SpareBytes1[40]; + PVOID SystemReserved2[10]; // Used by user/console for temp obja + GDI_TEB_BATCH GdiTebBatch; // Gdi batching + ULONG gdiRgn; + ULONG gdiPen; + ULONG gdiBrush; + CLIENT_ID RealClientId; + HANDLE GdiCachedProcessHandle; + ULONG GdiClientPID; + ULONG GdiClientTID; + PVOID GdiThreadLocalInfo; + PVOID UserReserved[5]; // unused + PVOID glDispatchTable[280]; // OpenGL + ULONG glReserved1[26]; // OpenGL + PVOID glReserved2; // OpenGL + PVOID glSectionInfo; // OpenGL + PVOID glSection; // OpenGL + PVOID glTable; // OpenGL + PVOID glCurrentRC; // OpenGL + PVOID glContext; // OpenGL + ULONG LastStatusValue; + UNICODE_STRING StaticUnicodeString; + WCHAR StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH]; + PVOID DeallocationStack; + PVOID TlsSlots[TLS_MINIMUM_AVAILABLE]; + LIST_ENTRY TlsLinks; + PVOID Vdm; + PVOID ReservedForNtRpc; + PVOID DbgSsReserved[2]; + ULONG HardErrorsAreDisabled; + PVOID Instrumentation[16]; + PVOID WinSockData; // WinSock + ULONG GdiBatchCount; + ULONG Spare2; + ULONG Spare3; + ULONG Spare4; + PVOID ReservedForOle; + ULONG WaitingOnLoaderLock; +} TEB; +typedef TEB *PTEB; + +typedef struct _KTHREAD_HDR { + + // + // The dispatcher header and mutant listhead are faifly infrequently + // referenced, but pad the thread to a 32-byte boundary (assumption + // that pool allocation is in units of 32-bytes). + // + + DISPATCHER_HEADER Header; + LIST_ENTRY MutantListHead; + + // + // The following fields are referenced during trap, interrupts, or + // context switches. + // + // N.B. The Teb address and TlsArray are loaded as a quadword quantity + // on MIPS and therefore must to on a quadword boundary. + // + + PVOID InitialStack; + PVOID StackLimit; + PVOID Teb; + PVOID TlsArray; + PVOID KernelStack; + BOOLEAN DebugActive; + UCHAR State; + BOOLEAN Alerted[MaximumMode]; + UCHAR Iopl; + UCHAR NpxState; + BOOLEAN Saturation; + SCHAR Priority; +/* KAPC_STATE ApcState; + ULONG ContextSwitches; + + // + // The following fields are referenced during wait operations. + // + + NTSTATUS WaitStatus; + KIRQL WaitIrql; + KPROCESSOR_MODE WaitMode; + BOOLEAN WaitNext; + UCHAR WaitReason; + PRKWAIT_BLOCK WaitBlockList; + LIST_ENTRY WaitListEntry; + ULONG WaitTime; + SCHAR BasePriority; + UCHAR DecrementCount; + SCHAR PriorityDecrement; + SCHAR Quantum; + KWAIT_BLOCK WaitBlock[THREAD_WAIT_OBJECTS + 1]; + PVOID LegoData; + ULONG KernelApcDisable; + KAFFINITY UserAffinity; + BOOLEAN SystemAffinityActive; + UCHAR Pad[3]; + PVOID ServiceTable; +// struct _ECHANNEL *Channel; +// PVOID Section; +// PCHANNEL_MESSAGE SystemView; +// PCHANNEL_MESSAGE ThreadView; + + // + // The following fields are referenced during queue operations. + // + + PRKQUEUE Queue; + KSPIN_LOCK ApcQueueLock; + KTIMER Timer; + LIST_ENTRY QueueListEntry; + + // + // The following fields are referenced during read and find ready + // thread. + // + + KAFFINITY Affinity; + BOOLEAN Preempted; + BOOLEAN ProcessReadyQueue; + BOOLEAN KernelStackResident; + UCHAR NextProcessor; + + // + // The following fields are referenced suring system calls. + // + + PVOID CallbackStack; + PVOID Win32Thread; + PKTRAP_FRAME TrapFrame; + PKAPC_STATE ApcStatePointer[2]; + UCHAR EnableStackSwap; + UCHAR LargeStack; + UCHAR ResourceIndex; + CCHAR PreviousMode; + + // + // The following entries are reference during clock interrupts. + // + + ULONG KernelTime; + ULONG UserTime; + + // + // The following fileds are referenced during APC queuing and process + // attach/detach. + // + + KAPC_STATE SavedApcState; + BOOLEAN Alertable; + UCHAR ApcStateIndex; + BOOLEAN ApcQueueable; + BOOLEAN AutoAlignment; + + // + // The following fields are referenced when the thread is initialized + // and very infrequently thereafter. + // + + PVOID StackBase; + KAPC SuspendApc; + KSEMAPHORE SuspendSemaphore; + LIST_ENTRY ThreadListEntry; + + // + // N.B. The below four UCHARs share the same DWORD and are modified + // by other threads. Therefore, they must ALWAYS be modified + // under the dispatcher lock to prevent granularity problems + // on Alpha machines. + // + CCHAR FreezeCount; + CCHAR SuspendCount; + UCHAR IdealProcessor; + UCHAR DisableBoost; +*/ +} KTHREAD_HDR, *PKTHREAD_HDR; + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + LONG e_lfanew; // File address of new exe header +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + + // + // NT additional fields. + // + + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; // RVA from base of image + DWORD AddressOfNames; // RVA from base of image + DWORD AddressOfNameOrdinals; // RVA from base of image +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +NTHALAPI +VOID +HalDisplayString ( + PUCHAR String + ); + +NTHALAPI +VOID +HalQueryDisplayParameters ( + OUT PULONG WidthInCharacters, + OUT PULONG HeightInLines, + OUT PULONG CursorColumn, + OUT PULONG CursorRow + ); + +NTHALAPI +VOID +HalSetDisplayParameters ( + IN ULONG CursorColumn, + IN ULONG CursorRow + ); + +extern ULONG NtBuildNumber; + +#endif //__NTDDK_EX__H__ diff --git a/reactos/drivers/storage/ide/uniata/ntddscsi.h b/reactos/drivers/storage/ide/uniata/ntddscsi.h new file mode 100644 index 00000000000..6ec175ae80c --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/ntddscsi.h @@ -0,0 +1,235 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1990-1993 Microsoft Corporation + +Module Name: + + ntddscsi.h + +Abstract: + + This is the include file that defines all constants and types for + accessing the SCSI port adapters. + +Author: + + Jeff Havens + +Revision History: + +--*/ + +#ifndef _NTDDSCSIH_ +#define _NTDDSCSIH_ + +#pragma pack(push, 8) + +// +// Device Name - this string is the name of the device. It is the name +// that should be passed to NtOpenFile when accessing the device. +// +// Note: For devices that support multiple units, it should be suffixed +// with the Ascii representation of the unit number. +// + +#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER + +#define DD_SCSI_DEVICE_NAME "\\Device\\ScsiPort" + + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// Define the SCSI pass through structure. +// + +typedef struct _SCSI_PASS_THROUGH { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + +// +// Define the SCSI pass through direct structure. +// + +typedef struct _SCSI_PASS_THROUGH_DIRECT { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + +// +// Define SCSI information. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_BUS_DATA { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +}SCSI_BUS_DATA, *PSCSI_BUS_DATA; + +// +// Define SCSI adapter bus information structure.. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_ADAPTER_BUS_INFO { + UCHAR NumberOfBuses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + +// +// Define SCSI adapter bus information. +// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL. +// + +typedef struct _SCSI_INQUIRY_DATA { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +}SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + +// +// Define header for I/O control SRB. +// + +typedef struct _SRB_IO_CONTROL { + ULONG HeaderLength; + UCHAR Signature[8]; + ULONG Timeout; + ULONG ControlCode; + ULONG ReturnCode; + ULONG Length; +} SRB_IO_CONTROL, *PSRB_IO_CONTROL; + +// +// SCSI port driver capabilities structure. +// + +typedef struct _IO_SCSI_CAPABILITIES { + + // + // Length of this structure + // + + ULONG Length; + + // + // Maximum transfer size in single SRB + // + + ULONG MaximumTransferLength; + + // + // Maximum number of physical pages per data buffer + // + + ULONG MaximumPhysicalPages; + + // + // Async calls from port to class + // + + ULONG SupportedAsynchronousEvents; + + // + // Alignment mask for data transfers. + // + + ULONG AlignmentMask; + + // + // Supports tagged queuing + // + + BOOLEAN TaggedQueuing; + + // + // Host adapter scans down for bios devices. + // + + BOOLEAN AdapterScansDown; + + // + // The host adapter uses programmed I/O. + // + + BOOLEAN AdapterUsesPio; + +} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES; + +typedef struct _SCSI_ADDRESS { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +}SCSI_ADDRESS, *PSCSI_ADDRESS; + +// +// Define structure for returning crash dump pointers. +// + +struct _ADAPTER_OBJECT; + +typedef struct _DUMP_POINTERS { + struct _ADAPTER_OBJECT *AdapterObject; + PVOID MappedRegisterBase; + PVOID PortConfiguration; + PVOID CommonBufferVa; + LARGE_INTEGER CommonBufferPa; + ULONG CommonBufferSize; +} DUMP_POINTERS, *PDUMP_POINTERS; + +// +// Define values for pass-through DataIn field. +// + +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +#pragma pack(pop) + +#endif + diff --git a/reactos/drivers/storage/ide/uniata/scsi.h b/reactos/drivers/storage/ide/uniata/scsi.h new file mode 100644 index 00000000000..b6d639554af --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/scsi.h @@ -0,0 +1,2849 @@ +/*++ + +Copyright (c) 2002-2005 Alexandr A. Telyatnikov (Alter) + +Module Name: + scsi.h + +Abstract: + This file contains SCSI protocol definitions + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + +--*/ +#ifndef __CDRW_DEVICE_H__ +#define __CDRW_DEVICE_H__ + +#include "srb.h" + +#pragma pack(push, 1) + +// Command Descriptor Block. Passed by SCSI controller chip over the SCSI bus + +typedef union _CDB { + + // Generic 6-Byte CDB + struct _CDB6 { + UCHAR OperationCode; + UCHAR Immediate : 1; + UCHAR CommandUniqueBits : 4; + UCHAR Lun : 3; + UCHAR CommandUniqueBytes[3]; + UCHAR Link : 1; + UCHAR Flag : 1; + UCHAR Reserved : 4; + UCHAR VendorUnique : 2; + } CDB6, *PCDB6; + + struct _REQUEST_SENSE { + UCHAR OperationCode; + UCHAR Reserved0 : 5; + UCHAR Lun : 3; + UCHAR Reserved1[2]; + UCHAR AllocationLength; + UCHAR Link : 1; + UCHAR Flag : 1; + UCHAR Reserved2 : 6; + } REQUEST_SENSE, *PREQUEST_SENSE; + + // Standard 6-byte CDB + struct _CDB6READWRITE { + UCHAR OperationCode; + UCHAR LBA2 : 5; + UCHAR Lun : 3; + UCHAR LBA0[2]; + UCHAR NumOfBlocks; + UCHAR Control; + } CDB6READWRITE, *PCDB6READWRITE; + + // SCSI Inquiry CDB + struct _CDB6INQUIRY { + UCHAR OperationCode; + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR PageCode; + UCHAR IReserved; + UCHAR AllocationLength; + UCHAR Control; + } CDB6INQUIRY, *PCDB6INQUIRY; + + // SCSI Format CDB + + struct _ERASE { + UCHAR OperationCode; + UCHAR Long : 1; + UCHAR Immediate : 1; + UCHAR Reserved1 : 3; + UCHAR Lun : 3; + UCHAR Reserved2[3]; + UCHAR Control; + } ERASE, *PERASE; + +#define FormatUnit_Code_Mask 0x07 +#define FormatUnit_Cmp 0x08 +#define FormatUnit_Fmt 0x10 + + struct _CDB6FORMAT { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR FormatCode : 3; + UCHAR Cmp:1; + UCHAR Fmt:1; + UCHAR Lun : 3; + } Fields; + } Byte1; + UCHAR FReserved1; + UCHAR Interleave[2]; + UCHAR FReserved2; + } CDB6FORMAT, *PCDB6FORMAT; + + // Standard 10-byte CDB + struct _CDB10 { + UCHAR OperationCode; + UCHAR RelativeAddress : 1; + UCHAR Reserved1 : 2; + UCHAR ForceUnitAccess : 1; + UCHAR DisablePageOut : 1; + UCHAR Lun : 3; + UCHAR LBA[4]; + UCHAR Reserved2; + UCHAR TransferBlocks[2]; + UCHAR Control; + } CDB10, *PCDB10; + + // CD Rom Audio CDBs + +#define PauseResume_Pause 0x00 +#define PauseResume_Resume 0x01 + + struct _PAUSE_RESUME { + UCHAR OperationCode; + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR Reserved2[6]; + UCHAR Action; + UCHAR Control; + } PAUSE_RESUME, *PPAUSE_RESUME; + + // Read Table of Contents (TOC) + +#define ReadTOC_Format_Mask 0x0f +#define ReadTOC_Format_TOC 0x00 +#define ReadTOC_Format_SesInfo 0x01 +#define ReadTOC_Format_FullTOC 0x02 +#define ReadTOC_Format_PMA 0x03 +#define ReadTOC_Format_ATIP 0x04 +#define ReadTOC_Format_CdText 0x05 + + struct _READ_TOC { + UCHAR OperationCode; + UCHAR Reserved0 : 1; + UCHAR Msf : 1; // HMSF MMC-3 + UCHAR Reserved1 : 3; + UCHAR Lun : 3; + + union { + UCHAR Flags; + struct { + UCHAR Format : 4; + UCHAR Reserved : 4; + } Fields; + } Byte2; + + UCHAR Reserved2[3]; + UCHAR Start_TrackSes;; + UCHAR AllocationLength[2]; + UCHAR Control : 6; + UCHAR Format : 2; + } READ_TOC, *PREAD_TOC; + + // Play Audio MSF + struct _PLAY_AUDIO_MSF { + UCHAR OperationCode; + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR Reserved2; + UCHAR StartingMSF[3]; + UCHAR EndingMSF[3]; + UCHAR Control; + } PLAY_AUDIO_MSF, *PPLAY_AUDIO_MSF; + + // Read SubChannel Data + +#define SubChannel_SubQ_Header 0x00 +#define SubChannel_SubQ_Block 0x01 + + struct _SUBCHANNEL { + UCHAR OperationCode; + UCHAR Reserved0 : 1; + UCHAR Msf : 1; + UCHAR Reserved1 : 3; + UCHAR Lun : 3; + UCHAR Reserved2 : 6; + UCHAR SubQ : 1; + UCHAR Reserved3 : 1; + UCHAR Format; + UCHAR Reserved4[2]; + UCHAR TrackNumber; + UCHAR AllocationLength[2]; + UCHAR Control; + } SUBCHANNEL, *PSUBCHANNEL; + + // Read CD (by LBA/MSF). Used by Atapi for raw sector reads. + +#define ReadCD_SecType_Mask 0x1c +#define ReadCD_SecType_Any 0x00 +#define ReadCD_SecType_CDDA 0x04 +#define ReadCD_SecType_M1 0x08 +#define ReadCD_SecType_M2 0x0c +#define ReadCD_SecType_M2F1 0x10 +#define ReadCD_SecType_M2F2 0x14 + + struct _READ_CD_MSF { + UCHAR OperationCode; + + UCHAR Reserved0 : 2; + UCHAR ExpectedSectorType : 3; + UCHAR Reserved1 : 3; + + UCHAR Reserved2; + UCHAR Starting_MSF[3]; + UCHAR Ending_MSF[3]; + + UCHAR Reserved3 : 1; + UCHAR ErrorFlags : 2; + UCHAR IncludeEDC : 1; + UCHAR IncludeUserData : 1; + UCHAR HeaderCode : 2; + UCHAR IncludeSyncData : 1; + + UCHAR SubChannelSelection : 3; + UCHAR Reserved4 : 5; + + UCHAR Control; + } READ_CD_MSF, *PREAD_CD_MSF; + + struct _READ_CD { + UCHAR OperationCode; + + UCHAR Reserved0 : 2; + UCHAR ExpectedSectorType : 3; + UCHAR Reserved1 : 3; + + UCHAR LBA[4]; + UCHAR NumOfBlocks[3]; + + UCHAR Reserved3 : 1; + UCHAR ErrorFlags : 2; + UCHAR IncludeEDC : 1; + UCHAR IncludeUserData : 1; + UCHAR HeaderCode : 2; + UCHAR IncludeSyncData : 1; + + UCHAR SubChannelSelection : 3; + UCHAR Reserved4 : 5; + + UCHAR Control; + } READ_CD, *PREAD_CD; + +#define WriteCd_RELADR 0x01 +#define WriteCd_FUA 0x08 +#define WriteCd_DPO 0x10 + + struct _WRITE_CD { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR RELADR : 1; + UCHAR Reserved0 : 2; + UCHAR FUA : 1; + UCHAR DPO : 1; + UCHAR Reserved1 : 3; + } Fields; + } Byte1; + UCHAR LBA [4]; + UCHAR Reserved1; + UCHAR NumOfBlocks [2]; + UCHAR Reserved2 [3]; + } WRITE_CD, *PWRITE_CD; + + // Mode sense + struct _MODE_SENSE { + UCHAR OperationCode; + UCHAR Reserved1 : 3; + UCHAR Dbd : 1; + UCHAR Reserved2 : 1; + UCHAR Lun : 3; + UCHAR PageCode : 6; + UCHAR Pc : 2; + UCHAR Reserved3; + UCHAR AllocationLength; + UCHAR Control; + } MODE_SENSE, *PMODE_SENSE; + + struct _MODE_SENSE10 { + UCHAR OperationCode; + UCHAR Reserved1 : 3; + UCHAR Dbd : 1; + UCHAR Reserved2 : 1; + UCHAR Lun : 3; + UCHAR PageCode : 6; + UCHAR Pc : 2; + UCHAR Reserved3[4]; + UCHAR AllocationLength[2]; + UCHAR Control; + } MODE_SENSE10, *PMODE_SENSE10; + + // Mode select + struct _MODE_SELECT { + UCHAR OperationCode; + UCHAR SPBit : 1; + UCHAR Reserved1 : 3; + UCHAR PFBit : 1; + UCHAR Lun : 3; + UCHAR Reserved2[2]; + UCHAR ParameterListLength; + UCHAR Control; + } MODE_SELECT, *PMODE_SELECT; + + struct _MODE_SELECT10 { + UCHAR OperationCode; + UCHAR SPBit : 1; + UCHAR Reserved1 : 3; + UCHAR PFBit : 1; + UCHAR Lun : 3; + UCHAR Reserved2[5]; + UCHAR ParameterListLength[2]; + UCHAR Control; + } MODE_SELECT10, *PMODE_SELECT10; + + struct _LOGSENSE { + UCHAR OperationCode; + UCHAR SPBit : 1; + UCHAR PPCBit : 1; + UCHAR Reserved1 : 3; + UCHAR Lun : 3; + UCHAR PageCode : 6; + UCHAR PCBit : 2; + UCHAR Reserved2; + UCHAR Reserved3; + UCHAR ParameterPointer[2]; // [0]=MSB, [1]=LSB + UCHAR AllocationLength[2]; // [0]=MSB, [1]=LSB + UCHAR Control; + } LOGSENSE, *PLOGSENSE; + + struct _SEEK { + UCHAR OperationCode; + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR LBA[4]; + UCHAR Reserved2[3]; + UCHAR Control; + } SEEK, *PSEEK; + +#define StartStop_Start 0x01 +#define StartStop_Load 0x02 + + struct _START_STOP { + UCHAR OperationCode; + UCHAR Immediate: 1; + UCHAR Reserved1 : 4; + UCHAR Lun : 3; + UCHAR Reserved2[2]; + UCHAR Start : 1; + UCHAR LoadEject : 1; + UCHAR Reserved3 : 6; + UCHAR Control; + } START_STOP, *PSTART_STOP; + + struct _MEDIA_REMOVAL { + UCHAR OperationCode; + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR Reserved2[2]; + UCHAR Prevent; + UCHAR Control; + } MEDIA_REMOVAL, *PMEDIA_REMOVAL; + + struct _READ_FORMAT_CAPACITIES { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR Reserved0 : 5; + UCHAR Reserved1 : 3; + } Fields; + } Byte1; + UCHAR Reserved0[5]; + UCHAR AllocationLength[2]; + UCHAR Control; + } READ_FORMAT_CAPACITIES, *PREAD_FORMAT_CAPACITIES; + + // Atapi 2.5 Changer 12-byte CDBs +#define LoadUnload_Start 0x01 +#define LoadUnload_Load 0x02 + + struct _LOAD_UNLOAD { + UCHAR OperationCode; + UCHAR Immediate : 1; + UCHAR Reserved1 : 7; + UCHAR Reserved2[2]; + UCHAR Start : 1; + UCHAR LoadEject : 1; + UCHAR Reserved3: 6; + UCHAR Reserved4[3]; + UCHAR Slot; + UCHAR Reserved5[3]; + } LOAD_UNLOAD, *PLOAD_UNLOAD; + + struct _MECH_STATUS { + UCHAR OperationCode; + UCHAR Reserved0[7]; + UCHAR AllocationLength[2]; + UCHAR Reserved2[2]; + } MECH_STATUS, *PMECH_STATUS; + + struct _LOCK_DOOR { + UCHAR OperationCode; + UCHAR Reserved0[9]; + } LOCK_DOOR, *PLOCK_DOOR; + +#define EventStat_Immed 0x01 + +#define EventStat_Class_OpChange 0x02 +#define EventStat_Class_PM 0x04 +#define EventStat_Class_ExternalReq 0x08 +#define EventStat_Class_Media 0x10 +#define EventStat_Class_MultiInit 0x20 +#define EventStat_Class_DevBusy 0x40 + + struct _GET_EVENT_STATUS { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR Immed : 1; + UCHAR Reserved0 : 7; + } Fields; + } Byte1; + UCHAR Reserved0[2]; + UCHAR NotificationClass; + UCHAR Reserved1[2]; + UCHAR AllocationLength[2]; + UCHAR Control; + } GET_EVENT_STATUS, *PGET_EVENT_STATUS; + + struct _READ_DISC_INFO { + UCHAR OperationCode; + UCHAR Reserved0[6]; + UCHAR AllocationLength[2]; + UCHAR Reserved2[3]; + } READ_DISC_INFO, *PREAD_DISC_INFO; + +#define ReadTrackInfo_Type_Mask 0x01 +#define ReadTrackInfo_Type_LBA 0x00 +#define ReadTrackInfo_Type_Track 0x01 + +#define ReadTrackInfo_LastTrk 0xff + + struct _READ_TRACK_INFO { + UCHAR OperationCode; + UCHAR Track : 1; + UCHAR Reserved0 : 7; + UCHAR LBA_TrkNum [4]; + UCHAR Reserved1; + UCHAR AllocationLength[2]; + UCHAR Reserved2[3]; + } READ_TRACK_INFO, *PREAD_TRACK_INFO; + +#define ReadTrackInfo3_Type_Mask 0x03 +#define ReadTrackInfo3_Type_LBA ReadTrackInfo_Type_LBA +#define ReadTrackInfo3_Type_Track ReadTrackInfo_Type_Track +#define ReadTrackInfo3_Type_Ses 0x02 + +#define ReadTrackInfo3_LastTrk ReadTrackInfo_LastTrk +#define ReadTrackInfo3_DiscLeadIn 0x00 // for Track type + + struct _READ_TRACK_INFO_3 { + UCHAR OperationCode; + UCHAR DataType : 2; + UCHAR Reserved0 : 6; + UCHAR LBA_TrkNum [4]; + UCHAR Reserved1; + UCHAR AllocationLength[2]; + UCHAR Reserved2[3]; + } READ_TRACK_INFO_3, *PREAD_TRACK_INFO_3; + + struct _RESERVE_TRACK { + UCHAR OperationCode; + UCHAR Reserved0[4]; + UCHAR Size[4]; + UCHAR Reserved2[3]; + } RESERVE_TRACK, *PRESERVE_TRACK; + +#define CloseTrkSes_Immed 0x01 + +#define CloseTrkSes_Trk 0x01 +#define CloseTrkSes_Ses 0x02 + +#define CloseTrkSes_LastTrkSes 0xff + +#define CloseTrkSes_Delay DEF_I64(3100000000) // 310 s + + struct _CLOSE_TRACK_SESSION { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR Immed : 1; + UCHAR Reserved0 : 7; + } Fields; + } Byte1; + union { + UCHAR Flags; + struct { + UCHAR Track : 1; + UCHAR Session : 1; + UCHAR Reserved0 : 6; + } Fields; + } Byte2; + UCHAR Reserved1 [2]; + UCHAR TrackNum; + UCHAR Reserved2 [6]; + + } CLOSE_TRACK_SESSION, *PCLOSE_TRACK_SESSION; + + struct _SET_CD_SPEED { + UCHAR OperationCode; + UCHAR Reserved0; + UCHAR ReadSpeed [2]; // Kbyte/sec + UCHAR WriteSpeed [2]; // Kbyte/sec + UCHAR Reserved1[6]; + } SET_CD_SPEED, *PSET_CD_SPEED; + +#define SyncCache_RELADR 0x01 +#define SyncCache_Immed 0x02 + + struct _SYNCHRONIZE_CACHE { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR RELADR : 1; + UCHAR Immed : 1; + UCHAR Reserved0 : 6; // All these are unused by drive + } Fields; + } Byte1; + UCHAR LBA [4]; + UCHAR Reserved1; + UCHAR NumOfBlocks [2]; + UCHAR Reserved2 [3]; +/* + UCHAR Unused [11];*/ + } SYNCHRONIZE_CACHE, *PSYNCHRONIZE_CACHE; + +#define BlankMedia_Mask 0x07 +#define BlankMedia_Complete 0x00 +#define BlankMedia_Minimal 0x01 +#define BlankMedia_Track 0x02 +#define BlankMedia_UnreserveTrack 0x03 +#define BlankMedia_TrackTail 0x04 +#define BlankMedia_UncloseLastSes 0x05 +#define BlankMedia_EraseSes 0x06 +#define BlankMedia_Immed 0x10 + + struct _BLANK_MEDIA { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR BlankType : 3; + UCHAR Reserved0 : 1; + UCHAR Immed : 1; + UCHAR Reserved1 : 3; + } Fields; + } Byte1; + UCHAR StartAddr_TrkNum [4]; + UCHAR Reserved2 [6]; + } BLANK_MEDIA, *PBLANK_MEDIA; + +#define SendKey_ReportAGID 0x00 +#define SendKey_ChallengeKey 0x01 +#define SendKey_Key1 0x02 +#define SendKey_Key2 0x03 +#define SendKey_TitleKey 0x04 +#define SendKey_ReportASF 0x05 +#define SendKey_InvalidateAGID 0x3F + + struct _SEND_KEY { + UCHAR OperationCode; + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR Reserved2[6]; + UCHAR ParameterListLength[2]; + UCHAR KeyFormat : 6; + UCHAR AGID : 2; + UCHAR Control; + } SEND_KEY, *PSEND_KEY; + + struct _REPORT_KEY { + UCHAR OperationCode; // 0xA4 + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR LBA[4]; // for title key + UCHAR Reserved2[2]; + UCHAR AllocationLength[2]; + UCHAR KeyFormat : 6; + UCHAR AGID : 2; + UCHAR Control; + } REPORT_KEY, *PREPORT_KEY; + + struct _READ_DVD_STRUCTURE { + UCHAR OperationCode; // 0xAD + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR RMDBlockNumber[4]; + UCHAR LayerNumber; + UCHAR Format; + UCHAR AllocationLength[2]; // [0]=MSB, [1]=LSB + UCHAR Reserved3 : 6; + UCHAR AGID : 2; + UCHAR Control; + } READ_DVD_STRUCTURE, *PREAD_DVD_STRUCTURE; + + struct _READ_BUFFER_CAPACITY { + UCHAR OperationCode; + UCHAR Reserved0 [6]; + UCHAR AllocationLength[2]; + UCHAR Reserved1 [3]; + } READ_BUFFER_CAPACITY, *PREAD_BUFFER_CAPACITY; + + struct _GET_CONFIGURATION { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR RT : 2; + UCHAR Reserved0 : 6; + } Fields; + } Byte1; + UCHAR StartFeatureNum [2]; + UCHAR Reserved0 [3]; + UCHAR AllocationLength[2]; + UCHAR Control; + } GET_CONFIGURATION, *PGET_CONFIGURATION; + + struct _SET_READ_AHEAD { + UCHAR OperationCode; + UCHAR Reserved0; + UCHAR TriggerLBA[4]; + UCHAR ReadAheadLBA[4]; + UCHAR Reserved1; + UCHAR Control; + } SET_READ_AHEAD, *PSET_READ_AHEAD; + +#define SendOpc_DoOpc 0x01 + + struct _SEND_OPC_INFO { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR DoOpc : 1; + UCHAR Reserved0 : 4; + UCHAR Reserved1 : 3; + } Fields; + } Byte1; + UCHAR Reserved0 [5]; + UCHAR AllocationLength[2]; + UCHAR Control; + } SEND_OPC_INFO, *PSEND_OPC_INFO; + + struct _SEND_CUE_SHEET { + UCHAR OperationCode; + UCHAR Reserved0 [5]; + UCHAR AllocationLength[3]; + UCHAR Control; + } SEND_CUE_SHEET, *PSEND_CUE_SHEET; + + struct _CDB12 { + UCHAR OperationCode; + UCHAR Params[11]; + } CDB12, *PCDB12; + + struct _CDB12READWRITE { + UCHAR OperationCode; + union { + UCHAR Flags; + struct { + UCHAR RELADR : 1; + UCHAR Reserved0 : 2; + UCHAR FUA : 1; + UCHAR DPO : 1; + UCHAR Reserved1 : 3; + } Fields; + } Byte1; + UCHAR LBA [4]; + UCHAR NumOfBlocks [4]; + UCHAR Reserved1[2]; + } CDB12READWRITE, *PCDB12READWRITE; + + // Plextor Read CD-DA + struct _PLXTR_READ_CDDA { + UCHAR OperationCode; + UCHAR Reserved0 : 5; + UCHAR Lun :3; + UCHAR LBA[4]; + UCHAR TransferBlock[4]; + UCHAR SubCode; + UCHAR Control; + } PLXTR_READ_CDDA, *PPLXTR_READ_CDDA; + + // NEC Read CD-DA + struct _NEC_READ_CDDA { + UCHAR OperationCode; + UCHAR Reserved0; + UCHAR LBA[4]; + UCHAR Reserved1; + UCHAR TransferBlock[2]; + UCHAR Control; + } NEC_READ_CDDA, *PNEC_READ_CDDA; + +} CDB, *PCDB; + +// Command Descriptor Block constants. + +#define CDB6GENERIC_LENGTH 6 +#define CDB10GENERIC_LENGTH 10 +#define CDB12GENERIC_LENGTH 12 + +#define MAXIMUM_NUMBER_OF_TRACKS 100 +#define MAXIMUM_NUMBER_OF_SESSIONS 1024 //maximal number of entries in Read Full TOC + +#define SETBITON 1 +#define SETBITOFF 0 + +// Mode Sense/Select page constants. + +#define MODE_PAGE_ERROR_RECOVERY 0x01 +#define MODE_PAGE_WRITE_PARAMS 0x05 +#define MODE_PAGE_VERIFY_ERROR 0x07 // shall not be used +#define MODE_PAGE_CACHING 0x08 // undocumented, but used by DirectCd +#define MODE_PAGE_MEDIUM_TYPES 0x0B // shall not be used +#define MODE_PAGE_CD_DEVICE_PARAMS 0x0D +#define MODE_PAGE_CD_AUDIO_CONTROL 0x0E +#define MODE_PAGE_POWER_CONDITION 0x1A +#define MODE_PAGE_FAIL_REPORT 0x1C +#define MODE_PAGE_TIMEOUT_AND_PROTECT 0x1D +#define MODE_PAGE_PHILIPS_SECTOR_TYPE 0x21 +#define MODE_PAGE_CAPABILITIES 0x2A + +#define MODE_SENSE_RETURN_ALL 0x3f + +#define MODE_SENSE_CURRENT_VALUES 0x00 +#define MODE_SENSE_CHANGEABLE_VALUES 0x40 +#define MODE_SENSE_DEFAULT_VAULES 0x80 +#define MODE_SENSE_SAVED_VALUES 0xc0 + +// SCSI CDB operation codes + +#define SCSIOP_TEST_UNIT_READY 0x00 +#define SCSIOP_REZERO_UNIT 0x01 +#define SCSIOP_REWIND 0x01 +#define SCSIOP_REQUEST_BLOCK_ADDR 0x02 +#define SCSIOP_REQUEST_SENSE 0x03 +#define SCSIOP_FORMAT_UNIT 0x04 +#define SCSIOP_READ_BLOCK_LIMITS 0x05 +#define SCSIOP_REASSIGN_BLOCKS 0x07 +#define SCSIOP_READ6 0x08 +#define SCSIOP_RECEIVE 0x08 +#define SCSIOP_WRITE6 0x0A +#define SCSIOP_PRINT 0x0A +#define SCSIOP_SEND 0x0A +#define SCSIOP_SEEK6 0x0B +#define SCSIOP_TRACK_SELECT 0x0B +#define SCSIOP_SLEW_PRINT 0x0B +#define SCSIOP_SEEK_BLOCK 0x0C +#define SCSIOP_PARTITION 0x0D +#define SCSIOP_READ_REVERSE 0x0F +#define SCSIOP_WRITE_FILEMARKS 0x10 +#define SCSIOP_FLUSH_BUFFER 0x10 +#define SCSIOP_SPACE 0x11 +#define SCSIOP_INQUIRY 0x12 +#define SCSIOP_VERIFY6 0x13 +#define SCSIOP_RECOVER_BUF_DATA 0x14 +#define SCSIOP_MODE_SELECT 0x15 +#define SCSIOP_RESERVE_UNIT 0x16 +#define SCSIOP_RELEASE_UNIT 0x17 +#define SCSIOP_COPY 0x18 +#define SCSIOP_ERASE 0x19 +#define SCSIOP_MODE_SENSE 0x1A +#define SCSIOP_START_STOP_UNIT 0x1B +#define SCSIOP_STOP_PRINT 0x1B +#define SCSIOP_LOAD_UNLOAD 0x1B +#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C +#define SCSIOP_SEND_DIAGNOSTIC 0x1D +#define SCSIOP_MEDIUM_REMOVAL 0x1E +#define SCSIOP_READ_FORMAT_CAPACITY 0x23 +#define SCSIOP_READ_CAPACITY 0x25 +#define SCSIOP_READ 0x28 +#define SCSIOP_WRITE 0x2A +#define SCSIOP_WRITE_CD 0x2A +#define SCSIOP_SEEK 0x2B +#define SCSIOP_LOCATE 0x2B +#define SCSIOP_ERASE10 0x2C +#define SCSIOP_WRITE_VERIFY 0x2E +#define SCSIOP_VERIFY 0x2F +#define SCSIOP_SEARCH_DATA_HIGH 0x30 +#define SCSIOP_SEARCH_DATA_EQUAL 0x31 +#define SCSIOP_SEARCH_DATA_LOW 0x32 +#define SCSIOP_SET_LIMITS 0x33 +#define SCSIOP_READ_POSITION 0x34 +#define SCSIOP_SYNCHRONIZE_CACHE 0x35 +#define SCSIOP_COMPARE 0x39 +#define SCSIOP_COPY_COMPARE 0x3A +#define SCSIOP_COPY_VERIFY 0x3A +#define SCSIOP_WRITE_DATA_BUFF 0x3B +#define SCSIOP_READ_DATA_BUFF 0x3C +#define SCSIOP_CHANGE_DEFINITION 0x40 +#define SCSIOP_PLAY_AUDIO10 0x41 +#define SCSIOP_READ_SUB_CHANNEL 0x42 +#define SCSIOP_READ_TOC 0x43 +#define SCSIOP_READ_HEADER 0x44 +#define SCSIOP_PLAY_AUDIO 0x45 +#define SCSIOP_GET_CONFIGURATION 0x46 +#define SCSIOP_PLAY_AUDIO_MSF 0x47 +#define SCSIOP_PLAY_TRACK_INDEX 0x48 +#define SCSIOP_PLAY_TRACK_RELATIVE 0x49 +#define SCSIOP_GET_EVENT_STATUS 0x4A +#define SCSIOP_PAUSE_RESUME 0x4B +#define SCSIOP_LOG_SELECT 0x4C +#define SCSIOP_LOG_SENSE 0x4D +#define SCSIOP_STOP_PLAY_SCAN 0x4E +#define SCSIOP_READ_DISC_INFO 0x51 +#define SCSIOP_READ_TRACK_INFO 0x52 +#define SCSIOP_RESERVE_TRACK 0x53 +#define SCSIOP_SEND_OPC_INFO 0x54 +#define SCSIOP_MODE_SELECT10 0x55 +#define SCSIOP_REPAIR_TRACK 0x58 // obsolete +#define SCSIOP_READ_MASTER_CUE 0x59 +#define SCSIOP_MODE_SENSE10 0x5A +#define SCSIOP_CLOSE_TRACK_SESSION 0x5B +#define SCSIOP_READ_BUFFER_CAPACITY 0x5C +#define SCSIOP_SEND_CUE_SHEET 0x5D +#define SCSIOP_BLANK 0xA1 +#define SCSIOP_SEND_KEY 0xA3 +#define SCSIOP_REPORT_KEY 0xA4 +#define SCSIOP_PLAY_AUDIO12 0xA5 +#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6 +#define SCSIOP_SET_READ_AHEAD 0xA7 +#define SCSIOP_READ12 0xA8 +#define SCSIOP_WRITE12 0xAA +#define SCSIOP_SEEK12 0xAB +#define SCSIOP_GET_PERFORMANCE 0xAC +#define SCSIOP_READ_DVD_STRUCTURE 0xAD +#define SCSIOP_WRITE_VERIFY12 0xAE +#define SCSIOP_VERIFY12 0xAF +#define SCSIOP_SET_STREAMING 0xB6 +#define SCSIOP_READ_CD_MSF 0xB9 +#define SCSIOP_SET_CD_SPEED 0xBB +#define SCSIOP_MECHANISM_STATUS 0xBD +#define SCSIOP_READ_CD 0xBE +#define SCSIOP_SEND_DVD_STRUCTURE 0xBF +#define SCSIOP_DOORLOCK 0xDE // lock door on removable drives +#define SCSIOP_DOORUNLOCK 0xDF // unlock door on removable drives + +// If the IMMED bit is 1, status is returned as soon +// as the operation is initiated. If the IMMED bit +// is 0, status is not returned until the operation +// is completed. + +#define CDB_RETURN_ON_COMPLETION 0 +#define CDB_RETURN_IMMEDIATE 1 + +// end_ntminitape + +// CDB Force media access used in extended read and write commands. + +#define CDB_FORCE_MEDIA_ACCESS 0x08 + +// Denon CD ROM operation codes + +#define SCSIOP_DENON_EJECT_DISC 0xE6 +#define SCSIOP_DENON_STOP_AUDIO 0xE7 +#define SCSIOP_DENON_PLAY_AUDIO 0xE8 +#define SCSIOP_DENON_READ_TOC 0xE9 +#define SCSIOP_DENON_READ_SUBCODE 0xEB + +// Philips/Matshushita CD-R(W) operation codes + +#define SCSIOP_PHILIPS_GET_NWA 0xE2 +#define SCSIOP_PHILIPS_RESERVE_TRACK 0xE4 +#define SCSIOP_PHILIPS_WRITE_TRACK 0xE6 +#define SCSIOP_PHILIPS_LOAD_UNLOAD 0xE7 +#define SCSIOP_PHILIPS_CLOSE_TRACK_SESSION 0xE9 +#define SCSIOP_PHILIPS_RECOVER_BUF_DATA 0xEC +#define SCSIOP_PHILIPS_READ_SESSION_INFO 0xEE + +// Plextor operation codes + +#define SCSIOP_PLEXTOR_READ_CDDA 0xD8 + +// NEC operation codes + +#define SCSIOP_NEC_READ_CDDA 0xD4 + +// SCSI Bus Messages + +#define SCSIMESS_ABORT 0x06 +#define SCSIMESS_ABORT_WITH_TAG 0x0D +#define SCSIMESS_BUS_DEVICE_RESET 0X0C +#define SCSIMESS_CLEAR_QUEUE 0X0E +#define SCSIMESS_COMMAND_COMPLETE 0X00 +#define SCSIMESS_DISCONNECT 0X04 +#define SCSIMESS_EXTENDED_MESSAGE 0X01 +#define SCSIMESS_IDENTIFY 0X80 +#define SCSIMESS_IDENTIFY_WITH_DISCON 0XC0 +#define SCSIMESS_IGNORE_WIDE_RESIDUE 0X23 +#define SCSIMESS_INITIATE_RECOVERY 0X0F +#define SCSIMESS_INIT_DETECTED_ERROR 0X05 +#define SCSIMESS_LINK_CMD_COMP 0X0A +#define SCSIMESS_LINK_CMD_COMP_W_FLAG 0X0B +#define SCSIMESS_MESS_PARITY_ERROR 0X09 +#define SCSIMESS_MESSAGE_REJECT 0X07 +#define SCSIMESS_NO_OPERATION 0X08 +#define SCSIMESS_HEAD_OF_QUEUE_TAG 0X21 +#define SCSIMESS_ORDERED_QUEUE_TAG 0X22 +#define SCSIMESS_SIMPLE_QUEUE_TAG 0X20 +#define SCSIMESS_RELEASE_RECOVERY 0X10 +#define SCSIMESS_RESTORE_POINTERS 0X03 +#define SCSIMESS_SAVE_DATA_POINTER 0X02 +#define SCSIMESS_TERMINATE_IO_PROCESS 0X11 + +// SCSI Extended Message operation codes + +#define SCSIMESS_MODIFY_DATA_POINTER 0X00 +#define SCSIMESS_SYNCHRONOUS_DATA_REQ 0X01 +#define SCSIMESS_WIDE_DATA_REQUEST 0X03 + +// SCSI Extended Message Lengths + +#define SCSIMESS_MODIFY_DATA_LENGTH 5 +#define SCSIMESS_SYNCH_DATA_LENGTH 3 +#define SCSIMESS_WIDE_DATA_LENGTH 2 + +// SCSI extended message structure + +typedef struct _SCSI_EXTENDED_MESSAGE { + UCHAR InitialMessageCode; + UCHAR MessageLength; + UCHAR MessageType; + union _EXTENDED_ARGUMENTS { + + struct { + UCHAR Modifier[4]; + } Modify; + + struct { + UCHAR TransferPeriod; + UCHAR ReqAckOffset; + } Synchronous; + + struct{ + UCHAR Width; + } Wide; + }ExtendedArguments; +}SCSI_EXTENDED_MESSAGE, *PSCSI_EXTENDED_MESSAGE; + +// SCSI bus status codes. + +#define SCSISTAT_GOOD 0x00 +#define SCSISTAT_CHECK_CONDITION 0x02 +#define SCSISTAT_CONDITION_MET 0x04 +#define SCSISTAT_BUSY 0x08 +#define SCSISTAT_INTERMEDIATE 0x10 +#define SCSISTAT_INTERMEDIATE_COND_MET 0x14 +#define SCSISTAT_RESERVATION_CONFLICT 0x18 +#define SCSISTAT_COMMAND_TERMINATED 0x22 +#define SCSISTAT_QUEUE_FULL 0x28 + +// Enable Vital Product Data Flag (EVPD) +// used with INQUIRY command. + +#define CDB_INQUIRY_EVPD 0x01 + +// retry time (in deci-seconds) +#define NOT_READY_RETRY_INTERVAL 20 + +// Defines for format CDB +#define LUN0_FORMAT_SAVING_DEFECT_LIST 0 +#define USE_DEFAULTMSB 0 +#define USE_DEFAULTLSB 0 + +#define START_UNIT_CODE 0x01 +#define STOP_UNIT_CODE 0x00 + +// Inquiry buffer structure. This is the data returned from the target +// after it receives an inquiry. +// +// This structure may be extended by the number of bytes specified +// in the field AdditionalLength. The defined size constant only +// includes fields through ProductRevisionLevel. +// +// The NT SCSI drivers are only interested in the first 36 bytes of data. + +#define INQUIRYDATABUFFERSIZE 36 + +typedef struct _INQUIRYDATA { + UCHAR DeviceType : 5; + UCHAR DeviceTypeQualifier : 3; + UCHAR DeviceTypeModifier : 7; + UCHAR RemovableMedia : 1; + UCHAR Versions; + UCHAR ResponseDataFormat; + UCHAR AdditionalLength; + UCHAR Reserved[2]; + UCHAR SoftReset : 1; + UCHAR CommandQueue : 1; + UCHAR Reserved2 : 1; + UCHAR LinkedCommands : 1; + UCHAR Synchronous : 1; + UCHAR Wide16Bit : 1; + UCHAR Wide32Bit : 1; + UCHAR RelativeAddressing : 1; + UCHAR VendorId[8]; + UCHAR ProductId[16]; + UCHAR ProductRevisionLevel[4]; + UCHAR VendorSpecific[20]; + UCHAR Reserved3[40]; +} INQUIRYDATA, *PINQUIRYDATA; + +// Inquiry defines. Used to interpret data returned from target as result +// of inquiry command. + +// DeviceType field + +#define DIRECT_ACCESS_DEVICE 0x00 // disks +#define SEQUENTIAL_ACCESS_DEVICE 0x01 // tapes +#define PRINTER_DEVICE 0x02 // printers +#define PROCESSOR_DEVICE 0x03 // scanners, printers, etc +#define WRITE_ONCE_READ_MULTIPLE_DEVICE 0x04 // worms +#define READ_ONLY_DIRECT_ACCESS_DEVICE 0x05 // cdroms +#define SCANNER_DEVICE 0x06 // scanners +#define OPTICAL_DEVICE 0x07 // optical disks +#define MEDIUM_CHANGER 0x08 // jukebox +#define COMMUNICATION_DEVICE 0x09 // network +#define LOGICAL_UNIT_NOT_PRESENT_DEVICE 0x7F +#define DEVICE_QUALIFIER_NOT_SUPPORTED 0x03 + +// DeviceTypeQualifier field + +#define DEVICE_CONNECTED 0x00 + +// Sense Data Format + +typedef struct _SENSE_DATA { + UCHAR ErrorCode:7; + UCHAR Valid:1; + UCHAR SegmentNumber; + UCHAR SenseKey:4; + UCHAR Reserved:1; + UCHAR IncorrectLength:1; + UCHAR EndOfMedia:1; + UCHAR FileMark:1; + UCHAR Information[4]; + UCHAR AdditionalSenseLength; + UCHAR CommandSpecificInformation[4]; + UCHAR AdditionalSenseCode; + UCHAR AdditionalSenseCodeQualifier; + UCHAR FieldReplaceableUnitCode; + UCHAR SenseKeySpecific[3]; +} SENSE_DATA, *PSENSE_DATA; + +// Default request sense buffer size + +#define SENSE_BUFFER_SIZE 18 + +// Sense keys + +#define SCSI_SENSE_NO_SENSE 0x00 +#define SCSI_SENSE_RECOVERED_ERROR 0x01 +#define SCSI_SENSE_NOT_READY 0x02 +#define SCSI_SENSE_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_HARDWARE_ERROR 0x04 +#define SCSI_SENSE_ILLEGAL_REQUEST 0x05 +#define SCSI_SENSE_UNIT_ATTENTION 0x06 +#define SCSI_SENSE_DATA_PROTECT 0x07 +#define SCSI_SENSE_BLANK_CHECK 0x08 +#define SCSI_SENSE_UNIQUE 0x09 +#define SCSI_SENSE_COPY_ABORTED 0x0A +#define SCSI_SENSE_ABORTED_COMMAND 0x0B +#define SCSI_SENSE_EQUAL 0x0C +#define SCSI_SENSE_VOL_OVERFLOW 0x0D +#define SCSI_SENSE_MISCOMPARE 0x0E +#define SCSI_SENSE_RESERVED 0x0F + +// Additional Sense codes + +// SK = 0x00 +#define SCSI_ADSENSE_NO_SENSE 0x00 + +// SK = 0x01 +#define SCSI_ADSENSE_WARNING 0x0B +#define SCSI_ADSENSE_REC_DATA_NOECC 0x17 +#define SCSI_ADSENSE_REC_DATA_ECC 0x18 +#define SCSI_ADSENSE_ROUNDED_PARAM 0x37 +#define SCSI_ADSENSE_FAILURE_PREDICTED 0x5D +#define SCSI_ADSENSE_CD_CONTROL_ERR 0x73 + +// SK = 0x02 +#define SCSI_ADSENSE_LUN_NOT_READY 0x04 +#define SCSI_ADSENSE_INCOMPATIBLE_MEDIA 0x30 +#define SCSI_ADSENSE_INVALID_MEDIA SCSI_ADSENSE_INCOMPATIBLE_MEDIA // for w2k +#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3A +#define SCSI_ADSENSE_POSITION_ERROR 0x3B +#define SCSI_ADSENSE_NOT_SELF_CONFIGURED 0x3E + + +// SK = 0x03 +#define SCSI_ADSENSE_NO_SEEK 0x02 +#define SCSI_ADSENSE_NO_REFERENCE 0x06 +#define SCSI_ADSENSE_CD_WRITE_ERROR 0x0C +#define SCSI_ADSENSE_CD_READ_ERROR 0x11 +#define SCSI_ADSENSE_TRACK_ERROR 0x14 +#define SCSI_ADSENSE_SEEK_ERROR 0x15 +#define SCSI_ADSENSE_FORMAT_CORRUPTED 0x31 +#define SCSI_ADSENSE_ENCLOSURE_FAILURE 0x34 +#define SCSI_ADSENSE_ENCLOSURE_SERVICE 0x35 +#define SCSI_ADSENSE_ERASE_ERROR 0x51 +#define SCSI_ADSENSE_UNRECOVERED_TOC 0x57 +#define SCSI_ADSENSE_SESSION_FIXATION 0x71 +//#define SCSI_ADSENSE_CD_CONTROL_ERR 0x73 // redefinition + +// SK = 0x04 +#define SCSI_ADSENSE_CLEAN_REQUEST 0x00 +#define SCSI_ADSENSE_SELECT 0x04 +#define SCSI_ADSENSE_COMMUNICATION 0x08 +#define SCSI_ADSENSE_LOST_STREAMING 0x09 +#define SCSI_ADSENSE_SYNC_ERROR 0x1B +#define SCSI_ADSENSE_MECH_ERROR 0x3B +#define SCSI_ADSENSE_LUN_ERROR 0x3E +#define SCSI_ADSENSE_DIAGNOSTIC 0x40 +#define SCSI_ADSENSE_INTERNAL 0x44 +#define SCSI_ADSENSE_SOFT_RESET 0x46 +#define SCSI_ADSENSE_SCSI_PARITY 0x47 +#define SCSI_ADSENSE_CMD_PHASE 0x4A +#define SCSI_ADSENSE_DATA_PHASE 0x4B +#define SCSI_ADSENSE_SELF_CONFIG 0x4C +#define SCSI_ADSENSE_MEDIUM_REMOVAL 0x53 +#define SCSI_ADSENSE_VOLTAGE 0x65 + +// SK = 0x05 +#define SCSI_ADSENSE_AUDIO_PLAY 0x00 +#define SCSI_ADSENSE_MULTISELECT 0x07 +#define SCSI_ADSENSE_INVALID_PARAM_LENGTH 0x1A +#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20 +#define SCSI_ADSENSE_ILLEGAL_BLOCK 0x21 +#define SCSI_ADSENSE_INVALID_CDB 0x24 +#define SCSI_ADSENSE_INVALID_LUN 0x25 +#define SCSI_ADSENSE_INVALID_VALUE 0x26 +#define SCSI_ADSENSE_WRITE_PROTECT 0x27 +#define SCSI_ADSENSE_CANT_DISCONNECT 0x2B +#define SCSI_ADSENSE_INVALID_CMD_SEQUENCE 0x2C +#define SCSI_ADSENSE_INVALID_SESSION_MODE 0x30 +#define SCSI_ADSENSE_SAVE_NOT_SUPPORTED 0x35 +#define SCSI_ADSENSE_INVALID_BITS_IN_IDENT_MSG 0x3D +#define SCSI_ADSENSE_MSG_ERROR 0x43 +//#define SCSI_ADSENSE_MEDIUM_REMOVAL 0x53 // redefinition +#define SCSI_ADSENSE_SYS_RESOURCE_FAILURE 0x55 +#define SCSI_ADSENSE_OUT_OF_SPACE 0x63 +#define SCSI_ADSENSE_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 +#define SCSI_ADSENSE_CD_COPY_ERROR 0x6F +#define SCSI_ADSENSE_INCOMPLETE_DATA 0x72 +#define SCSI_ADSENSE_VENDOR_UNIQUE 0x80 +#define SCSI_ADSENSE_MUSIC_AREA 0xA0 +#define SCSI_ADSENSE_DATA_AREA 0xA1 +#define SCSI_ADSENSE_VOLUME_OVERFLOW 0xA7 + +// SK = 0x06 +#define SCSI_ADSENSE_LOG_OVERFLOW 0x0A +#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28 +#define SCSI_ADSENSE_BUS_RESET 0x29 +#define SCSI_ADSENSE_PARAM_CHANGE 0x2A +#define SCSI_ADSENSE_CMD_CLEARED_BY_ANOTHER 0x2F +#define SCSI_ADSENSE_MEDIA_STATE 0x3B +#define SCSI_ADSENSE_FUNCTIONALTY_CHANGE 0x3F +#define SCSI_ADSENSE_OPERATOR 0x5A +#define SCSI_ADSENSE_MAX_LOG 0x5B +#define SCSI_ADSENSE_POWER 0x5E + +// SK = 0x0B +#define SCSI_ADSENSE_READ_LOST_STREAMING 0x11 +#define SCSI_ADSENSE_RESELECT_FAILURE 0x45 +#define SCSI_ADSENSE_ERR_MSG_DETECTED 0x48 +#define SCSI_ADSENSE_INVALID_ERR_MSG 0x49 +#define SCSI_ADSENSE_TEGGED_OVERLAPPED 0x4D +#define SCSI_ADSENSE_OVERLAPPED_ATTEMPT 0x4E + +// Additional sense code qualifier + +#define SCSI_SENSEQ_NO_SENSE 0x00 + +// SK:ASC = 02:04 +//#define SCSI_SENSEQ_NO_SENSE 0x00 +#define SCSI_SENSEQ_CAUSE_NOT_REPORTABLE 0x00 +#define SCSI_SENSEQ_BECOMING_READY 0x01 +#define SCSI_SENSEQ_INIT_COMMAND_REQUIRED 0x02 +#define SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED 0x03 +#define SCSI_SENSEQ_FORMAT_IN_PROGRESS 0x04 +#define SCSI_SENSEQ_OPERATION_IN_PROGRESS 0x07 +#define SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS 0x08 + +// SK:ASC = 02:30 +#define SCSI_SENSEQ_INCOMPATIBLE_MEDIA_INSTALLED 0x00 +#define SCSI_SENSEQ_UNKNOWN_FORMAT 0x01 +#define SCSI_SENSEQ_INCOMPATIBLE_FORMAT 0x02 +#define SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED 0x03 +#define SCSI_SENSEQ_WRITE_UNKNOWN_FORMAT 0x04 +#define SCSI_SENSEQ_WRITE_INCOMPATIBLE_FORMAT 0x05 +#define SCSI_SENSEQ_FORMAT_INCOMPATIBLE_MEDIUM 0x06 +#define SCSI_SENSEQ_CLEANING_FAILURE 0x07 + +// SK:ASC = 02:3A +#define SCSI_SENSEQ_TRAY_CLOSED 0x01 +#define SCSI_SENSEQ_TRAY_OPEN 0x02 + +// SK:ASC = 03:0C +#define SENSEQ_W_RECOVERY_NEEDED 0x07 +#define SENSEQ_W_RECOVERY_FAILED 0x08 +#define SENSEQ_LOST_STREAMING 0x09 +#define SENSEQ_PADDING_BLOCKS_ADDED 0x0A + +// SK:ASC = 03:72 +//#define SCSI_SENSEQ_NO_SENSE 0x00 +#define SCSI_SENSEQ_LEAD_IN_ERROR 0x01 +#define SCSI_SENSEQ_LEAD_OUT_ERRROR 0x02 +#define SCSI_SENSEQ_INCOMPLETE_TRACK 0x03 +#define SCSI_SENSEQ_INCOMPLETE_RESERVED_TRACK 0x04 +#define SCSI_SENSEQ_NO_MORE_RESERVATION 0x05 + +// SK:ASC = 05:26 +#define SCSI_SENSEQ_PARAM_NOT_SUPPORTED 0x01 +#define SCSI_SENSEQ_PARAM_INVALID_VALUE 0x02 +#define SCSI_SENSEQ_THRESHOLD_PARAM_NOT_SUPPORTED 0x03 +#define SCSI_SENSEQ_INVALID_RELEASE_OF_PERSISTENT_RESERVATION 0x04 + +// SK:ASC = 05:27 +#define SCSI_SENSEQ_HW_PROTECTION 0x01 +#define SCSI_SENSEQ_LUN_SOFT_PROTECTION 0x02 +#define SCSI_SENSEQ_ASSOCIATED_PROTECTION 0x03 +#define SCSI_SENSEQ_PERSIST_PROTECTION 0x04 +#define SCSI_SENSEQ_PERMANENT_PROTECTION 0x05 + +// SK:ASC = 05:2C +#define SCSI_SENSEQ_PROGRAMM_AREA_NOT_EMPTY 0x03 +#define SCSI_SENSEQ_PROGRAMM_AREA_EMPTY 0x04 + +// SK:ASC = 05:30 +#define SCSI_SENSEQ_APP_CODE_MISSMATCH 0x08 +#define SCSI_SENSEQ_NOT_FIXED_FOR_APPEND 0x09 + +// SK:ASC = 05:6F +#define SCSI_SENSEQ_AUTHENTICATION_FAILURE 0x00 +#define SCSI_SENSEQ_KEY_NOT_PRESENT 0x01 +#define SCSI_SENSEQ_KEY_NOT_ESTABLISHED 0x02 +#define SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION 0x03 +#define SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT 0x04 +#define SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR 0x05 + +// SK:ASC = 06:28 +#define SCSI_SENSEQ_IMPORT_OR_EXPERT_ELEMENT_ACCESS 0x01 + +// SK:ASC = 06:29 +#define SCSI_SENSEQ_POWER_ON 0x01 +#define SCSI_SENSEQ_SCSI_BUS 0x02 +#define SCSI_SENSEQ_BUS_DEVICE_FUNCTION 0x03 +#define SCSI_SENSEQ_DEVICE_INTERNAL 0x04 + +// SK:ASC = 06:2A +#define SCSI_SENSEQ_MODE_PARAMETERS 0x01 +#define SCSI_SENSEQ_LOG_PARAMETERS 0x02 +#define SCSI_SENSEQ_RESERVATIONS_PREEMPTED 0x03 + +// SK:ASC = 06:3B +#define SCSI_SENSEQ_DESTINATION_ELEMENT_FULL 0x0D +#define SCSI_SENSEQ_SOURCE_ELEMENT_EMPTY 0x0E +#define SCSI_SENSEQ_END_OF_MEDIUM 0x0F +#define SCSI_SENSEQ_MAGAZINE_NOT_ACCESSIBLE 0x11 +#define SCSI_SENSEQ_MAGAZINE_REMOVED 0x12 +#define SCSI_SENSEQ_MAGAZINE_INSERTED 0x13 +#define SCSI_SENSEQ_MAGAZINE_LOCKED 0x14 +#define SCSI_SENSEQ_MAGAZINE_UNLOCKED 0x15 + +// SK:ASC = 06:3F +#define SCSI_SENSEQ_MICROCODE 0x01 +#define SCSI_SENSEQ_OPERATION_DEFINITION 0x02 +#define SCSI_SENSEQ_INQUIRY_DATA 0x03 + +// SK:ASC = 06:5A +#define SCSI_SENSEQ_MEDIUM_CHANGE_REQ 0x01 +#define SCSI_SENSEQ_W_PROTECT_SELECTED 0x02 +#define SCSI_SENSEQ_W_PROTECT_PERMITED 0x03 + +// SK:ASC = 06:5E +#define SCSI_SENSEQ_LOW_POWER_COND 0x00 +#define SCSI_SENSEQ_IDLE_BY_TIMER 0x01 +#define SCSI_SENSEQ_STANDBY_BY_TIMER 0x02 +#define SCSI_SENSEQ_IDLE_BY_CMD 0x03 +#define SCSI_SENSEQ_STANDBY_BY_CMD 0x04 + +#define SCSI_SENSEQ_FILEMARK_DETECTED 0x01 +#define SCSI_SENSEQ_SETMARK_DETECTED 0x03 +#define SCSI_SENSEQ_END_OF_MEDIA_DETECTED 0x02 +#define SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED 0x04 + +// SCSI IO Device Control Codes + +#define FILE_DEVICE_SCSI 0x0000001b + +#define IOCTL_SCSI_EXECUTE_IN ((FILE_DEVICE_SCSI << 16) + 0x0011) +#define IOCTL_SCSI_EXECUTE_OUT ((FILE_DEVICE_SCSI << 16) + 0x0012) +#define IOCTL_SCSI_EXECUTE_NONE ((FILE_DEVICE_SCSI << 16) + 0x0013) + +// SMART support in atapi + +#define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500) +#define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501) +#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502) +#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503) +#define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504) +#define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505) +#define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506) +#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507) +#define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508) +#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509) + +// Read Capacity Data - returned in Big Endian format + +typedef struct _READ_CAPACITY_DATA { + ULONG LogicalBlockAddress; + ULONG BytesPerBlock; +} READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; + +// CD ROM Read Table Of Contents (TOC) structures +// Format 0 - Get table of contents + +#define TocControl_TrkMode_Mask WParam_TrkMode_Mask +#define TocControl_TrkMode_Audio WParam_TrkMode_Audio +#define TocControl_TrkMode_Audio_PreEmph WParam_TrkMode_Audio_PreEmph +#define TocControl_TrkMode_Data WParam_TrkMode_Data +#define TocControl_TrkMode_IncrData WParam_TrkMode_IncrData +#define TocControl_TrkMode_QAudio_PreEmph WParam_TrkMode_QAudio_PreEmph +#define TocControl_TrkMode_AllowCpy WParam_TrkMode_AllowCpy + +typedef struct _TOC_TRACK_INFO { + UCHAR Reserved; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TrackNum; + UCHAR Reserved1; + UCHAR LBA[4]; +} TOC_TRACK_INFO, *PTOC_TRACK_INFO; + +typedef struct _READ_TOC_HEADER { + UCHAR Length[2]; + UCHAR First_TrackSes; + UCHAR Last_TrackSes; +} READ_TOC_HEADER, *PREAD_TOC_HEADER; + +#define TOC_LastTrack_ID 0xAA + +typedef struct _READ_TOC_TOC { + READ_TOC_HEADER Tracks; + TOC_TRACK_INFO TrackData[MAXIMUM_NUMBER_OF_TRACKS+1]; +} READ_TOC_TOC, *PREAD_TOC_TOC; + +// Format 1 - Session Info + +typedef struct _READ_TOC_SES { + READ_TOC_HEADER Sessions; + TOC_TRACK_INFO LastSes_1stTrack; // First Track Number In Last Complete Session +} READ_TOC_SES, *PREAD_TOC_SES; + +// Format 2,3 - Full TOC, PMA + +// ADR = 1 +#define POINT_StartPositionOfTrack_Min 0x01 +#define POINT_StartPositionOfTrack_Max 0x63 +#define POINT_FirstTrackNum 0xA0 +#define POINT_LastTrackNum 0xA1 +#define POINT_StartPositionOfLeadOut 0xA2 +// ADR = 5 +#define POINT_SkipInterval_Min 0x01 +#define POINT_SkipInterval_Max 0x40 +#define POINT_StartPositionOfNextProgramArea 0xB0 +#define POINT_NumOfSkips 0xB1 +#define POINT_SkipTrackAssignmet_Min 0xB2 +#define POINT_SkipTrackAssignmet_Max 0xB4 +#define POINT_StartPositionOfFirstLeadIn 0xC0 +#define POINT_CopyOfAdditionalAreaInATIP 0xC1 + +typedef struct _TOC_SES_INFO { + UCHAR SesNumber; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TNO; + UCHAR POINT; + + union { + + struct { + UCHAR MSF[3]; + UCHAR Reserved; + UCHAR P_MSF[3]; + } GENERIC; + +// ADR = 1: + +//0x01 - 0x63 + struct { + UCHAR ATIME[3]; + UCHAR Zero; + UCHAR MSF[3]; + } StartPositionOfTrack; + +//0xA0 +#define FullTOC_DiscType_CDDA_or_M1 WParam_SesFmt_CdRom // 0x00 +#define FullTOC_DiscType_CDI WParam_SesFmt_CdI // 0x10 +#define FullTOC_DiscType_CDXA_M2 WParam_SesFmt_CdRomXa // 0x20 + + struct { + UCHAR ATIME[3]; + UCHAR Zero; + UCHAR FirstTrackNum; + UCHAR DiscType; + UCHAR Zero1; + } FirstTrackNum; + +//0xA1 + struct { + UCHAR ATIME[3]; + UCHAR Zero; + UCHAR LastTrackNum; + UCHAR Zero1[2]; + } LastTrackNum; + +//0xA2 + struct { + UCHAR ATIME[3]; + UCHAR Zero; + UCHAR MSF[3]; + } StartPositionOfLeadOut; + +// ADR = 5: + +//0x01 - 0x40 + struct { + UCHAR End_MSF[3]; + UCHAR Reserved; + UCHAR Start_MSF[3]; + } SkipInterval; + +//0xB0 + struct { + UCHAR Program_MSF[3]; + UCHAR NumOfPointers_M5; + UCHAR MaxLeadOut_MSF[3]; + } StartPositionOfNextProgramArea; + +//0xB1 + struct { + UCHAR Zero[4]; + UCHAR Intervals; + UCHAR Tracks; + UCHAR Zero1; + } NumOfSkips; + +//0xB2 - 0xB4 + struct { + UCHAR SkipNum[7]; + } SkipTrackAsignment; + +//0xC0 + struct { + UCHAR OptimumRecordingPower; + UCHAR SpecInfoATIP[3]; + UCHAR LeadIn_MSF[3]; + } StartPositionOfFirstLeadIn; + +//0xC1 + struct { + UCHAR Bytes[7]; + } AdditionalAreaInATIP; + + } Params; +} TOC_SES_INFO, *PTOC_SES_INFO; + +typedef struct _READ_TOC_FULL_TOC { + READ_TOC_HEADER Sessions; + TOC_SES_INFO SessionData[MAXIMUM_NUMBER_OF_SESSIONS]; +} READ_TOC_FULL_TOC, *PREAD_TOC_FULL_TOC; + +typedef READ_TOC_FULL_TOC READ_TOC_PMA; +typedef PREAD_TOC_FULL_TOC PREAD_TOC_PMA; + +// Format 4 - ATIP + +typedef struct _READ_TOC_ATIP { + UCHAR Length[2]; + UCHAR Reserved[2]; + +#define ATIP_SpeedRef_Mask 0x07 +#define ATIP_SpeedRef_2X 0x01 +#define ATIP_WritingPower_Mask 0x07 + + union { + UCHAR Flags; + struct { + UCHAR SpeedRef: 3; + UCHAR Reserved: 1; + UCHAR WritingPower: 3; + UCHAR One: 1; + } Fields; + } Flags1; + +#define ATIP_URU 0x40 + + union { + UCHAR Flags; + struct { + UCHAR Reserved: 6; + UCHAR URU: 1; + UCHAR Zero: 1; + } Fields; + } Flags2; + +#define ATIP_A1 0x01 // 16-18 are valid +#define ATIP_A2 0x02 // 20-22 are valid +#define ATIP_A3 0x04 // 24-26 are valid +#define ATIP_SubType_Mask 0x38 // shall be set to zero +#define ATIP_Type_Mask 0x40 +#define ATIP_Type_CDR 0x00 +#define ATIP_Type_CDRW 0x40 + + union { + UCHAR Flags; + struct { + UCHAR A1: 1; + UCHAR A2: 1; + UCHAR A3: 1; + UCHAR SubType: 3; + UCHAR Type: 1; + UCHAR One: 1; + } Fields; + } DiscType; + + UCHAR Reserved0; + UCHAR LeadIn_MSF[3]; + UCHAR Reserved1; + UCHAR LeadOut_MSF[3]; + UCHAR Reserved2; + +#define ATIP_MinSpeedCVL_Mask 0x70 +#define ATIP_MinSpeedCVL_2X 0x10 +#define ATIP_MaxSpeedCVL_Mask 0x0f +#define ATIP_MaxSpeedCVL_2X 0x01 +#define ATIP_MaxSpeedCVL_4X 0x02 +#define ATIP_MaxSpeedCVL_6X 0x03 +#define ATIP_MaxSpeedCVL_8X 0x04 + + union { + UCHAR Flags; + struct { + UCHAR MaxSpeedCVL: 4; + UCHAR MinSpeedCVL: 3; + UCHAR Zero: 1; + } Fields; + } Speed; + +#define ATIP_Power_Y_Mask 0x0e +#define ATIP_Power_P_Mask 0x70 + + union { + UCHAR Flags; + struct { + UCHAR Reserved: 1; + UCHAR Y_value: 3; + UCHAR P_factor: 3; + UCHAR Zero: 1; + } Fields; + } Power; + +#define ATIP_PW_ratio_Mask 0x70 + + union { + UCHAR Flags; + struct { + UCHAR Reserved: 4; + UCHAR P_W_ratio: 3; + UCHAR Zero: 1; + } Fields; + } ErasePower; + + UCHAR Reserved3; + UCHAR A1_value[3]; + UCHAR Reserved4; + UCHAR A2_value[3]; + UCHAR Reserved5; + UCHAR A3_value[3]; + +} READ_TOC_ATIP, *PREAD_TOC_ATIP; + +// Format 5 - CD-TEXT + +typedef struct _CD_TEXT_PACK_DATA { + +#define CdText_ID1_Title 0x80 // ID2 = 0 - Album, ID2 = 1-63 - Track +#define CdText_ID1_Performer 0x81 +#define CdText_ID1_Songwriter 0x82 +#define CdText_ID1_Composer 0x83 +#define CdText_ID1_Arranger 0x84 +#define CdText_ID1_Message 0x85 +#define CdText_ID1_DiscID 0x86 +#define CdText_ID1_GenreInfo 0x87 +#define CdText_ID1_TOC 0x88 +#define CdText_ID1_TOC2 0x89 +#define CdText_ID1_Special 0x8D +#define CdText_ID1_UPC_EAN_ISRC 0x8E +#define CdText_ID1_BlockSizeInfo 0x8F + + UCHAR ID1; + UCHAR ID2; + UCHAR ID3; + +#define CdText_CharPos_Mask 0x0f +#define CdText_BlkNum_Mask 0x70 + + union { + UCHAR Flags; + struct { + UCHAR CharPos: 4; + UCHAR BlkNum: 3; + UCHAR DBCC: 1; // used to indicate Double Byte text encoding (Unicode ?) + } Fields; + } BlkNum_CharPos; + + UCHAR TextData[12]; + UCHAR CRC[2]; +} CD_TEXT_PACK_DATA, *PCD_TEXT_PACK_DATA; + +typedef struct _READ_TOC_CD_TEXT { + UCHAR Length[2]; + UCHAR Reserved[2]; + CD_TEXT_PACK_DATA Chunk0; +} READ_TOC_CD_TEXT, *PREAD_TOC_CD_TEXT; + +// OPC block + +typedef struct _OPC_INFO_BLOCK { + UCHAR Speed[2]; + UCHAR OpcValue[6]; +} OPC_INFO_BLOCK, *POPC_INFO_BLOCK; + +// Buffer Capacity format + +typedef struct _BUFFER_CAPACITY_BLOCK { + UCHAR DataLength[2]; + UCHAR Reserved0[2]; + UCHAR BufferLength[4]; + UCHAR BlankBufferLength[4]; +} BUFFER_CAPACITY_BLOCK, *PBUFFER_CAPACITY_BLOCK; + +// Format Unit structures + +typedef struct _FORMAT_LIST_HEADER { + UCHAR Reserved0; + +#define FormatHeader_VS 0x01 +#define FormatHeader_Immed 0x02 +#define FormatHeader_DSP 0x04 +#define FormatHeader_IP 0x08 +#define FormatHeader_STPF 0x10 +#define FormatHeader_DCRT 0x20 +#define FormatHeader_DPRY 0x40 +#define FormatHeader_FOV 0x80 + + union { + UCHAR Flags; + struct { + UCHAR VS: 1; + UCHAR Immed: 1; + UCHAR DSP: 1; + UCHAR IP: 1; + UCHAR STPF: 1; + UCHAR DCRT: 1; + UCHAR DPRY: 1; + UCHAR FOV: 1; + } Fields; + } Flags; + UCHAR FormatDescriptorLength[2]; // =0x0008 +} FORMAT_LIST_HEADER, *PFORMAT_LIST_HEADER; + +typedef struct _CDRW_FORMAT_DESCRIPTOR { + +#define FormatDesc_Grow 0x40 +#define FormatDesc_Ses 0x80 + + union { + UCHAR Flags; + struct { + UCHAR Reserved0: 6; + UCHAR Grow: 1; + UCHAR Ses: 1; + } Fields; + } Flags; + UCHAR Reserved1[3]; + UCHAR FormatSize[4]; +} CDRW_FORMAT_DESCRIPTOR, *PCDRW_FORMAT_DESCRIPTOR; + +typedef struct _FORMAT_UNIT_PARAMETER_LIST { + FORMAT_LIST_HEADER Header; + UCHAR InitPatternDescr[4]; + CDRW_FORMAT_DESCRIPTOR FormatDescr; +} FORMAT_UNIT_PARAMETER_LIST, *PFORMAT_UNIT_PARAMETER_LIST; + +// define Read Format Capacities info blocks + +typedef struct _CAPACITY_LIST_HEADER { + UCHAR Reserved[3]; + UCHAR Length; +} CAPACITY_LIST_HEADER, *PCAPACITY_LIST_HEADER; + +typedef struct _FORMATTABLE_CAPACITY_DESCRIPTOR { + UCHAR NumOfBlocks [4]; + union { + UCHAR Flags; + struct { + UCHAR DescType: 2; + UCHAR Reserved0: 6; + } Fields; + } Flags; + UCHAR BlockSize [3]; +} FORMATTABLE_CAPACITY_DESCRIPTOR, *PFORMATTABLE_CAPACITY_DESCRIPTOR; + +typedef struct _FORMAT_CAPACITIES_DATA { + CAPACITY_LIST_HEADER Header; +} FORMAT_CAPACITIES_DATA, *PFORMAT_CAPACITIES_DATA; + +// Define Event Status info blocks + +typedef struct _EVENT_STAT_HEADER { + UCHAR DataLength[2]; + +#define EventRetStat_Class_Mask 0x07 +#define EventRetStat_Class_OpChange 0x01 +#define EventRetStat_Class_PM 0x02 +#define EventRetStat_Class_Media 0x04 +#define EventRetStat_Class_DevBusy 0x06 +#define EventRetStat_NEA 0x80 + + union { + UCHAR Flags; + struct { + UCHAR Class: 3; + UCHAR Reserved0: 4; + UCHAR NEA: 1; + } Fields; + } Flags; + + UCHAR SupportedClasses; // see command format + +} EVENT_STAT_HEADER, *PEVENT_STAT_HEADER; + +typedef struct _EVENT_STAT_OPERATIONAL_BLOCK { + + EVENT_STAT_HEADER Header; + +#define EventStat_OpEvent_Mask 0x0f + + union { + UCHAR Flags; + struct { + UCHAR OpEvent : 4; + UCHAR Reserved0: 4; + } Fields; + } Byte0; + +#define EventStat_OpStat_Mask 0x0f +#define EventStat_OpStat_Ready 0x00 +#define EventStat_OpStat_TempBusy 0x01 +#define EventStat_OpStat_Busy 0x02 + + union { + UCHAR Flags; + struct { + UCHAR OpStatus : 4; + UCHAR Reserved0 : 3; + UCHAR PersistentPrevent: 1; + } Fields; + } Byte1; + +#define EventStat_OpReport_NoChg 0x00 +#define EventStat_OpReport_Change 0x01 +#define EventStat_OpReport_AddChg 0x02 +#define EventStat_OpReport_Reset 0x03 +#define EventStat_OpReport_FirmwareChg 0x04 // microcode change +#define EventStat_OpReport_InquaryChg 0x05 +#define EventStat_OpReport_CtrlReq 0x06 +#define EventStat_OpReport_CtrlRelease 0x07 + + UCHAR OpReport[2]; + +} EVENT_STAT_OPERATIONAL_BLOCK, *PEVENT_STAT_OPERATIONAL_BLOCK; + +typedef struct _EVENT_STAT_PM_BLOCK { + + EVENT_STAT_HEADER Header; + +#define EventStat_PowerEvent_Mask 0x0f +#define EventStat_PowerEvent_NoChg 0x00 +#define EventStat_PowerEvent_ChgOK 0x01 +#define EventStat_PowerEvent_ChgFail 0x02 + + union { + UCHAR Flags; + struct { + UCHAR PowerEvent : 4; + UCHAR Reserved0 : 4; + } Fields; + } Byte0; + +#define EventStat_PowerStat_Mask 0x0f +#define EventStat_PowerStat_Active 0x01 +#define EventStat_PowerStat_Idle 0x02 +#define EventStat_PowerStat_Standby 0x03 +#define EventStat_PowerStat_Sleep 0x04 + + union { + UCHAR Flags; + struct { + UCHAR PowerStatus: 4; + UCHAR Reserved0 : 4; + } Fields; + } Byte1; + + UCHAR Reserved0[2]; + +} EVENT_STAT_PM_BLOCK, *PEVENT_STAT_PM_BLOCK; + +typedef struct _EVENT_STAT_MEDIA_BLOCK { + + EVENT_STAT_HEADER Header; + +#define EventStat_MediaEvent_Mask 0x0f +#define EventStat_MediaEvent_None 0x00 +#define EventStat_MediaEvent_EjectReq 0x01 +#define EventStat_MediaEvent_New 0x02 +#define EventStat_MediaEvent_Removal 0x03 +#define EventStat_MediaEvent_Chg 0x04 + + union { + UCHAR Flags; + struct { + UCHAR MediaEvent : 4; + UCHAR Reserved0 : 4; + } Fields; + } Byte0; + +#define EventStat_MediaStat_DoorOpen 0x01 +#define EventStat_MediaStat_Present 0x02 + + union { + UCHAR Flags; + struct { + UCHAR DoorOpen : 1; + UCHAR Present : 1; + UCHAR Reserved0 : 6; + } Fields; + } Byte1; + + UCHAR StartSlot; + UCHAR EndSlot; + +} EVENT_STAT_MEDIA_BLOCK, *PEVENT_STAT_MEDIA_BLOCK; + +typedef struct _EVENT_STAT_DEV_BUSY_BLOCK { + + EVENT_STAT_HEADER Header; + +#define EventStat_BusyEvent_Mask 0x0f +#define EventStat_BusyEvent_None 0x00 +#define EventStat_BusyEvent_Busy 0x01 + + union { + UCHAR Flags; + struct { + UCHAR BusyEvent : 4; + UCHAR Reserved0 : 4; + } Fields; + } Byte0; + +#define EventStat_BusyStat_Mask 0x0f +#define EventStat_BusyStat_NoEvent 0x00 +#define EventStat_BusyStat_Power 0x01 +#define EventStat_BusyStat_Immed 0x02 +#define EventStat_BusyStat_Deferred 0x03 + + union { + UCHAR Flags; + struct { + UCHAR BusyStatus: 4; + UCHAR Reserved0 : 4; + } Fields; + } Byte1; + + UCHAR Time[2]; + +} EVENT_STAT_DEV_BUSY_BLOCK, *PEVENT_STAT_DEV_BUSY_BLOCK; + +// Define mode disc info block. + +typedef struct _DISC_INFO_BLOCK { // + UCHAR DataLength [2]; + +#define DiscInfo_Disk_Mask 0x03 +#define DiscInfo_Disk_Empty 0x00 +#define DiscInfo_Disk_Appendable 0x01 +#define DiscInfo_Disk_Complete 0x02 + +#define DiscInfo_Ses_Mask 0x0C +#define DiscInfo_Ses_Empty 0x00 +#define DiscInfo_Ses_Incomplete 0x04 +#define DiscInfo_Ses_Complete 0x0C + +#define DiscInfo_Disk_Erasable 0x10 + + union { + UCHAR Flags; + struct { + UCHAR DiscStat : 2; + UCHAR LastSesStat : 2; + UCHAR Erasable : 1; + UCHAR Reserved0: 3; + } Fields; + } DiscStat; + + UCHAR FirstTrackNum; + UCHAR NumOfSes; + UCHAR FirstTrackNumLastSes; + UCHAR LastTrackNumLastSes; + +#define DiscInfo_URU 0x20 +#define DiscInfo_DBC_V 0x40 +#define DiscInfo_DID_V 0x80 + + union { + UCHAR Flags; + struct { + UCHAR Reserved1: 5; + UCHAR URU : 1; + UCHAR DBC_V : 1; // 0 + UCHAR DID_V : 1; + } Fields; + } Flags; + +#define DiscInfo_Type_cdrom 0x00 // CD-DA / CD-ROM +#define DiscInfo_Type_cdi 0x10 // CD-I +#define DiscInfo_Type_cdromxa 0x20 // CD-ROM XA +#define DiscInfo_Type_unknown 0xFF // HZ ;) + + UCHAR DiskType; + UCHAR NumOfSes2; // MSB MMC-3 + UCHAR FirstTrackNumLastSes2; // MSB MMC-3 + UCHAR LastTrackNumLastSes2; // MSB MMC-3 + UCHAR DiskId [4]; + UCHAR LastSesLeadInTime [4]; // MSF + UCHAR LastSesLeadOutTime [4]; // MSF + UCHAR DiskBarCode [8]; + UCHAR Reserved3; + UCHAR OPCNum; +} DISC_INFO_BLOCK, *PDISC_INFO_BLOCK; + +// Define track info block. + +typedef struct _TRACK_INFO_BLOCK { + UCHAR DataLength [2]; + UCHAR TrackNum; + UCHAR SesNum; + UCHAR Reserved0; + +#define TrkInfo_Trk_Mask 0x0F +#define TrkInfo_Trk_Mode1 0x01 +#define TrkInfo_Trk_Mode2 0x02 +#define TrkInfo_Trk_XA 0x02 +#define TrkInfo_Trk_DDCD 0x04 // MMC-3 +#define TrkInfo_Trk_NonCD 0x04 // MMC-3 +#define TrkInfo_Trk_Inc 0x05 // MMC-3 +#define TrkInfo_Trk_unknown 0x0F +#define TrkInfo_Copy 0x10 +#define TrkInfo_Damage 0x20 + + UCHAR TrackParam; +/* UCHAR TrackMode : 4; + UCHAR Copy : 1; + UCHAR Damage : 1; + UCHAR Reserved1 : 2; */ + +#define TrkInfo_Dat_Mask 0x0F +#define TrkInfo_Dat_Mode1 0x01 +#define TrkInfo_Dat_Mode2 0x02 +#define TrkInfo_Dat_XA 0x02 +#define TrkInfo_Dat_DDCD 0x02 +#define TrkInfo_Dat_unknown 0x0F +#define TrkInfo_FP 0x10 +#define TrkInfo_Packet 0x20 +#define TrkInfo_Blank 0x40 +#define TrkInfo_RT 0x80 + + UCHAR DataParam; +/* UCHAR DataMode : 4; + UCHAR FP : 1; + UCHAR Packet : 1; + UCHAR Blank : 1; + UCHAR RT : 1; */ + +#define TrkInfo_NWA_V 0x01 +#define TrkInfo_LRA_V 0x02 // MMC-3 + + UCHAR NWA_V; +/* UCHAR NWA_V : 1; + UCHAR LRA_V : 1; + UCHAR Reserved : 6; */ + + UCHAR TrackStartAddr [4]; + UCHAR NextWriteAddr [4]; + UCHAR FreeBlocks [4]; + UCHAR FixPacketSize [4]; + UCHAR TrackLength [4]; + +// MMC-3 + + UCHAR LastRecordedAddr [4]; + UCHAR TrackNum2; // MSB + UCHAR SesNum2; // MSB + UCHAR Reserved2[2]; + +}TRACK_INFO_BLOCK, *PTRACK_INFO_BLOCK; + +// Mode data structures. + +// Define Mode parameter header. + +#define MediaType_Unknown 0x00 +#define MediaType_120mm_CDROM_DataOnly 0x01 +#define MediaType_120mm_CDROM_AudioOnly 0x02 //CDDA +#define MediaType_120mm_CDROM_DataAudioCombined 0x03 +#define MediaType_120mm_CDROM_Hybrid_PhotoCD 0x04 +#define MediaType_80mm_CDROM_DataOnly 0x05 +#define MediaType_80mm_CDROM_AudioOnly 0x06 //CDDA +#define MediaType_80mm_CDROM_DataAudioCombined 0x07 +#define MediaType_80mm_CDROM_Hybrid_PhotoCD 0x08 + +#define MediaType_UnknownSize_CDR 0x10 +#define MediaType_120mm_CDR_DataOnly 0x11 +#define MediaType_120mm_CDR_AudioOnly 0x12 //CDDA +#define MediaType_120mm_CDR_DataAudioCombined 0x13 +#define MediaType_120mm_CDR_Hybrid_PhotoCD 0x14 +#define MediaType_80mm_CDR_DataOnly 0x15 +#define MediaType_80mm_CDR_AudioOnly 0x16 //CDDA +#define MediaType_80mm_CDR_DataAudioCombined 0x17 +#define MediaType_80mm_CDR_Hybrid_Photo_CD 0x18 + +#define MediaType_UnknownSize_CDRW 0x20 +#define MediaType_120mm_CDRW_DataOnly 0x21 +#define MediaType_120mm_CDRW_AudioOnly 0x22 //CDDA +#define MediaType_120mm_CDRW_DataAudioCombined 0x23 +#define MediaType_120mm_CDRW_Hybrid 0x24 +#define MediaType_80mm_CDRW_DataOnly 0x25 +#define MediaType_80mm_CDRW_AudioOnly 0x26 //CDDA +#define MediaType_80mm_CDRW_DataAudioCombined 0x27 +#define MediaType_80mm_CDRW_Hybrid 0x28 + +#define MediaType_NoDiscPresent 0x70 +#define MediaType_DoorOpen 0x71 + +//********************************************************************************************* + +typedef struct _MODE_PARAMETER_HEADER { + UCHAR ModeDataLength; + UCHAR MediumType; + UCHAR DeviceSpecificParameter; + UCHAR BlockDescriptorLength; +} MODE_PARAMETER_HEADER, *PMODE_PARAMETER_HEADER; + +typedef struct _MODE_PARAMETER_HEADER10 { + UCHAR ModeDataLength[2]; + UCHAR MediumType; + UCHAR DeviceSpecificParameter; + UCHAR Reserved[2]; + UCHAR BlockDescriptorLength[2]; +} MODE_PARAMETER_HEADER10, *PMODE_PARAMETER_HEADER10; + +#define MODE_FD_SINGLE_SIDE 0x01 +#define MODE_FD_DOUBLE_SIDE 0x02 +#define MODE_FD_MAXIMUM_TYPE 0x1E +#define MODE_DSP_FUA_SUPPORTED 0x10 +#define MODE_DSP_WRITE_PROTECT 0x80 + +// Define the mode parameter block. + +typedef struct _MODE_PARAMETER_BLOCK { + UCHAR DensityCode; + UCHAR NumberOfBlocks[3]; + UCHAR Reserved; + UCHAR BlockLength[3]; +} MODE_PARAMETER_BLOCK, *PMODE_PARAMETER_BLOCK; + +typedef struct _MODE_PARM_READ_WRITE { + + MODE_PARAMETER_HEADER ParameterListHeader; // List Header Format + MODE_PARAMETER_BLOCK ParameterListBlock; // List Block Descriptor + +} MODE_PARM_READ_WRITE_DATA, *PMODE_PARM_READ_WRITE_DATA; + +//********************************************************************************************* +// Define read write recovery page + +typedef struct _MODE_READ_WRITE_RECOVERY_PAGE { // 0x01 + + UCHAR PageCode : 6; + UCHAR Reserved1 : 1; + UCHAR PSBit : 1; + UCHAR PageLength; + union { + UCHAR Flags; + struct { + UCHAR DCRBit : 1; + UCHAR DTEBit : 1; + UCHAR PERBit : 1; + UCHAR EERBit : 1; + UCHAR RCBit : 1; + UCHAR TBBit : 1; + UCHAR ARRE : 1; + UCHAR AWRE : 1; + } Fields; + } ErrorRecoveryParam; + UCHAR ReadRetryCount; + UCHAR CorrectionSpan; //SCSI CBS only + UCHAR HeadOffsetCount; //SCSI CBS only + UCHAR DataStrobOffsetCount; //SCSI CBS only + UCHAR Reserved4; + UCHAR WriteRetryCount; + UCHAR Reserved5; + UCHAR RecoveryTimeLimit[2]; // 0 + +} MODE_READ_WRITE_RECOVERY_PAGE, *PMODE_READ_WRITE_RECOVERY_PAGE; + +// Define Read Recovery page - cdrom + +typedef struct _MODE_READ_RECOVERY_PAGE { // 0x01 + + UCHAR PageCode : 6; + UCHAR Reserved1 : 1; + UCHAR PSBit : 1; + UCHAR PageLength; + UCHAR DCRBit : 1; + UCHAR DTEBit : 1; + UCHAR PERBit : 1; + UCHAR Reserved2 : 1; + UCHAR RCBit : 1; + UCHAR TBBit : 1; + UCHAR Reserved3 : 2; + UCHAR ReadRetryCount; + UCHAR Reserved4[4]; + +} MODE_READ_RECOVERY_PAGE, *PMODE_READ_RECOVERY_PAGE; + +//********************************************************************************************* +// Define mode write parameters page. + +typedef struct _MODE_WRITE_PARAMS_PAGE { // 0x05 + UCHAR PageCode : 6; + UCHAR Reserved1: 1; + UCHAR PageSavable : 1; + + UCHAR PageLength; // 0x32 + +#define WParam_WType_Mask 0x0f +#define WParam_WType_Packet 0x00 +#define WParam_WType_TAO 0x01 +#define WParam_WType_Ses 0x02 +#define WParam_WType_Raw 0x03 +#define WParam_TestWrite 0x10 +#define WParam_LS_V 0x20 +#define WParam_BUFF 0x40 + + union { + UCHAR Flags; + struct { + UCHAR WriteType: 4; // 1 + UCHAR TestWrite: 1; + UCHAR LS_V: 1; + UCHAR BUFF: 1; + UCHAR Reserved1: 1; + } Fields; + } Byte2; + +#define WParam_TrkMode_Mask 0x0d // xx0x +#define WParam_TrkMode_None 0x00 +#define WParam_TrkMode_Audio 0x00 +#define WParam_TrkMode_Audio_PreEmph 0x01 +#define WParam_TrkMode_Data 0x04 +#define WParam_TrkMode_IncrData 0x05 +#define WParam_TrkMode_QAudio_PreEmph 0x08 +#define WParam_TrkMode_AllowCpy 0x02 +#define WParam_Copy 0x10 +#define WParam_FP 0x20 +#define WParam_MultiSes_Mask 0xc0 +#define WParam_Multises_None 0x00 +#define WParam_Multises_Final 0x80 +#define WParam_Multises_Multi 0xc0 + + union { + UCHAR Flags; + struct { + UCHAR TrackMode: 4; // 4 + UCHAR Copy : 1; // 0 + UCHAR FP : 1; // 0 + UCHAR Multisession: 2; // 11 + } Fields; + } Byte3; + +#define WParam_BlkType_Mask 0x0f +#define WParam_BlkType_Raw_2352 0x00 +#define WParam_BlkType_RawPQ_2368 0x01 +#define WParam_BlkType_RawPW_2448 0x02 +#define WParam_BlkType_RawPW_R_2448 0x03 +#define WParam_BlkType_VendorSpec1 0x07 +#define WParam_BlkType_M1_2048 0x08 +#define WParam_BlkType_M2_2336 0x09 +#define WParam_BlkType_M2XAF1_2048 0x0a +#define WParam_BlkType_M2XAF1SH_2056 0x0b +#define WParam_BlkType_M2XAF2_2324 0x0c +#define WParam_BlkType_M2XAFXSH_2332 0x0d +#define WParam_BlkType_VendorSpec2 0x0f + + union { + UCHAR Flags; + struct { + UCHAR DataBlockType: 4; // 8 + UCHAR Reserved2: 4; + } Fields; + } Byte4; + + UCHAR LinkSize; + UCHAR Reserved3; + + union { + UCHAR Flags; + struct { + UCHAR HostAppCode : 6; // 0 + UCHAR Reserved4 : 2; + } Fields; + } Byte7; + +#define WParam_SesFmt_CdRom 0x00 +#define WParam_SesFmt_CdI 0x10 +#define WParam_SesFmt_CdRomXa 0x20 + + UCHAR SesFmt; // 0 + UCHAR Reserved5; + UCHAR PacketSize[4]; // 0 + UCHAR AudioPause[2]; // 150 + + UCHAR Reserved6: 7; + UCHAR MCVAL : 1; + + UCHAR N[13]; + UCHAR Zero; + UCHAR AFRAME; + + UCHAR Reserved7: 7; + UCHAR TCVAL : 1; + + UCHAR I[12]; + UCHAR Zero_2; + UCHAR AFRAME_2; + UCHAR Reserved8; + + struct { + union { + UCHAR MSF[3]; + struct _SubHdrParams1 { + UCHAR FileNum; + UCHAR ChannelNum; + +#define WParam_SubHdr_SubMode0 0x00 +#define WParam_SubHdr_SubMode1 0x08 + + UCHAR SubMode; + } Params1; + } Params; + +#define WParam_SubHdr_Mode_Mask 0x03 +#define WParam_SubHdr_Mode0 0x00 +#define WParam_SubHdr_Mode1 0x01 +#define WParam_SubHdr_Mode2 0x02 +#define WParam_SubHdr_Format_Mask 0xe0 +#define WParam_SubHdr_Format_UserData 0x00 +#define WParam_SubHdr_Format_RunIn4 0x20 +#define WParam_SubHdr_Format_RunIn3 0x40 +#define WParam_SubHdr_Format_RunIn2 0x60 +#define WParam_SubHdr_Format_RunIn1 0x80 +#define WParam_SubHdr_Format_Link 0xa0 +#define WParam_SubHdr_Format_RunOut2 0xc0 +#define WParam_SubHdr_Format_RunOut1 0xe0 + + union { + UCHAR Flags; + struct { + UCHAR Mode : 2; + UCHAR Reserved : 3; + UCHAR Format : 3; + } Fields; + } Mode; + } SubHeader ; + +} MODE_WRITE_PARAMS_PAGE, *PMODE_WRITE_PARAMS_PAGE; + +typedef struct _MODE_WRITE_PARAMS_PAGE_3 { + MODE_WRITE_PARAMS_PAGE Standard; + UCHAR VendorSpec[4]; +} MODE_WRITE_PARAMS_PAGE_3, *PMODE_WRITE_PARAMS_PAGE_3; + +//********************************************************************************************* +// Define Caching page. + +typedef struct _MODE_CACHING_PAGE { // 0x08 + UCHAR PageCode : 6; + UCHAR Reserved1: 1; + UCHAR PageSavable : 1; + UCHAR PageLength; + UCHAR ReadDisableCache : 1; + UCHAR MultiplicationFactor : 1; + UCHAR WriteCacheEnable : 1; + UCHAR Reserved2 : 5; + UCHAR WriteRetensionPriority : 4; + UCHAR ReadRetensionPriority : 4; + UCHAR DisablePrefetchTransfer[2]; + UCHAR MinimumPrefetch[2]; + UCHAR MaximumPrefetch[2]; + UCHAR MaximumPrefetchCeiling[2]; +} MODE_CACHING_PAGE, *PMODE_CACHING_PAGE; + +//********************************************************************************************* +// Define CD Parameters page. + +typedef struct _MODE_CD_PARAMS_PAGE { // 0x0D + UCHAR PageCode : 6; + UCHAR Reserved : 1; + UCHAR PageSavable : 1; + + UCHAR PageLength; // 0x06 + UCHAR Reserved1; + +#define CdParams_InactvityTime_Mask 0x0f + + union { + UCHAR Flags; + struct { + UCHAR InactivityTime: 4; // 1 - 125ms, 2 - 250ms... 9 - 32s, A - 1min... + UCHAR Reserved0 : 4; + } Fields; + } Byte2; + + UCHAR SUnits_per_MUnit[2]; + UCHAR FUnits_per_SUnit[2]; +} MODE_CD_PARAMS_PAGE, *PMODE_CD_PARAMS_PAGE; + +//********************************************************************************************* +// Define CD Audio Control Mode page. + +typedef struct _CDDA_PORT_CONTROL { + +#define CddaPort_Channel_Mask 0x0f +#define CddaPort_Channel_Mute 0x00 +#define CddaPort_Channel_0 0x01 +#define CddaPort_Channel_1 0x02 +#define CddaPort_Channel_0_1 0x03 +#define CddaPort_Channel_2 0x04 +#define CddaPort_Channel_3 0x08 + + UCHAR ChannelSelection; + UCHAR Volume; +} CDDA_PORT_CONTROL, *PCDDA_PORT_CONTROL; + +typedef struct _MODE_CD_AUDIO_CONTROL_PAGE { // 0x0E + UCHAR PageCode : 6; + UCHAR Reserved1: 1; + UCHAR PageSavable : 1; + + UCHAR PageLength; // 0x0E + +#define CdAudio_SOTC 0x02 +#define CdAudio_Immed 0x04 + + union { + UCHAR Flags; + struct { + UCHAR Reserved0 : 1; + UCHAR SOTC : 1; + UCHAR Immed : 1; + UCHAR Reserved1 : 5; + } Fields; + } Byte2; + + UCHAR Reserved2[2]; + UCHAR LbaFormat; + UCHAR LogicalBlocksPerSecond[2]; + CDDA_PORT_CONTROL Port[4]; +} MODE_CD_AUDIO_CONTROL_PAGE, *PMODE_CD_AUDIO_CONTROL_PAGE; + +//********************************************************************************************* +// Define Power Condition Mode page. + +typedef struct _MODE_POWER_CONDITION_PAGE { // 0x1A + UCHAR PageCode : 6; + UCHAR Reserved1: 1; + UCHAR PageSavable : 1; + + UCHAR PageLength; // 0x0A + UCHAR Reserved2; + +#define PowerCond_Standby 0x01 +#define PowerCond_Idle 0x02 + + union { + UCHAR Flags; + struct { + UCHAR Standby : 1; + UCHAR Idle : 1; + UCHAR Reserved1 : 6; + } Fields; + } Byte3; + + UCHAR IdleTimer[4]; // 1unit = 100ms + UCHAR StandbyTimer[4]; // 1unit = 100ms +} MODE_POWER_CONDITION_PAGE, *PMODE_POWER_CONDITION_PAGE; + +//********************************************************************************************* +// Define Fault/Failure Reporting Control page. + +typedef struct _MODE_FAIL_REPORT_PAGE { // 0x1C + UCHAR PageCode : 6; + UCHAR Reserved1: 1; + UCHAR PageSavable : 1; + + UCHAR PageLength; // 0x0A + +#define FailReport_LogErr 0x01 +#define FailReport_Test 0x04 +#define FailReport_DExcept 0x08 +#define FailReport_Perf 0x80 + + union { + UCHAR Flags; + struct { + UCHAR LogErr : 1; + UCHAR Reserved1 : 1; + UCHAR Test : 1; + UCHAR DExcept : 1; + UCHAR Reserved2 : 3; + UCHAR Perf : 1; + } Fields; + } Byte2; + + union { + UCHAR Flags; + struct { + UCHAR MRIE : 4; + UCHAR Reserved1 : 4; + } Fields; + } Byte3; + + UCHAR IntervalTimer[4]; // 1unit = 100ms + UCHAR ReportCount[4]; +} MODE_FAIL_REPORT_PAGE, *PMODE_FAIL_REPORT_PAGE; + +//********************************************************************************************* +// Define Time-out and Protect page. + +typedef struct _MODE_TIMEOUT_AND_PROTECT_PAGE { // 0x1D + UCHAR PageCode : 6; + UCHAR Reserved1: 1; + UCHAR PageSavable : 1; + + UCHAR PageLength; // 0x08 + + UCHAR Reserved2[2]; + +#define Timeout_SW 0x01 +#define Timeout_DISP 0x02 +#define Timeout_TMOE 0x04 + + union { + UCHAR Flags; + struct { + UCHAR SW : 1; + UCHAR DISP : 1; + UCHAR TMOE : 1; + UCHAR Reserved : 5; + } Fields; + } Byte4; + + UCHAR Reserved3; + + UCHAR Group1_Timeout[2]; // 1unit = 1s + UCHAR Group2_Timeout[2]; // 1unit = 1s +} MODE_TIMEOUT_AND_PROTECT_PAGE, *PMODE_TIMEOUT_AND_PROTECT_PAGE; + +//********************************************************************************************* +// Define Philips CD-R(W) Sector Mode page. + +typedef struct _MODE_PHILIPS_SECTOR_TYPE_PAGE { // 0x21 + UCHAR PageCode : 6; + UCHAR Reserved1 : 1; + UCHAR PSBit : 1; + + UCHAR PageLength; + + UCHAR Reserved0[2]; + + union { + UCHAR Flags; + struct { + UCHAR DataBlockType: 4; // 8 + UCHAR Reserved2: 4; + } Fields; + } Byte4; + +#define WParams_Philips_CreateNewTrack 0 + + UCHAR Track; + UCHAR ISRC[9]; + + UCHAR Reserved3[2]; +} MODE_PHILIPS_SECTOR_TYPE_PAGE, *PMODE_PHILIPS_SECTOR_TYPE_PAGE; + +//********************************************************************************************* +// Define CD-X Capabilities and Mechanical Status page. + +typedef struct _MODE_CAPABILITIES_PAGE2 { // 0x2A + UCHAR PageCode : 6; + UCHAR Reserved1 : 1; + UCHAR PSBit : 1; + + UCHAR PageLength; + +#define DevCap_read_cd_r 0x01 // reserved in 1.2 +#define DevCap_read_cd_rw 0x02 // reserved in 1.2 +#define DevCap_method2 0x04 +#define DevCap_read_dvd_rom 0x08 +#define DevCap_read_dvd_r 0x10 +#define DevCap_read_dvd_ram 0x20 + + UCHAR ReadCap; // DevCap_*_read +/* UCHAR cd_r_read : 1; // reserved in 1.2 + UCHAR cd_rw_read : 1; // reserved in 1.2 + UCHAR method2 : 1; + UCHAR dvd_rom : 1; + UCHAR dvd_r_read : 1; + UCHAR dvd_ram_read : 1; + UCHAR Reserved2 : 2;*/ + +#define DevCap_write_cd_r 0x01 // reserved in 1.2 +#define DevCap_write_cd_rw 0x02 // reserved in 1.2 +#define DevCap_test_write 0x04 +#define DevCap_write_dvd_r 0x10 +#define DevCap_write_dvd_ram 0x20 + + UCHAR WriteCap; // DevCap_*_write +/* UCHAR cd_r_write : 1; // reserved in 1.2 + UCHAR cd_rw_write : 1; // reserved in 1.2 + UCHAR test_write : 1; + UCHAR reserved3a : 1; + UCHAR dvd_r_write : 1; + UCHAR dvd_ram_write : 1; + UCHAR Reserved3 : 2;*/ + +#define DevCap_audio_play 0x01 +#define DevCap_composite 0x02 +#define DevCap_digport1 0x04 +#define DevCap_digport2 0x08 +#define DevCap_mode2_form1 0x10 +#define DevCap_mode2_form2 0x20 +#define DevCap_multisession 0x40 + + UCHAR Capabilities0; +/* UCHAR audio_play : 1; + UCHAR composite : 1; + UCHAR digport1 : 1; + UCHAR digport2 : 1; + UCHAR mode2_form1 : 1; + UCHAR mode2_form2 : 1; + UCHAR multisession : 1; + UCHAR Reserved4 : 1;*/ + +#define DevCap_cdda 0x01 +#define DevCap_cdda_accurate 0x02 +#define DevCap_rw_supported 0x04 +#define DevCap_rw_corr 0x08 +#define DevCap_c2_pointers 0x10 +#define DevCap_isrc 0x20 +#define DevCap_upc 0x40 +#define DevCap_read_bar_code 0x80 + + UCHAR Capabilities1; +/* UCHAR cdda : 1; + UCHAR cdda_accurate : 1; + UCHAR rw_supported : 1; + UCHAR rw_corr : 1; + UCHAR c2_pointers : 1; + UCHAR isrc : 1; + UCHAR upc : 1; + UCHAR Reserved5 : 1;*/ + +#define DevCap_lock 0x01 +#define DevCap_lock_state 0x02 +#define DevCap_prevent_jumper 0x04 +#define DevCap_eject 0x08 +#define DevCap_mechtype_mask 0xE0 +#define DevCap_mechtype_caddy 0x00 +#define DevCap_mechtype_tray (0x01<<5) +#define DevCap_mechtype_popup (0x02<<5) +#define DevCap_mechtype_individual_changer (0x04<<5) +#define DevCap_mechtype_cartridge_changer (0x05<<5) + + UCHAR Capabilities2; +/* UCHAR lock : 1; + UCHAR lock_state : 1; + UCHAR prevent_jumper : 1; + UCHAR eject : 1; + UCHAR Reserved6 : 1; + UCHAR mechtype : 3;*/ + +#define DevCap_separate_volume 0x01 +#define DevCap_separate_mute 0x02 +#define DevCap_disc_present 0x04 // reserved in 1.2 +#define DevCap_sw_slot_select 0x08 // reserved in 1.2 +#define DevCap_change_side_cap 0x10 +#define DevCap_rw_leadin_read 0x20 + + UCHAR Capabilities3; +/* UCHAR separate_volume : 1; + UCHAR separate_mute : 1; + UCHAR disc_present : 1; // reserved in 1.2 + UCHAR sss : 1; // reserved in 1.2 + UCHAR Reserved7 : 4;*/ + + UCHAR MaximumSpeedSupported[2]; + UCHAR NumberVolumeLevels[2]; + UCHAR BufferSize[2]; + UCHAR CurrentSpeed[2]; + + UCHAR Reserved8; + + UCHAR SpecialParameters0; +/* UCHAR Reserved9 : 1; + UCHAR BCK : 1; + UCHAR RCK : 1; + UCHAR LSBF : 1; + UCHAR Length : 2; + UCHAR Reserved10 : 2;*/ + + UCHAR MaximumWriteSpeedSupported[2]; + UCHAR CurrentWriteSpeed[2]; + UCHAR CopyManagementRevision[2]; + UCHAR Reserved11[2]; + +// MMC3 + + UCHAR Reserved12; + + UCHAR SpecialParameters1; +/* UCHAR RCS : 2; // rotation control selected + UCHAR Reserved13 : 6; */ + + UCHAR CurrentWriteSpeed3[2]; + UCHAR LunWPerfDescriptorCount[2]; + +// LUN_WRITE_PERF_DESC LunWPerfDescriptor[0]; + +} MODE_CAPABILITIES_PAGE2, *PMODE_CAPABILITIES_PAGE2; + +typedef struct _LUN_WRITE_PERF_DESC { + UCHAR Reserved; + +#define LunWPerf_RotCtrl_Mask 0x07 +#define LunWPerf_RotCtrl_CLV 0x00 +#define LunWPerf_RotCtrl_CAV 0x01 + + UCHAR RotationControl; + UCHAR WriteSpeedSupported[2]; // kbps + +} LUN_WRITE_PERF_DESC, *PLUN_WRITE_PERF_DESC; + +// Mode parameter list block descriptor - +// set the block length for reading/writing + +#define MODE_BLOCK_DESC_LENGTH 8 +#define MODE_HEADER_LENGTH 4 +#define MODE_HEADER_LENGTH10 8 + +#define CDB_USE_MSF 0x01 + +// Atapi 2.5 changer +typedef struct _MECHANICAL_STATUS_INFORMATION_HEADER { + UCHAR CurrentSlot : 5; + UCHAR ChangerState : 2; + UCHAR Fault : 1; + UCHAR Reserved : 5; + UCHAR MechanismState : 3; + UCHAR CurrentLogicalBlockAddress[3]; + UCHAR NumberAvailableSlots; + UCHAR SlotTableLength[2]; +} MECHANICAL_STATUS_INFORMATION_HEADER, *PMECHANICAL_STATUS_INFORMATION_HEADER; + +typedef struct _SLOT_TABLE_INFORMATION { + UCHAR DiscChanged : 1; + UCHAR Reserved : 6; + UCHAR DiscPresent : 1; + UCHAR Reserved2[3]; +} SLOT_TABLE_INFORMATION, *PSLOT_TABLE_INFORMATION; + +typedef struct _MECHANICAL_STATUS { + MECHANICAL_STATUS_INFORMATION_HEADER MechanicalStatusHeader; + SLOT_TABLE_INFORMATION SlotTableInfo[1]; +} MECHANICAL_STATUS, *PMECHANICAL_STATUS; + +// DVD structure blocks + +typedef struct _DVD_DESCRIPTOR_HEADER { + UCHAR Length[2]; + UCHAR Reserved[2]; +} DVD_DESCRIPTOR_HEADER, *PDVD_DESCRIPTOR_HEADER; + +typedef struct _DVD_LAYER_DESCRIPTOR { + DVD_DESCRIPTOR_HEADER Header; + UCHAR Length[2]; + UCHAR BookVersion : 4; + UCHAR BookType : 4; + UCHAR MinimumRate : 4; + UCHAR DiskSize : 4; + UCHAR LayerType : 4; + UCHAR TrackPath : 1; + UCHAR NumberOfLayers : 2; + UCHAR Reserved1 : 1; + UCHAR TrackDensity : 4; + UCHAR LinearDensity : 4; + UCHAR StartingDataSector[4]; + UCHAR EndDataSector[4]; + UCHAR EndLayerZeroSector[4]; + UCHAR Reserved5 : 7; + UCHAR BCAFlag : 1; + UCHAR Reserved6; +} DVD_LAYER_DESCRIPTOR, *PDVD_LAYER_DESCRIPTOR; + +typedef struct _DVD_COPYRIGHT_INFORMATION { + UCHAR CopyrightProtectionSystemType; + UCHAR RegionManagementInformation; + UCHAR Reserved[2]; +} DVD_COPYRIGHT_INFORMATION, *PDVD_COPYRIGHT_INFORMATION; + +typedef struct _DVD_DISK_KEY_STRUCTURES { + UCHAR DiskKeyData[2048]; +} DVD_DISK_KEY_STRUCTURES, *PDVD_DISK_KEY_STRUCTURES; + +typedef struct _CDVD_KEY_HEADER { + UCHAR DataLength[2]; + UCHAR Reserved[2]; +} CDVD_KEY_HEADER, *PCDVD_KEY_HEADER; + +typedef struct _CDVD_REPORT_AGID_DATA { + CDVD_KEY_HEADER Header; + UCHAR Reserved1[3]; + UCHAR Reserved2 : 6; + UCHAR AGID : 2; +} CDVD_REPORT_AGID_DATA, *PCDVD_REPORT_AGID_DATA; + +typedef struct _CDVD_CHALLENGE_KEY_DATA { + CDVD_KEY_HEADER Header; + UCHAR ChallengeKeyValue[10]; + UCHAR Reserved[2]; +} CDVD_CHALLENGE_KEY_DATA, *PCDVD_CHALLENGE_KEY_DATA; + +typedef struct _CDVD_KEY_DATA { + CDVD_KEY_HEADER Header; + UCHAR Key[5]; + UCHAR Reserved[3]; +} CDVD_KEY_DATA, *PCDVD_KEY_DATA; + +typedef struct _CDVD_REPORT_ASF_DATA { + CDVD_KEY_HEADER Header; + UCHAR Reserved1[3]; + UCHAR Success : 1; + UCHAR Reserved2 : 7; +} CDVD_REPORT_ASF_DATA, *PCDVD_REPORT_ASF_DATA; + +typedef struct _CDVD_TITLE_KEY_HEADER { + CDVD_KEY_HEADER Header; + UCHAR DataLength[2]; + UCHAR Reserved1[1]; + UCHAR Reserved2 : 3; + UCHAR CGMS : 2; + UCHAR CP_SEC : 1; + UCHAR CPM : 1; + UCHAR Zero : 1; + CDVD_KEY_DATA TitleKey; +} CDVD_TITLE_KEY_HEADER, *PCDVD_TITLE_KEY_HEADER; + +typedef struct _DVD_COPYRIGHT_DESCRIPTOR { + UCHAR CopyrightProtectionType; + UCHAR RegionManagementInformation; + UCHAR Reserved[2]; +} DVD_COPYRIGHT_DESCRIPTOR, *PDVD_COPYRIGHT_DESCRIPTOR; + +typedef struct _DVD_RPC_KEY { + UCHAR UserResetsAvailable:3; + UCHAR ManufacturerResetsAvailable:3; + UCHAR TypeCode:2; + UCHAR RegionMask; + UCHAR RpcScheme; + UCHAR Reserved2[1]; +} DVD_RPC_KEY, * PDVD_RPC_KEY; + +#pragma pack(pop) + +#endif //__CDRW_DEVICE_H__ diff --git a/reactos/drivers/storage/ide/uniata/srb.h b/reactos/drivers/storage/ide/uniata/srb.h new file mode 100644 index 00000000000..39ecd3ae798 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/srb.h @@ -0,0 +1,970 @@ +/* + Module Name: + + srb.h + + Abstract: + + This file defines the interface between SCSI mini-port drivers and the + SCSI port driver. It is also used by SCSI class drivers to talk to the + SCSI port driver. + w2k-related definitions are added by Alter from w2k/xp DDK + */ + +#ifndef _NTSRB_ +#define _NTSRB_ + +// Define SCSI maximum configuration parameters. + +#define SCSI_MAXIMUM_LOGICAL_UNITS 8 +#define SCSI_MAXIMUM_TARGETS_PER_BUS 128 +#define SCSI_MAXIMUM_LUNS_PER_TARGET 255 +#define SCSI_MAXIMUM_BUSES 8 +#define SCSI_MINIMUM_PHYSICAL_BREAKS 16 +#define SCSI_MAXIMUM_PHYSICAL_BREAKS 255 + +// This constant is for backward compatibility. +// This use to be the maximum number of targets supported. + +#define SCSI_MAXIMUM_TARGETS 8 +// begin_ntminitape +#define MAXIMUM_CDB_SIZE 12 +// end_ntminitape + +#ifndef USER_MODE + +typedef PHYSICAL_ADDRESS SCSI_PHYSICAL_ADDRESS, *PSCSI_PHYSICAL_ADDRESS; + +typedef struct _ACCESS_RANGE { + SCSI_PHYSICAL_ADDRESS RangeStart; + ULONG RangeLength; + BOOLEAN RangeInMemory; +}ACCESS_RANGE, *PACCESS_RANGE; + +// +// Configuration information structure. Contains the information necessary +// to initialize the adapter. NOTE: This structure's must be a multiple of +// quadwords. +// + +typedef struct _PORT_CONFIGURATION_INFORMATION { + ULONG Length; // Length of port configuation information strucuture. + ULONG SystemIoBusNumber; // IO bus number (0 for machines that have only 1 IO bus + INTERFACE_TYPE AdapterInterfaceType; // EISA, MCA or ISA + ULONG BusInterruptLevel; // Interrupt request level for device + // Bus interrupt vector used with hardware buses which use as vector as + // well as level, such as internal buses. + ULONG BusInterruptVector; + KINTERRUPT_MODE InterruptMode; // Interrupt mode (level-sensitive or edge-triggered) + + ULONG MaximumTransferLength; // Max bytes that can be transferred in a single SRB + ULONG NumberOfPhysicalBreaks; // Number of contiguous blocks of physical memory + ULONG DmaChannel; // DMA channel for devices using system DMA + ULONG DmaPort; + DMA_WIDTH DmaWidth; + DMA_SPEED DmaSpeed; + ULONG AlignmentMask; // Alignment masked for the adapter for data transfers. + ULONG NumberOfAccessRanges; // Number of allocated access range elements. + ACCESS_RANGE (*AccessRanges)[]; // Pointer to array of access range elements. + PVOID Reserved; + UCHAR NumberOfBuses; // Number of SCSI buses attached to the adapter. + CCHAR InitiatorBusId[8]; // SCSI bus ID for adapter + BOOLEAN ScatterGather; // Indicates that the adapter does scatter/gather + BOOLEAN Master; // Indicates that the adapter is a bus master + BOOLEAN CachesData; // Host caches data or state. + BOOLEAN AdapterScansDown; // Host adapter scans down for bios devices. + BOOLEAN AtdiskPrimaryClaimed; // Primary at disk address (0x1F0) claimed. + BOOLEAN AtdiskSecondaryClaimed; // Secondary at disk address (0x170) claimed. + BOOLEAN Dma32BitAddresses; // The master uses 32-bit DMA addresses. + BOOLEAN DemandMode; // Use Demand Mode DMA rather than Single Request. + BOOLEAN MapBuffers; // Data buffers must be mapped into virtual address space. + BOOLEAN NeedPhysicalAddresses; // We need to tranlate virtual to physical addresses. + BOOLEAN TaggedQueuing; // Supports tagged queuing + BOOLEAN AutoRequestSense; // Supports auto request sense. + BOOLEAN MultipleRequestPerLu; // Supports multiple requests per logical unit. + BOOLEAN ReceiveEvent; // Support receive event function. + BOOLEAN RealModeInitialized; // Indicates the real-mode driver has initialized the card. + + BOOLEAN BufferAccessScsiPortControlled; // Indicate that the miniport will not touch + // the data buffers directly. + UCHAR MaximumNumberOfTargets; // Indicator for wide scsi. + UCHAR ReservedUchars[2]; // Ensure quadword alignment. + ULONG SlotNumber; // Adapter slot number + ULONG BusInterruptLevel2; // Interrupt information for a second IRQ. + ULONG BusInterruptVector2; + KINTERRUPT_MODE InterruptMode2; + ULONG DmaChannel2; // DMA information for a second channel. + ULONG DmaPort2; + DMA_WIDTH DmaWidth2; + DMA_SPEED DmaSpeed2; + +} PORT_CONFIGURATION_INFORMATION, *PPORT_CONFIGURATION_INFORMATION; + +typedef struct _PORT_CONFIGURATION_INFORMATION_NT { + // Fields added to allow for the miniport + // to update these sizes based on requirements + // for large transfers ( > 64K); + ULONG DeviceExtensionSize; + ULONG SpecificLuExtensionSize; + ULONG SrbExtensionSize; +} PORT_CONFIGURATION_INFORMATION_NT, *PPORT_CONFIGURATION_INFORMATION_NT; + +typedef struct _PORT_CONFIGURATION_INFORMATION_2K { + // Used to determine whether the system and/or the miniport support + // 64-bit physical addresses. See SCSI_DMA64_* flags below. + UCHAR Dma64BitAddresses; + // Indicates that the miniport can accept a SRB_FUNCTION_RESET_DEVICE + // to clear all requests to a particular LUN. + BOOLEAN ResetTargetSupported; + // Indicates that the miniport can support more than 8 logical units per + // target (maximum LUN number is one less than this field). + UCHAR MaximumNumberOfLogicalUnits; + // Supports WMI? + BOOLEAN WmiDataProvider; +} PORT_CONFIGURATION_INFORMATION_2K, *PPORT_CONFIGURATION_INFORMATION_2K; + +typedef struct _PORT_CONFIGURATION_INFORMATION_COMMON { + PORT_CONFIGURATION_INFORMATION comm; + PORT_CONFIGURATION_INFORMATION_NT nt4; + PORT_CONFIGURATION_INFORMATION_2K w2k; +} PORT_CONFIGURATION_INFORMATION_COMMON, *PPORT_CONFIGURATION_INFORMATION_COMMON; + +// +// Version control for ConfigInfo structure. +// + +#define CONFIG_INFO_VERSION_2 sizeof(PORT_CONFIGURATION_INFORMATION) + +// +// Flags for controlling 64-bit DMA use (PORT_CONFIGURATION_INFORMATION field +// Dma64BitAddresses) +// + +// +// Set by scsiport on entering HwFindAdapter if the system can support 64-bit +// physical addresses. The miniport can use this information before calling +// ScsiPortGetUncachedExtension to modify the DeviceExtensionSize, +// SpecificLuExtensionSize & SrbExtensionSize fields to account for the extra +// size of the scatter gather list. +// + +#define SCSI_DMA64_SYSTEM_SUPPORTED 0x80 + +// +// Set by the miniport before calling ScsiPortGetUncachedExtension to indicate +// that scsiport should provide it with 64-bit physical addresses. If the +// system does not support 64-bit PA's then this bit will be ignored. +// + +#define SCSI_DMA64_MINIPORT_SUPPORTED 0x01 + + +// +// Command type (and parameter) definition(s) for AdapterControl requests. +// + +typedef enum _SCSI_ADAPTER_CONTROL_TYPE { + ScsiQuerySupportedControlTypes = 0, + ScsiStopAdapter, + ScsiRestartAdapter, + ScsiSetBootConfig, + ScsiSetRunningConfig, + ScsiAdapterControlMax, + MakeAdapterControlTypeSizeOfUlong = 0xffffffff +} SCSI_ADAPTER_CONTROL_TYPE, *PSCSI_ADAPTER_CONTROL_TYPE; + +// +// Adapter control status values +// + +typedef enum _SCSI_ADAPTER_CONTROL_STATUS { + ScsiAdapterControlSuccess = 0, + ScsiAdapterControlUnsuccessful +} SCSI_ADAPTER_CONTROL_STATUS, *PSCSI_ADAPTER_CONTROL_STATUS; + +// +// Parameters for Adapter Control Functions: +// + +// +// ScsiQuerySupportedControlTypes: +// + +#pragma warning(disable:4200) +typedef struct _SCSI_SUPPORTED_CONTROL_TYPE_LIST { + + // + // Specifies the number of entries in the adapter control type list. + // + + IN ULONG MaxControlType; + + // + // The miniport will set TRUE for each control type it supports. + // The number of entries in this array is defined by MaxAdapterControlType + // - the miniport must not attempt to set any AC types beyond the maximum + // value specified. + // + + OUT BOOLEAN SupportedTypeList[0]; + +} SCSI_SUPPORTED_CONTROL_TYPE_LIST, *PSCSI_SUPPORTED_CONTROL_TYPE_LIST; +#pragma warning(default:4200) + +// +// Uninitialized flag value. +// + +#define SP_UNINITIALIZED_VALUE ((ULONG) ~0) +#define SP_UNTAGGED ((UCHAR) ~0) + +// +// Set asynchronous events. +// + +#define SRBEV_BUS_RESET 0x0001 +#define SRBEV_SCSI_ASYNC_NOTIFICATION 0x0002 + +// begin_ntminitape + +// +// SCSI I/O Request Block +// + +typedef struct _SCSI_REQUEST_BLOCK { + USHORT Length; // offset 0 + UCHAR Function; // offset 2 + UCHAR SrbStatus; // offset 3 + UCHAR ScsiStatus; // offset 4 + UCHAR PathId; // offset 5 + UCHAR TargetId; // offset 6 + UCHAR Lun; // offset 7 + UCHAR QueueTag; // offset 8 + UCHAR QueueAction; // offset 9 + UCHAR CdbLength; // offset a + UCHAR SenseInfoBufferLength; // offset b + ULONG SrbFlags; // offset c + ULONG DataTransferLength; // offset 10 + ULONG TimeOutValue; // offset 14 + PVOID DataBuffer; // offset 18 + PVOID SenseInfoBuffer; // offset 1c + struct _SCSI_REQUEST_BLOCK *NextSrb; // offset 20 + PVOID OriginalRequest; // offset 24 + PVOID SrbExtension; // offset 28 + union { + ULONG InternalStatus; // offset 2c + ULONG QueueSortKey; // offset 2c + }; + +#if defined(_WIN64) + // Force PVOID alignment of Cdb + ULONG Reserved; + +#endif + + UCHAR Cdb[16]; // offset 30 +} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK; + +#define SCSI_REQUEST_BLOCK_SIZE sizeof(SCSI_REQUEST_BLOCK) + +// +// SCSI I/O Request Block for WMI Requests +// + +typedef struct _SCSI_WMI_REQUEST_BLOCK { + USHORT Length; + UCHAR Function; // SRB_FUNCTION_WMI + UCHAR SrbStatus; + UCHAR WMISubFunction; + UCHAR PathId; // If SRB_WMI_FLAGS_ADAPTER_REQUEST is set in + UCHAR TargetId; // WMIFlags then PathId, TargetId and Lun are + UCHAR Lun; // reserved fields. + UCHAR Reserved1; + UCHAR WMIFlags; + UCHAR Reserved2[2]; + ULONG SrbFlags; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + PVOID DataPath; + PVOID Reserved3; + PVOID OriginalRequest; + PVOID SrbExtension; + ULONG Reserved4; + UCHAR Reserved5[16]; +} SCSI_WMI_REQUEST_BLOCK, *PSCSI_WMI_REQUEST_BLOCK; + +// +// SRB Functions +// + +#define SRB_FUNCTION_EXECUTE_SCSI 0x00 +#define SRB_FUNCTION_CLAIM_DEVICE 0x01 +#define SRB_FUNCTION_IO_CONTROL 0x02 +#define SRB_FUNCTION_RECEIVE_EVENT 0x03 +#define SRB_FUNCTION_RELEASE_QUEUE 0x04 +#define SRB_FUNCTION_ATTACH_DEVICE 0x05 +#define SRB_FUNCTION_RELEASE_DEVICE 0x06 +#define SRB_FUNCTION_SHUTDOWN 0x07 +#define SRB_FUNCTION_FLUSH 0x08 +#define SRB_FUNCTION_ABORT_COMMAND 0x10 +#define SRB_FUNCTION_RELEASE_RECOVERY 0x11 +#define SRB_FUNCTION_RESET_BUS 0x12 +#define SRB_FUNCTION_RESET_DEVICE 0x13 +#define SRB_FUNCTION_TERMINATE_IO 0x14 +#define SRB_FUNCTION_FLUSH_QUEUE 0x15 +#define SRB_FUNCTION_REMOVE_DEVICE 0x16 +#define SRB_FUNCTION_WMI 0x17 +#define SRB_FUNCTION_LOCK_QUEUE 0x18 +#define SRB_FUNCTION_UNLOCK_QUEUE 0x19 +#define SRB_FUNCTION_RESET_LOGICAL_UNIT 0x20 + +// +// SRB Status +// + +#define SRB_STATUS_PENDING 0x00 +#define SRB_STATUS_SUCCESS 0x01 +#define SRB_STATUS_ABORTED 0x02 +#define SRB_STATUS_ABORT_FAILED 0x03 +#define SRB_STATUS_ERROR 0x04 +#define SRB_STATUS_BUSY 0x05 +#define SRB_STATUS_INVALID_REQUEST 0x06 +#define SRB_STATUS_INVALID_PATH_ID 0x07 +#define SRB_STATUS_NO_DEVICE 0x08 +#define SRB_STATUS_TIMEOUT 0x09 +#define SRB_STATUS_SELECTION_TIMEOUT 0x0A +#define SRB_STATUS_COMMAND_TIMEOUT 0x0B +#define SRB_STATUS_MESSAGE_REJECTED 0x0D +#define SRB_STATUS_BUS_RESET 0x0E +#define SRB_STATUS_PARITY_ERROR 0x0F +#define SRB_STATUS_REQUEST_SENSE_FAILED 0x10 +#define SRB_STATUS_NO_HBA 0x11 +#define SRB_STATUS_DATA_OVERRUN 0x12 +#define SRB_STATUS_UNEXPECTED_BUS_FREE 0x13 +#define SRB_STATUS_PHASE_SEQUENCE_FAILURE 0x14 +#define SRB_STATUS_BAD_SRB_BLOCK_LENGTH 0x15 +#define SRB_STATUS_REQUEST_FLUSHED 0x16 +#define SRB_STATUS_INVALID_LUN 0x20 +#define SRB_STATUS_INVALID_TARGET_ID 0x21 +#define SRB_STATUS_BAD_FUNCTION 0x22 +#define SRB_STATUS_ERROR_RECOVERY 0x23 +#define SRB_STATUS_NOT_POWERED 0x24 + +// +// This value is used by the port driver to indicate that a non-scsi-related +// error occured. Miniports must never return this status. +// + +#define SRB_STATUS_INTERNAL_ERROR 0x30 + +// +// Srb status values 0x38 through 0x3f are reserved for internal port driver +// use. +// + + + +// +// SRB Status Masks +// + +#define SRB_STATUS_QUEUE_FROZEN 0x40 +#define SRB_STATUS_AUTOSENSE_VALID 0x80 + +#define SRB_STATUS(Status) (Status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) + +// +// SRB Flag Bits +// + +#define SRB_FLAGS_QUEUE_ACTION_ENABLE 0x00000002 +#define SRB_FLAGS_DISABLE_DISCONNECT 0x00000004 +#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER 0x00000008 +#define SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010 +#define SRB_FLAGS_DISABLE_AUTOSENSE 0x00000020 +#define SRB_FLAGS_DATA_IN 0x00000040 +#define SRB_FLAGS_DATA_OUT 0x00000080 +#define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000 +#define SRB_FLAGS_UNSPECIFIED_DIRECTION (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) +#define SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100 +#define SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200 +#define SRB_FLAGS_FREE_SENSE_BUFFER 0x00000400 +#define SRB_FLAGS_IS_ACTIVE 0x00010000 +#define SRB_FLAGS_ALLOCATED_FROM_ZONE 0x00020000 +#define SRB_FLAGS_SGLIST_FROM_POOL 0x00040000 +#define SRB_FLAGS_BYPASS_LOCKED_QUEUE 0x00080000 + +#define SRB_FLAGS_NO_KEEP_AWAKE 0x00100000 +#define SRB_FLAGS_PORT_DRIVER_ALLOCSENSE 0x00200000 +#define SRB_FLAGS_PORT_DRIVER_SENSEHASPORT 0x00400000 +#define SRB_FLAGS_DONT_START_NEXT_PACKET 0x00800000 + +#define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000 +#define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000 +// +// Queue Action +// + +#define SRB_SIMPLE_TAG_REQUEST 0x20 +#define SRB_HEAD_OF_QUEUE_TAG_REQUEST 0x21 +#define SRB_ORDERED_QUEUE_TAG_REQUEST 0x22 + +#define SRB_WMI_FLAGS_ADAPTER_REQUEST 0x01 + +// end_ntminitape + +// +// SCSI Adapter Dependent Routines +// + +typedef +BOOLEAN +(*PHW_INITIALIZE) ( + IN PVOID DeviceExtension + ); + +typedef +BOOLEAN +(*PHW_STARTIO) ( + IN PVOID DeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb + ); + +typedef +BOOLEAN +(*PHW_INTERRUPT) ( + IN PVOID DeviceExtension + ); + +typedef +VOID +(*PHW_TIMER) ( + IN PVOID DeviceExtension + ); + +typedef +VOID +(*PHW_DMA_STARTED) ( + IN PVOID DeviceExtension + ); + +typedef +ULONG +(*PHW_FIND_ADAPTER) ( + IN PVOID DeviceExtension, + IN PVOID HwContext, + IN PVOID BusInformation, + IN PCHAR ArgumentString, + IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, + OUT PBOOLEAN Again + ); + +typedef +BOOLEAN +(*PHW_RESET_BUS) ( + IN PVOID DeviceExtension, + IN ULONG PathId + ); + +typedef +BOOLEAN +(*PHW_ADAPTER_STATE) ( + IN PVOID DeviceExtension, + IN PVOID Context, + IN BOOLEAN SaveState + ); + +typedef +SCSI_ADAPTER_CONTROL_STATUS +(*PHW_ADAPTER_CONTROL) ( + IN PVOID DeviceExtension, + IN SCSI_ADAPTER_CONTROL_TYPE ControlType, + IN PVOID Parameters + ); + +// +// Port driver error codes +// + +#define SP_BUS_PARITY_ERROR 0x0001 +#define SP_UNEXPECTED_DISCONNECT 0x0002 +#define SP_INVALID_RESELECTION 0x0003 +#define SP_BUS_TIME_OUT 0x0004 +#define SP_PROTOCOL_ERROR 0x0005 +#define SP_INTERNAL_ADAPTER_ERROR 0x0006 +#define SP_REQUEST_TIMEOUT 0x0007 +#define SP_IRQ_NOT_RESPONDING 0x0008 +#define SP_BAD_FW_WARNING 0x0009 +#define SP_BAD_FW_ERROR 0x000a +#define SP_LOST_WMI_MINIPORT_REQUEST 0x000b + + +// +// Return values for SCSI_HW_FIND_ADAPTER. +// + +#define SP_RETURN_NOT_FOUND 0 +#define SP_RETURN_FOUND 1 +#define SP_RETURN_ERROR 2 +#define SP_RETURN_BAD_CONFIG 3 + +// +// Notification Event Types +// + +typedef enum _SCSI_NOTIFICATION_TYPE { + RequestComplete, + NextRequest, + NextLuRequest, + ResetDetected, + CallDisableInterrupts, + CallEnableInterrupts, + RequestTimerCall, + BusChangeDetected, /* New */ + WMIEvent, + WMIReregister +} SCSI_NOTIFICATION_TYPE, *PSCSI_NOTIFICATION_TYPE; + +// +// Structure passed between miniport initialization +// and SCSI port initialization +// + +typedef struct _HW_INITIALIZATION_DATA { + + ULONG HwInitializationDataSize; + // Adapter interface type: + // + // Internal + // Isa + // Eisa + // MicroChannel + // TurboChannel + // PCIBus + // VMEBus + // NuBus + // PCMCIABus + // CBus + // MPIBus + // MPSABus + INTERFACE_TYPE AdapterInterfaceType; + // Miniport driver routines + PHW_INITIALIZE HwInitialize; + PHW_STARTIO HwStartIo; + PHW_INTERRUPT HwInterrupt; + PHW_FIND_ADAPTER HwFindAdapter; + PHW_RESET_BUS HwResetBus; + PHW_DMA_STARTED HwDmaStarted; + PHW_ADAPTER_STATE HwAdapterState; + ULONG DeviceExtensionSize; + ULONG SpecificLuExtensionSize; + ULONG SrbExtensionSize; + ULONG NumberOfAccessRanges; + PVOID Reserved; + + BOOLEAN MapBuffers; // Data buffers must be mapped into virtual address space. + BOOLEAN NeedPhysicalAddresses; // We need to tranlate virtual to physical addresses. + BOOLEAN TaggedQueuing; // Supports tagged queuing + BOOLEAN AutoRequestSense; // Supports auto request sense. + BOOLEAN MultipleRequestPerLu; // Supports multiple requests per logical unit. + BOOLEAN ReceiveEvent; // Support receive event function. + USHORT VendorIdLength; // Vendor identification length + PVOID VendorId; // Vendor identification + USHORT ReservedUshort; // Pad for alignment and future use. + USHORT DeviceIdLength; // Device identification length + PVOID DeviceId; // Device identification + +} HW_INITIALIZATION_DATA, *PHW_INITIALIZATION_DATA; + +typedef struct _HW_INITIALIZATION_DATA_2K { + // Stop adapter routine. + PHW_ADAPTER_CONTROL HwAdapterControl; + +} HW_INITIALIZATION_DATA_2K, *PHW_INITIALIZATION_DATA_2K; + +typedef struct _HW_INITIALIZATION_DATA_COMMON { + HW_INITIALIZATION_DATA comm; + HW_INITIALIZATION_DATA_2K w2k; +}HW_INITIALIZATION_DATA_COMMON, *PHW_INITIALIZATION_DATA_COMMON; + +// begin_ntminitape + +#ifndef _NTDDK_ +#define SCSIPORT_API DECLSPEC_IMPORT +#else +#define SCSIPORT_API +#endif + +// end_ntminitape + +// +// Port driver routines called by miniport driver +// + +SCSIPORT_API +ULONG +ScsiPortInitialize( + IN PVOID Argument1, + IN PVOID Argument2, + IN struct _HW_INITIALIZATION_DATA *HwInitializationData, + IN PVOID HwContext + ); + +SCSIPORT_API +VOID +ScsiPortFreeDeviceBase( + IN PVOID HwDeviceExtension, + IN PVOID MappedAddress + ); + +SCSIPORT_API +ULONG +ScsiPortGetBusData( + IN PVOID DeviceExtension, + IN ULONG BusDataType, + IN ULONG SystemIoBusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length + ); + +SCSIPORT_API +ULONG +ScsiPortSetBusDataByOffset( + IN PVOID DeviceExtension, + IN ULONG BusDataType, + IN ULONG SystemIoBusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +SCSIPORT_API +PVOID +ScsiPortGetDeviceBase( + IN PVOID HwDeviceExtension, + IN INTERFACE_TYPE BusType, + IN ULONG SystemIoBusNumber, + IN SCSI_PHYSICAL_ADDRESS IoAddress, + IN ULONG NumberOfBytes, + IN BOOLEAN InIoSpace + ); + +SCSIPORT_API +PVOID +ScsiPortGetLogicalUnit( + IN PVOID HwDeviceExtension, + IN UCHAR PathId, + IN UCHAR TargetId, + IN UCHAR Lun + ); + +SCSIPORT_API +PSCSI_REQUEST_BLOCK +ScsiPortGetSrb( + IN PVOID DeviceExtension, + IN UCHAR PathId, + IN UCHAR TargetId, + IN UCHAR Lun, + IN LONG QueueTag + ); + +SCSIPORT_API +SCSI_PHYSICAL_ADDRESS +ScsiPortGetPhysicalAddress( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN PVOID VirtualAddress, + OUT ULONG *Length + ); + +SCSIPORT_API +PVOID +ScsiPortGetVirtualAddress( + IN PVOID HwDeviceExtension, + IN SCSI_PHYSICAL_ADDRESS PhysicalAddress + ); + +SCSIPORT_API +PVOID +ScsiPortGetUncachedExtension( + IN PVOID HwDeviceExtension, + IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, + IN ULONG NumberOfBytes + ); + +SCSIPORT_API +VOID +ScsiPortFlushDma( + IN PVOID DeviceExtension + ); + +SCSIPORT_API +VOID +ScsiPortIoMapTransfer( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb, + IN PVOID LogicalAddress, + IN ULONG Length + ); + +SCSIPORT_API +VOID +ScsiPortNotification( + IN SCSI_NOTIFICATION_TYPE NotificationType, + IN PVOID HwDeviceExtension, + ... + ); + +SCSIPORT_API +VOID +ScsiPortLogError( + IN PVOID HwDeviceExtension, + IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, + IN UCHAR PathId, + IN UCHAR TargetId, + IN UCHAR Lun, + IN ULONG ErrorCode, + IN ULONG UniqueId + ); + +SCSIPORT_API +VOID +ScsiPortCompleteRequest( + IN PVOID HwDeviceExtension, + IN UCHAR PathId, + IN UCHAR TargetId, + IN UCHAR Lun, + IN UCHAR SrbStatus + ); + +SCSIPORT_API +VOID +ScsiPortMoveMemory( + IN PVOID WriteBuffer, + IN PVOID ReadBuffer, + IN ULONG Length + ); + +SCSIPORT_API +UCHAR +ScsiPortReadPortUchar( + IN PUCHAR Port + ); + +SCSIPORT_API +USHORT +ScsiPortReadPortUshort( + IN PUSHORT Port + ); + +SCSIPORT_API +ULONG +ScsiPortReadPortUlong( + IN PULONG Port + ); + +SCSIPORT_API +VOID +ScsiPortReadPortBufferUchar( + IN PUCHAR Port, + IN PUCHAR Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortReadPortBufferUshort( + IN PUSHORT Port, + IN PUSHORT Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortReadPortBufferUlong( + IN PULONG Port, + IN PULONG Buffer, + IN ULONG Count + ); + +SCSIPORT_API +UCHAR +ScsiPortReadRegisterUchar( + IN PUCHAR Register + ); + +SCSIPORT_API +USHORT +ScsiPortReadRegisterUshort( + IN PUSHORT Register + ); + +SCSIPORT_API +ULONG +ScsiPortReadRegisterUlong( + IN PULONG Register + ); + +SCSIPORT_API +VOID +ScsiPortReadRegisterBufferUchar( + IN PUCHAR Register, + IN PUCHAR Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortReadRegisterBufferUshort( + IN PUSHORT Register, + IN PUSHORT Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortReadRegisterBufferUlong( + IN PULONG Register, + IN PULONG Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortStallExecution( + IN ULONG Delay + ); + +SCSIPORT_API +VOID +ScsiPortWritePortUchar( + IN PUCHAR Port, + IN UCHAR Value + ); + +SCSIPORT_API +VOID +ScsiPortWritePortUshort( + IN PUSHORT Port, + IN USHORT Value + ); + +SCSIPORT_API +VOID +ScsiPortWritePortUlong( + IN PULONG Port, + IN ULONG Value + ); + +SCSIPORT_API +VOID +ScsiPortWritePortBufferUchar( + IN PUCHAR Port, + IN PUCHAR Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortWritePortBufferUshort( + IN PUSHORT Port, + IN PUSHORT Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortWritePortBufferUlong( + IN PULONG Port, + IN PULONG Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortWriteRegisterUchar( + IN PUCHAR Register, + IN UCHAR Value + ); + +SCSIPORT_API +VOID +ScsiPortWriteRegisterUshort( + IN PUSHORT Register, + IN USHORT Value + ); + +SCSIPORT_API +VOID +ScsiPortWriteRegisterUlong( + IN PULONG Register, + IN ULONG Value + ); + +SCSIPORT_API +VOID +ScsiPortWriteRegisterBufferUchar( + IN PUCHAR Register, + IN PUCHAR Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortWriteRegisterBufferUshort( + IN PUSHORT Register, + IN PUSHORT Buffer, + IN ULONG Count + ); + +SCSIPORT_API +VOID +ScsiPortWriteRegisterBufferUlong( + IN PULONG Register, + IN PULONG Buffer, + IN ULONG Count + ); + +SCSIPORT_API +SCSI_PHYSICAL_ADDRESS +ScsiPortConvertUlongToPhysicalAddress( + ULONG UlongAddress + ); + +SCSIPORT_API +ULONG +ScsiPortConvertPhysicalAddressToUlong( + SCSI_PHYSICAL_ADDRESS Address + ); + +#define ScsiPortConvertPhysicalAddressToUlong(Address) ((Address).LowPart) + +SCSIPORT_API +BOOLEAN +ScsiPortValidateRange( + IN PVOID HwDeviceExtension, + IN INTERFACE_TYPE BusType, + IN ULONG SystemIoBusNumber, + IN SCSI_PHYSICAL_ADDRESS IoAddress, + IN ULONG NumberOfBytes, + IN BOOLEAN InIoSpace + ); + +// begin_ntminitape + +SCSIPORT_API +VOID +ScsiDebugPrint( + ULONG DebugPrintLevel, + PCCHAR DebugMessage, + ... + ); + +// end_ntminitape + +#endif //USER_MODE + +#endif // diff --git a/reactos/drivers/storage/ide/uniata/stdafx.cpp b/reactos/drivers/storage/ide/uniata/stdafx.cpp new file mode 100644 index 00000000000..fd4f341c7b2 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/reactos/drivers/storage/ide/uniata/stdafx.h b/reactos/drivers/storage/ide/uniata/stdafx.h new file mode 100644 index 00000000000..e0f83cc7cac --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/stdafx.h @@ -0,0 +1,25 @@ +extern "C" { + +#include + +}; +#include "stddef.h" +#include "stdarg.h" + +#include "inc\CrossNt.h" + +#include "atapi.h" // includes scsi.h +#include "ntdddisk.h" +#include "ntddscsi.h" +#include "bsmaster.h" +#include "uniata_ver.h" +#include "id_sata.h" + +#ifndef UNIATA_CORE + +#include "id_queue.h" + +#endif //UNIATA_CORE + +#include "badblock.h" + diff --git a/reactos/drivers/storage/ide/uniata/tools.h b/reactos/drivers/storage/ide/uniata/tools.h new file mode 100644 index 00000000000..ac40559c8aa --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/tools.h @@ -0,0 +1,375 @@ +/*++ + +Copyright (c) 2002-2005 Alexandr A. Telyatnikov (Alter) + +Module Name: + tools.h + +Abstract: + This header contains some useful definitions for data manipulation. + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + +--*/ + +#ifndef __TOOLS_H__ +#define __TOOLS_H__ + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +//---------------- + +#ifndef USER_MODE +#include // various NT definitions +#endif //USER_MODE + +//---------------- + +#ifndef FOUR_BYTE_DEFINED +#define FOUR_BYTE_DEFINED +typedef struct _FOUR_BYTE { + UCHAR Byte0; + UCHAR Byte1; + UCHAR Byte2; + UCHAR Byte3; +} FOUR_BYTE, *PFOUR_BYTE; +#endif //FOUR_BYTE_DEFINED + +#ifdef _DEBUG + +#ifndef DBG +#define DBG +#endif // DBG + +#else // _DEBUG + +#ifdef DBG +#undef DBG +#endif // DBG + +#endif // _DEBUG + +// This macro has the effect of Bit = log2(Data) + +#define WHICH_BIT(Data, Bit) { \ + for (Bit = 0; Bit < 32; Bit++) { \ + if ((Data >> Bit) == 1) { \ + break; \ + } \ + } \ +} + +#define PAGE_MASK (PAGE_SIZE-1) + +#define ntohs(x) ( (((USHORT)x[0])<<8) | x[1] ) +#define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive) +#define MSF_TO_LBA(Minutes,Seconds,Frames) \ + (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150)) +#define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \ +{ \ + (Minutes) = (UCHAR)(Lba / (60 * 75)); \ + (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \ + (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \ +} +#define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10)) + +/* + +#if defined _X86_ && !defined(__GNUC__) + +#define MOV_DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm bswap eax \ + __asm mov ebx,_to_ \ + __asm mov [ebx],eax \ +} + +#define MOV_DW_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov ax,[ebx] \ + __asm rol ax,8 \ + __asm mov ebx,_to_ \ + __asm mov [ebx],ax \ +} + +#define REVERSE_DD(a) { \ + PFOUR_BYTE _from_; \ + _from_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm bswap eax \ + __asm mov [ebx],eax \ +} + +#define REVERSE_DW(a) { \ + PFOUR_BYTE _from_; \ + _from_ = ((PFOUR_BYTE)&(a)); \ + __asm mov eax,_from_ \ + __asm rol word ptr [eax],8 \ +} + +#define MOV_DW2DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov ax,[ebx] \ + __asm rol ax,8 \ + __asm mov ebx,_to_ \ + __asm mov [ebx+2],ax \ + __asm mov [ebx],0 \ +} + +#define MOV_SWP_DW2DD(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm xor eax,eax \ + __asm mov ax,[ebx] \ + __asm rol ax,8 \ + __asm mov ebx,_to_ \ + __asm mov [ebx],eax \ +} + +#define MOV_MSF(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm mov ebx,_to_ \ + __asm mov [ebx],ax \ + __asm shr eax,16 \ + __asm mov [ebx+2],al \ +} + +#define MOV_MSF_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov eax,[ebx] \ + __asm mov ebx,_to_ \ + __asm mov [ebx+2],al \ + __asm bswap eax \ + __asm shr eax,8 \ + __asm mov [ebx],ax \ +} + +#define XCHG_DD(a,b) \ +{ \ + PULONG _from_, _to_; \ + _from_ = ((PULONG)&(b)); \ + _to_ = ((PULONG)&(a)); \ + __asm mov ebx,_from_ \ + __asm mov ecx,_to_ \ + __asm mov eax,[ebx] \ + __asm xchg eax,[ecx] \ + __asm mov [ebx],eax \ +} + +#else // NO X86 optimization , use generic C/C++ + +#define MOV_DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte3; \ + _to_->Byte1 = _from_->Byte2; \ + _to_->Byte2 = _from_->Byte1; \ + _to_->Byte3 = _from_->Byte0; \ +} + +#define MOV_DW_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte1; \ + _to_->Byte1 = _from_->Byte0; \ +} + +#define REVERSE_DD(a) { \ + ULONG _i_; \ + MOV_DD_SWP(_i_,(a)); \ + *((PULONG)&(a)) = _i_; \ +} + +#define REVERSE_DW(a) { \ + USHORT _i_; \ + MOV_DW_SWP(_i_,(a)); \ + *((PUSHORT)&(a)) = _i_; \ +} + +#define MOV_DW2DD_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + *((PUSHORT)_to_) = 0; \ + _to_->Byte2 = _from_->Byte1; \ + _to_->Byte3 = _from_->Byte0; \ +} + +#define MOV_MSF(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte0; \ + _to_->Byte1 = _from_->Byte1; \ + _to_->Byte2 = _from_->Byte2; \ +} + +#define MOV_MSF_SWP(a,b) \ +{ \ + PFOUR_BYTE _from_, _to_; \ + _from_ = ((PFOUR_BYTE)&(b)); \ + _to_ = ((PFOUR_BYTE)&(a)); \ + _to_->Byte0 = _from_->Byte2; \ + _to_->Byte1 = _from_->Byte1; \ + _to_->Byte2 = _from_->Byte0; \ +} + +#define XCHG_DD(a,b) \ +{ \ + ULONG _temp_; \ + PULONG _from_, _to_; \ + _from_ = ((PULONG)&(b)); \ + _to_ = ((PULONG)&(a)); \ + _temp_ = *_from_; \ + *_from_ = *_to_; \ + *_to_ = _temp_; \ +} + +#endif // _X86_ + +#define MOV_3B_SWP(a,b) MOV_MSF_SWP(a,b) + +*/ + +#ifdef DBG + +#define KdDump(a,b) \ +if((a)!=NULL) { \ + ULONG i; \ + for(i=0; i<(b); i++) { \ + ULONG c; \ + c = (ULONG)(*(((PUCHAR)(a))+i)); \ + KdPrint(("%2.2x ",c)); \ + if ((i & 0x0f) == 0x0f) KdPrint(("\n")); \ + } \ + KdPrint(("\n")); \ +} + +#define BrutePoint() {} + +#define DbgAllocatePool(x,y) ExAllocatePool(x,y) +#define DbgFreePool(x) ExFreePool(x) +#define DbgAllocatePoolWithTag(a,b,c) ExAllocatePoolWithTag(a,b,c) + +#else + +#define KdDump(a,b) {} + +#define DbgAllocatePool(x,y) ExAllocatePool(x,y) +#define DbgFreePool(x) ExFreePool(x) +#define DbgAllocatePoolWithTag(a,b,c) ExAllocatePoolWithTag(a,b,c) + +#define BrutePoint() {} + +#endif //DBG + + + +#define WAIT_FOR_XXX_EMU_DELAY DEF_I64(5000000) // 0.5 s + +// neat little hacks to count number of bits set efficiently +__inline ULONG CountOfSetBitsUChar(UCHAR _X) +{ ULONG i = 0; while (_X) { _X &= _X - 1; i++; } return i; } +__inline ULONG CountOfSetBitsULong(ULONG _X) +{ ULONG i = 0; while (_X) { _X &= _X - 1; i++; } return i; } + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif //max + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif //min +//#define abs(a) (((a) < 0) ? (-(a)) : (a)) + +/* +extern ULONG MajorVersion; +extern ULONG MinorVersion; +extern ULONG BuildNumber; +extern ULONG SPVersion; +*/ + +#ifdef __cplusplus +}; +#endif //__cplusplus + +#ifndef USER_MODE +extern UNICODE_STRING SavedSPString; +#endif //USER_MODE + +/* +#define WinVer_Is351 (MajorVersion==0x03) +#define WinVer_IsNT (MajorVersion==0x04) +#define WinVer_Is2k (MajorVersion==0x05 && MinorVersion==0x00) +#define WinVer_IsXP (MajorVersion==0x05 && MinorVersion==0x01) +#define WinVer_IsdNET (MajorVersion==0x05 && MinorVersion==0x02) + +#define WinVer_Id() ((MajorVersion << 8) | MinorVersion) + +#define WinVer_351 (0x0351) +#define WinVer_NT (0x0400) +#define WinVer_2k (0x0500) +#define WinVer_XP (0x0501) +#define WinVer_dNET (0x0502) +*/ + +#define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG)(OFFSET) - (ULONG)(BASE))) + +#ifndef offsetof +#define offsetof(type, field) (ULONG)&(((type *)0)->field) +#endif //offsetof + +#endif // __TOOLS_H__ diff --git a/reactos/drivers/storage/ide/uniata/uata_ctl.h b/reactos/drivers/storage/ide/uniata/uata_ctl.h new file mode 100644 index 00000000000..1845b4c59b4 --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/uata_ctl.h @@ -0,0 +1,229 @@ +/*++ + +Copyright (c) 2004-2005 Alexandr A. Telyatnikov (Alter) + +Module Name: + uata_ctl.h + +Abstract: + This header contains definitions for private UniATA SRB_IOCTL. + +Author: + Alexander A. Telyatnikov (Alter) + +Environment: + kernel mode only + +Notes: + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Revision History: + +--*/ + +#ifndef __UNIATA_IO_CONTROL_CODES__H__ +#define __UNIATA_IO_CONTROL_CODES__H__ + +//#include "scsi.h" + +#pragma pack(push, 8) + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#define AHCI_MAX_PORT 32 +#define IDE_MAX_CHAN 8 +// Thanks to SATA Port Multipliers: +#define IDE_MAX_LUN_PER_CHAN 16 +#define IDE_MAX_LUN (AHCI_MAX_PORT*IDE_MAX_LUN_PER_CHAN) + +#define MAX_QUEUE_STAT 8 + + +#ifndef UNIATA_CORE + +#define IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES ((FILE_DEVICE_SCSI << 16) + 0x09a0) +#define IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE ((FILE_DEVICE_SCSI << 16) + 0x09a1) +#define IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE ((FILE_DEVICE_SCSI << 16) + 0x09a2) +#define IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE ((FILE_DEVICE_SCSI << 16) + 0x09a3) +#define IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO ((FILE_DEVICE_SCSI << 16) + 0x09a4) +//#define IOCTL_SCSI_MINIPORT_UNIATA_LUN_IDENT ((FILE_DEVICE_SCSI << 16) + 0x09a5) -> IOCTL_SCSI_MINIPORT_IDENTIFY +#define IOCTL_SCSI_MINIPORT_UNIATA_RESETBB ((FILE_DEVICE_SCSI << 16) + 0x09a5) +#define IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE ((FILE_DEVICE_SCSI << 16) + 0x09a6) +#define IOCTL_SCSI_MINIPORT_UNIATA_REG_IO ((FILE_DEVICE_SCSI << 16) + 0x09a7) + +typedef struct _ADDREMOVEDEV { + ULONG WaitForPhysicalLink; // us +} ADDREMOVEDEV, *PADDREMOVEDEV; + +typedef struct _SETTRANSFERMODE { + ULONG MaxMode; + ULONG OrigMode; + BOOLEAN ApplyImmediately; + UCHAR Reserved[3]; +} SETTRANSFERMODE, *PSETTRANSFERMODE; + +typedef struct _GETTRANSFERMODE { + ULONG MaxMode; + ULONG OrigMode; + ULONG CurrentMode; + ULONG Reserved; +} GETTRANSFERMODE, *PGETTRANSFERMODE; + +typedef struct _CHANINFO { + ULONG MaxTransferMode; // may differ from Controller's value due to 40-pin cable + ULONG ChannelCtrlFlags; +//#ifdef QUEUE_STATISTICS + LONGLONG QueueStat[MAX_QUEUE_STAT]; + LONGLONG ReorderCount; + LONGLONG IntersectCount; + LONGLONG TryReorderCount; + LONGLONG TryReorderHeadCount; + LONGLONG TryReorderTailCount; /* in-order requests */ +//#endif //QUEUE_STATISTICS +} CHANINFO, *PCHANINFO; + +typedef struct _ADAPTERINFO { + // Device identification + ULONG HeaderLength; + ULONG DevID; + ULONG RevID; + ULONG slotNumber; + ULONG SystemIoBusNumber; + ULONG DevIndex; + + ULONG Channel; + + ULONG HbaCtrlFlags; + BOOLEAN simplexOnly; + BOOLEAN MemIo; + BOOLEAN UnknownDev; + BOOLEAN MasterDev; + + ULONG MaxTransferMode; + ULONG HwFlags; + ULONG OrigAdapterInterfaceType; + + CHAR DeviceName[64]; + + ULONG BusInterruptLevel; // Interrupt level + ULONG InterruptMode; // Interrupt Mode (Level or Edge) + ULONG BusInterruptVector; + // 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; + + BOOLEAN ChanInfoValid; + + CHANINFO Chan[AHCI_MAX_PORT]; + +} ADAPTERINFO, *PADAPTERINFO; + +#ifndef ATA_FLAGS_DRDY_REQUIRED + +//The ATA_PASS_THROUGH_DIRECT structure is used in conjunction with an IOCTL_ATA_PASS_THROUGH_DIRECT request to instruct the port driver to send an embedded ATA command to the target device. + +typedef struct _ATA_PASS_THROUGH_DIRECT { + USHORT Length; + USHORT AtaFlags; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR ReservedAsUchar; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG ReservedAsUlong; + PVOID DataBuffer; + UCHAR PreviousTaskFile[8]; + UCHAR CurrentTaskFile[8]; +} ATA_PASS_THROUGH_DIRECT, *PATA_PASS_THROUGH_DIRECT; + +#define ATA_FLAGS_DRDY_REQUIRED 0x01 // Wait for DRDY status from the device before sending the command to the device. +#define ATA_FLAGS_DATA_OUT 0x02 // Write data to the device. +#define ATA_FLAGS_DATA_IN 0x04 // Read data from the device. +#define ATA_FLAGS_48BIT_COMMAND 0x08 // The ATA command to be send uses the 48 bit LBA feature set. + // When this flag is set, the contents of the PreviousTaskFile member in the + // ATA_PASS_THROUGH_DIRECT structure should be valid. + +#endif //ATA_FLAGS_DRDY_REQUIRED + +#pragma pack(1) +typedef struct _IDEREGS_EX { + UCHAR bFeaturesReg; // Used for specifying SMART "commands". + UCHAR bSectorCountReg; // IDE sector count register + UCHAR bSectorNumberReg; // IDE sector number register + UCHAR bCylLowReg; // IDE low order cylinder value + UCHAR bCylHighReg; // IDE high order cylinder value + UCHAR bDriveHeadReg; // IDE drive/head register + UCHAR bCommandReg; // Actual IDE command. + UCHAR bOpFlags; // 00 - send + // 01 - read regs + // 08 - lba48 + // 10 - treat timeout as msec + +#define UNIATA_SPTI_EX_SND 0x00 +#define UNIATA_SPTI_EX_RCV 0x01 +#define UNIATA_SPTI_EX_LBA48 0x08 +#define UNIATA_SPTI_EX_SPEC_TO 0x10 +//#define UNIATA_SPTI_EX_FREEZE_TO 0x20 // do not reset device on timeout and keep interrupts disabled + + UCHAR bFeaturesRegH; // feature (high part for LBA48 mode) + UCHAR bSectorCountRegH; // IDE sector count register (high part for LBA48 mode) + UCHAR bSectorNumberRegH; // IDE sector number register (high part for LBA48 mode) + UCHAR bCylLowRegH; // IDE low order cylinder value (high part for LBA48 mode) + UCHAR bCylHighRegH; // IDE high order cylinder value (high part for LBA48 mode) + UCHAR bReserved; // 0 +} IDEREGS_EX, *PIDEREGS_EX, *LPIDEREGS_EX; + +typedef struct _UNIATA_REG_IO { + USHORT RegIDX; + UCHAR RegSz:2; // 0=1, 1=2, 2=4, 3=2+2 (for lba48) + UCHAR InOut:1; // 0=in, 1=out + UCHAR Reserved:5; + UCHAR Reserved1; + ULONG Data; +} UNIATA_REG_IO, *PUNIATA_REG_IO; + +typedef struct _UNIATA_REG_IO_HDR { + ULONG ItemCount; + UNIATA_REG_IO r[1]; +} UNIATA_REG_IO_HDR, *PUNIATA_REG_IO_HDR; +#pragma pack() + +typedef struct _UNIATA_CTL { + SRB_IO_CONTROL hdr; + SCSI_ADDRESS addr; + union { + UCHAR RawData[1]; + ADDREMOVEDEV FindDelDev; + SETTRANSFERMODE SetMode; + GETTRANSFERMODE GetMode; + ADAPTERINFO AdapterInfo; +// IDENTIFY_DATA2 LunIdent; +// ATA_PASS_THROUGH_DIRECT AtaDirect; + UNIATA_REG_IO_HDR RegIo; + }; +} UNIATA_CTL, *PUNIATA_CTL; + +#endif //UNIATA_CORE + +#ifdef __cplusplus +}; +#endif //__cplusplus + +#pragma pack(pop) + +#endif //__UNIATA_IO_CONTROL_CODES__H__ diff --git a/reactos/drivers/storage/ide/uniata/uniata_ver.h b/reactos/drivers/storage/ide/uniata/uniata_ver.h new file mode 100644 index 00000000000..d5a3377000e --- /dev/null +++ b/reactos/drivers/storage/ide/uniata/uniata_ver.h @@ -0,0 +1,2 @@ + +#define UNIATA_VER_STR "38c2"