Index: drivers/storage/ide/uniata/atapi.h =================================================================== --- drivers/storage/ide/uniata/atapi.h (revision 57016) +++ drivers/storage/ide/uniata/atapi.h (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2002-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2002-2012 Alexandr A. Telyatnikov (Alter) Module Name: atapi.h @@ -106,7 +106,7 @@ #define PRINT_PREFIX // Note, that using DbgPrint on raised IRQL will crash w2k -// tis will not happen immediately, so we shall see some logs +// ttis will not happen immediately, so we shall see some logs //#define LOG_ON_RAISED_IRQL_W2K TRUE //#define LOG_ON_RAISED_IRQL_W2K FALSE @@ -249,6 +249,7 @@ #define DFLAGS_REINIT_DMA 0x4000 // #define DFLAGS_HIDDEN 0x8000 // Hidden device, available only with special IOCTLs // via communication virtual device +#define DFLAGS_MANUAL_CHS 0x10000 // For devices those have no IDENTIFY commands //#define DFLAGS_ 0x10000 // // // Used to disable 'advanced' features. @@ -299,6 +300,7 @@ // IDE command definitions // +#define IDE_COMMAND_DATA_SET_MGMT 0x06 // TRIM #define IDE_COMMAND_ATAPI_RESET 0x08 #define IDE_COMMAND_RECALIBRATE 0x10 #define IDE_COMMAND_READ 0x20 @@ -380,7 +382,10 @@ #define IDE_STATUS_IDLE 0x50 #define IDE_STATUS_BUSY 0x80 +#define IDE_STATUS_WRONG 0xff +#define IDE_STATUS_MASK 0xff + // // IDE drive select/head definitions // @@ -615,7 +620,11 @@ USHORT CurrentMultiSector:8; // 59 USHORT CurrentMultiSectorValid:1; - USHORT Reserved59_9:7; + USHORT Reserved59_9_11:3; + USHORT SanitizeSupported:1; + USHORT CryptoScrambleExtSupported:1; + USHORT OverwriteExtSupported:1; + USHORT BlockEraseExtSupported:1; ULONG UserAddressableSectors; // 60-61 @@ -637,7 +646,20 @@ USHORT MinimumPIOCycleTime; // 67 USHORT MinimumPIOCycleTimeIORDY; // 68 - USHORT Reserved69_70[2]; // 69-70 + USHORT Reserved69_0_4:5; // 69 + USHORT ReadZeroAfterTrim:1; + USHORT Lba28Support:1; + USHORT Reserved69_7_IEEE1667:1; + USHORT MicrocodeDownloadDMA:1; + USHORT MaxPwdDMA:1; + USHORT WriteBufferDMA:1; + USHORT ReadBufferDMA:1; + USHORT DevConfigDMA:1; + USHORT LongSectorErrorReporting:1; + USHORT DeterministicReadAfterTrim:1; + USHORT CFastSupport:1; + + USHORT Reserved70; // 70 USHORT ReleaseTimeOverlapped; // 71 USHORT ReleaseTimeServiceCommand; // 72 USHORT Reserved73_74[2]; // 73-74 @@ -651,6 +673,9 @@ #define ATA_SATA_GEN3 0x0008 #define ATA_SUPPORT_NCQ 0x0100 #define ATA_SUPPORT_IFPWRMNGTRCV 0x0200 +#define ATA_SUPPORT_PHY_EVENT_COUNTER 0x0400 +#define ATA_SUPPORT_NCQ_UNLOAD 0x0800 +#define ATA_SUPPORT_NCQ_PRI_INFO 0x1000 USHORT Reserved77; // 77 @@ -664,6 +689,12 @@ USHORT MajorRevision; // 80 USHORT MinorRevision; // 81 +#define ATA_VER_MJ_ATA4 0x0010 +#define ATA_VER_MJ_ATA5 0x0020 +#define ATA_VER_MJ_ATA6 0x0040 +#define ATA_VER_MJ_ATA7 0x0080 +#define ATA_VER_MJ_ATA8_ASC 0x0100 + struct { USHORT Smart:1; // 82/85 USHORT Security:1; @@ -734,7 +765,8 @@ ULONGLONG UserAddressableSectors48; // 100-103 - USHORT Reserved104[2]; // 104-105 + USHORT StreamingTransferTimePIO; // 104 + USHORT MaxLBARangeDescBlockCount; // 105 // in 512b blocks union { USHORT PhysLogSectorSize; // 106 struct { @@ -745,22 +777,101 @@ USHORT PLSS_Signature:2; // = 0x01 = 01b }; }; - USHORT Reserved107[10]; // 107-116 + USHORT InterSeekDelay; // 107 + USHORT WorldWideName[4]; // 108-111 + USHORT Reserved112[5]; // 112-116 ULONG LargeSectorSize; // 117-118 - USHORT Reserved117[8]; // 119-126 + USHORT Reserved119[8]; // 119-126 USHORT RemovableStatus; // 127 USHORT SecurityStatus; // 128 - USHORT FeaturesSupport4; // 129 - USHORT Reserved130[30]; // 130-159 + USHORT Reserved129[31]; // 129-159 USHORT CfAdvPowerMode; // 160 - USHORT Reserved161[14]; // 161-175 + USHORT Reserved161[7]; // 161-167 + USHORT DeviceNominalFormFactor:4; // 168 + USHORT Reserved168_4_15:12; + USHORT DataSetManagementSupported:1; // 169 + USHORT Reserved169_1_15:15; + USHORT AdditionalProdNum[4]; // 170-173 + USHORT Reserved174[2]; // 174-175 USHORT MediaSerial[30]; // 176-205 - USHORT Reserved206[49]; // 205-254 - USHORT Integrity; // 255 + union { + USHORT SCT; // 206 + struct { + USHORT SCT_Supported:1; + USHORT Reserved:1; + USHORT SCT_WriteSame:1; + USHORT SCT_ErrorRecovery:1; + USHORT SCT_Feature:1; + USHORT SCT_DataTables:1; + USHORT Reserved_6_15:10; + }; + }; + USHORT Reserved_CE_ATA[2]; // 207-208 + USHORT LogicalSectorOffset:14; // 209 + USHORT Reserved209_14_One:1; + USHORT Reserved209_15_Zero:1; + + USHORT WriteReadVerify_CountMode2[2]; // 210-211 + USHORT WriteReadVerify_CountMode3[2]; // 212-213 + + USHORT NVCache_PM_Supported:1; // 214 + USHORT NVCache_PM_Enabled:1; + USHORT NVCache_Reserved_2_3:2; + USHORT NVCache_Enabled:1; + USHORT NVCache_Reserved_5_7:3; + USHORT NVCache_PM_Version:4; + USHORT NVCache_Version:4; + + USHORT NVCache_Size_LogicalBlocks[2]; // 215-216 + USHORT NominalMediaRotationRate; // 217 + USHORT Reserved218; // 218 + USHORT NVCache_DeviceSpinUpTime:8; // 219 + USHORT NVCache_Reserved219_8_15:8; + + USHORT WriteReadVerify_CurrentMode:8; // 220 + USHORT WriteReadVerify_Reserved220_8_15:8; + + USHORT Reserved221; // 221 + union { + struct { + USHORT VersionFlags:12; + USHORT TransportType:4; + }; + struct { + USHORT ATA8_APT:1; + USHORT ATA_ATAPI7:1; + USHORT Reserved:14; + } PATA; + struct { + USHORT ATA8_AST:1; + USHORT v10a:1; + USHORT II_Ext:1; + USHORT v25:1; + USHORT v26:1; + USHORT v30:1; + USHORT Reserved:10; + } SATA; + } TransportMajor; + USHORT TransportMinor; // 223 + + USHORT Reserved224[10]; // 224-233 + + USHORT MinBlocks_MicrocodeDownload_Mode3; // 234 + USHORT MaxBlocks_MicrocodeDownload_Mode3; // 235 + + USHORT Reserved236[19]; // 236-254 + + union { + USHORT Integrity; // 255 + struct { + USHORT ChecksumValid:8; + USHORT Checksum:8; + }; + }; } IDENTIFY_DATA, *PIDENTIFY_DATA; // @@ -813,10 +924,18 @@ #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 + +// for IDE_COMMAND_DATA_SET_MGMT +typedef struct _TRIM_DATA { + ULONGLONG Lba:48; + ULONGLONG BlockCount:16; +} TRIM_DATA, *PTRIM_DATA; + /* #define PCI_DEV_HW_SPEC(idhi, idlo) \ { #idlo, 4, #idhi, 4} @@ -1219,6 +1338,12 @@ IN ULONG c ); +extern VOID +UniataExpectChannelInterrupt( + IN struct _HW_CHANNEL* chan, + IN BOOLEAN Expecting + ); + #define CHAN_NOT_SPECIFIED (0xffffffffL) #define CHAN_NOT_SPECIFIED_CHECK_CABLE (0xfffffffeL) #define DEVNUM_NOT_SPECIFIED (0xffffffffL) @@ -1303,7 +1428,7 @@ ULONGLONG lba ); -BOOLEAN +ULONG NTAPI UniataAnybodyHome( IN PVOID HwDeviceExtension, @@ -1311,10 +1436,18 @@ IN ULONG deviceNumber ); +#define ATA_AT_HOME_HDD 0x01 +#define ATA_AT_HOME_ATAPI 0x02 +#define ATA_AT_HOME_XXX 0x04 +#define ATA_AT_HOME_NOBODY 0x00 + #define ATA_CMD_FLAG_LBAIOsupp 0x01 #define ATA_CMD_FLAG_48supp 0x02 #define ATA_CMD_FLAG_48 0x04 #define ATA_CMD_FLAG_DMA 0x08 +#define ATA_CMD_FLAG_FUA 0x10 +#define ATA_CMD_FLAG_In 0x40 +#define ATA_CMD_FLAG_Out 0x80 extern UCHAR AtaCommands48[256]; extern UCHAR AtaCommandFlags[256]; @@ -1327,6 +1460,15 @@ ( ((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) && (supp48) && (((lba+count) >= ATA_MAX_IOLBA28) || (count > 256)) ) || \ (lba > ATA_MAX_LBA28) || (count > 255) ) +#define UniAtaClearAtaReq(AtaReq) \ +{ \ + RtlZeroMemory((PCHAR)(AtaReq), FIELD_OFFSET(ATA_REQ, ata)); \ +} + + +//#define ATAPI_DEVICE(de, ldev) (de->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) +#define ATAPI_DEVICE(chan, dev) ((chan->lun[dev]->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE) + #ifdef _DEBUG #define PrintNtConsole _PrintNtConsole #else //_DEBUG Index: drivers/storage/ide/uniata/bm_devs.h =================================================================== --- drivers/storage/ide/uniata/bm_devs.h (revision 57016) +++ drivers/storage/ide/uniata/bm_devs.h (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2002-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2002-2012 Alexandr A. Telyatnikov (Alter) Module Name: bm_devs.h @@ -88,11 +88,17 @@ #ifndef __IDE_BUSMASTER_DEVICES_H__ #define __IDE_BUSMASTER_DEVICES_H__ +#ifdef USER_MODE +#define PVEN_STR PCSTR +#else // USER_MODE +#define PVEN_STR PCHAR +#endif // USER_MODE + typedef struct _BUSMASTER_CONTROLLER_INFORMATION { - PCHAR VendorId; + PVEN_STR VendorId; ULONG VendorIdLength; ULONG nVendorId; - PCHAR DeviceId; + PVEN_STR DeviceId; ULONG DeviceIdLength; ULONG nDeviceId; ULONG nRevId; @@ -692,10 +698,10 @@ #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} + { (PVEN_STR) #idlo, 4, 0x##idlo, (PVEN_STR) #idhi, 4, 0x##idhi, rev, mode, name, flags} #else #define PCI_DEV_HW_SPEC_BM(idhi, idlo, rev, mode, name, flags) \ - { (PCHAR) #idlo, 4, 0x##idlo, (PCHAR) #idhi, 4, 0x##idhi, rev, mode, NULL, flags} + { (PVEN_STR) #idlo, 4, 0x##idlo, (PVEN_STR) #idhi, 4, 0x##idhi, rev, mode, NULL, flags} #endif #define BMLIST_TERMINATOR (0xffffffffL) Index: drivers/storage/ide/uniata/bsmaster.h =================================================================== --- drivers/storage/ide/uniata/bsmaster.h (revision 57016) +++ drivers/storage/ide/uniata/bsmaster.h (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2002-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2002-2012 Alexandr A. Telyatnikov (Alter) Module Name: bsmaster.h @@ -163,12 +163,14 @@ // HBA Capabilities struct { ULONG NOP:5; // number of ports - ULONG Reserved5_7:1; + ULONG SXS:1; // Supports External SATA + ULONG EMS:1; // Enclosure Management Supported + ULONG CCCS:1; // Command Completion Coalescing Supported 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 FBSS:1; // FIS-based Switching Supported ULONG SPM:1; // port multiplier ULONG SAM:1; // AHCI mode only @@ -179,7 +181,7 @@ ULONG SALP:1; // aggressive link power management ULONG SSS:1; // staggered spin-up ULONG SIS:1; // interlock switch - ULONG Reserved29:1; + ULONG SSNTF:1; // Supports SNotification Register ULONG SNCQ:1; // native command queue ULONG S64A:1; // 64bit addr } CAP; @@ -206,15 +208,41 @@ #define AHCI_GHC_AE 0x80000000 // Interrupt status (bit mask) - ULONG IS; + ULONG IS; // 0x08 // Ports implemented (bit mask) - ULONG PI; + ULONG PI; // 0x0c // AHCI Version - ULONG VS; - ULONG Reserved[3]; + ULONG VS; // 0x10 - UCHAR Reserved2[0x80]; + ULONG CCC_CTL; // 0x14 + ULONG CCC_PORTS; // 0x18 + ULONG EM_LOC; // 0x1c + ULONG EM_CTL; // 0x20 + // Extended HBA Capabilities + struct { // 0x24 + ULONG BOH:1; // BIOS/OS Handoff + ULONG NVMP:1; // NVMHCI Present + ULONG APST:1; // Automatic Partial to Slumber Transitions + ULONG Reserved:29; + } CAP2; + +#define AHCI_CAP2_BOH 0x00000001 +#define AHCI_CAP2_NVMP 0x00000002 +#define AHCI_CAP2_APST 0x00000004 + + // BIOS/OS Handoff Control and Status + struct { // 0x28 + ULONG BB:1; // BIOS Busy + ULONG OOC:1; // OS Ownership Change + ULONG SOOE:1; // SMI on OS Ownership Change Enable + ULONG OOS:1; // OS Owned Semaphore + ULONG BOS:1; // BIOS Owned Semaphore + ULONG Reserved:27; + } BOHC; + + UCHAR Reserved2[0x74]; + UCHAR VendorSpec[0x60]; } IDE_AHCI_REGISTERS, *PIDE_AHCI_REGISTERS; @@ -223,6 +251,8 @@ #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)) +#define IDX_AHCI_CAP2 (FIELD_OFFSET(IDE_AHCI_REGISTERS, CAP2)) +#define IDX_AHCI_BOHC (FIELD_OFFSET(IDE_AHCI_REGISTERS, BOHC)) typedef union _SATA_SSTATUS_REG { @@ -561,7 +591,22 @@ }; } SNTF; // 0x100 + 0x80*c + 0x003c - ULONG FIS_Switching_Reserved[12]; + // AHCI 1.2 + union { + ULONG Reg; + struct { + ULONG EN:1; // Enable + ULONG DEC:1; // Device Error Clear + ULONG SDE:1; // Single Device Error + ULONG Reserved_3_7:5; // Reserved + ULONG DEV:4; // Device To Issue + ULONG ADO:4; // Active Device Optimization (recommended parallelism) + ULONG DWE:4; // Device With Error + ULONG Reserved_20_31:12; // Reserved + }; + } FBS; // 0x100 + 0x80*c + 0x0040 + + ULONG Reserved_44_7f[11]; UCHAR VendorSpec[16]; } IDE_AHCI_PORT_REGISTERS, *PIDE_AHCI_PORT_REGISTERS; @@ -617,9 +662,14 @@ }; ULONG Reserved1; - ULONG DBC:22; - ULONG Reserved2:9; - ULONG I:1; + union { + struct { + ULONG DBC:22; + ULONG Reserved2:9; + ULONG I:1; + }; + ULONG DBC_ULONG; + }; } IDE_AHCI_PRD_ENTRY, *PIDE_AHCI_PRD_ENTRY; @@ -628,7 +678,51 @@ #define AHCI_FIS_TYPE_ATA_H2D 0x27 #define AHCI_FIS_TYPE_ATA_D2H 0x34 +#define AHCI_FIS_TYPE_DMA_D2H 0x39 +#define AHCI_FIS_TYPE_DMA_BiDi 0x41 +#define AHCI_FIS_TYPE_DATA_BiDi 0x46 +#define AHCI_FIS_TYPE_BIST_BiDi 0x58 +#define AHCI_FIS_TYPE_PIO_D2H 0x5f +#define AHCI_FIS_TYPE_DEV_BITS_D2H 0xA1 +typedef struct _AHCI_ATA_H2D_FIS { + UCHAR FIS_Type; // = 0x27 + UCHAR Reserved1:7; + UCHAR Cmd:1; // update Command register + UCHAR Command; // [2] + UCHAR Feature; // [3] + + UCHAR BlockNumber; // [4] + UCHAR CylinderLow; // [5] + UCHAR CylinderHigh; // [6] + UCHAR DriveSelect; // [7] + + UCHAR BlockNumberExp; // [8] + UCHAR CylinderLowExp; // [9] + UCHAR CylinderHighExp; // [10] + UCHAR FeatureExp; // [11] + + UCHAR BlockCount; // [12] + UCHAR BlockCountExp; // [13] + UCHAR Reserved14; // [14] + UCHAR Control; // [15] + +} AHCI_ATA_H2D_FIS, *PAHCI_ATA_H2D_FIS; + +#define IDX_AHCI_o_Command (FIELD_OFFSET(AHCI_ATA_H2D_FIS, Command)) +#define IDX_AHCI_o_Feature (FIELD_OFFSET(AHCI_ATA_H2D_FIS, Feature)) +#define IDX_AHCI_o_BlockNumber (FIELD_OFFSET(AHCI_ATA_H2D_FIS, BlockNumber )) +#define IDX_AHCI_o_CylinderLow (FIELD_OFFSET(AHCI_ATA_H2D_FIS, CylinderLow )) +#define IDX_AHCI_o_CylinderHigh (FIELD_OFFSET(AHCI_ATA_H2D_FIS, CylinderHigh)) +#define IDX_AHCI_o_DriveSelect (FIELD_OFFSET(AHCI_ATA_H2D_FIS, DriveSelect )) +#define IDX_AHCI_o_BlockCount (FIELD_OFFSET(AHCI_ATA_H2D_FIS, BlockCount)) +#define IDX_AHCI_o_Control (FIELD_OFFSET(AHCI_ATA_H2D_FIS, Control)) +#define IDX_AHCI_o_FeatureExp (FIELD_OFFSET(AHCI_ATA_H2D_FIS, FeatureExp)) +#define IDX_AHCI_o_BlockNumberExp (FIELD_OFFSET(AHCI_ATA_H2D_FIS, BlockNumberExp )) +#define IDX_AHCI_o_CylinderLowExp (FIELD_OFFSET(AHCI_ATA_H2D_FIS, CylinderLowExp )) +#define IDX_AHCI_o_CylinderHighExp (FIELD_OFFSET(AHCI_ATA_H2D_FIS, CylinderHighExp)) +#define IDX_AHCI_o_BlockCountExp (FIELD_OFFSET(AHCI_ATA_H2D_FIS, BlockCountExp)) + #define AHCI_FIS_COMM_PM (0x80 | AHCI_DEV_SEL_PM) #define AHCI_DEV_SEL_1 0x00 @@ -638,8 +732,8 @@ /* 128-byte aligned */ typedef struct _IDE_AHCI_CMD { UCHAR cfis[64]; - UCHAR acmd[32]; - UCHAR Reserved[32]; + UCHAR acmd[16]; + UCHAR Reserved[48]; IDE_AHCI_PRD_ENTRY prd_tab[ATA_AHCI_DMA_ENTRIES]; // also 128-byte aligned } IDE_AHCI_CMD, *PIDE_AHCI_CMD; @@ -665,11 +759,11 @@ typedef struct _IDE_AHCI_RCV_FIS { UCHAR dsfis[28]; UCHAR Reserved1[4]; - UCHAR psfis[24]; - UCHAR Reserved2[8]; - UCHAR rfis[24]; + UCHAR psfis[20]; + UCHAR Reserved2[12]; + UCHAR rfis[20]; UCHAR Reserved3[4]; - ULONG SDBFIS; + UCHAR SDBFIS[8]; UCHAR ufis[64]; UCHAR Reserved4[96]; } IDE_AHCI_RCV_FIS, *PIDE_AHCI_RCV_FIS; @@ -678,7 +772,7 @@ typedef struct _IDE_AHCI_CHANNEL_CTL_BLOCK { IDE_AHCI_CMD_LIST cmd_list[ATA_AHCI_MAX_TAGS]; // 1K-size (32*32) IDE_AHCI_RCV_FIS rcv_fis; - IDE_AHCI_CMD cmd; // for single internal comamnds w/o associated AtaReq + IDE_AHCI_CMD cmd; // for single internal commands w/o associated AtaReq } IDE_AHCI_CHANNEL_CTL_BLOCK, *PIDE_AHCI_CHANNEL_CTL_BLOCK; @@ -741,7 +835,7 @@ ULONG in_bcount; ULONG in_status; USHORT io_cmd_flags; // out - + UCHAR in_error; } ahci; }; }; @@ -781,7 +875,8 @@ #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_ATAPI_EXPECTING_DATA_INTR2 0x43 +#define REQ_STATE_ATAPI_DO_NOTHING_INTR 0x44 #define REQ_STATE_EARLY_INTR 0x48 @@ -832,9 +927,12 @@ struct _HW_LU_EXTENSION; typedef struct _IORES { - ULONG Addr; /* Base address*/ + union { + ULONG Addr; /* Base address*/ + PVOID pAddr; /* Base address in pointer form */ + }; ULONG MemIo:1; /* Memory mapping (1) vs IO ports (0) */ - ULONG Proc:1; /* Need special process via IO_Proc */ + ULONG Proc:1; /* Need special processing via IO_Proc */ ULONG Reserved:30; } IORES, *PIORES; @@ -867,7 +965,7 @@ //BOOLEAN MemIo; BOOLEAN AltRegMap; - //UCHAR Reserved[3]; + UCHAR Reserved[3]; MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData; SENSE_DATA MechStatusSense; @@ -923,9 +1021,14 @@ PIDE_AHCI_CHANNEL_CTL_BLOCK AhciCtlBlock; // 128-byte aligned ULONGLONG AHCI_CTL_PhAddr; IORES BaseIoAHCI_Port; + ULONG AhciPrevCI; + ULONG AhciCompleteCI; + ULONG AhciLastIS; //PVOID AHCI_FIS; // is not actually used by UniATA now, but is required by AHCI controller //ULONGLONG AHCI_FIS_PhAddr; // Note: in contrast to FBSD, we keep PRD and CMD item in AtaReq structure + PATA_REQ AhciInternalAtaReq; + PSCSI_REQUEST_BLOCK AhciInternalSrb; #ifdef QUEUE_STATISTICS LONGLONG QueueStat[MAX_QUEUE_STAT]; @@ -999,6 +1102,7 @@ ULONG last_write; ULONG LunSelectWaitCount; + ULONG AtapiReadyWaitDelay; // tuning options ULONG opt_GeomType; @@ -1072,6 +1176,7 @@ ULONG ActiveDpcChan; ULONG FirstDpcChan; + ULONG ExpectingInterrupt; // Indicates entire controller expecting an interrupt /* PHW_TIMER HwScsiTimer1; PHW_TIMER HwScsiTimer2; @@ -1115,16 +1220,20 @@ INTERFACE_TYPE AdapterInterfaceType; ULONG MaximumDmaTransferLength; ULONG AlignmentMask; + ULONG DmaSegmentLength; + ULONG DmaSegmentAlignmentMask; // must be PAGE-aligned //ULONG BaseMemAddress; //PIDE_SATA_REGISTERS BaseIoAddressSATA_0; - IORES BaseIoAddressSATA_0; + IORES BaseIoAddressSATA_0; //PIDE_SATA_REGISTERS BaseIoAddressSATA[IDE_MAX_CHAN]; - IORES BaseIoAHCI_0; + IORES BaseIoAHCI_0; //PIDE_AHCI_PORT_REGISTERS BaseIoAHCIPort[AHCI_MAX_PORT]; - ULONG AHCI_CAP; + ULONG AHCI_CAP; + PATA_REQ AhciInternalAtaReq0; + PSCSI_REQUEST_BLOCK AhciInternalSrb0; BOOLEAN opt_AtapiDmaZeroTransfer; // default FALSE BOOLEAN opt_AtapiDmaControlCmd; // default FALSE @@ -1186,13 +1295,17 @@ #define UNIATA_ALLOCATE_NEW_LUNS 0x00 -extern BOOLEAN -NTAPI +extern BOOLEAN NTAPI UniataAllocateLunExt( PHW_DEVICE_EXTENSION deviceExtension, ULONG NewNumberChannels ); +extern VOID NTAPI +UniataFreeLunExt( + PHW_DEVICE_EXTENSION deviceExtension + ); + extern ULONG NTAPI UniataFindBusMasterController( IN PVOID HwDeviceExtension, @@ -1476,9 +1589,13 @@ SetPciConfig4(offs, a); \ } +#define DMA_MODE_NONE 0x00 +#define DMA_MODE_BM 0x01 +#define DMA_MODE_AHCI 0x02 + #ifndef GetDmaStatus #define GetDmaStatus(de, c) \ - (((de)->BusMaster) ? AtapiReadPort1(&((de)->chan[c]), IDX_BM_Status) : 0) + (((de)->BusMaster == DMA_MODE_BM) ? AtapiReadPort1(&((de)->chan[c]), IDX_BM_Status) : 0) #endif //GetDmaStatus #ifdef USE_OWN_DMA @@ -1655,6 +1772,7 @@ extern ULONG SkipRaids; extern ULONG ForceSimplex; extern BOOLEAN g_opt_AtapiDmaRawRead; +extern BOOLEAN hasPCI; extern BOOLEAN InDriverEntry; Index: drivers/storage/ide/uniata/config.h =================================================================== --- drivers/storage/ide/uniata/config.h (revision 57016) +++ drivers/storage/ide/uniata/config.h (working copy) @@ -110,16 +110,16 @@ #define DEF_U64(x) (x##ULL) #define DEF_I64(x) (x##LL) + /* ReactOS-specific defines */ + #ifndef DDKAPI - #define DDKAPI __attribute__((stdcall)) + #define DDKAPI __attribute__((stdcall)) #endif - #ifndef DDKCDECLAPI - #define DDKCDECLAPI __attribute__((cdecl)) + #define DDKCDECLAPI __attribute__((cdecl)) #endif - #ifndef DDKFASTAPI - #define DDKFASTAPI __attribute__((fastcall)) + #define DDKFASTAPI __attribute__((fastcall)) #endif #define DECLSPEC_NAKED __attribute__((naked)) @@ -129,16 +129,16 @@ #define DEF_U64(x) (x##UI64) #define DEF_I64(x) (x##I64) + /* ReactOS-specific defines */ + #ifndef DDKAPI - #define DDKAPI __stdcall + #define DDKAPI __stdcall #endif - #ifndef DDKCDECLAPI - #define DDKCDECLAPI _cdecl + #define DDKCDECLAPI _cdecl #endif - #ifndef DDKFASTAPI - #define DDKFASTAPI __fastcall + #define DDKFASTAPI __fastcall #endif #define DECLSPEC_NAKED __declspec(naked) Index: drivers/storage/ide/uniata/id_ata.cpp =================================================================== --- drivers/storage/ide/uniata/id_ata.cpp (revision 57016) +++ drivers/storage/ide/uniata/id_ata.cpp (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2002-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2002-2012 Alexandr A. Telyatnikov (Alter) Module Name: id_ata.cpp @@ -86,8 +86,12 @@ ULONG g_opt_WaitBusyCount = 200; // 20000 ULONG g_opt_WaitBusyDelay = 10; // 150 ULONG g_opt_WaitDrqDelay = 10; // 100 -BOOLEAN g_opt_AtapiSendDisableIntr = 1; // 0 +ULONG g_opt_WaitBusyLongCount = 2000; // 2000 +ULONG g_opt_WaitBusyLongDelay = 250; // 250 +ULONG g_opt_MaxIsrWait = 40; // +BOOLEAN g_opt_AtapiSendDisableIntr = 0; // 0 BOOLEAN g_opt_AtapiDmaRawRead = 1; // 0 +BOOLEAN hasPCI = FALSE; ULONG g_opt_VirtualMachine = 0; // Auto @@ -503,10 +507,11 @@ { ULONG i; UCHAR Status; - for (i=0; i<200; i++) { + + for (i=0; iDeviceExtension, Status); - if(Status2 == 0xff) { + if(Status2 == IDE_STATUS_WRONG) { // no drive ? break; } else @@ -702,17 +707,25 @@ GetBaseStatus(chan, statusByte2); KdPrint2((PRINT_PREFIX " statusByte2 %x:\n", statusByte2)); SelectDrive(chan, DeviceNumber); - AtapiStallExecution(500); - AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET); + if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MANUAL_CHS) { + // For ESDI/MFM + AtapiStallExecution(10000); + for (i = 0; i < 1000; i++) { + AtapiStallExecution(999); + } + } else { + AtapiStallExecution(500); + AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET); - // ReactOS modification: Already stop looping when we know that the drive has finished resetting. - // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that - // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original - // implementation. (which is around 1 second) - while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) && - i--) - { - AtapiStallExecution(30); + // ReactOS modification: Already stop looping when we know that the drive has finished resetting. + // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that + // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original + // implementation. (which is around 1 second) + while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) && + i--) + { + AtapiStallExecution(30); + } } SelectDrive(chan, DeviceNumber); @@ -757,7 +770,7 @@ IN ULONGLONG lba, IN USHORT count, IN USHORT feature, - IN ULONG flags + IN ULONG wait_flags ) { PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; @@ -769,27 +782,23 @@ deviceExtension->DevIndex, deviceExtension->Channel, DeviceNumber, command, lba, count, feature )); if(deviceExtension->HwFlags & UNIATA_AHCI) { - PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd); + //PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd); KdPrint3((" (ahci)\n")); - RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis)); + statusByte = UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber, + (PSCSI_REQUEST_BLOCK)NULL, + NULL, + 0, + command, + lba, count, + feature, + 0 /* ahci flags */ , + wait_flags, + 1000 /* timeout 1 sec */ + ); - if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel, - &(AHCI_CMD->cfis[0]), - command, - lba, - count, - feature, - ATA_IMMEDIATE - )) { - return 0xff; - } - if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) { - KdPrint2((" timeout\n")); - return 0xff; - } - return IDE_STATUS_IDLE; + return statusByte; } SelectDrive(chan, DeviceNumber); @@ -806,7 +815,7 @@ // and not cleared after SELECT //>>>>>> NV: 2006/08/03 - if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) && + if(((AtaCommandFlags[command] & (ATA_CMD_FLAG_LBAIOsupp|ATA_CMD_FLAG_FUA)) == ATA_CMD_FLAG_LBAIOsupp) && CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) { KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count)); return IDE_STATUS_ERROR; @@ -868,7 +877,7 @@ // write command code to device AtapiWritePort1(chan, IDX_IO1_o_Command, command); - switch (flags) { + switch (wait_flags) { case ATA_WAIT_INTR: // caller requested wait for interrupt @@ -890,7 +899,7 @@ GetStatus(chan, statusByte); statusByte = UniataIsIdle(deviceExtension, statusByte); - if(statusByte == 0xff) { + if(statusByte == IDE_STATUS_WRONG) { // no drive ? break; } else @@ -930,7 +939,7 @@ KdPrint2((PRINT_PREFIX " try to continue\n")); statusByte &= ~IDE_STATUS_ERROR; } - chan->ExpectingInterrupt = TRUE; + UniataExpectChannelInterrupt(chan, TRUE); // !!!!! InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); @@ -959,37 +968,28 @@ IN UCHAR sector, IN UCHAR count, IN UCHAR feature, - IN ULONG flags + IN ULONG wait_flags ) { if(!(deviceExtension->HwFlags & UNIATA_AHCI)) { return AtaCommand48(deviceExtension, DeviceNumber, lChannel, command, (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24), - count, feature, flags); + count, feature, wait_flags); } else { - PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; - PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd); + return UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber, + (PSCSI_REQUEST_BLOCK)NULL, + NULL, + 0, + command, + (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24), + count, + feature, + 0 /* ahci flags */ , + wait_flags, + 1000 /* timeout 1 sec */ + ); - KdPrint3(("AtaCommand(ahci)\n")); - - RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis)); - - if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel, - &(AHCI_CMD->cfis[0]), - command, - (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24), - count, - feature, - ATA_IMMEDIATE - )) { - return 0xff; - } - if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) { - KdPrint2((" timeout\n")); - return 0xff; - } - return IDE_STATUS_IDLE; } } // end AtaCommand() @@ -1026,7 +1026,7 @@ return 1; if (ident->PioCycleTimingMode == 0) return 0; - return -1; + return IOMODE_NOT_SPECIFIED; } // end AtaPioMode() LONG @@ -1039,7 +1039,7 @@ return 1; if (ident->MultiWordDMASupport & 0x01) return 0; - return -1; + return IOMODE_NOT_SPECIFIED; } // end AtaWmode() LONG @@ -1047,7 +1047,7 @@ AtaUmode(PIDENTIFY_DATA2 ident) { if (!ident->UdmaModesValid) - return -1; + return IOMODE_NOT_SPECIFIED; if (ident->UltraDMASupport & 0x40) return 6; if (ident->UltraDMASupport & 0x20) @@ -1062,7 +1062,7 @@ return 1; if (ident->UltraDMASupport & 0x01) return 0; - return -1; + return IOMODE_NOT_SPECIFIED; } // end AtaUmode() @@ -1210,6 +1210,7 @@ #endif //UNIATA_CORE +#if DBG VOID NTAPI UniataDumpATARegs( @@ -1240,6 +1241,7 @@ } return; } // end UniataDumpATARegs() +#endif /*++ @@ -1277,8 +1279,12 @@ UCHAR signatureLow, signatureHigh; BOOLEAN atapiDev = FALSE; + BOOLEAN use_ahci = FALSE; PHW_LU_EXTENSION LunExt = chan->lun[DeviceNumber]; + use_ahci = UniataIsSATARangeAvailable(deviceExtension, lChannel) && + (deviceExtension->HwFlags & UNIATA_AHCI); + if(chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM) { if(chan->PmLunMap & (1 << DeviceNumber)) { // OK @@ -1296,16 +1302,19 @@ return FALSE; } - if(deviceExtension->HwFlags & UNIATA_AHCI) { + if(use_ahci) { statusByte = WaitOnBusyLong(chan); +#if DBG + if(!chan->AhciInternalAtaReq) { + KdPrint2((PRINT_PREFIX "!AhciInternalAtaReq\n")); + } +#endif } else { 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) { @@ -1341,6 +1350,10 @@ // Wait for Busy to drop. AtapiStallExecution(100); GetStatus(chan, statusByte); + if(statusByte == IDE_STATUS_WRONG) { + KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_WRONG (dev %d)\n", DeviceNumber)); + return FALSE; + } } while ((statusByte & IDE_STATUS_BUSY) && waitCount--); GetBaseStatus(chan, statusByte2); @@ -1370,6 +1383,9 @@ } } else { KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI. Status (%#x)\n", statusByte)); + if(statusByte == IDE_STATUS_WRONG) { + return FALSE; + } //if(!(deviceExtension->HwFlags & UNIATA_SATA)) { if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) { statusByte = WaitForIdleLong(chan); @@ -1379,6 +1395,26 @@ } // if(deviceExtension->HwFlags & UNIATA_SATA) { + if(use_ahci) { + statusByte = UniataAhciSendPIOCommand(HwDeviceExtension, lChannel, DeviceNumber, + (PSCSI_REQUEST_BLOCK)NULL, + (PUCHAR)(&deviceExtension->FullIdentifyData), + DEV_BSIZE, + Command, + 0, 0, + 0, + 0 /* ahci flags */ , + ATA_WAIT_INTR, + 1000 /* timeout 1 sec */ + ); + j = 9; // AHCI is rather different, skip loop at all + } else + if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) { + j = 9; // don't send IDENTIFY, assume it is not supported + KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS\n")); + RtlZeroMemory(&(deviceExtension->FullIdentifyData), sizeof(deviceExtension->FullIdentifyData)); + RtlCopyMemory(&(deviceExtension->FullIdentifyData), &(LunExt->IdentifyData), sizeof(LunExt->IdentifyData)); + } else if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) { j = 4; // skip old-style checks } else { @@ -1386,7 +1422,9 @@ } 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); + + // Load CylinderHigh and CylinderLow with number bytes to transfer for old devices, use 0 for newer. + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, (j < 4) ? DEV_BSIZE : 0 /* cyl */, 0, 0, 0, 0, ATA_WAIT_INTR); // Clear interrupt if (statusByte & IDE_STATUS_DRQ) { @@ -1446,65 +1484,77 @@ 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(use_ahci) { + // everything should already be done by controller + } else + if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) { + j = 9; // don't send IDENTIFY, assume it is not supported + KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS (2)\n")); + statusByte = WaitForDrq(chan); + statusByte = WaitOnBusyLong(chan); + KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte)); + GetBaseStatus(chan, statusByte); + } else { - if (!(statusByte & IDE_STATUS_DRQ)) { - KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte)); + 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); - return FALSE; - } - GetBaseStatus(chan, statusByte); - KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte)); + KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte)); - if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) { + if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) { - KdPrint2((PRINT_PREFIX " use 16bit IO\n")); + 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++) { -/* + 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):\n", + " IO_%#x (%#x), %s:\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; - } + 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); + 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); + // 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, (PULONG)&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: 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) { @@ -1525,6 +1575,9 @@ KdPrint2((PRINT_PREFIX "UDMA: %x\n", deviceExtension->FullIdentifyData.UltraDMAActive)); } KdPrint2((PRINT_PREFIX "SATA: %x\n", deviceExtension->FullIdentifyData.SataEnable)); + KdPrint2((PRINT_PREFIX "SATA support: %x, CAPs %#x\n", + deviceExtension->FullIdentifyData.SataSupport, + deviceExtension->FullIdentifyData.SataCapabilities)); // Check out a few capabilities / limitations of the device. if (deviceExtension->FullIdentifyData.RemovableStatus & 1) { @@ -1534,6 +1587,10 @@ deviceExtension->FullIdentifyData.RemovableStatus)); LunExt->DeviceFlags |= DFLAGS_REMOVABLE_DRIVE; } + if(use_ahci) { + // AHCI doesn't recommend using PIO and multiblock + LunExt->MaximumBlockXfer = 0; + } else if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) { // Determine max. block transfer for this device. LunExt->MaximumBlockXfer = @@ -1626,21 +1683,24 @@ 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) ; + if(use_ahci) { + NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba; + } else { + 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 ); + 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 "Read high order bytes\n")); + NativeNumOfSectors |= + (ULONG)((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 @@ -1654,13 +1714,17 @@ IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY); if(!(statusByte & IDE_STATUS_ERROR)) { - NativeNumOfSectors = (ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) | + if(use_ahci) { + NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba; + } else { + 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)) { @@ -1681,7 +1745,7 @@ NumOfSectors = NativeNumOfSectors; } } - } + } // !error } if(NumOfSectors < 0x2100000 /*&& NumOfSectors > 31*1000*1000*/) { @@ -1693,11 +1757,14 @@ 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); - + if(use_ahci) { + NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba; + } else { + 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) { @@ -1925,6 +1992,7 @@ ) { LunExt->DeviceFlags &= DFLAGS_HIDDEN; + LunExt->AtapiReadyWaitDelay = 0; } // end UniataForgetDevice() @@ -1948,7 +2016,7 @@ IN ULONG PathId ) { - KdPrint2((PRINT_PREFIX "AtapiResetController()\n")); + KdPrint2((PRINT_PREFIX "AtapiResetController(%x)\n", PathId)); return AtapiResetController__(HwDeviceExtension, PathId, RESET_COMPLETE_ALL); } // end AtapiResetController() @@ -1983,6 +2051,7 @@ UCHAR tmp16; KdPrint2((PRINT_PREFIX "AtapiResetController: Reset IDE %#x/%#x @ %#x\n", VendorID, DeviceID, slotNumber)); + KdPrint2((PRINT_PREFIX "simplexOnly %d\n", deviceExtension->simplexOnly)); if(!deviceExtension->simplexOnly && (PathId != CHAN_NOT_SPECIFIED)) { // we shall reset both channels on SimplexOnly devices, @@ -2076,7 +2145,7 @@ // Save control flags ChannelCtrlFlags = chan->ChannelCtrlFlags; // Clear expecting interrupt flag. - chan->ExpectingInterrupt = FALSE; + UniataExpectChannelInterrupt(chan, FALSE); chan->RDP = FALSE; chan->ChannelCtrlFlags = 0; InterlockedExchange(&(chan->CheckIntr), @@ -2085,6 +2154,10 @@ // Reset controller if(ChipFlags & UNIATA_AHCI) { KdPrint2((PRINT_PREFIX " AHCI path\n")); +#if DBG + UniataDumpAhciPortRegs(chan); +#endif + AtapiDisableInterrupts(deviceExtension, j); UniataAhciReset(HwDeviceExtension, j); } else { KdPrint2((PRINT_PREFIX " ATA path\n")); @@ -2136,7 +2209,7 @@ GetPciConfig2(0x92, tmp16); if (((tmp16 >> pshift) & mask) == mask) { GetBaseStatus(chan, statusByte); - if(statusByte != 0xff) { + if(statusByte != IDE_STATUS_WRONG) { break; } } @@ -2238,7 +2311,7 @@ if(!IssueIdentify(HwDeviceExtension, i, j, - (chan->lun[i]->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? + ATAPI_DEVICE(chan, i) ? IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY, FALSE)) { KdPrint2((PRINT_PREFIX " identify failed !\n")); @@ -2257,14 +2330,14 @@ AtapiStallExecution(10); statusByte = WaitOnBusyLong(chan); statusByte = UniataIsIdle(deviceExtension, statusByte); - if(statusByte == 0xff) { + if(statusByte == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "no drive, status %#x\n", statusByte)); UniataForgetDevice(chan->lun[i]); } else // Check for ATAPI disk. - if (chan->lun[i]->DeviceFlags & DFLAGS_ATAPI_DEVICE) { + if (ATAPI_DEVICE(chan, i)) { // Issue soft reset and issue identify. GetStatus(chan, statusByte); KdPrint2((PRINT_PREFIX "AtapiResetController: Status before Atapi reset (%#x).\n", @@ -2315,7 +2388,7 @@ } #endif //0 - // Enable interrupts, note, the we can have here recursive disable + // Enable interrupts, note, we can have here recursive disable AtapiStallExecution(10); KdPrint2((PRINT_PREFIX "AtapiResetController: deviceExtension->chan[%d].DisableIntr %d -> 1\n", j, @@ -2683,7 +2756,7 @@ UCHAR statusByte; if (LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT && - !(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) { statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY); @@ -2788,7 +2861,7 @@ AtapiDisableInterrupts(deviceExtension, lChannel); AtapiStallExecution(1); - if (!(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + if (!(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) { KdPrint2((PRINT_PREFIX "AtapiHwInitialize: IDE branch\n")); // Enable media status notification @@ -2812,7 +2885,7 @@ statusByte = AtaCommand(deviceExtension, i, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, - LunExt->MaximumBlockXfer, 0, ATA_WAIT_BASE_READY); + 0, 0, ATA_WAIT_BASE_READY); if (statusByte & IDE_STATUS_ERROR) { // Read the error register. @@ -2954,9 +3027,12 @@ // 10000 * 100us = 1000,000us = 1000ms = 1s waitCount = 10000; GetStatus(chan, statusByte); + if(statusByte == IDE_STATUS_WRONG) { + waitCount = 0; + } while ((statusByte & IDE_STATUS_BUSY) && waitCount) { - KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x\n)", statusByte)); + KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x)\n", statusByte)); // Wait for Busy to drop. AtapiStallExecution(100); GetStatus(chan, statusByte); @@ -2964,10 +3040,12 @@ } // 5000 * 100us = 500,000us = 500ms = 0.5s - waitCount = 5000; - do { - AtapiStallExecution(100); - } while (waitCount--); + if(statusByte != IDE_STATUS_WRONG) { + waitCount = 5000; + do { + AtapiStallExecution(100); + } while (waitCount--); + } } GetBaseStatus(chan, statusByte); AtapiEnableInterrupts(deviceExtension, lChannel); @@ -2976,7 +3054,7 @@ return; -} // end AtapiHwInitialize() +} // end AtapiHwInitialize__() #ifndef UNIATA_CORE @@ -3296,9 +3374,13 @@ // Check other channel // In simplex mode no interrupts must appear on other channels - for(_c=0; _cNumberChannels-1; _c++) { + for(_c=0; _cNumberChannels; _c++) { c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels; + if(c == lChannel) { + continue; + } + chan = &(deviceExtension->chan[c]); if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr), @@ -3324,7 +3406,7 @@ ) { AtapiCallBack__(HwDeviceExtension, (UCHAR)((PHW_DEVICE_EXTENSION)HwDeviceExtension)->ActiveDpcChan); -} +} // end AtapiCallBack_X() #endif //UNIATA_CORE @@ -3355,41 +3437,66 @@ ULONG c_state; ULONG i_res = 0; ULONG pass; - BOOLEAN checked[AHCI_MAX_PORT]; + //BOOLEAN checked[AHCI_MAX_PORT]; ULONG hIS; + ULONG checked; - KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID)); + KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x (ex %d)\n", + deviceExtension->DevID, deviceExtension->RevID, deviceExtension->ExpectingInterrupt )); if(deviceExtension->HwFlags & UNIATA_AHCI) { + // AHCI may generate state change notification, never skip this check hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS); - KdPrint2((PRINT_PREFIX "AtapiInterrupt2: AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel)); + KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel)); if(!hIS) { return FALSE; } + checked = ~hIS; // assume all non-interrupted ports to be already checked + } else { + checked = 0; // assume all ports are not checked } - for(_c=0; _cNumberChannels; _c++) { - checked[_c] = FALSE; + if(!deviceExtension->ExpectingInterrupt) { + // if we do not expect interrupt, exit now, + // but keep in mind that it can be unexpected one + // Note: this is just a hint, not exact counter + KdPrint2((PRINT_PREFIX "unexpected, 1st chance\n")); + //deviceExtension->ExpectingInterrupt++; + //return FALSE; } + // clear this flag now, it can be set again in sub-calls + deviceExtension->ExpectingInterrupt=0; + +// for(_c=0; _cNumberChannels; _c++) { +// checked[_c] = (UCHAR)((hIS >> _c) & 0x01); +// } + // fc = for(pass=0; pass<2; pass++) { + //KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): pass %d\n", pass)); + if(status && pass) { + // we catched some expected interrupts now. + // do not touch unexpected until next ISR call + break; + } for(_c=0; _cNumberChannels; _c++) { c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels; - if(checked[c]) + if((checked>>c) & 0x01) continue; // check non-empty and expecting interrupt channels first if(!pass && !deviceExtension->chan[c].ExpectingInterrupt) continue; - checked[c] = TRUE; + checked |= (ULONG)1 << c; KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c)); if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) { + // we get here on idle channels or when ISR is posted to DPC KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): disabled INTR on ch %d\n", c)); continue; } @@ -3428,7 +3535,9 @@ if(i_res == INTERRUPT_REASON_UNEXPECTED) { KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): Catch unexpected\n")); InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE); - return TRUE; + //return TRUE; + status = TRUE; + continue; } // disable interrupts on other channel of legacy mode // ISA-bridged onboard controller @@ -3479,6 +3588,9 @@ IN PVOID Isr2HwDeviceExtension ) { + // This ISR is intended to catch interrupts when we are already in other ISR instance + // for the same device. This may happen when we have multiple channels, + // especially on SMP machines PISR2_DEVICE_EXTENSION Isr2DeviceExtension = (PISR2_DEVICE_EXTENSION)Isr2HwDeviceExtension; PHW_DEVICE_EXTENSION deviceExtension = Isr2DeviceExtension->HwDeviceExtension; @@ -3487,6 +3599,7 @@ ULONG c_count = 0; ULONG i_res; ULONG hIS; + ULONG checked; // we should never get here for ISA/MCA if(!BMList[deviceExtension->DevIndex].Isr2Enable) { @@ -3495,16 +3608,31 @@ } if(deviceExtension->HwFlags & UNIATA_AHCI) { + // AHCI may generate state change notification, never skip this check hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS); KdPrint2((PRINT_PREFIX "AtapiInterrupt2: AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel)); if(!hIS) { return FALSE; } + checked = ~hIS; // assume all non-interrupted ports to be already checked + } else { + checked = 0; // assume all ports are not checked } + if(!deviceExtension->ExpectingInterrupt) { + KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !deviceExtension->ExpectingInterrupt\n")); + deviceExtension->ExpectingInterrupt++; + return FALSE; + } + //deviceExtension->ExpectingInterrupt = 0; for(c=0; cNumberChannels; c++) { KdPrint2((PRINT_PREFIX "AtapiInterrupt2: cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c)); + if((checked>>c) & 0x01) + continue; + + checked |= (ULONG)1 << c; + if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) { KdPrint2((PRINT_PREFIX "AtapiInterrupt2: disabled INTR\n")); continue; @@ -3663,6 +3791,8 @@ { PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; PHW_CHANNEL chan; + //UCHAR statusByte; + if(c >= deviceExtension->NumberChannels) { KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: WRONG CHANNEL\n",c)); return; @@ -3671,10 +3801,27 @@ KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, chan->DisableIntr)); if(!InterlockedDecrement(&chan->DisableIntr)) { if(deviceExtension->HwFlags & UNIATA_AHCI) { - UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0); + UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, + (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | + ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | + ((/*ch->pm_level == */0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) | + ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | /* DEBUG */ + ATA_AHCI_P_IX_DI | + ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | + ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR) + ); } else { + //SelectDrive(chan, 0); + //GetBaseStatus(chan, statusByte); AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_A_4BIT ); + //if(chan->NumberLuns) { + // SelectDrive(chan, 1); + // GetBaseStatus(chan, statusByte); + // AtapiWritePort1(chan, IDX_IO2_o_Control, + // IDE_DC_A_4BIT ); + // SelectDrive(chan, chan->cur_cdev); + //} } chan->ChannelCtrlFlags &= ~CTRFLAGS_INTR_DISABLED; } else { @@ -3702,16 +3849,17 @@ // mark channel as busy if(InterlockedIncrement(&chan->DisableIntr)) { if(deviceExtension->HwFlags & UNIATA_AHCI) { - UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, - (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | - ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | - ((/*ch->pm_level == */0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) | - ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | - ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR) - ); + UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0); } else { + //SelectDrive(chan, 0); AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ ); + //if(chan->NumberLuns) { + // SelectDrive(chan, 1); + // AtapiWritePort1(chan, IDX_IO2_o_Control, + // IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ ); + // SelectDrive(chan, chan->cur_cdev); + //} } chan->ChannelCtrlFlags |= CTRFLAGS_INTR_DISABLED; } @@ -3719,6 +3867,21 @@ return; } // end AtapiDisableInterrupts() +VOID +UniataExpectChannelInterrupt( + IN struct _HW_CHANNEL* chan, + IN BOOLEAN Expecting + ) +{ + chan->ExpectingInterrupt = Expecting; + if(Expecting) { + chan->DeviceExtension->ExpectingInterrupt++; + } else + if(chan->DeviceExtension->ExpectingInterrupt) { + chan->DeviceExtension->ExpectingInterrupt--; + } + return; +} // end UniataExpectChannelInterrupt() /* Check hardware for interrupt state @@ -3732,7 +3895,7 @@ { PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; PHW_CHANNEL chan = &(deviceExtension->chan[c]); - PHW_LU_EXTENSION LunExt = chan->lun[chan->cur_cdev]; + PHW_LU_EXTENSION LunExt; ULONG VendorID = deviceExtension->DevID & 0xffff; ULONG ChipType = deviceExtension->HwFlags & CHIPTYPE_MASK; @@ -3750,18 +3913,45 @@ UCHAR lChannel; BOOLEAN DmaTransfer = FALSE; BOOLEAN OurInterrupt = FALSE; + BOOLEAN StatusValid = FALSE; // ULONG k; UCHAR interruptReason; BOOLEAN EarlyIntr = FALSE; + BOOLEAN SingleBlockIntr = FALSE; KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__:\n")); lChannel = c; Channel = (UCHAR)(deviceExtension->Channel + lChannel); + LunExt = chan->lun[chan->cur_cdev]; + //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ chan %#x:\n", chan)); + //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ (%d/%d):\n", Channel, chan->cur_cdev)); + if((ChipFlags & UNIATA_AHCI) && UniataIsSATARangeAvailable(deviceExtension, lChannel)) { - OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, -1); + OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED); + if((OurInterrupt == INTERRUPT_REASON_UNEXPECTED) && + (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + UniataAhciWaitCommandReady(chan, 2 /* ms */ ); + statusByte = (UCHAR)UniataAhciWaitReady(chan, 0 /* immediate */); + if(!(statusByte & (IDE_STATUS_BUSY)) ) { + KdPrint2((PRINT_PREFIX "ATAPI special case READY\n")); + //deviceExtension->ExpectingInterrupt++; // will be updated in ISR on ReturnEnableInterrupts + OurInterrupt = INTERRUPT_REASON_OUR; + } else + if((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRDY)) == (IDE_STATUS_BUSY | IDE_STATUS_DRDY) ) { + KdPrint2((PRINT_PREFIX "ATAPI special case pre ERR-READY\n")); + OurInterrupt = INTERRUPT_REASON_OUR; + } else + if(statusByte & IDE_STATUS_ERROR) { + KdPrint2((PRINT_PREFIX "ATAPI special case ERR-READY\n")); + OurInterrupt = INTERRUPT_REASON_OUR; + } else { + KdPrint2((PRINT_PREFIX "ATAPI special case ? %x\n", statusByte)); + OurInterrupt = INTERRUPT_REASON_OUR; + } + } return OurInterrupt; } @@ -3985,6 +4175,7 @@ } else { KdPrint2((PRINT_PREFIX " getting status...\n")); GetStatus(chan, statusByte); + StatusValid = 1; KdPrint2((PRINT_PREFIX " status %#x\n", statusByte)); if(statusByte & IDE_STATUS_ERROR) { KdPrint2((PRINT_PREFIX " IDE_STATUS_ERROR -> our\n", statusByte)); @@ -3994,6 +4185,14 @@ (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) && (dma_status == BM_STATUS_ACTIVE)) { KdPrint2((PRINT_PREFIX " special case DMA + ATAPI + IDE_STATUS_DSC -> our\n", statusByte)); + // some devices interrupts on each block transfer even in DMA mode + if(LunExt->TransferMode >= ATA_SDMA && LunExt->TransferMode <= ATA_WDMA2) { + KdPrint2((PRINT_PREFIX " wait for completion\n")); + ///* clear interrupt and get status */ + //GetBaseStatus(chan, statusByte); + //return INTERRUPT_REASON_IGNORE; + SingleBlockIntr = TRUE; + } } else { return INTERRUPT_REASON_IGNORE; } @@ -4009,20 +4208,22 @@ } } skip_dma_stat_check: - if(!(ChipFlags & UNIATA_SATA)) { + if(!(ChipFlags & UNIATA_SATA) && chan->ExpectingInterrupt) { AtapiStallExecution(1); } /* if drive is busy it didn't interrupt */ /* the exception is DCS + BSY state of ATAPI devices */ - KdPrint2((PRINT_PREFIX " getting status...\n")); - GetStatus(chan, statusByte); + if(!StatusValid) { + KdPrint2((PRINT_PREFIX " getting status...\n")); + GetStatus(chan, statusByte); + } if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) { KdPrint3((PRINT_PREFIX " ATAPI status %#x\n", statusByte)); } else { KdPrint2((PRINT_PREFIX " IDE status %#x\n", statusByte)); } - if (statusByte == 0xff) { + if (statusByte == IDE_STATUS_WRONG) { // interrupt from empty controller ? } else if (statusByte & IDE_STATUS_BUSY) { @@ -4052,6 +4253,9 @@ KdPrint3((PRINT_PREFIX " our interrupt with BSY set, try wait in ISR or post to DPC\n")); /* clear interrupt and get status */ GetBaseStatus(chan, statusByte); + if(!(dma_status & BM_STATUS_ACTIVE)) { + AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL); + } KdPrint3((PRINT_PREFIX " base status %#x (+BM_STATUS_INTR)\n", statusByte)); return INTERRUPT_REASON_OUR; } @@ -4075,7 +4279,7 @@ /* clear interrupt and get status */ GetBaseStatus(chan, statusByte); KdPrint2((PRINT_PREFIX " base status %#x\n", statusByte)); - if (statusByte == 0xff) { + if (statusByte == IDE_STATUS_WRONG) { // interrupt from empty controller ? } else if(!(statusByte & (IDE_STATUS_DRQ | IDE_STATUS_DRDY))) { @@ -4085,7 +4289,7 @@ #ifndef UNIATA_PIO_ONLY if(DmaTransfer) { - if(!EarlyIntr || g_WaitBusyInISR) { + if(!SingleBlockIntr && (!EarlyIntr || g_WaitBusyInISR)) { dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/); } else { PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan); @@ -4093,9 +4297,13 @@ //ASSERT(AtaReq); - KdPrint2((PRINT_PREFIX " set REQ_STATE_EARLY_INTR.\n")); + if(SingleBlockIntr) { + KdPrint2((PRINT_PREFIX " set REQ_STATE_ATAPI_EXPECTING_DATA_INTR2.\n")); + } else { + KdPrint2((PRINT_PREFIX " set REQ_STATE_EARLY_INTR.\n")); + } if(AtaReq) { - AtaReq->ReqState = REQ_STATE_EARLY_INTR; + AtaReq->ReqState = SingleBlockIntr ? REQ_STATE_ATAPI_EXPECTING_DATA_INTR2 : REQ_STATE_EARLY_INTR; } } } @@ -4151,6 +4359,7 @@ BOOLEAN DmaTransfer = FALSE; UCHAR error = 0; ULONG TimerValue = 1000; + ULONG TotalTimerValue = 0; #ifdef UNIATA_USE_XXableInterrupts BOOLEAN InDpc = (KeGetCurrentIrql() == DISPATCH_LEVEL); #else @@ -4180,7 +4389,8 @@ 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)) ) { + (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) || + (deviceExtension->HwFlags & UNIATA_AHCI)) { DmaTransfer = TRUE; KdPrint2((PRINT_PREFIX " DmaTransfer = TRUE\n")); } @@ -4238,6 +4448,7 @@ case REQ_STATE_ATAPI_EXPECTING_CMD_INTR: KdPrint3((PRINT_PREFIX " EXPECTING_CMD_INTR\n")); case REQ_STATE_ATAPI_EXPECTING_DATA_INTR: + case REQ_STATE_ATAPI_EXPECTING_DATA_INTR2: case REQ_STATE_DPC_WAIT_BUSY0: case REQ_STATE_DPC_WAIT_BUSY1: KdPrint2((PRINT_PREFIX " continue service interrupt\n")); @@ -4289,6 +4500,7 @@ // disable interrupts for this channel, // but avoid recursion and double-disable if(OldReqState != REQ_STATE_DPC_WAIT_BUSY1) { + UniataExpectChannelInterrupt(chan, FALSE); AtapiDisableInterrupts(deviceExtension, lChannel); } // go to ISR DPC @@ -4312,6 +4524,13 @@ CallTimerDpc: AtaReq->ReqState = REQ_STATE_PROCESSING_INTR; CallTimerDpc2: + if(!InDpc && OldReqState != REQ_STATE_DPC_WAIT_BUSY1) { + // we must block interrupts from this channel + // If device generate new interrupt before we get to DPC, + // ISR will assume, that it is NOT our interrupt + AtapiDisableInterrupts(deviceExtension, lChannel); + // We should not clean ExpectingInterrupt flag on channel, since it is used in DPC + } // Will raise IRQL to DIRQL AtapiQueueTimerDpc(HwDeviceExtension, c, AtapiCallBack_X, @@ -4352,11 +4571,11 @@ AtapiStallExecution(10); } */ + /* clear interrupt and get status */ - if(deviceExtension->HwFlags & UNIATA_AHCI) { UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, srb); - statusByte = (UCHAR)(AtaReq->ahci.in_status & 0xff); + statusByte = (UCHAR)(AtaReq->ahci.in_status & IDE_STATUS_MASK); } else { GetBaseStatus(chan, statusByte); } @@ -4371,11 +4590,11 @@ InDpc = TRUE; } - if(deviceExtension->HwFlags & UNIATA_AHCI) { - KdPrint3((PRINT_PREFIX " AHCI branch\n")); - } else if (!atapiDev) { // IDE + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint3((PRINT_PREFIX " AHCI branch (IDE)\n")); + } else if (statusByte & IDE_STATUS_BUSY) { if (deviceExtension->DriverMustPoll) { // Crashdump is polling and we got caught with busy asserted. @@ -4423,25 +4642,49 @@ // ATAPI if(!LunExt->IdentifyData.MajorRevision && InDpc && - !atapiDev && + /*!atapiDev &&*/ !(deviceExtension->HwFlags & UNIATA_SATA) ) { - KdPrint2((PRINT_PREFIX " additional delay 10us for old devices (2)\n")); - AtapiStallExecution(10); + //KdPrint2((PRINT_PREFIX " additional delay 10us for old devices (2)\n")); + //AtapiStallExecution(10); } + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint3((PRINT_PREFIX " AHCI branch (ATAPI)\n")); + } else { + interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3); + KdPrint3((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason)); + } + if (statusByte & IDE_STATUS_BUSY) { //if(chan->ChannelCtrlFlags & CTRFLAGS_DSC_BSY) {} - KdPrint3((PRINT_PREFIX " BUSY on ATAPI device, waiting\n")); +/* +#ifndef UNIATA_CORE + // This is just workaround + // We should DISABLE interrupts before entering WAIT state + UniataExpectChannelInterrupt(chan, TRUE); +#endif //UNIATA_CORE +*/ + KdPrint3((PRINT_PREFIX " BUSY on ATAPI device, waiting %d us\n", LunExt->AtapiReadyWaitDelay)); +#ifndef UNIATA_CORE + if(LunExt->AtapiReadyWaitDelay && (LunExt->AtapiReadyWaitDelay > g_opt_MaxIsrWait) && !InDpc && UseDpc) { + TimerValue = LunExt->AtapiReadyWaitDelay; + KdPrint2((PRINT_PREFIX " too long wait: ISR -> DPC (0)\n")); + AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0; + goto CallTimerDpc2; + } +#endif //UNIATA_CORE + TimerValue = 10; for(k=20; k; k--) { - GetStatus(chan, statusByte); + GetBaseStatus(chan, statusByte); KdPrint3((PRINT_PREFIX " status re-check %#x\n", statusByte)); KdPrint3((PRINT_PREFIX " Error reg (%#x)\n", - AtapiReadPort1(chan, IDX_IO1_i_Error))); + AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Error))); if (!(statusByte & IDE_STATUS_BUSY)) { KdPrint2((PRINT_PREFIX " expecting intr + cleared BUSY\n")); break; } - if(k <= 18) { + TotalTimerValue += TimerValue; + if(k <= 1) { KdPrint3((PRINT_PREFIX " too long wait -> DPC\n")); if(!InDpc) { KdPrint2((PRINT_PREFIX " too long wait: ISR -> DPC\n")); @@ -4453,14 +4696,22 @@ AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY1; } #ifndef UNIATA_CORE - goto CallTimerDpc2; -#else //UNIATA_CORE - AtapiStallExecution(TimerValue); + if(UseDpc) { + if(!LunExt->AtapiReadyWaitDelay) { + LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3; + } + goto CallTimerDpc2; + } #endif //UNIATA_CORE } - AtapiStallExecution(10); + AtapiStallExecution(TimerValue); + TimerValue += 10; } + if(!LunExt->AtapiReadyWaitDelay) { + LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3; + KdPrint2((PRINT_PREFIX " store AtapiReadyWaitDelay: %d\n", LunExt->AtapiReadyWaitDelay)); + } if (statusByte & IDE_STATUS_BUSY) { KdPrint3((PRINT_PREFIX " expecting intr + BUSY (2), try DPC wait\n")); goto try_dpc_wait; @@ -4487,7 +4738,23 @@ (dma_status & BM_STATUS_ERR)) { if(deviceExtension->HwFlags & UNIATA_AHCI) { - error = (UCHAR)((AtaReq->ahci.in_status >> 8) && 0xff); + error = (UCHAR)((AtaReq->ahci.in_status >> 8) & 0xff); + // wait ready +#if DBG + UniataDumpAhciPortRegs(chan); +#endif + UniataAhciStop(chan); + UniataAhciStart(chan); + + UniataAhciWaitCommandReady(chan, 10); + // clear interrupts again +#if DBG + UniataDumpAhciPortRegs(chan); +#endif + UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED); +#if DBG + UniataDumpAhciPortRegs(chan); +#endif } else { error = AtapiReadPort1(chan, IDX_IO1_i_Error); } @@ -4519,7 +4786,7 @@ LunExt->DeviceFlags & DFLAGS_INT_DRQ)); for (k = atapiDev ? 0 : 200; k; k--) { - GetStatus(chan, statusByte); + GetBaseStatus(chan, statusByte); if (!(statusByte & IDE_STATUS_DRQ)) { AtapiStallExecution(50); } else { @@ -4674,7 +4941,7 @@ PIO_wait_DRQ0: // The ISR hits with DRQ low, but comes up later. for (k = 0; k < 5000; k++) { - GetStatus(chan, statusByte); + GetBaseStatus(chan, statusByte); if (statusByte & IDE_STATUS_DRQ) { break; } @@ -4714,8 +4981,20 @@ KdPrint2((PRINT_PREFIX "AtapiInterrupt: i-reason=%d, status=%#x\n", interruptReason, statusByte)); if(deviceExtension->HwFlags & UNIATA_AHCI) { - KdPrint2((PRINT_PREFIX " AHCI path\n")); - goto ReturnEnableIntr; + KdPrint2((PRINT_PREFIX " AHCI path, WordsTransfered %x, WordsLeft %x\n", AtaReq->WordsTransfered, AtaReq->WordsLeft)); + if(chan->AhciLastIS & ATA_AHCI_P_IX_OF) { + status = SRB_STATUS_DATA_OVERRUN; + DataOverrun = TRUE; + } else { + status = SRB_STATUS_SUCCESS; + } + if(AtaReq->WordsTransfered >= AtaReq->WordsLeft) { + AtaReq->WordsLeft = 0; + } else { + AtaReq->WordsLeft -= AtaReq->WordsTransfered; + } + chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; + goto CompleteRequest; } else if (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) { // Write the packet. @@ -4741,7 +5020,7 @@ AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow); wordCount |= - AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8; + (USHORT)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8; // Covert bytes to words. wordCount >>= 1; @@ -4774,13 +5053,25 @@ } } - if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) { + if (DmaTransfer && + (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) { //ASSERT(AtaReq->WordsLeft == wordCount); + if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) { + KdPrint2((PRINT_PREFIX + "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount)); + if(AtaReq->WordsLeft > wordCount) { + AtaReq->WordsLeft -= wordCount; + AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; + goto ReturnEnableIntr; + } + dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/); + } 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) { @@ -4805,7 +5096,7 @@ } else { KdPrint3((PRINT_PREFIX - "AtapiInterrupt: Int reason %#x, but srb is for a write %#x.\n", + "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n", interruptReason, srb)); @@ -4813,7 +5104,6 @@ status = SRB_STATUS_ERROR; goto CompleteRequest; } - // Advance data buffer pointer and bytes left. AtaReq->DataBuffer += wordCount; AtaReq->WordsLeft -= wordCount; @@ -4834,8 +5124,8 @@ AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) | (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8); - // Covert bytes to words. - wordCount /= 2; + // Convert bytes to words. + wordCount >>= 1; KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount)); if (wordCount != AtaReq->WordsLeft) { @@ -4863,7 +5153,18 @@ } } - if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) { + if(DmaTransfer && + (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) { + if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) { + KdPrint2((PRINT_PREFIX + "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount)); + if(AtaReq->WordsLeft > wordCount) { + AtaReq->WordsLeft -= wordCount; + AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; + goto ReturnEnableIntr; + } + dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/); + } //ASSERT(AtaReq->WordsLeft == wordCount); AtaReq->WordsLeft = 0; status = SRB_STATUS_SUCCESS; @@ -4892,7 +5193,7 @@ KdDump(AtaReq->DataBuffer, wordCount*2); } - GetStatus(chan, statusByte); + GetBaseStatus(chan, statusByte); KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte)); if(DataOverrun) { @@ -4947,6 +5248,19 @@ *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000; AtaReq->DataBuffer += wordCount; } + + GetStatus(chan, statusByte); + if(!(statusByte & IDE_STATUS_BUSY)) { + // Assume command is completed if BUSY is cleared + // and all data read + // Optionally, we may receive COMPLETE interrupt later and + // treat it as unexpected + KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete ? status %x\n", statusByte)); + + status = SRB_STATUS_SUCCESS; + goto CompleteRequest; + } + } else { /* @@ -4966,6 +5280,17 @@ } else { if (atapiDev) { AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; + GetStatus(chan, statusByte); + if(!(statusByte & IDE_STATUS_BUSY)) { + // Assume command is completed if BUSY is cleared + // even if NOT all data read + // Optionally, we may receive COMPLETE interrupt later and + // treat it as unexpected + KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete + underrun ? status %x\n", statusByte)); + + status = SRB_STATUS_SUCCESS; + goto CompleteRequest; + } } } @@ -5104,6 +5429,7 @@ if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) && chan->MechStatusRetryCount) { + KdPrint3((PRINT_PREFIX "AtapiInterrupt: MechStatusRetryCount %#x\n", chan->MechStatusRetryCount)); // The sense key doesn't say the last request is illegal, so try again chan->MechStatusRetryCount--; srb = AtaReq->Srb = BuildMechanismStatusSrb ( @@ -5187,7 +5513,7 @@ KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO completion, wait BUSY\n")); // Wait for busy to drop. for (i = 0; i < 5*30; i++) { - GetStatus(chan, statusByte); + GetBaseStatus(chan, statusByte); if (!(statusByte & IDE_STATUS_BUSY)) { break; } @@ -5245,7 +5571,7 @@ PIO_wait_DRQ: KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO_wait_DRQ\n")); for (i = 0; i < 200; i++) { - GetStatus(chan, statusByte); + GetBaseStatus(chan, statusByte); if (!(statusByte & IDE_STATUS_DRQ)) { break; } @@ -5282,7 +5608,8 @@ } // Clear interrupt expecting flag. - chan->ExpectingInterrupt = FALSE; + UniataExpectChannelInterrupt(chan, FALSE); + // clear this flag now, it can be set again in sub-calls InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); @@ -5308,7 +5635,10 @@ } } if(status == SRB_STATUS_SUCCESS) { - AtaReq->WordsTransfered += AtaReq->bcount * DEV_BSIZE/2; + if(!(deviceExtension->HwFlags & UNIATA_AHCI)) { + // This should be set in UniataAhciEndTransaction() for AHCI + AtaReq->WordsTransfered += AtaReq->bcount * DEV_BSIZE/2; + } if(!atapiDev && AtaReq->WordsTransfered*2 < AtaReq->TransferLength) { KdPrint2((PRINT_PREFIX "AtapiInterrupt: more I/O required (%x of %x bytes) -> reenqueue\n", @@ -5394,7 +5724,7 @@ if (chan->RDP) { // Check DSC for (i = 0; i < 5; i++) { - GetStatus(chan, statusByte); + GetBaseStatus(chan, statusByte); if(!(statusByte & IDE_STATUS_BUSY)) { KdPrint2((PRINT_PREFIX "AtapiInterrupt: RDP + cleared BUSY\n")); chan->RDP = FALSE; @@ -5465,6 +5795,8 @@ ReturnEnableIntr: KdPrint2((PRINT_PREFIX "AtapiInterrupt: ReturnEnableIntr\n",srb)); + //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt + deviceExtension->ExpectingInterrupt = TRUE; if(UseDpc) { if(CrNtInterlockedExchangeAdd(&(chan->DisableIntr), 0)) { KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiEnableInterrupts__()\n")); @@ -5811,6 +6143,15 @@ // assume best case here // we cannot reinit Dma until previous request is completed + if(deviceExtension->HwFlags & UNIATA_AHCI) { + UniataAhciSetupCmdPtr(AtaReq); + if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb, + (PUCHAR)(AtaReq->DataBuffer), + AtaReq->bcount * DEV_BSIZE)) { + KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !DMA\n")); + return SRB_STATUS_ERROR; + } + } else if ((LunExt->LimitedTransferMode >= ATA_DMA)) { use_dma = TRUE; // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success @@ -5821,29 +6162,25 @@ } } - if(use_dma && (deviceExtension->HwFlags & UNIATA_AHCI)) { - UniataAhciSetupCmdPtr(AtaReq); - KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n")); + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint2((PRINT_PREFIX "IdeReadWrite: setup AHCI FIS\n")); RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis)); fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel, &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]), - (AtaReq->Flags & REQ_FLAG_READ) ? IDE_COMMAND_READ_DMA : /*IDE_COMMAND_WRITE_DMA*/ IDE_COMMAND_READ_DMA, + (AtaReq->Flags & REQ_FLAG_READ) ? IDE_COMMAND_READ_DMA : IDE_COMMAND_WRITE_DMA, lba, (USHORT)(AtaReq->bcount), - 0, - ATA_IMMEDIATE + 0 + /*,(AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE*/ ); if(!fis_size) { - KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n")); + KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !FIS\n")); return SRB_STATUS_ERROR; } - AtaReq->ahci.io_cmd_flags = (USHORT)(((AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE) | - /*((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |*/ - (fis_size / sizeof(ULONG)) | - (DeviceNumber << 12)); + AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0, (AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE, fis_size, DeviceNumber); KdPrint2((PRINT_PREFIX "IdeReadWrite ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags)); } @@ -5916,9 +6253,13 @@ chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; } - if(use_dma && (deviceExtension->HwFlags & UNIATA_AHCI)) { + if(deviceExtension->HwFlags & UNIATA_AHCI) { + // AHCI doesn't distinguish DMA and PIO //AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb); - UniataAhciBeginTransaction(HwDeviceExtension, DeviceNumber, lChannel, Srb); + UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb); + UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt + InterlockedExchange(&(chan->CheckIntr), + CHECK_INTR_IDLE); return SRB_STATUS_PENDING; } @@ -5929,7 +6270,7 @@ (USHORT)(AtaReq->bcount), // (UCHAR)((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE), 0, ATA_IMMEDIATE); - if(statusByte2 != 0xff) { + if(statusByte2 != IDE_STATUS_WRONG) { GetStatus(chan, statusByte2); } if(statusByte2 & IDE_STATUS_ERROR) { @@ -5950,9 +6291,9 @@ 0, ATA_WAIT_INTR); if (!(statusByte & IDE_STATUS_DRQ) || - statusByte == 0xff) { + statusByte == IDE_STATUS_WRONG) { - if(statusByte == 0xff) { + if(statusByte == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "IdeReadWrite: error sending command (%#x)\n", statusByte)); @@ -5965,17 +6306,17 @@ AtaReq->WordsLeft = 0; // Clear interrupt expecting flag. - chan->ExpectingInterrupt = FALSE; + UniataExpectChannelInterrupt(chan, FALSE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); // Clear current SRB. UniataRemoveRequest(chan, Srb); - return (statusByte == 0xff) ? SRB_STATUS_ERROR : SRB_STATUS_TIMEOUT; + return (statusByte == IDE_STATUS_WRONG) ? SRB_STATUS_ERROR : SRB_STATUS_TIMEOUT; } - chan->ExpectingInterrupt = TRUE; + UniataExpectChannelInterrupt(chan, TRUE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); @@ -6156,6 +6497,7 @@ 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; @@ -6221,8 +6563,10 @@ if(CmdAction == CMD_ACTION_PREPARE) { - KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE\n")); + KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE, Cdb %x\n", &(Srb->Cdb))); switch (Srb->Cdb[0]) { + case SCSIOP_RECEIVE: + case SCSIOP_SEND: case SCSIOP_READ: case SCSIOP_WRITE: case SCSIOP_READ12: @@ -6241,15 +6585,56 @@ } } +#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 (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) && + !AtaReq->OriginalSrb) { + + ULONG srbStatus; + + KdPrint3((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. + LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED; + + chan->MechStatusRetryCount = 3; + AtaReq->OriginalSrb = Srb; + AtaReq->Srb = BuildMechanismStatusSrb ( + HwDeviceExtension, + Srb); + + KdPrint3((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 + if((CmdAction & CMD_ACTION_PREPARE) && (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) { - KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x\n", Srb->Cdb[0])); + KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x (Cdb %x)\n", Srb->Cdb[0], &(Srb->Cdb))); // 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; + // reset this to force PRD init. May be already setup by recursive SRB + AtaReq->dma_entries = 0; // check if reorderable switch(Srb->Cdb[0]) { @@ -6282,14 +6667,20 @@ switch(Srb->Cdb[0]) { case SCSIOP_WRITE: case SCSIOP_WRITE12: + case SCSIOP_SEND: if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_RO) break; /* FALLTHROUGH */ + case SCSIOP_RECEIVE: case SCSIOP_READ: case SCSIOP_READ12: if(deviceExtension->opt_AtapiDmaReadWrite) { call_dma_setup: + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n")); + use_dma = TRUE; + } else if(AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb, (PUCHAR)(AtaReq->DataBuffer), Srb->DataTransferLength @@ -6324,6 +6715,10 @@ } // try setup DMA if(use_dma) { + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n")); + //use_dma = TRUE; + } else if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb, (PUCHAR)(AtaReq->DataBuffer), Srb->DataTransferLength)) { @@ -6340,6 +6735,17 @@ if(deviceExtension->HwFlags & UNIATA_AHCI) { UniataAhciSetupCmdPtr(AtaReq); + + if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb, + (PUCHAR)(AtaReq->DataBuffer), + Srb->DataTransferLength)) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: no AHCI dma!\n")); + return SRB_STATUS_ERROR; + } + if(!use_dma) { + AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; + } + KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n")); RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis)); RtlCopyMemory(&(AtaReq->ahci.ahci_cmd_ptr->acmd), Srb->Cdb, 16); @@ -6349,8 +6755,7 @@ IDE_COMMAND_ATAPI_PACKET /* command */, 0 /* lba */, (Srb->DataTransferLength >= 0x10000) ? (USHORT)(0xffff) : (USHORT)(Srb->DataTransferLength), - use_dma ? ATA_F_DMA : 0/* feature */, - ATA_IMMEDIATE /* flags */ + use_dma ? ATA_F_DMA : 0/* feature */ ); if(!fis_size) { @@ -6358,11 +6763,17 @@ return SRB_STATUS_ERROR; } + AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0, + ((AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE) | + (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH), + fis_size, DeviceNumber); +#if 0 AtaReq->ahci.io_cmd_flags = (USHORT)(((AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE) | /*((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |*/ (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) | (fis_size / sizeof(ULONG)) | (DeviceNumber << 12)); +#endif KdPrint2((PRINT_PREFIX "AtapiSendCommand ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags)); } @@ -6389,16 +6800,16 @@ KdPrint2((PRINT_PREFIX "AtapiSendCommand: !CMD_ACTION_EXEC => SRB_STATUS_PENDING\n")); return SRB_STATUS_PENDING; } - KdPrint3((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma)); + KdPrint3((PRINT_PREFIX "AtapiSendCommand: use_dma=%d, Cmd %x\n", use_dma, Srb->Cdb[0])); if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) { KdPrint2((PRINT_PREFIX " REQ_FLAG_DMA_OPERATION\n")); } - if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) { + if((Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) /*&& !(deviceExtension->HwFlags & UNIATA_AHCI)*/) { KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE -> no dma setup (2)\n")); use_dma = FALSE; AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; - //AtapiDmaReinit(deviceExtension, LunExt, AtaReq); + AtapiDmaReinit(deviceExtension, LunExt, AtaReq); } if(AtaReq->TransferLength) { if(!dma_reinited) { KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n")); @@ -6427,47 +6838,8 @@ 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 (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) && - !AtaReq->OriginalSrb) { - - ULONG srbStatus; - - KdPrint3((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. - LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED; - - chan->MechStatusRetryCount = 3; - AtaReq->OriginalSrb = Srb; - AtaReq->Srb = BuildMechanismStatusSrb ( - HwDeviceExtension, - Srb); - - KdPrint3((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 - - KdPrint3((PRINT_PREFIX "AtapiSendCommand: Command %#x to TargetId %d lun %d\n", - Srb->Cdb[0], Srb->TargetId, Srb->Lun)); + KdPrint3((PRINT_PREFIX "AtapiSendCommand: Cdb %x Command %#x to TargetId %d lun %d\n", + &(Srb->Cdb), Srb->Cdb[0], Srb->TargetId, Srb->Lun)); // Make sure command is to ATAPI device. flags = LunExt->DeviceFlags; @@ -6488,25 +6860,14 @@ return SRB_STATUS_SELECTION_TIMEOUT; } retry: - if(deviceExtension->HwFlags & UNIATA_AHCI) { - KdPrint2((PRINT_PREFIX "AtapiSendCommand: AHCI, begin transaction\n")); - if(use_dma) { - chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION; - } else { - chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; - } - UniataAhciBeginTransaction(HwDeviceExtension, DeviceNumber, lChannel, Srb); - return SRB_STATUS_PENDING; - } - - // Select device 0 or 1. + // Select device 0 or 1. Or more for PM SelectDrive(chan, DeviceNumber); // Verify that controller is ready for next command. GetStatus(chan, statusByte); KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entered with status %#x\n", statusByte)); - if(statusByte == 0xff) { + if(statusByte == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "AtapiSendCommand: bad status 0xff on entry\n")); goto make_reset; } @@ -6520,6 +6881,16 @@ goto make_reset; } } + if(deviceExtension->HwFlags & UNIATA_AHCI) { + ULONG CI; + // Check if command list is free + CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI); + if(CI) { + // controller is busy, however we expect it to be free + KdPrint2((PRINT_PREFIX "AtapiSendCommand: Controller busy (CI=%#x) -> reset\n", CI)); + goto make_reset; + } + } if(statusByte & IDE_STATUS_ERROR) { if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) { @@ -6582,7 +6953,7 @@ // 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; + UniataExpectChannelInterrupt(chan, FALSE); chan->RDP = FALSE; InterlockedExchange(&(deviceExtension->chan[GET_CHANNEL(Srb)].CheckIntr), CHECK_INTR_IDLE); @@ -6620,6 +6991,14 @@ chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION; } + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint2((PRINT_PREFIX "AtapiSendCommand: AHCI, begin transaction\n")); + //AtaReq->Flags = ~REQ_FLAG_DMA_OPERATION; // keep proped DMA flag for proper RETRY handling + UniataExpectChannelInterrupt(chan, TRUE); + UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb); + return SRB_STATUS_PENDING; + } + statusByte = WaitOnBusy(chan); KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entry Status (%#x)\n", statusByte)); @@ -6645,7 +7024,7 @@ KdPrint3((PRINT_PREFIX "AtapiSendCommand: Wait for int. to send packet. Status (%#x)\n", statusByte)); - chan->ExpectingInterrupt = TRUE; + UniataExpectChannelInterrupt(chan, TRUE); AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_CMD_INTR; InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); @@ -6663,7 +7042,7 @@ KdPrint2((PRINT_PREFIX "AtapiSendCommand: Poll for int. to send packet. Status (%#x)\n", statusByte)); - chan->ExpectingInterrupt = TRUE; + UniataExpectChannelInterrupt(chan, TRUE); AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR; InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); @@ -6699,7 +7078,7 @@ statusByte = WaitOnBaseBusy(chan); // Indicate expecting an interrupt and wait for it. - chan->ExpectingInterrupt = TRUE; + UniataExpectChannelInterrupt(chan, TRUE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR; @@ -6767,6 +7146,7 @@ UCHAR lChannel; PHW_CHANNEL chan; PCDB cdb; + PHW_LU_EXTENSION LunExt; SetCheckPoint(4); @@ -6810,6 +7190,7 @@ chan = &(deviceExtension->chan[lChannel]); //ldev = GET_LDEV(Srb); DeviceNumber = GET_CDEV(Srb); + LunExt = chan->lun[DeviceNumber]; SetCheckPoint(0x40); if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER) @@ -6835,6 +7216,7 @@ } } + cdb = (PCDB)(Srb->Cdb); SetCheckPoint(0x100 | Srb->Cdb[0]); switch (Srb->Cdb[0]) { case SCSIOP_INQUIRY: @@ -6842,11 +7224,10 @@ 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. + // Filter out wrong TIDs. if ((Srb->Lun != 0) || (Srb->PathId >= deviceExtension->NumberChannels) || - (Srb->TargetId > deviceExtension->NumberLuns)) { + (Srb->TargetId >= deviceExtension->NumberLuns)) { KdPrint2((PRINT_PREFIX "IdeSendCommand: SCSIOP_INQUIRY rejected\n")); @@ -6859,7 +7240,7 @@ KdPrint2((PRINT_PREFIX "IdeSendCommand: SCSIOP_INQUIRY ok\n")); PINQUIRYDATA inquiryData = (PINQUIRYDATA)(Srb->DataBuffer); - PIDENTIFY_DATA2 identifyData = &(chan->lun[DeviceNumber]->IdentifyData); + PIDENTIFY_DATA2 identifyData = &(LunExt->IdentifyData); if (!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) { @@ -6890,13 +7271,13 @@ inquiryData->DeviceType = DIRECT_ACCESS_DEVICE; // Set the removable bit, if applicable. - if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) { + if (LunExt->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) { KdPrint2((PRINT_PREFIX "RemovableMedia\n")); inquiryData->RemovableMedia = 1; } // Set the Relative Addressing (LBA) bit, if applicable. - if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_LBA_ENABLED) { + if (LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) { inquiryData->RelativeAddressing = 1; KdPrint2((PRINT_PREFIX "RelativeAddressing\n")); @@ -6933,16 +7314,34 @@ // 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 (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { + if(cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING) { + PMODE_CACHING_PAGE modeData; - SelectDrive(chan, DeviceNumber); - AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS); - statusByte = WaitOnBusy(chan); + KdPrint2((PRINT_PREFIX "MODE_PAGE_CACHING\n")); + modeData = (PMODE_CACHING_PAGE)Srb->DataBuffer; + if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_CACHING_PAGE)) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlZeroMemory(modeData, sizeof(MODE_CACHING_PAGE)); + modeData->PageCode = MODE_PAGE_CACHING; + modeData->PageLength = sizeof(MODE_CACHING_PAGE)-sizeof(MODE_PARAMETER_HEADER); + modeData->ReadDisableCache = (LunExt->DeviceFlags & DFLAGS_RCACHE_ENABLED) ? 0 : 1; + modeData->WriteCacheEnable = (LunExt->DeviceFlags & DFLAGS_WCACHE_ENABLED) ? 1 : 0; + Srb->DataTransferLength = sizeof(MODE_CACHING_PAGE); + status = SRB_STATUS_SUCCESS; + } + } else + if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { - if (!(statusByte & IDE_STATUS_ERROR)){ + //SelectDrive(chan, DeviceNumber); + //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS); + //statusByte = WaitOnBusy(chan); + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY); + if (!(statusByte & IDE_STATUS_ERROR)) { + // no error occured return success, media is not protected - chan->ExpectingInterrupt = FALSE; + UniataExpectChannelInterrupt(chan, FALSE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); status = SRB_STATUS_SUCCESS; @@ -6953,7 +7352,7 @@ errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error); GetBaseStatus(chan, statusByte); - chan->ExpectingInterrupt = FALSE; + UniataExpectChannelInterrupt(chan, FALSE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); status = SRB_STATUS_SUCCESS; @@ -6981,14 +7380,14 @@ if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { // Select device 0 or 1. - SelectDrive(chan, DeviceNumber); - AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS); - + //SelectDrive(chan, DeviceNumber); + //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS); // Wait for busy. If media has not changed, return success - statusByte = WaitOnBusy(chan); + //statusByte = WaitOnBusy(chan); + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY); if (!(statusByte & IDE_STATUS_ERROR)){ - chan->ExpectingInterrupt = FALSE; + UniataExpectChannelInterrupt(chan, FALSE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); status = SRB_STATUS_SUCCESS; @@ -7000,7 +7399,7 @@ // 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; + UniataExpectChannelInterrupt(chan, FALSE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); status = SRB_STATUS_SUCCESS; @@ -7008,7 +7407,7 @@ } else { // Request sense buffer to be build - chan->ExpectingInterrupt = TRUE; + UniataExpectChannelInterrupt(chan, TRUE); InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE); status = SRB_STATUS_PENDING; @@ -7031,10 +7430,10 @@ MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock, i ); // Calculate last sector. - if(!(i = (ULONG)chan->lun[DeviceNumber]->NumOfSectors)) { - i = chan->lun[DeviceNumber]->IdentifyData.SectorsPerTrack * - chan->lun[DeviceNumber]->IdentifyData.NumberOfHeads * - chan->lun[DeviceNumber]->IdentifyData.NumberOfCylinders; + if(!(i = (ULONG)LunExt->NumOfSectors)) { + i = LunExt->IdentifyData.SectorsPerTrack * + LunExt->IdentifyData.NumberOfHeads * + LunExt->IdentifyData.NumberOfCylinders; } i--; @@ -7047,9 +7446,9 @@ KdPrint2((PRINT_PREFIX "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x\n", Srb->TargetId, - chan->lun[DeviceNumber]->IdentifyData.SectorsPerTrack, - chan->lun[DeviceNumber]->IdentifyData.NumberOfHeads, - chan->lun[DeviceNumber]->IdentifyData.NumberOfCylinders)); + LunExt->IdentifyData.SectorsPerTrack, + LunExt->IdentifyData.NumberOfHeads, + LunExt->IdentifyData.NumberOfCylinders)); status = SRB_STATUS_SUCCESS; @@ -7090,32 +7489,38 @@ statusByte = WaitOnBaseBusy(chan); // Eject media, // first select device 0 or 1. - SelectDrive(chan, DeviceNumber); - AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT); + //SelectDrive(chan, DeviceNumber); + //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT); + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_MEDIA_EJECT, 0, 0, 0, 0, 0, ATA_IMMEDIATE); } status = SRB_STATUS_SUCCESS; break; case SCSIOP_MEDIUM_REMOVAL: - cdb = (PCDB)Srb->Cdb; + cdb = (PCDB)Srb->Cdb; - statusByte = WaitOnBaseBusy(chan); + if(LunExt->IdentifyData.Removable) { + statusByte = WaitOnBaseBusy(chan); - SelectDrive(chan, DeviceNumber); - 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; + //SelectDrive(chan, DeviceNumber); + if (cdb->MEDIA_REMOVAL.Prevent == TRUE) { + //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_LOCK); + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_LOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE); + } else { + //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_UNLOCK); + statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_UNLOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE); + } + status = SRB_STATUS_SUCCESS; + } else { + status = SRB_STATUS_INVALID_REQUEST; + } + break; +#if 0 // 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: @@ -7134,7 +7539,7 @@ KdPrint2((PRINT_PREFIX "IdeSendCommand: SCSIOP_REQUEST_SENSE PATH:LUN:TID = %#x:%#x:%#x\n", Srb->PathId, Srb->Lun, Srb->TargetId)); - if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { + if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) { status = IdeBuildSenseBuffer(HwDeviceExtension,Srb); break; } @@ -7360,6 +7765,7 @@ UCHAR statusByte,errorByte; chan = &(deviceExtension->chan[lChannel]); + SelectDrive(chan, DeviceNumber); if (EnableMSN == TRUE){ @@ -7600,7 +8006,8 @@ */ if(TopLevel && Srb && Srb->SrbExtension) { KdPrint2((PRINT_PREFIX "TopLevel\n")); - RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ)); + //RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ)); + UniAtaClearAtaReq(Srb->SrbExtension); } do { @@ -7624,6 +8031,7 @@ ((Srb->Function == SRB_FUNCTION_IO_CONTROL) || (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI && Srb->Cdb[0] == SCSIOP_INQUIRY)) ) { + // This is our virtual device KdPrint2((PRINT_PREFIX "AtapiStartIo: Communication port\n")); if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) { @@ -7906,7 +8314,7 @@ // 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 + // revert not-responding device to operational state KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset device request received\n")); UniataUserDeviceReset(deviceExtension, LunExt, lChannel); status = SRB_STATUS_SUCCESS; @@ -7992,35 +8400,6 @@ 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 (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) { - status = SRB_STATUS_SUCCESS; - } else { - status = AtaCommand(deviceExtension, GET_CDEV(Srb), 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; @@ -8063,7 +8442,7 @@ status = SRB_STATUS_SELECTION_TIMEOUT; break; } - + if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT) || atapiDev) { @@ -8079,6 +8458,9 @@ // S M S M // 3 2 1 0 + if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) { + deviceNumber = 1 << lChannel; + } else if (deviceExtension->NumberChannels == 1) { if (chan->PrimaryAddress) { deviceNumber = 1 << DeviceNumber; @@ -8086,7 +8468,7 @@ deviceNumber = 4 << DeviceNumber; } } else { - deviceNumber = (1 << DeviceNumber) << lChannel; + deviceNumber = 1 << (DeviceNumber+lChannel*2); } versionParameters->bIDEDeviceMap = deviceNumber; @@ -8105,7 +8487,14 @@ // Extract the target. targetId = cmdInParameters.bDriveNumber; KdPrint2((PRINT_PREFIX "targetId %d\n", targetId)); - if((targetId >= deviceExtension->NumberChannels*2) || + if(deviceExtension->HwFlags & UNIATA_AHCI) { + // cheat code for AHCI :) + // upper layer assumes that we have 2 devices per channel + // TODO: we should invent something to handle PM here + targetId /= 2; + } + + if((targetId >= deviceExtension->NumberChannels*deviceExtension->NumberLuns) || !(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) { KdPrint2((PRINT_PREFIX "Error: xxx_ID_CMD for non-existant device\n")); status = SRB_STATUS_SELECTION_TIMEOUT; @@ -8505,13 +8894,17 @@ // Set status in SRB. Srb->SrbStatus = (UCHAR)status; + KdPrint2((PRINT_PREFIX "AtapiStartIo: AtapiDmaDBSync(%x, %x)\n", chan, Srb)); AtapiDmaDBSync(chan, Srb); + KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataRemoveRequest(%x, %x)\n", chan, Srb)); UniataRemoveRequest(chan, Srb); // Indicate command complete. + KdPrint2((PRINT_PREFIX "AtapiStartIo: ScsiPortNotification\n")); ScsiPortNotification(RequestComplete, deviceExtension, Srb); + KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataGetCurRequest\n")); // Remove current Srb & get next one if((Srb = UniataGetCurRequest(chan))) { AtaReq = (PATA_REQ)(Srb->SrbExtension); @@ -8521,6 +8914,7 @@ Srb = NULL; } } + KdPrint2((PRINT_PREFIX "AtapiStartIo: chan %x, Src %x\n", chan, Srb)); if(!chan) { //ASSERT(TopLevel); } @@ -8561,7 +8955,7 @@ flags = 0; command = i; - KdPrint2((PRINT_PREFIX "cmd %2.2x: ", command)); + //KdPrint2((PRINT_PREFIX "cmd %2.2x: ", command)); switch(command) { case IDE_COMMAND_READ_DMA48: @@ -8582,11 +8976,19 @@ case IDE_COMMAND_WRITE_LOG_DMA48: case IDE_COMMAND_TRUSTED_RCV_DMA: case IDE_COMMAND_TRUSTED_SEND_DMA: - KdPrint2((PRINT_PREFIX "DMA ")); + case IDE_COMMAND_DATA_SET_MGMT: + //KdPrint2((PRINT_PREFIX "DMA ")); flags |= ATA_CMD_FLAG_DMA; } switch(command) { + case IDE_COMMAND_WRITE_FUA_DMA48: + case IDE_COMMAND_WRITE_FUA_DMA_Q48: + case IDE_COMMAND_WRITE_MUL_FUA48: + + flags |= ATA_CMD_FLAG_FUA; + /* FALL THROUGH */ + case IDE_COMMAND_READ48: case IDE_COMMAND_READ_DMA48: case IDE_COMMAND_READ_DMA_Q48: @@ -8599,13 +9001,10 @@ 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: - KdPrint2((PRINT_PREFIX "48 ")); + //KdPrint2((PRINT_PREFIX "48 ")); flags |= ATA_CMD_FLAG_48; /* FALL THROUGH */ @@ -8620,10 +9019,23 @@ case IDE_COMMAND_FLUSH_CACHE: case IDE_COMMAND_VERIFY: - KdPrint2((PRINT_PREFIX "LBA ")); + //KdPrint2((PRINT_PREFIX "LBA ")); flags |= ATA_CMD_FLAG_LBAIOsupp; } + switch(command) { + case IDE_COMMAND_READ_NATIVE_SIZE48: + case IDE_COMMAND_SET_NATIVE_SIZE48: + // we cannot set LBA flag for these commands to avoid BadBlock handling + //flags |= ATA_CMD_FLAG_LBAIOsupp; + flags |= ATA_CMD_FLAG_48; + + case IDE_COMMAND_READ_NATIVE_SIZE: + case IDE_COMMAND_SET_NATIVE_SIZE: + + flags |= ATA_CMD_FLAG_LBAIOsupp | ATA_CMD_FLAG_FUA; + } + flags |= ATA_CMD_FLAG_48supp; switch (command) { @@ -8652,11 +9064,42 @@ case IDE_COMMAND_VERIFY: command = IDE_COMMAND_VERIFY48; break; default: - KdPrint2((PRINT_PREFIX "!28->48 ")); + //KdPrint2((PRINT_PREFIX "!28->48 ")); flags &= ~ATA_CMD_FLAG_48supp; } - KdPrint2((PRINT_PREFIX "\t -> %2.2x (%2.2x)\n", command, flags)); + switch (command) { + case IDE_COMMAND_READ: + case IDE_COMMAND_READ_MULTIPLE: + 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_READ_DMA_Q: + case IDE_COMMAND_READ_DMA: + case IDE_COMMAND_READ_LOG_DMA48: + case IDE_COMMAND_TRUSTED_RCV_DMA: + case IDE_COMMAND_IDENTIFY: + case IDE_COMMAND_ATAPI_IDENTIFY: + //KdPrint2((PRINT_PREFIX "RD ")); + flags |= ATA_CMD_FLAG_In; + break; + case IDE_COMMAND_WRITE: + case IDE_COMMAND_WRITE_MULTIPLE: + case IDE_COMMAND_WRITE_DMA48: + case IDE_COMMAND_WRITE_DMA_Q48: + 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: + //KdPrint2((PRINT_PREFIX "WR ")); + flags |= ATA_CMD_FLAG_Out; + break; + } + + //KdPrint2((PRINT_PREFIX "\t -> %2.2x (%2.2x)\n", command, flags)); AtaCommands48[i] = command; AtaCommandFlags[i] = flags; } @@ -8727,7 +9170,7 @@ return status; } #endif // USE_REACTOS_DDK - KdPrint(("UniATA Init: OS ver %x.%x (%d)\n", MajorVersion, MinorVersion, BuildNumber)); + KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, *KeNumberProcessors)); KeQuerySystemTime(&t0); do { @@ -8827,21 +9270,36 @@ switch(g_opt_VirtualMachine) { case VM_VBOX: + KdPrint2((PRINT_PREFIX "adjust options for VirtualBox\n")); // adjust options for VirtualBox g_opt_WaitBusyCount = 20000; g_opt_WaitBusyDelay = 150; g_opt_WaitDrqDelay = 100; + g_opt_WaitBusyLongCount = 20000; + g_opt_MaxIsrWait = 200; g_opt_AtapiSendDisableIntr = 0; g_opt_AtapiDmaRawRead = FALSE; break; } + if(!hasPCI) { + KdPrint2((PRINT_PREFIX "old slow machine, adjust timings\n")); + // old slow machine, adjust timings + g_opt_WaitBusyCount = 20000; + g_opt_WaitBusyDelay = 150; + g_opt_WaitDrqDelay = 100; + g_opt_WaitBusyLongCount = 20000; + g_opt_MaxIsrWait = 200; + } + g_opt_WaitBusyCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyCount", g_opt_WaitBusyCount); // 200 vs 20000 g_opt_WaitBusyDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyDelay", g_opt_WaitBusyDelay); // 10 vs 150 g_opt_WaitDrqDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitDrqDelay", g_opt_WaitDrqDelay); // 10 vs 100 + g_opt_WaitBusyLongCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongCount", g_opt_WaitBusyLongCount); // 2000 vs 20000 + g_opt_WaitBusyLongDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongDelay", g_opt_WaitBusyLongDelay); // 250 vs 250 g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr", g_opt_AtapiSendDisableIntr); // 1 vs 0 g_opt_AtapiDmaRawRead = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead", g_opt_AtapiDmaRawRead); // 1 vs 0 - + g_opt_MaxIsrWait = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait", g_opt_MaxIsrWait); // 40 vs xxx } // Look for legacy ISA-bridged PCI IDE controller (onboard) @@ -9067,6 +9525,11 @@ hwInitializationData.comm.DeviceId = 0; hwInitializationData.comm.DeviceIdLength = 0; + if(!BMListLen) { + hwInitializationData.comm.SrbExtensionSize = FIELD_OFFSET(ATA_REQ, ata); + KdPrint2((PRINT_PREFIX "using AtaReq sz %x\n", hwInitializationData.comm.SrbExtensionSize)); + } + // The adapter count is used by the find adapter routine to track how // which adapter addresses have been tested. Index: drivers/storage/ide/uniata/id_badblock.cpp =================================================================== --- drivers/storage/ide/uniata/id_badblock.cpp (revision 57016) +++ drivers/storage/ide/uniata/id_badblock.cpp (working copy) @@ -182,6 +182,7 @@ for(i=0; ilun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) - ULONG NTAPI AtapiVirtToPhysAddr_( IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb, IN PUCHAR data, - IN PULONG count, + OUT PULONG count, /* bytes */ OUT PULONG ph_addru ) { @@ -242,11 +240,12 @@ IN ULONG lChannel, // logical channel, IN PSCSI_REQUEST_BLOCK Srb, IN PUCHAR data, - IN ULONG count + IN ULONG count /* bytes */ ) { PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; ULONG dma_count, dma_base, dma_baseu; + ULONG dma_count0, dma_base0; ULONG i; PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]); PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); @@ -254,7 +253,15 @@ BOOLEAN use_AHCI = (deviceExtension->HwFlags & UNIATA_AHCI) ? TRUE : FALSE; ULONG orig_count = count; ULONG max_entries = use_AHCI ? ATA_AHCI_DMA_ENTRIES : ATA_DMA_ENTRIES; + //ULONG max_frag = use_AHCI ? (0x3fffff+1) : (4096); // DEBUG, replace 4096 for procer chipset-specific value + ULONG max_frag = deviceExtension->DmaSegmentLength; + ULONG seg_align = deviceExtension->DmaSegmentAlignmentMask; + if(AtaReq->dma_entries) { + KdPrint2((PRINT_PREFIX "AtapiDmaSetup: already setup, %d entries\n", AtaReq->dma_entries)); + return TRUE; + } + AtaReq->ata.dma_base = 0; AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION; KdPrint2((PRINT_PREFIX "AtapiDmaSetup: mode %#x, data %x, count %x, lCh %x, dev %x\n", @@ -282,9 +289,9 @@ //KdPrint2((PRINT_PREFIX " checkpoint 4\n" )); if(use_AHCI) { - KdPrint2((PRINT_PREFIX " get Phys(AHCI_CMD=%x)\n", &(AtaReq->ahci.ahci_cmd_ptr->prd_tab) )); - dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab), &i, &dma_baseu); - AtaReq->ahci.ahci_base64 = NULL; // clear before setup + KdPrint2((PRINT_PREFIX " get Phys(AHCI_CMD=%x)\n", AtaReq->ahci.ahci_cmd_ptr )); + dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)(AtaReq->ahci.ahci_cmd_ptr), &i, &dma_baseu); + AtaReq->ahci.ahci_base64 = 0; // clear before setup } else { KdPrint2((PRINT_PREFIX " get Phys(PRD=%x)\n", &(AtaReq->dma_tab) )); dma_base = AtapiVirtToPhysAddr(HwDeviceExtension, NULL, (PUCHAR)&(AtaReq->dma_tab) /*chan->dma_tab*/, &i, &dma_baseu); @@ -301,9 +308,9 @@ KdPrint2((PRINT_PREFIX "AtapiDmaSetup: No BASE\n" )); return FALSE; } - AtaReq->ata.dma_base = dma_base; // aliased to ahci_base64 + AtaReq->ata.dma_base = dma_base; // aliased to AtaReq->ahci.ahci_base64 - KdPrint2((PRINT_PREFIX " get Phys(data=%x)\n", data )); + KdPrint2((PRINT_PREFIX " get Phys(data[0]=%x)\n", data )); 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)); @@ -328,15 +335,40 @@ count -= dma_count; i = 0; + dma_count0 = dma_count; + dma_base0 = dma_base; + while (count) { +/* KdPrint2((PRINT_PREFIX " segments %#x+%#x == %#x && %#x+%#x <= %#x\n", + dma_base0, dma_count0, dma_base, + dma_count0, dma_count, max_frag));*/ + if(dma_base0+dma_count0 == dma_base && + dma_count0+dma_count <= max_frag) { + // 'i' should be always > 0 here + // for BM we cannot cross 64k boundary + if(dma_base & seg_align) { + //KdPrint2((PRINT_PREFIX " merge segments\n" )); + ASSERT(i); + //BrutePoint(); + i--; + dma_base = dma_base0; + dma_count += dma_count0; + } + } if(use_AHCI) { AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].base = dma_base; AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].baseu = dma_baseu; - AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC = ((dma_count-1) & 0x3fffff); + AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved1 = 0; + *((PULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC_ULONG)) = ((dma_count-1) & 0x3fffff); +/* AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved2 = 0; + AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].I = 0;*/ + KdPrint2((PRINT_PREFIX " ph data[%d]=%x:%x (%x)\n", i, dma_baseu, dma_base, AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC)); } else { AtaReq->dma_tab[i].base = dma_base; AtaReq->dma_tab[i].count = (dma_count & 0xffff); } + dma_count0 = dma_count; + dma_base0 = dma_base; i++; if (i >= max_entries) { KdPrint2((PRINT_PREFIX "too many segments in DMA table\n" )); @@ -344,7 +376,7 @@ AtaReq->ahci.ahci_base64 = NULL; return FALSE; } - KdPrint2((PRINT_PREFIX " get Phys(data[n]=%x)\n", data )); + KdPrint2((PRINT_PREFIX " get Phys(data[n=%d]=%x)\n", i, data )); 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)); @@ -369,15 +401,45 @@ count -= min(count, PAGE_SIZE); } KdPrint2((PRINT_PREFIX " set TERM\n" )); +/* KdPrint2((PRINT_PREFIX " segments %#x+%#x == %#x && #x+%#x <= %#x\n", + dma_base0, dma_count0, dma_base, + dma_count0, dma_count, max_frag));*/ + if(dma_base0+dma_count0 == dma_base && + dma_count0+dma_count <= max_frag) { + // 'i' should be always > 0 here + if(dma_base & seg_align) { + //KdPrint2((PRINT_PREFIX " merge segments\n" )); + //BrutePoint(); + ASSERT(i); + i--; + dma_base = dma_base0; + dma_count += dma_count0; + } + } if(use_AHCI) { AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].base = dma_base; AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].baseu = dma_baseu; - AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC = ((dma_count-1) & 0x3fffff); + AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved1 = 0; + //AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC = ((dma_count-1) & 0x3fffff); + //AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].Reserved2 = 0; + *((PULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC_ULONG)) = ((dma_count-1) & 0x3fffff); + //AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].I = 1; // interrupt when ready + KdPrint2((PRINT_PREFIX " ph data[%d]=%x:%x (%x)\n", i, dma_baseu, dma_base, AtaReq->ahci.ahci_cmd_ptr->prd_tab[i].DBC)); + if(((ULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab) & ~PAGE_MASK) != ((ULONG)&(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i]) & ~PAGE_MASK)) { + KdPrint2((PRINT_PREFIX "PRD table crosses page boundary! %x vs %x\n", + &AtaReq->ahci.ahci_cmd_ptr->prd_tab, &(AtaReq->ahci.ahci_cmd_ptr->prd_tab[i]) )); + //AtaReq->Flags |= REQ_FLAG_DMA_DBUF_PRD; + } } else { AtaReq->dma_tab[i].base = dma_base; AtaReq->dma_tab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT; + if(((ULONG)&(AtaReq->dma_tab) & ~PAGE_MASK) != ((ULONG)&(AtaReq->dma_tab[i]) & ~PAGE_MASK)) { + KdPrint2((PRINT_PREFIX "DMA table crosses page boundary! %x vs %x\n", + &AtaReq->dma_tab, &(AtaReq->dma_tab[i]) )); + //AtaReq->Flags |= REQ_FLAG_DMA_DBUF_PRD; + } } - AtaReq->dma_entries = i; + AtaReq->dma_entries = i+1; if(use_DB_IO) { AtaReq->Flags |= REQ_FLAG_DMA_DBUF; @@ -589,7 +651,7 @@ if(deviceExtension->HwFlags & UNIATA_AHCI) { KdPrint2((PRINT_PREFIX " ACHTUNG! should not be called for AHCI!\n")); - return 0xff; + return IDE_STATUS_WRONG; } switch(VendorID) { @@ -645,6 +707,13 @@ { SCHAR apiomode; + if((deviceExtension->HwFlags & UNIATA_AHCI) && + !(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + // skip unnecessary checks + KdPrint2((PRINT_PREFIX "AtapiDmaReinit: ahci, nothing to do for HDD\n")); + return; + } + apiomode = (CHAR)AtaPioMode(&(LunExt->IdentifyData)); if(!(AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) { @@ -655,8 +724,8 @@ if(deviceExtension->HwFlags & UNIATA_AHCI) { if(!AtaReq->ahci.ahci_base64) { KdPrint2((PRINT_PREFIX - "AtapiDmaReinit: no AHCI PRD, fall to PIO on Device %d\n", LunExt->Lun)); - goto limit_pio; + "AtapiDmaReinit: no AHCI PRD, fatal on Device %d\n", LunExt->Lun)); + goto exit; } } else if(!AtaReq->ata.dma_base) { @@ -722,6 +791,9 @@ "AtapiDmaReinit: restore IO mode on Device %d\n", LunExt->Lun)); AtapiDmaInit__(deviceExtension, LunExt); } + +exit: + return; } // end AtapiDmaReinit() VOID @@ -773,9 +845,19 @@ 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(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) { + statusByte = mode <= ATA_PIO2 ? IDE_STATUS_IDLE : IDE_STATUS_ERROR; + } else { + if(deviceExtension->HwFlags & UNIATA_AHCI) { + AtapiDisableInterrupts(deviceExtension, lChannel); + } + 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(deviceExtension->HwFlags & UNIATA_AHCI) { + AtapiEnableInterrupts(deviceExtension, lChannel); + } + } if(statusByte & IDE_STATUS_ERROR) { KdPrint3((PRINT_PREFIX " wait ready after error\n")); if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) { @@ -819,11 +901,13 @@ PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; //LONG statusByte = 0; ULONG dev = Channel*2 + DeviceNumber; // for non-SATA/AHCI only! - ULONG ldev = lChannel*2 + DeviceNumber; // for non-SATA/AHCI only! + //ULONG ldev = lChannel*2 + DeviceNumber; // for non-SATA/AHCI only! + BOOLEAN isAtapi = ATAPI_DEVICE(chan, DeviceNumber); ULONG slotNumber = deviceExtension->slotNumber; ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber; LONG i; PHW_LU_EXTENSION LunExt = chan->lun[DeviceNumber]; + UCHAR ModeByte; ULONG VendorID = deviceExtension->DevID & 0xffff; //ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff; @@ -888,29 +972,27 @@ 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(!(ChipFlags & UNIATA_AHCI)) { - if(deviceExtension->UnknownDev) { - KdPrint2((PRINT_PREFIX "Unknown chip, omit Vendor/Dev checks\n")); - goto try_generic_dma; - } + // this is necessary for future PM support + 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(UniataIsSATARangeAvailable(deviceExtension, lChannel)) { - //if(ChipFlags & UNIATA_SATA) { + //if(ChipFlags & (UNIATA_SATA | UNIATA_AHCI)) { /****************/ /* SATA Generic */ /****************/ - UCHAR ModeByte; KdPrint2((PRINT_PREFIX "SATA Generic\n")); if(udmamode > 5) { @@ -922,7 +1004,7 @@ if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, min(LunExt->LimitedTransferMode, LunExt->OrigTransferMode))) { return; } - udmamode = min(udmamode, 5); + udmamode = min(udmamode, 6); } else { KdPrint2((PRINT_PREFIX "SATA -> PATA adapter ?\n")); @@ -931,7 +1013,7 @@ udmamode = 2; apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO0)); } else { - udmamode = min(udmamode, 5); + udmamode = min(udmamode, 6); } } } @@ -950,10 +1032,21 @@ AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ModeByte); return; } + + if(deviceExtension->UnknownDev) { + KdPrint2((PRINT_PREFIX "Unknown chip, omit Vendor/Dev checks\n")); + goto try_generic_dma; + } + 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)); + if(LunExt->IdentifyData.SataCapabilities != 0x0000 && + LunExt->IdentifyData.SataCapabilities != 0xffff) { + KdPrint2((PRINT_PREFIX "AtapiDmaInit: SATA beyond adapter or Controller compat mode\n")); + } else { + 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", @@ -1021,8 +1114,8 @@ /* 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)) { + if(ATAPI_DEVICE(chan, 0) && + ATAPI_DEVICE(chan, 1)) { // 2 devices on this channel - NO DMA chan->MaxTransferMode = min(chan->MaxTransferMode, ATA_PIO4); @@ -1364,7 +1457,7 @@ SetPciConfig2(0x4a, (reg4a & ~(0x3 << (dev<<2))) | (0x01 + !(i & 0x01)) ); } - if(i >= 3) { + if(i >= 2) { reg54 |= (0x1 << dev); } else { reg54 &= ~(0x1 << dev); @@ -1412,8 +1505,7 @@ GetPciConfig1(0x44, reg44); /* Allow PIO/WDMA timing controls. */ - reg40 &= ~0x00ff00ff; - reg40 |= ~0x40774077; + mask40 = 0x000000ff; /* Set PIO/WDMA timings. */ if(!(DeviceNumber & 1)) { mask40 |= 0x00003300; @@ -1423,6 +1515,7 @@ new44 = ((intel_timings[idx] & 0x30) >> 2) | (intel_timings[idx] & 0x03); } + new40 |= 0x00004077; if (Channel) { mask40 <<= 16; @@ -1441,7 +1534,7 @@ /* Promise */ /***********/ if(ChipType < PRTX) { - if (ATAPI_DEVICE(deviceExtension, ldev)) { + if (isAtapi) { udmamode = wdmamode = -1; } @@ -1919,12 +2012,12 @@ reg40 &= 0xff00; reg40 |= 0x4033; - if(!(ldev & 1)) { - reg40 |= (ATAPI_DEVICE(deviceExtension, ldev) ? 0x04 : 0x00); + if(!(DeviceNumber & 1)) { + reg40 |= (isAtapi ? 0x04 : 0x00); mask40 = 0x3300; new40 = timing << 8; } else { - reg40 |= (ATAPI_DEVICE(deviceExtension, ldev) ? 0x40 : 0x00); + reg40 |= (isAtapi ? 0x40 : 0x00); mask44 = 0x0f; new44 = ((timing & 0x30) >> 2) | (timing & 0x03); @@ -1980,7 +2073,7 @@ /* unknown controller chip */ /* better not try generic DMA on ATAPI devices it almost never works */ - if (ATAPI_DEVICE(deviceExtension, ldev)) { + if (isAtapi) { KdPrint2((PRINT_PREFIX "ATAPI on unknown controller -> PIO\n")); udmamode = wdmamode = -1; @@ -1989,9 +2082,9 @@ /* 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 && + /*deviceExtension->BaseIoAddressBM[lChannel]*/ (deviceExtension->BusMaster==DMA_MODE_BM) && (GetDmaStatus(deviceExtension, lChannel) & - (!(ldev & 1) ? + (!(DeviceNumber & 1) ? BM_STATUS_DRIVE_0_DMA : BM_STATUS_DRIVE_1_DMA))) { // LunExt->TransferMode = ATA_DMA; // return; Index: drivers/storage/ide/uniata/id_init.cpp =================================================================== --- drivers/storage/ide/uniata/id_init.cpp (revision 57016) +++ drivers/storage/ide/uniata/id_init.cpp (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2004-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2004-2012 Alexandr A. Telyatnikov (Alter) Module Name: id_init.cpp @@ -69,8 +69,8 @@ deviceExtension->NumberChannels = 1; } if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhciPM", 1 /* DEBUG */)) { - KdPrint2((PRINT_PREFIX "SATA/AHCI w/o PM, max luns 1\n")); - deviceExtension->NumberLuns = 2; + KdPrint2((PRINT_PREFIX "SATA/AHCI w/o PM, max luns 1 or 2\n")); + deviceExtension->NumberLuns = 2; // we may be in Legacy mode //chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; } else { KdPrint2((PRINT_PREFIX "SATA/AHCI -> possible PM, max luns %d\n", SATA_MAX_PM_UNITS)); @@ -133,8 +133,8 @@ if(ChipFlags & SIIBUG) { /* work around errata in early chips */ - ConfigInfo->AlignmentMask = 0x1fff; - deviceExtension->MaximumDmaTransferLength = 15 * DEV_BSIZE; + deviceExtension->DmaSegmentLength = 15 * DEV_BSIZE; + deviceExtension->DmaSegmentAlignmentMask = 8192-1; } if(ChipType != SIIMIO) { break; @@ -255,11 +255,15 @@ deviceExtension->MaxTransferMode = BaseIoAddressBM ? ATA_DMA : ATA_PIO4; ConfigInfo->MaximumTransferLength = DEV_BSIZE*256; deviceExtension->MaximumDmaTransferLength = ConfigInfo->MaximumTransferLength; + //deviceExtension->NumberOfPhysicalBreaks = min(deviceExtension->MaximumDmaTransferLength/PAGE_SIZE+1, ATA_DMA_ENTRIES); + deviceExtension->DmaSegmentLength = 0x10000; + deviceExtension->DmaSegmentAlignmentMask = 0xffff; KdPrint2((PRINT_PREFIX "i: %#x\n", i)); if(i != BMLIST_TERMINATOR) { DevTypeInfo = (PBUSMASTER_CONTROLLER_INFORMATION)&BusMasterAdapters[i]; } else { +unknown_dev: if(Ata_is_ahci_dev(pciData)) { KdPrint2((PRINT_PREFIX " AHCI candidate")); @@ -268,10 +272,9 @@ KdPrint2((PRINT_PREFIX " AHCI init failed - not detected\n")); return STATUS_UNSUCCESSFUL; } - KdPrint2((PRINT_PREFIX " unknown AHCI dev, addr %#x", deviceExtension->BaseIoAHCI_0.Addr)); + KdPrint2((PRINT_PREFIX " unknown AHCI dev, addr %#x ", deviceExtension->BaseIoAHCI_0.Addr)); } -unknown_dev: - KdPrint2((PRINT_PREFIX " unknown dev, BM addr %#I64x", BaseIoAddressBM)); + KdPrint2((PRINT_PREFIX " unknown dev, BM addr %#x ", BaseIoAddressBM)); DevTypeInfo = NULL; KdPrint2((PRINT_PREFIX " MaxTransferMode %#x\n", deviceExtension->MaxTransferMode)); @@ -281,8 +284,9 @@ if(!UniataAllocateLunExt(deviceExtension, UNIATA_ALLOCATE_NEW_LUNS)) { return STATUS_UNSUCCESSFUL; } - - return STATUS_NOT_FOUND; + // DEBUG, we shall return success when AHCI is completly supported + //return STATUS_NOT_FOUND; + return STATUS_SUCCESS; } static BUSMASTER_CONTROLLER_INFORMATION const SiSAdapters[] = { @@ -447,7 +451,7 @@ deviceExtension->BaseIoAddressBM_0); deviceExtension->BaseIoAddressBM_0 = 0; - deviceExtension->BusMaster = FALSE; + deviceExtension->BusMaster = DMA_MODE_NONE; deviceExtension->MaxTransferMode = ATA_PIO4; break; @@ -1020,10 +1024,10 @@ /* if BAR(5) is IO it should point to SATA interface registers */ if(deviceExtension->DevID == 0x28288086 && pciData->u.type0.SubVendorID == 0x106b) { + /* Skip BAR(5) on ICH8M Apples, system locks up on access. */ + KdPrint2((PRINT_PREFIX "Ignore BAR5 on ICH8M Apples\n")); BaseMemAddress = 0; - KdPrint2((PRINT_PREFIX "Ignore BAR5 on ICH8M Apples\n")); } else { - /* Skip BAR(5) on ICH8M Apples, system locks up on access. */ BaseMemAddress = AtapiGetIoRange(HwDeviceExtension, ConfigInfo, pciData, SystemIoBusNumber, 5, 0, 0x10); if(BaseMemAddress && (*ConfigInfo->AccessRanges)[5].RangeInMemory) { @@ -1465,16 +1469,44 @@ } tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"GeomType", 0xffffffff); - if(tmp32 > 2) { + if(tmp32 > GEOM_MANUAL) { tmp32 = 0xffffffff; } LunExt->opt_GeomType = tmp32; + if(tmp32 == GEOM_MANUAL) { + LunExt->DeviceFlags |= DFLAGS_MANUAL_CHS; + LunExt->opt_GeomType = GEOM_ORIG; + // assume IdentifyData is already zero-filled + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"C", 0); + LunExt->IdentifyData.NumberOfCurrentCylinders = + LunExt->IdentifyData.NumberOfCylinders = (USHORT)tmp32; + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"H", 0); + LunExt->IdentifyData.NumberOfCurrentHeads = + LunExt->IdentifyData.NumberOfHeads = (USHORT)tmp32; + tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"S", 0); + LunExt->IdentifyData.CurrentSectorsPerTrack = + LunExt->IdentifyData.SectorsPerTrack = (USHORT)tmp32; + memcpy(LunExt->IdentifyData.ModelNumber, "SEIDH DD", 8); // ESDI HDD + memcpy(LunExt->IdentifyData.SerialNumber, ".10", 4); + memcpy(LunExt->IdentifyData.FirmwareRevision, ".10", 4); + if(!LunExt->IdentifyData.SectorsPerTrack || + !LunExt->IdentifyData.NumberOfCylinders || + !LunExt->IdentifyData.SectorsPerTrack) { + // ERROR + KdPrint2((PRINT_PREFIX "Wrong CHS\n")); + LunExt->opt_GeomType = GEOM_AUTO; + } else { + LunExt->DeviceFlags |= DFLAGS_MANUAL_CHS; + LunExt->opt_GeomType = GEOM_ORIG; + } + } tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"Hidden", 0); if(tmp32) { LunExt->DeviceFlags |= DFLAGS_HIDDEN; } + return; } // end UniAtaReadLunConfig() @@ -2284,6 +2316,7 @@ BaseIoAddressBM_0++; } } + return; } // end UniataInitMapBM() VOID @@ -2305,6 +2338,7 @@ chan->RegTranslation[IDX_IO2+i].MemIo = FALSE; } UniataInitSyncBaseIO(chan); + return; } // end UniataInitMapBase() VOID @@ -2315,6 +2349,7 @@ { 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])); + return; } // end UniataInitSyncBaseIO() VOID @@ -2327,7 +2362,10 @@ { ULONG i; + KdPrint2((PRINT_PREFIX "AtapiSetupLunPtrs for channel %d of %d, %d luns \n", c, deviceExtension->NumberChannels, deviceExtension->NumberLuns)); + if(!deviceExtension->NumberLuns) { + KdPrint2((PRINT_PREFIX "Achtung !deviceExtension->NumberLuns \n")); deviceExtension->NumberLuns = IDE_MAX_LUN_PER_CHAN; } chan->DeviceExtension = deviceExtension; @@ -2343,5 +2381,106 @@ chan->lun[i]->chan = chan; chan->lun[i]->Lun = i; } + if((deviceExtension->HwFlags & UNIATA_AHCI) && + deviceExtension->AhciInternalAtaReq0 && + deviceExtension->AhciInternalSrb0) { + chan->AhciInternalAtaReq = &(deviceExtension->AhciInternalAtaReq0[c]); + chan->AhciInternalSrb = &(deviceExtension->AhciInternalSrb0[c]); + UniataAhciSetupCmdPtr(chan->AhciInternalAtaReq); + chan->AhciInternalSrb->SrbExtension = chan->AhciInternalAtaReq; + chan->AhciInternalAtaReq->Srb = chan->AhciInternalSrb; + } + return; } // end AtapiSetupLunPtrs() +BOOLEAN +NTAPI +UniataAllocateLunExt( + PHW_DEVICE_EXTENSION deviceExtension, + ULONG NewNumberChannels + ) +{ + PHW_LU_EXTENSION old_luns = NULL; + PHW_CHANNEL old_chans = NULL; + + KdPrint2((PRINT_PREFIX "allocate %d Luns for %d channels\n", deviceExtension->lun, deviceExtension->NumberChannels)); + + old_luns = deviceExtension->lun; + old_chans = deviceExtension->chan; + + if(old_luns || old_chans) { + if(NewNumberChannels == UNIATA_ALLOCATE_NEW_LUNS) { + KdPrint2((PRINT_PREFIX "already allocated!\n")); + return FALSE; + } + } + + if(!deviceExtension->NumberLuns) { + KdPrint2((PRINT_PREFIX "default NumberLuns=2\n")); + deviceExtension->NumberLuns = 2; + } + + if(deviceExtension->HwFlags & UNIATA_AHCI) { + if(!deviceExtension->AhciInternalAtaReq0) { + deviceExtension->AhciInternalAtaReq0 = (PATA_REQ)ExAllocatePool(NonPagedPool, sizeof(ATA_REQ)*deviceExtension->NumberChannels); + if (!deviceExtension->AhciInternalAtaReq0) { + KdPrint2((PRINT_PREFIX "!deviceExtension->AhciInternalAtaReq0 => SP_RETURN_ERROR\n")); + return FALSE; + } + RtlZeroMemory(deviceExtension->AhciInternalAtaReq0, sizeof(ATA_REQ)*deviceExtension->NumberChannels); + } + if(!deviceExtension->AhciInternalSrb0) { + deviceExtension->AhciInternalSrb0 = (PSCSI_REQUEST_BLOCK)ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)*deviceExtension->NumberChannels); + if (!deviceExtension->AhciInternalSrb0) { + KdPrint2((PRINT_PREFIX "!deviceExtension->AhciInternalSrb0 => SP_RETURN_ERROR\n")); + UniataFreeLunExt(deviceExtension); + return FALSE; + } + RtlZeroMemory(deviceExtension->AhciInternalSrb0, sizeof(SCSI_REQUEST_BLOCK)*deviceExtension->NumberChannels); + } + } + + deviceExtension->lun = (PHW_LU_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(HW_LU_EXTENSION) * (deviceExtension->NumberChannels+1) * deviceExtension->NumberLuns); + if (!deviceExtension->lun) { + KdPrint2((PRINT_PREFIX "!deviceExtension->lun => SP_RETURN_ERROR\n")); + UniataFreeLunExt(deviceExtension); + return FALSE; + } + RtlZeroMemory(deviceExtension->lun, sizeof(HW_LU_EXTENSION) * (deviceExtension->NumberChannels+1) * deviceExtension->NumberLuns); + + deviceExtension->chan = (PHW_CHANNEL)ExAllocatePool(NonPagedPool, sizeof(HW_CHANNEL) * (deviceExtension->NumberChannels+1)); + if (!deviceExtension->chan) { + UniataFreeLunExt(deviceExtension); + KdPrint2((PRINT_PREFIX "!deviceExtension->chan => SP_RETURN_ERROR\n")); + return FALSE; + } + RtlZeroMemory(deviceExtension->chan, sizeof(HW_CHANNEL) * (deviceExtension->NumberChannels+1)); + return TRUE; +} // end UniataAllocateLunExt() + +VOID +NTAPI +UniataFreeLunExt( + PHW_DEVICE_EXTENSION deviceExtension + ) +{ + if (deviceExtension->lun) { + ExFreePool(deviceExtension->lun); + deviceExtension->lun = NULL; + } + if (deviceExtension->chan) { + ExFreePool(deviceExtension->chan); + deviceExtension->chan = NULL; + } + if(deviceExtension->AhciInternalAtaReq0) { + ExFreePool(deviceExtension->AhciInternalAtaReq0); + deviceExtension->AhciInternalAtaReq0 = NULL; + } + if(deviceExtension->AhciInternalSrb0) { + ExFreePool(deviceExtension->AhciInternalSrb0); + deviceExtension->AhciInternalSrb0 = NULL; + } + + return; +} // end UniataFreeLunExt() + Index: drivers/storage/ide/uniata/id_probe.cpp =================================================================== --- drivers/storage/ide/uniata/id_probe.cpp (revision 57016) +++ drivers/storage/ide/uniata/id_probe.cpp (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2002-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2002-2012 Alexandr A. Telyatnikov (Alter) Module Name: id_probe.cpp @@ -112,7 +112,36 @@ (*ConfigInfo->AccessRanges)[rid].RangeInMemory )); + if(!(*ConfigInfo->AccessRanges)[rid].RangeInMemory) { + 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; + } + if((pciData->u.type0.BaseAddresses[rid] & PCI_ADDRESS_IO_SPACE)) { + (*ConfigInfo->AccessRanges)[rid].RangeInMemory = FALSE; + } else { + KdPrint2((PRINT_PREFIX " AtapiGetIoRange: adjust mem 0 -> 1\n")); + (*ConfigInfo->AccessRanges)[rid].RangeInMemory = TRUE; + } + } else { + io_start = 0; + } + } + if((*ConfigInfo->AccessRanges)[rid].RangeInMemory) { + if(offset) { + KdPrint2((PRINT_PREFIX " AtapiGetIoRange: can't map memory range with offset\n")); + return 0; + } io_start = // Get the system physical address for this IO range. ((ULONG_PTR)ScsiPortGetDeviceBase(HwDeviceExtension, @@ -132,27 +161,6 @@ // } } - 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; - } - if((pciData->u.type0.BaseAddresses[rid] & PCI_ADDRESS_IO_SPACE)) { - (*ConfigInfo->AccessRanges)[rid].RangeInMemory = FALSE; - } else { - (*ConfigInfo->AccessRanges)[rid].RangeInMemory = TRUE; - } - } else { - io_start = 0; - } KdPrint2((PRINT_PREFIX " AtapiGetIoRange: (2) %#x\n", io_start)); return io_start; @@ -164,7 +172,7 @@ 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 + Thus, we build list here. Later we pretend that always knew about found devices. We shall initiate ISA device init, but callback will use @@ -298,6 +306,9 @@ maxPciBus = busNumber; break; } + // indicate that system has PCI bus(es) + hasPCI =TRUE; + // no device in this slot if(busDataRead == 2) { NeedPciAltInit = TRUE; @@ -321,12 +332,14 @@ //KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass )); + // check for (g_opt_VirtualMachine == VM_AUTO) is performed inside each + // VM check for debug purposes + // Do not optimize :) if(VendorID == 0x80ee && DeviceID == 0xcafe) { KdPrint2((PRINT_PREFIX "-- BusID: %#x:%#x:%#x - VirtualBox Guest Service\n",busNumber,slotNumber,funcNumber)); if(g_opt_VirtualMachine == VM_AUTO) { g_opt_VirtualMachine = VM_VBOX; } - //continue; } else if((VendorID == 0x15ad) || (SubVendorID == 0x15ad && SubSystemID == 0x1976)) { @@ -334,7 +347,6 @@ if(g_opt_VirtualMachine == VM_AUTO) { g_opt_VirtualMachine = VM_VMWARE; } - //g_opt_VirtualBox = TRUE; } else if(SubVendorID == 0x1af4 && SubSystemID == 0x1100) { KdPrint2((PRINT_PREFIX "-- BusID: %#x:%#x:%#x - QEmu\n",busNumber,slotNumber,funcNumber)); @@ -350,7 +362,7 @@ KdPrint2((PRINT_PREFIX "-- BusID: %#x:%#x:%#x\n",busNumber,slotNumber,funcNumber)); KdPrint2((PRINT_PREFIX "Storage Class\n")); - KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass )); + KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X, ProgIf %2.2X\n", dev_id, BaseClass, SubClass, pciData.ProgIf )); // look for known chipsets found = FALSE; known = FALSE; @@ -837,52 +849,6 @@ ); } // end UniataFindCompatBusMasterController2() -BOOLEAN -NTAPI -UniataAllocateLunExt( - PHW_DEVICE_EXTENSION deviceExtension, - ULONG NewNumberChannels - ) -{ - PHW_LU_EXTENSION old_luns = NULL; - PHW_CHANNEL old_chans = NULL; - - KdPrint2((PRINT_PREFIX "allocate Luns for %d channels\n", deviceExtension->NumberChannels)); - - old_luns = deviceExtension->lun; - old_chans = deviceExtension->chan; - - if(old_luns || old_chans) { - if(NewNumberChannels == UNIATA_ALLOCATE_NEW_LUNS) { - KdPrint2((PRINT_PREFIX "already allocated!\n")); - return FALSE; - } - } - - if(!deviceExtension->NumberLuns) { - KdPrint2((PRINT_PREFIX "default NumberLuns=2\n")); - deviceExtension->NumberLuns = 2; - } - - deviceExtension->lun = (PHW_LU_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(HW_LU_EXTENSION) * (deviceExtension->NumberChannels+1) * deviceExtension->NumberLuns); - if (!deviceExtension->lun) { - KdPrint2((PRINT_PREFIX "!deviceExtension->lun => SP_RETURN_ERROR\n")); - return FALSE; - } - RtlZeroMemory(deviceExtension->lun, sizeof(HW_LU_EXTENSION) * (deviceExtension->NumberChannels+1) * deviceExtension->NumberLuns); - - deviceExtension->chan = (PHW_CHANNEL)ExAllocatePool(NonPagedPool, sizeof(HW_CHANNEL) * (deviceExtension->NumberChannels+1)); - if (!deviceExtension->chan) { - ExFreePool(deviceExtension->lun); - deviceExtension->lun = NULL; - KdPrint2((PRINT_PREFIX "!deviceExtension->chan => SP_RETURN_ERROR\n")); - return FALSE; - } - RtlZeroMemory(deviceExtension->chan, sizeof(HW_CHANNEL) * (deviceExtension->NumberChannels+1)); - return TRUE; -} // end UniataAllocateLunExt() - - /*++ Routine Description: @@ -1194,14 +1160,19 @@ } } } + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint2((PRINT_PREFIX " AHCI registers layout\n")); + } else 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; + if(!deviceExtension->BusMaster) { + deviceExtension->BusMaster = DMA_MODE_BM; + } } } else { - deviceExtension->BusMaster = FALSE; + deviceExtension->BusMaster = DMA_MODE_NONE; if(WinVer_WDM_Model && !deviceExtension->UnknownDev) { ULONG i; @@ -1259,7 +1230,7 @@ UniataInitMapBM(deviceExtension, BaseIoAddressBM_0, (*ConfigInfo->AccessRanges)[4].RangeInMemory ? TRUE : FALSE); - deviceExtension->BusMaster = TRUE; + deviceExtension->BusMaster = DMA_MODE_BM; deviceExtension->BaseIoAddressBM_0.Addr = (ULONGIO_PTR)BaseIoAddressBM_0; if((*ConfigInfo->AccessRanges)[4].RangeInMemory) { deviceExtension->BaseIoAddressBM_0.MemIo = TRUE; @@ -1277,8 +1248,9 @@ KdPrint2((PRINT_PREFIX "IsBusMaster == TRUE && !MasterDev\n")); statusByte = AtapiReadPort1(&(deviceExtension->chan[0]), IDX_BM_Status); KdPrint2((PRINT_PREFIX " BM statusByte = %x\n", statusByte)); - if(statusByte == 0xff) { + if(statusByte == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX " invalid port ?\n")); + deviceExtension->BusMaster = DMA_MODE_NONE; /* if(BaseIoAddressBM_0) { ScsiPortFreeDeviceBase(HwDeviceExtension, @@ -1315,7 +1287,7 @@ KdPrint2((PRINT_PREFIX "simplexOnly = %d (2)", simplexOnly)); - //TODO: fix hang with UseDpn=TRUE in Simplex mode + //TODO: fix hang with UseDpc=TRUE in Simplex mode //deviceExtension->UseDpc = TRUE; if(simplexOnly) { KdPrint2((PRINT_PREFIX "simplexOnly => UseDpc = FALSE\n")); @@ -1413,7 +1385,12 @@ KdPrint2((PRINT_PREFIX "update ConfigInfo->nt4\n")); _ConfigInfo->nt4.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); _ConfigInfo->nt4.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION); - _ConfigInfo->nt4.SrbExtensionSize = sizeof(ATA_REQ); + if(deviceExtension->HwFlags & UNIATA_AHCI) { + _ConfigInfo->nt4.SrbExtensionSize = sizeof(ATA_REQ); + } else { + _ConfigInfo->nt4.SrbExtensionSize = FIELD_OFFSET(ATA_REQ, dma_tab) + sizeof(BM_DMA_ENTRY)*ATA_DMA_ENTRIES; + } + KdPrint2((PRINT_PREFIX "using AtaReq sz %x\n", _ConfigInfo->nt4.SrbExtensionSize)); } if((WinVer_Id() > WinVer_2k) || (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4) + sizeof(_ConfigInfo->w2k))) { @@ -1478,10 +1455,6 @@ 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 - KdPrint2((PRINT_PREFIX "BMList[i].channel %#x, NumberChannels %#x, channel %#x\n",BMList[i].channel, deviceExtension->NumberChannels, channel)); for (; channel < (BMList[i].channel + deviceExtension->NumberChannels); channel++, c++) { @@ -1645,7 +1618,9 @@ chan->RegTranslation[IDX_SATA_IO].MemIo ? "mem" : "io")); if(!(deviceExtension->HwFlags & UNIATA_AHCI)) { +#if DBG UniataDumpATARegs(chan); +#endif #ifndef UNIATA_CORE #ifdef UNIATA_INIT_ON_PROBE @@ -1744,6 +1719,11 @@ ScsiPortFreeDeviceBase(HwDeviceExtension, BaseIoAddressBM_0); + if(deviceExtension->BaseIoAHCI_0.Addr) { + ScsiPortFreeDeviceBase(HwDeviceExtension, + deviceExtension->BaseIoAHCI_0.pAddr); + } + KdPrint2((PRINT_PREFIX "return SP_RETURN_NOT_FOUND\n")); goto exit_notfound; } else { @@ -1751,7 +1731,7 @@ KdPrint2((PRINT_PREFIX "exit: init spinlock\n")); //KeInitializeSpinLock(&(deviceExtension->DpcSpinLock)); deviceExtension->ActiveDpcChan = - deviceExtension->FirstDpcChan = -1; + deviceExtension->FirstDpcChan = CHAN_NOT_SPECIFIED; BMList[i].Isr2Enable = FALSE; @@ -1796,13 +1776,11 @@ return SP_RETURN_FOUND; exit_error: - if (deviceExtension->lun) ExFreePool(deviceExtension->lun); - if (deviceExtension->chan) ExFreePool(deviceExtension->chan); + UniataFreeLunExt(deviceExtension); return SP_RETURN_ERROR; exit_notfound: - ExFreePool(deviceExtension->lun); - ExFreePool(deviceExtension->chan); + UniataFreeLunExt(deviceExtension); return SP_RETURN_NOT_FOUND; } // end UniataFindBusMasterController() @@ -2056,7 +2034,7 @@ UniataInitMapBM(deviceExtension, BaseIoAddressBM_0, (*ConfigInfo->AccessRanges)[4].RangeInMemory ? TRUE : FALSE); - deviceExtension->BusMaster = TRUE; + deviceExtension->BusMaster = DMA_MODE_BM; deviceExtension->BaseIoAddressBM_0.Addr = (ULONGIO_PTR)BaseIoAddressBM_0; if((*ConfigInfo->AccessRanges)[4].RangeInMemory) { deviceExtension->BaseIoAddressBM_0.MemIo = TRUE; @@ -2129,13 +2107,11 @@ return SP_RETURN_FOUND; exit_error: - if (deviceExtension->lun) ExFreePool(deviceExtension->lun); - if (deviceExtension->chan) ExFreePool(deviceExtension->chan); + UniataFreeLunExt(deviceExtension); return SP_RETURN_ERROR; exit_notfound: - ExFreePool(deviceExtension->lun); - ExFreePool(deviceExtension->chan); + UniataFreeLunExt(deviceExtension); return SP_RETURN_NOT_FOUND; } // end UniataFindFakeBusMasterController() @@ -2184,6 +2160,13 @@ TRUE) { // Ok, continue... KdPrint2((PRINT_PREFIX "Multichannel native mode, go...\n")); +#ifndef UNIATA_USE_XXableInterrupts + // If we raise IRQL to TIMER value, other interrupt cannot occure on the same CPU + if(KeNumberProcessors < 2) { + KdPrint2((PRINT_PREFIX "Unnecessary (?), UP machine\n")); + //return STATUS_SUCCESS; + } +#endif //UNIATA_USE_XXableInterrupts } else { KdPrint2((PRINT_PREFIX "Unnecessary\n")); return STATUS_SUCCESS; @@ -2500,6 +2483,42 @@ UniataInitMapBase(chan, BaseIoAddress1, BaseIoAddress2); UniataInitMapBM(deviceExtension, 0, FALSE); +#if DBG + UniataDumpATARegs(chan); +#endif + + // Select master. + SelectDrive(chan, 0); + + statusByte = AtapiReadPort1(chan, IDX_IO1_i_Status); + + if(statusByte != AtapiReadPort1(chan, IDX_IO2_AltStatus)) { + KdPrint2((PRINT_PREFIX "AtapiFindController: Status vs AlsStatus missmatch, abort init ?\n")); + + if(BaseIoAddress2) { + ScsiPortFreeDeviceBase(HwDeviceExtension, + (PCHAR)BaseIoAddress2); + BaseIoAddress2 = NULL; + } + BaseIoAddress2 = (PIDE_REGISTERS_2)((ULONGIO_PTR)BaseIoAddress1 + 0x0E); + ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension, + ConfigInfo->AdapterInterfaceType, + ConfigInfo->SystemIoBusNumber, + ScsiPortConvertUlongToPhysicalAddress((ULONGIO_PTR)BaseIoAddress2), + ATA_ALTIOSIZE, + TRUE); + if(!ioSpace) { + BaseIoAddress2 = NULL; + KdPrint2((PRINT_PREFIX " abort (0)\n")); + goto not_found; + } + UniataInitMapBase(chan, BaseIoAddress1, BaseIoAddress2); + if(statusByte != AtapiReadPort1(chan, IDX_IO2_AltStatus)) { + KdPrint2((PRINT_PREFIX " abort\n")); + goto not_found; + } + } + retryIdentifier: // Select master. @@ -2507,16 +2526,18 @@ // Check if card at this address. AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, 0xAA); + statusByte = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); // Check if indentifier can be read back. - if ((statusByte = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)) != 0xAA) { + if (AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) != 0xAA || + statusByte == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "AtapiFindController: Identifier read back from Master (%#x)\n", statusByte)); statusByte = AtapiReadPort1(chan, IDX_IO2_AltStatus); - if (statusByte & IDE_STATUS_BUSY) { + if (statusByte != IDE_STATUS_WRONG && (statusByte & IDE_STATUS_BUSY)) { i = 0; @@ -2537,11 +2558,13 @@ // Select slave. SelectDrive(chan, 1); + statusByte = AtapiReadPort1(chan, IDX_IO2_AltStatus); // See if slave is present. AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, 0xAA); - if ((statusByte = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)) != 0xAA) { + if (AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) != 0xAA || + statusByte == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "AtapiFindController: Identifier read back from Slave (%#x)\n", @@ -2578,6 +2601,12 @@ (*ConfigInfo->AccessRanges)[0].RangeLength = 8; (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; + if(BaseIoAddress2) { + (*ConfigInfo->AccessRanges)[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress((ULONG)BaseIoAddress2); + (*ConfigInfo->AccessRanges)[1].RangeLength = 2; + (*ConfigInfo->AccessRanges)[1].RangeInMemory = FALSE; + } + // Indicate the interrupt level corresponding to this IO range. if (irq) { ConfigInfo->BusInterruptLevel = irq; @@ -2604,10 +2633,13 @@ KdPrint2((PRINT_PREFIX "chan = %#x\n", chan)); //PrintNtConsole("chan = %#x, c=%#x\n", chan, c); +/* + // should be already set up in AtapiSetupLunPtrs(chan, deviceExtension, 0); + chan->DeviceExtension = deviceExtension; chan->lChannel = 0; chan->lun[0] = &(deviceExtension->lun[0]); - chan->lun[1] = &(deviceExtension->lun[1]); + chan->lun[1] = &(deviceExtension->lun[1]);*/ /* do extra channel-specific setups */ AtapiReadChipConfig(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, 0); @@ -2661,6 +2693,8 @@ // Save the Interrupe Mode for later use deviceExtension->InterruptMode = ConfigInfo->InterruptMode; + deviceExtension->BusInterruptLevel = ConfigInfo->BusInterruptLevel; + deviceExtension->BusInterruptVector = ConfigInfo->BusInterruptVector; KdPrint2((PRINT_PREFIX "AtapiFindController: look for devices\n")); @@ -2702,6 +2736,7 @@ MCACount++; } + ConfigInfo->NumberOfBuses++; // add virtual channel for communication port KdPrint2((PRINT_PREFIX "AtapiFindController: return SP_RETURN_FOUND\n")); return(SP_RETURN_FOUND); @@ -2720,18 +2755,16 @@ KdPrint2((PRINT_PREFIX "AtapiFindController: return SP_RETURN_NOT_FOUND\n")); - ExFreePool(deviceExtension->lun); - ExFreePool(deviceExtension->chan); + UniataFreeLunExt(deviceExtension); return(SP_RETURN_NOT_FOUND); exit_error: - if (deviceExtension->lun) ExFreePool(deviceExtension->lun); - if (deviceExtension->chan) ExFreePool(deviceExtension->chan); + UniataFreeLunExt(deviceExtension); return SP_RETURN_ERROR; } // end AtapiFindController() -BOOLEAN +ULONG NTAPI UniataAnybodyHome( IN PVOID HwDeviceExtension, @@ -2747,64 +2780,98 @@ SATA_SSTATUS_REG SStatus; UCHAR signatureLow; UCHAR signatureHigh; - + if(LunExt->DeviceFlags & DFLAGS_HIDDEN) { KdPrint2((PRINT_PREFIX " hidden\n")); UniataForgetDevice(LunExt); - return FALSE; + return ATA_AT_HOME_NOBODY; } - // Select the device. - SelectDrive(chan, deviceNumber); + if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) { - signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow); - signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh); + SStatus.Reg = UniataSataReadPort4(chan, IDX_SATA_SStatus, deviceNumber); + 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 ATA_AT_HOME_NOBODY; + } + if(SStatus.SPD < SStatus_SPD_Gen1) { + KdPrint2((PRINT_PREFIX " SATA SPD < SStatus_SPD_Gen1\n")); + return ATA_AT_HOME_NOBODY; + } + if(SStatus.IPM == SStatus_IPM_NoDev) { + KdPrint2((PRINT_PREFIX " SATA IPN == SStatus_IPM_NoDev\n")); + return ATA_AT_HOME_NOBODY; + } + if(!(deviceExtension->HwFlags & UNIATA_AHCI)) { + // Select the device for legacy. + goto legacy_select; + } + } else { +legacy_select: + // Select the device. + SelectDrive(chan, deviceNumber); + AtapiStallExecution(5); + } + + if((deviceExtension->HwFlags & UNIATA_AHCI) && + UniataIsSATARangeAvailable(deviceExtension, lChannel)) { + KdPrint2((PRINT_PREFIX " AHCI check\n")); + ULONG SIG = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_SIG); + signatureLow = (UCHAR)(SIG >> 16); + signatureHigh = (UCHAR)(SIG >> 24); + } else { + 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 " ATAPI at home\n", signatureLow)); - return TRUE; + KdPrint2((PRINT_PREFIX " ATAPI at home\n")); + return ATA_AT_HOME_ATAPI; } + if(deviceExtension->HwFlags & UNIATA_AHCI) { + KdPrint2((PRINT_PREFIX " AHCI HDD at home\n")); + return ATA_AT_HOME_HDD; + } - if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) { - AtapiStallExecution(10); + AtapiStallExecution(10); - AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0x55); - AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0x55); - AtapiStallExecution(5); - signatureLow = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber); - if(signatureLow != 0x55) { + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0x55); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0x55); + AtapiStallExecution(5); + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber); + if(signatureLow != 0x55) { + if(signatureLow == 0xff || signatureLow == 0) { KdPrint2((PRINT_PREFIX " nobody home! %#x != 0x55\n", signatureLow)); UniataForgetDevice(LunExt); - return FALSE; + return ATA_AT_HOME_NOBODY; } - - AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0xAA); - AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0xAA); + // another chance + signatureLow = AtapiReadPort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh); + signatureLow += 2; + AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh, signatureLow); AtapiStallExecution(5); - signatureLow = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber); - if(signatureLow != 0xAA) { - KdPrint2((PRINT_PREFIX " nobody home! %#x != 0xAA\n", signatureLow)); + signatureHigh = AtapiReadPort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh); + if(signatureLow != signatureHigh) { + KdPrint2((PRINT_PREFIX " nobody home! last chance failed %#x != %#x\n", signatureLow, signatureHigh)); UniataForgetDevice(LunExt); - return FALSE; + return ATA_AT_HOME_NOBODY; } - } else { + return ATA_AT_HOME_XXX; + } - SStatus.Reg = UniataSataReadPort4(chan, IDX_SATA_SStatus, deviceNumber); - 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; - } + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0xAA); + AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, 0xAA); + AtapiStallExecution(5); + signatureLow = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber); + if(signatureLow != 0xAA) { + KdPrint2((PRINT_PREFIX " nobody home! %#x != 0xAA\n", signatureLow)); + UniataForgetDevice(LunExt); + return ATA_AT_HOME_NOBODY; } - return TRUE; + KdPrint2((PRINT_PREFIX " HDD at home\n")); + return ATA_AT_HOME_HDD; } // end UniataAnybodyHome() ULONG @@ -2830,10 +2897,14 @@ KdPrint2((PRINT_PREFIX "CheckDevice: Device %#x\n", deviceNumber)); - if(deviceNumber > chan->NumberLuns) { + if(deviceNumber >= chan->NumberLuns) { return 0; } - + if(deviceExtension->HwFlags & UNIATA_AHCI) { + if(!UniataAnybodyHome(HwDeviceExtension, lChannel, deviceNumber)) { + return 0; + } + } LunExt = chan->lun[deviceNumber]; if(ResetDev && (deviceExtension->HwFlags & UNIATA_AHCI)) { @@ -2856,11 +2927,11 @@ } statusByte = WaitOnBusy(chan); - if((statusByte | IDE_STATUS_BUSY) == 0xff) { + if((statusByte | IDE_STATUS_BUSY) == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "CheckDevice: bad status %x\n", statusByte)); } else - if(statusByte != 0xff && (statusByte & IDE_STATUS_BUSY)) { + if(statusByte != IDE_STATUS_WRONG && (statusByte & IDE_STATUS_BUSY)) { // Perform hard-reset. KdPrint2((PRINT_PREFIX "CheckDevice: BUSY\n")); @@ -2882,16 +2953,18 @@ "CheckDevice: status after hard reset %x\n", statusByte)); } - if((statusByte | IDE_STATUS_BUSY) == 0xff) { + if((statusByte | IDE_STATUS_BUSY) == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "CheckDevice: no dev ?\n")); + UniataForgetDevice(LunExt); + return 0; } else if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) { //if(deviceExtension->HwFlags & UNIATA_SATA) { KdPrint2((PRINT_PREFIX "CheckDevice: try enable SATA Phy\n")); statusByte = UniataSataPhyEnable(HwDeviceExtension, lChannel, deviceNumber); - if(statusByte == 0xff) { + if(statusByte == IDE_STATUS_WRONG) { KdPrint2((PRINT_PREFIX "CheckDevice: status %#x (no dev)\n", statusByte)); UniataForgetDevice(LunExt); return 0; @@ -2919,7 +2992,7 @@ } KdPrint2((PRINT_PREFIX "CheckDevice: status %#x\n", statusByte)); - if(((statusByte | IDE_STATUS_BUSY) == 0xff) || + if(((statusByte | IDE_STATUS_BUSY) == IDE_STATUS_WRONG) || (statusByte & IDE_STATUS_BUSY)) { KdPrint2((PRINT_PREFIX "CheckDevice: busy => return\n")); UniataForgetDevice(LunExt); @@ -2934,6 +3007,7 @@ LunExt->RwSwitchCost = REORDER_COST_SWITCH_RW_HDD; LunExt->RwSwitchMCost = REORDER_MCOST_SWITCH_RW_HDD; LunExt->SeekBackMCost = REORDER_MCOST_SEEK_BACK_HDD; + LunExt->AtapiReadyWaitDelay = 0; if(deviceExtension->HwFlags & UNIATA_AHCI) { if(RetVal & DFLAGS_DEVICE_PRESENT) { @@ -2946,8 +3020,11 @@ KdPrint2((PRINT_PREFIX "CheckDevice: detected AHCI Device %#x\n", deviceNumber)); } else { - RetVal &= ~DFLAGS_ATAPI_DEVICE; - LunExt->DeviceFlags &= ~DFLAGS_ATAPI_DEVICE; + //RetVal &= ~DFLAGS_ATAPI_DEVICE; + //LunExt->DeviceFlags &= ~DFLAGS_ATAPI_DEVICE; + + UniataForgetDevice(LunExt); + RetVal = 0; } } } else @@ -3074,7 +3151,7 @@ // 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; + UniataExpectChannelInterrupt(chan, FALSE); // chan->CurrentSrb = NULL; // max_ldev = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : IDE_MAX_LUN_PER_CHAN; max_ldev = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : deviceExtension->NumberLuns; Index: drivers/storage/ide/uniata/id_queue.cpp =================================================================== --- drivers/storage/ide/uniata/id_queue.cpp (revision 57016) +++ drivers/storage/ide/uniata/id_queue.cpp (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2008-2010 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2008-2012 Alexandr A. Telyatnikov (Alter) Module Name: id_probe.cpp @@ -306,11 +306,13 @@ 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; + if(chan->NumberLuns > 1) { + 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 && @@ -320,10 +322,12 @@ // 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++; + if(chan->NumberLuns > 1) { + if(!chan->lun[cdev ^ 1]->queue_depth) { + chan->lun[cdev ^ 1]->LunSelectWaitCount=0; + } else { + chan->lun[cdev ^ 1]->LunSelectWaitCount++; + } } chan->lun[cdev]->LunSelectWaitCount=0; Index: drivers/storage/ide/uniata/id_sata.cpp =================================================================== --- drivers/storage/ide/uniata/id_sata.cpp (revision 57016) +++ drivers/storage/ide/uniata/id_sata.cpp (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2008-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2008-2012 Alexandr A. Telyatnikov (Alter) Module Name: id_probe.cpp @@ -76,7 +76,7 @@ } if(i >= 100) { KdPrint2((PRINT_PREFIX "UniataSataConnect: SStatus %8.8x\n", SStatus.Reg)); - return 0xff; + return IDE_STATUS_WRONG; } /* clear SATA error register */ UniataSataWritePort4(chan, IDX_SATA_SError, @@ -156,7 +156,7 @@ } KdPrint2((PRINT_PREFIX "UniataSataPhyEnable: failed\n")); - return 0xff; + return IDE_STATUS_WRONG; } // end UniataSataPhyEnable() BOOLEAN @@ -200,6 +200,7 @@ return TRUE; } } + //return TRUE; } } return FALSE; @@ -408,7 +409,7 @@ if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) { return UniataAhciWritePM(chan, DeviceNumber, Reg, value); } - return 0xff; + return IDE_STATUS_WRONG; } // end UniataSataWritePM() ULONG @@ -628,6 +629,10 @@ GHC | AHCI_GHC_AE); GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC); KdPrint2((PRINT_PREFIX " AHCI GHC %#x\n", GHC)); + if(!(GHC & AHCI_GHC_AE)) { + KdPrint2((PRINT_PREFIX " Can't enable AHCI mode\n")); + return FALSE; + } deviceExtension->AHCI_CAP = CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP); @@ -718,7 +723,9 @@ ULONG i, n; ULONG PI; ULONG CAP; + ULONG CAP2; ULONG GHC; + ULONG BOHC; ULONG NumberChannels; ULONG v_Mn, v_Mj; ULONG BaseMemAddress; @@ -726,7 +733,7 @@ KdPrint2((PRINT_PREFIX " UniataAhciDetect:\n")); - if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhci", 1 /* DEBUG */)) { + if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhci", 0)) { KdPrint((" AHCI excluded\n")); return FALSE; } @@ -762,11 +769,16 @@ } CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP); - KdPrint2((PRINT_PREFIX " AHCI CAP %#x\n", CAP)); + CAP2 = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP2); + KdPrint2((PRINT_PREFIX " AHCI CAP %#x, CAP2 %#x\n", CAP, CAP2)); if(CAP & AHCI_CAP_S64A) { KdPrint2((PRINT_PREFIX " AHCI 64bit\n")); //deviceExtension->Host64 = TRUE; } + if(CAP2 & AHCI_CAP2_BOH) { + BOHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_BOHC); + KdPrint2((PRINT_PREFIX " AHCI BOHC %#x\n", BOHC)); + } /* get the number of HW channels */ PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI); @@ -807,7 +819,7 @@ KdPrint2((PRINT_PREFIX " PM supported\n")); if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreAhciPM", 1 /* DEBUG */)) { KdPrint2((PRINT_PREFIX "SATA/AHCI w/o PM, max luns 1\n")); - deviceExtension->NumberLuns = 2; + deviceExtension->NumberLuns = 1; //chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE; } else { KdPrint2((PRINT_PREFIX "SATA/AHCI -> possible PM, max luns %d\n", SATA_MAX_PM_UNITS)); @@ -819,7 +831,14 @@ deviceExtension->NumberLuns = 1; } - if((v_Mj != 0x01) || (v_Mn > 0x20)) { + switch(version) { + case 0x00000905: + case 0x00010000: + case 0x00010100: + case 0x00010200: + case 0x00010300: + break; + default: KdPrint2((PRINT_PREFIX " Unknown AHCI revision\n")); if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"CheckAhciRevision", 1)) { KdPrint((" AHCI revision excluded\n")); @@ -827,12 +846,16 @@ } } - deviceExtension->HwFlags |= UNIATA_SATA; - deviceExtension->HwFlags |= UNIATA_AHCI; + deviceExtension->HwFlags |= UNIATA_SATA | UNIATA_AHCI; if(deviceExtension->NumberChannels < NumberChannels) { deviceExtension->NumberChannels = NumberChannels; } + deviceExtension->DmaSegmentLength = 0x3fffff+1; // 4MB + deviceExtension->DmaSegmentAlignmentMask = -1; // no restrictions + deviceExtension->BusMaster = DMA_MODE_AHCI; + deviceExtension->MaxTransferMode = max(deviceExtension->MaxTransferMode, ATA_SA150); + return TRUE; } // end UniataAhciDetect() @@ -855,7 +878,7 @@ //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS); ULONG tag=0; - KdPrint(("UniataAhciStatus:\n")); + KdPrint(("UniataAhciStatus(%d-%d):\n", lChannel, Channel)); hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS); KdPrint((" hIS %#x\n", hIS)); @@ -873,7 +896,7 @@ UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS.Reg); AtapiWritePort4(chan, IDX_SATA_SError, SError.Reg); - KdPrint((" AHCI: status=%08x sstatus=%08x error=%08x CI=%08x\n", + KdPrint((" AHCI: istatus=%08x sstatus=%08x serror=%08x CI=%08x\n", IS.Reg, SStatus.Reg, SError.Reg, CI)); /* do we have cold connect surprise */ @@ -887,11 +910,35 @@ if(IS.PRCS) { UniataSataEvent(HwDeviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH); } + chan->AhciCompleteCI = (chan->AhciPrevCI ^ CI) & chan->AhciPrevCI; // only 1->0 states + chan->AhciPrevCI = CI; + KdPrint((" AHCI: complete mask %#x\n", chan->AhciCompleteCI)); + chan->AhciLastIS = IS.Reg; if(CI & (1 << tag)) { - return INTERRUPT_REASON_OUR; +#ifdef DBG + UniataDumpAhciPortRegs(chan); +#endif //DBG + //deviceExtension->ExpectingInterrupt++; // will be updated in ISR on ReturnEnableInterrupts + if(IS.Reg & + (ATA_AHCI_P_IX_OF | ATA_AHCI_P_IX_INF | ATA_AHCI_P_IX_IF | + ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_HBF | ATA_AHCI_P_IX_TFE)) { + KdPrint((" AHCI: unexpected, error\n")); + } else { + KdPrint((" AHCI: unexpected, incomplete command or error ?\n")); +/* + ULONG TFD; + + TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); + KdPrint2((" TFD %#x\n", TFD)); + if(TFD & IDE_STATUS_BUSY) { + KdPrint2((" Seems to be interrupt on error\n")); + return INTERRUPT_REASON_OUR; + } +*/ + return INTERRUPT_REASON_UNEXPECTED; + } } - KdPrint((" AHCI: unexpected\n")); - return INTERRUPT_REASON_UNEXPECTED; + return INTERRUPT_REASON_OUR; } // end UniataAhciStatus() @@ -905,35 +952,42 @@ IN UCHAR command, IN ULONGLONG lba, IN USHORT count, - IN USHORT feature, - IN ULONG flags + IN USHORT feature ) { - ULONG i; + //ULONG i; PUCHAR plba; BOOLEAN need48; PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; - KdPrint2((PRINT_PREFIX " AHCI setup FIS ch %d, dev %d\n", lChannel, DeviceNumber)); - i = 0; + KdPrint2((PRINT_PREFIX " AHCI setup FIS %x, ch %d, dev %d\n", fis, lChannel, DeviceNumber)); + //i = 0; plba = (PUCHAR)&lba; + RtlZeroMemory(fis, 20); + fis[0] = AHCI_FIS_TYPE_ATA_H2D; /* host to device */ fis[1] = 0x80 | ((UCHAR)DeviceNumber & 0x0f); /* command FIS (note PM goes here) */ - fis[7] = IDE_USE_LBA; - fis[15] = IDE_DC_A_4BIT; + fis[IDX_AHCI_o_DriveSelect] = IDE_DRIVE_SELECT_1 | + ((AtaCommandFlags[command] & (ATA_CMD_FLAG_LBAIOsupp | ATA_CMD_FLAG_48)) ? IDE_USE_LBA : 0); + fis[IDX_AHCI_o_Control] = IDE_DC_A_4BIT; - if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE) { - fis[2] = IDE_COMMAND_ATAPI_PACKET; + // IDE_COMMAND_ATAPI_IDENTIFY should be processed as regular ATA command, + // the rest of ATAPI requests are processed via IDE_COMMAND_ATAPI_PACKET + if(/*(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE) && + */ + command == IDE_COMMAND_ATAPI_PACKET) { + fis[IDX_AHCI_o_Command] = IDE_COMMAND_ATAPI_PACKET; if(feature & ATA_F_DMA) { - fis[3] = (UCHAR)(feature & 0xff); + fis[IDX_AHCI_o_Feature] = (UCHAR)(feature & 0xff); } else { - fis[5] = (UCHAR)(count & 0xff); - fis[6] = (UCHAR)(count>>8) & 0xff; + fis[IDX_AHCI_o_CylinderLow] = (UCHAR)(count & 0xff); + fis[IDX_AHCI_o_CylinderHigh] = (UCHAR)(count>>8) & 0xff; } + //fis[IDX_AHCI_o_Control] |= IDE_DC_A_4BIT; } else { - if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) && + if(((AtaCommandFlags[command] & (ATA_CMD_FLAG_LBAIOsupp|ATA_CMD_FLAG_FUA)) == ATA_CMD_FLAG_LBAIOsupp) && CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) { KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count)); //return IDE_STATUS_ERROR; @@ -954,32 +1008,40 @@ } } - fis[2] = command; - fis[3] = (UCHAR)feature; + fis[IDX_AHCI_o_Command] = command; + fis[IDX_AHCI_o_Feature] = (UCHAR)feature; - fis[4] = plba[0]; - fis[5] = plba[1]; - fis[6] = plba[2]; + fis[IDX_AHCI_o_BlockNumber] = plba[0]; + fis[IDX_AHCI_o_CylinderLow] = plba[1]; + fis[IDX_AHCI_o_CylinderHigh] = plba[2]; + + fis[IDX_AHCI_o_BlockCount] = (UCHAR)count & 0xff; + if(need48) { - i++; + //i++; + fis[IDX_AHCI_o_Control] |= IDE_DC_USE_HOB; + + fis[IDX_AHCI_o_BlockNumberExp] = plba[3]; + fis[IDX_AHCI_o_CylinderLowExp] = plba[4]; + fis[IDX_AHCI_o_CylinderHighExp] = plba[5]; + + fis[IDX_AHCI_o_BlockCountExp] = (UCHAR)(count>>8) & 0xff; + + fis[IDX_AHCI_o_FeatureExp] = (UCHAR)(feature>>8) & 0xff; + + chan->ChannelCtrlFlags |= CTRFLAGS_LBA48; } else { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4333) // right shift by too large amount, data loss -#endif - fis[7] |= IDE_DRIVE_1 | ((plba[3] >> 24) & 0x0f); -#ifdef _MSC_VER -#pragma warning(pop) -#endif +//#ifdef _MSC_VER +//#pragma warning(push) +//#pragma warning(disable:4333) // right shift by too large amount, data loss +//#endif + fis[IDX_AHCI_o_DriveSelect] |= /*IDE_DRIVE_1 |*/ (plba[3] & 0x0f); + chan->ChannelCtrlFlags &= ~CTRFLAGS_LBA48; +//#ifdef _MSC_VER +//#pragma warning(pop) +//#endif } - fis[8] = plba[3]; - fis[9] = plba[4]; - fis[10] = plba[5]; - fis[11] = (UCHAR)(feature>>8) & 0xff; - - fis[12] = (UCHAR)count & 0xff; - fis[13] = (UCHAR)(count>>8) & 0xff; //fis[14] = 0x00; } @@ -991,11 +1053,71 @@ UCHAR NTAPI +UniataAhciWaitCommandReady( + IN PHW_CHANNEL chan, + IN ULONG timeout + ) +{ + AHCI_IS_REG IS; + ULONG CI=0; + ULONG i; + ULONG SError; + ULONG tag=0; + + timeout *= 5; + + for (i=0; i> tag) & 0x01)) { + break; + } + IS.Reg = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS); + //KdPrint((" IS %#x\n", IS.Reg)); + if(IS.Reg) { + break; + } + SError = AtapiReadPort4(chan, IDX_SATA_SError); + if(SError) { + KdPrint((" AHCI: error %#x\n", SError)); + i = timeout; + break; + } + AtapiStallExecution(200); + } + KdPrint((" CI %#x\n", CI)); + + //SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus); + //SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError); + + /* clear interrupt(s) */ + IS.Reg = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS); + KdPrint((" IS %#x\n", IS.Reg)); + UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS.Reg); + + if (timeout && (i >= timeout)) { +#ifdef DBG + ULONG TFD; + + SError = AtapiReadPort4(chan, IDX_SATA_SError); + KdPrint((" AHCI: timeout, SError %#x\n", SError)); + + TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); + KdPrint2((" TFD %#x\n", TFD)); +#endif //DBG + + return IDE_STATUS_WRONG; + } + + return IDE_STATUS_IDLE; +} // end UniataAhciWaitCommandReady() + +UCHAR +NTAPI UniataAhciSendCommand( IN PVOID HwDeviceExtension, IN ULONG lChannel, IN ULONG DeviceNumber, - IN ULONG flags, + IN USHORT ahci_flags, IN ULONG timeout ) { @@ -1003,63 +1125,150 @@ PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; //ULONG Channel = deviceExtension->Channel + lChannel; //ULONG hIS; - ULONG CI = 0; - AHCI_IS_REG IS; - ULONG SError; + //ULONG SError; //SATA_SSTATUS_REG SStatus; //SATA_SERROR_REG SError; //ULONG offs = sizeof(IDE_AHCI_REGISTERS) + Channel*sizeof(IDE_AHCI_PORT_REGISTERS); //ULONGIO_PTR base; ULONG tag=0; - ULONG i; PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]); KdPrint(("UniataAhciSendCommand: lChan %d\n", chan->lChannel)); AHCI_CL->prd_length = 0; - AHCI_CL->cmd_flags = (20 / sizeof(ULONG)) | flags | (DeviceNumber << 12); + //AHCI_CL->cmd_flags = (20 / sizeof(ULONG)) | ahci_flags | (DeviceNumber << 12); + AHCI_CL->cmd_flags = UniAtaAhciAdjustIoFlags(0, ahci_flags, 20, DeviceNumber); + AHCI_CL->bytecount = 0; AHCI_CL->cmd_table_phys = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, cmd); if(AHCI_CL->cmd_table_phys & AHCI_CMD_ALIGNEMENT_MASK) { KdPrint2((PRINT_PREFIX " AHCI CMD address is not aligned (mask %#x)\n", (ULONG)AHCI_CMD_ALIGNEMENT_MASK)); } - UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, ATA_AHCI_P_CMD_ST); + UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, 1 << tag); - for (i=0; ichan[lChannel]; + UCHAR statusByte; + PATA_REQ AtaReq; + ULONG fis_size; + ULONG tag=0; + //PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd); + PIDE_AHCI_CMD AHCI_CMD = NULL; + + PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]); + + KdPrint2((PRINT_PREFIX "UniataAhciSendPIOCommand: cntrlr %#x:%#x dev %#x, cmd %#x, lba %#I64x bcount %#x feature %#x, buff %#x, len %#x, WF %#x \n", + deviceExtension->DevIndex, lChannel, DeviceNumber, command, lba, bcount, feature, data, length, wait_flags )); + + if(length/DEV_BSIZE != bcount) { + KdPrint((" length/DEV_BSIZE != bcount\n")); + } + +#ifdef DBG + //UniataDumpAhciPortRegs(chan); +#endif // DBG + + if(!Srb) { + Srb = BuildAhciInternalSrb(HwDeviceExtension, DeviceNumber, lChannel, data, length); + if(!Srb) { + KdPrint((" !Srb\n")); + return IDE_STATUS_WRONG; } + //UniataAhciSetupCmdPtr(AtaReq); // must be called before DMA setup + //should be already called on init } - KdPrint((" CI %#x\n", CI)); + AtaReq = (PATA_REQ)(Srb->SrbExtension); + //KdPrint((" Srb %#x, AtaReq %#x\n", Srb, AtaReq)); - //SStatus.Reg = AtapiReadPort4(chan, IDX_SATA_SStatus); - //SError.Reg = AtapiReadPort4(chan, IDX_SATA_SError); + AHCI_CMD = AtaReq->ahci.ahci_cmd_ptr; - /* clear interrupt(s) */ - IS.Reg = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_IS); - KdPrint((" IS %#x\n", IS.Reg)); - UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IS, IS.Reg); + fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel, + &(AHCI_CMD->cfis[0]), + command, + lba, + bcount, + feature + ); - if (timeout && (i >= timeout)) { - ULONG TFD; + if(!fis_size) { + KdPrint2(("!fis_size\n")); + return IDE_STATUS_WRONG; + } - SError = AtapiReadPort4(chan, IDX_SATA_SError); - KdPrint((" AHCI: timeout, SError %#x\n", SError)); + //KdPrint2(("UniAtaAhciAdjustIoFlags(command, ahci_flags, fis_size, DeviceNumber)\n")); + ahci_flags = UniAtaAhciAdjustIoFlags(command, ahci_flags, fis_size, DeviceNumber); + KdPrint2(("ahci_flags %#x\n", ahci_flags)); - TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); - KdPrint2((" TFD %#x\n", TFD)); - - return 0xff; + if(data) { + if(ahci_flags & ATA_AHCI_CMD_WRITE) { + AtaReq->Flags &= ~REQ_FLAG_READ; + Srb->SrbFlags |= SRB_FLAGS_DATA_OUT; + KdPrint((" assume OUT\n")); + } else { + AtaReq->Flags |= REQ_FLAG_READ; + Srb->SrbFlags |= SRB_FLAGS_DATA_IN; + KdPrint((" assume IN\n")); + } + if(!AtapiDmaSetup(HwDeviceExtension, + DeviceNumber, + lChannel, // logical channel, + Srb, + data, + length)) { + KdPrint2((" can't setup buffer\n")); + return IDE_STATUS_WRONG; + } } - return IDE_STATUS_IDLE; + AtaReq->ahci.io_cmd_flags = ahci_flags; -} // end UniataAhciSendCommand() +#ifdef DBG + //UniataDumpAhciPortRegs(chan); +#endif // DBG + UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb); + +#ifdef DBG + //UniataDumpAhciPortRegs(chan); +#endif // DBG + + if(wait_flags == ATA_IMMEDIATE) { + statusByte = 0; + KdPrint2((" return imemdiately\n")); + } else { + statusByte = UniataAhciWaitCommandReady(chan, timeout); + UniataAhciStatus(HwDeviceExtension, lChannel, DeviceNumber); + UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb); + } + + return statusByte; + +} // end UniataAhciSendPIOCommand() + ULONG NTAPI UniataAhciSoftReset( @@ -1082,7 +1291,7 @@ PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]); #ifdef DBG - UniataDumpAhciPortRegs(chan); +// UniataDumpAhciPortRegs(chan); #endif // DBG /* kick controller into sane state */ @@ -1091,7 +1300,7 @@ UniataAhciStart(chan); #ifdef DBG - UniataDumpAhciPortRegs(chan); +// UniataDumpAhciPortRegs(chan); #endif // DBG /* pull reset active */ @@ -1101,7 +1310,7 @@ //AHCI_CMD->cfis[7] = IDE_USE_LBA | IDE_DRIVE_SELECT; AHCI_CMD->cfis[15] = (IDE_DC_A_4BIT | IDE_DC_RESET_CONTROLLER); - if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY, 100) == 0xff) { + if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY, 100) == IDE_STATUS_WRONG) { KdPrint2((" timeout\n")); return (ULONG)(-1); } @@ -1113,7 +1322,7 @@ AHCI_CMD->cfis[1] = (UCHAR)DeviceNumber & 0x0f; //AHCI_CMD->cfis[7] = IDE_USE_LBA | IDE_DRIVE_SELECT; AHCI_CMD->cfis[15] = (IDE_DC_A_4BIT); - if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) { + if(UniataAhciSendCommand(HwDeviceExtension, lChannel, DeviceNumber, 0, 3000) == IDE_STATUS_WRONG) { KdPrint2((" timeout (2)\n")); return (ULONG)(-1); } @@ -1172,9 +1381,9 @@ (*signature) = 0xffffffff; UniataAhciStop(chan); - if(UniataSataPhyEnable(HwDeviceExtension, lChannel, 0/* dev0*/, UNIATA_SATA_RESET_ENABLE) == 0xff) { + if(UniataSataPhyEnable(HwDeviceExtension, lChannel, 0/* dev0*/, UNIATA_SATA_RESET_ENABLE) == IDE_STATUS_WRONG) { KdPrint((" no PHY\n")); - return 0xff; + return IDE_STATUS_WRONG; } /* Wait for clearing busy status. */ @@ -1467,31 +1676,60 @@ PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]); - KdPrint2(("UniataAhciBeginTransaction: lChan %d\n", chan->lChannel)); + KdPrint2(("UniataAhciBeginTransaction: lChan %d, AtaReq %#x\n", chan->lChannel, AtaReq)); - if(AtaReq->dma_entries > (USHORT)0xffff) { - KdPrint2(("UniataAhciBeginTransaction too long DMA tab\n")); + if(Srb->DataTransferLength && (!AtaReq->dma_entries || AtaReq->dma_entries >= (USHORT)0xffff)) { + KdPrint2(("UniataAhciBeginTransaction wrong DMA tab len %x\n", AtaReq->dma_entries)); return 0; } - AHCI_CL->prd_length = (USHORT)AtaReq->dma_entries; + AHCI_CL->prd_length = (USHORT)(AtaReq->dma_entries); AHCI_CL->cmd_flags = AtaReq->ahci.io_cmd_flags; AHCI_CL->bytecount = 0; - AHCI_CL->cmd_table_phys = AtaReq->ahci.ahci_base64; + if(AtaReq->ahci.ahci_base64) { + KdPrint2((PRINT_PREFIX " AHCI AtaReq CMD %#x (ph %#x)\n", AtaReq->ahci.ahci_cmd_ptr, (ULONG)(AtaReq->ahci.ahci_base64))); + AHCI_CL->cmd_table_phys = AtaReq->ahci.ahci_base64; + } else + if(AtaReq->ahci.ahci_cmd_ptr) { + KdPrint2((PRINT_PREFIX " AHCI AtaReq->Chan CMD %#x (ph %#x) -> %#x (ph %#x)\n", + AtaReq->ahci.ahci_cmd_ptr, (ULONG)(AtaReq->ahci.ahci_base64), + &(chan->AhciCtlBlock->cmd), chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, cmd) )); + RtlCopyMemory(&(chan->AhciCtlBlock->cmd), AtaReq->ahci.ahci_cmd_ptr, + FIELD_OFFSET(IDE_AHCI_CMD, prd_tab)+AHCI_CL->prd_length*sizeof(IDE_AHCI_PRD_ENTRY)); + AHCI_CL->cmd_table_phys = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, cmd); + } else { + KdPrint2((PRINT_PREFIX " no AHCI CMD\n")); + //AHCI_CL->cmd_table_phys = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, cmd); + return 0; + } if(AHCI_CL->cmd_table_phys & AHCI_CMD_ALIGNEMENT_MASK) { KdPrint2((PRINT_PREFIX " AHCI CMD address is not aligned (mask %#x)\n", (ULONG)AHCI_CMD_ALIGNEMENT_MASK)); + return 0; } +#ifdef DBG + KdPrint2((" prd_length %#x, flags %#x, base %I64x\n", AHCI_CL->prd_length, AHCI_CL->cmd_flags, + AHCI_CL->cmd_table_phys)); +#endif // DBG + CMD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CMD); KdPrint2((" CMD %#x\n", CMD)); - CMD &= ~ATA_AHCI_P_CMD_ATAPI; - KdPrint2((" send CMD %#x\n", CMD)); + // switch controller to ATAPI mode for ATA_PACKET commands only + if(ATAPI_DEVICE(chan, DeviceNumber) && + AtaReq->ahci.ahci_cmd_ptr->cfis[2] == IDE_COMMAND_ATAPI_PACKET) { + KdPrint2((" ATAPI\n")); + CMD |= ATA_AHCI_P_CMD_ATAPI; + } else { + CMD &= ~ATA_AHCI_P_CMD_ATAPI; + } + KdPrint2((" send CMD %#x, entries %#x\n", CMD, AHCI_CL->prd_length)); UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CMD, CMD); /* issue command to controller */ - UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, ATA_AHCI_P_CMD_ST); + UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_CI, 0x01 << tag); + chan->AhciPrevCI |= 0x01 << tag; - if(!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE)) { + if(!ATAPI_DEVICE(chan, DeviceNumber)) { // TODO: check if we send ATA_RESET and wait for ready of so. if(AtaReq->ahci.ahci_cmd_ptr->cfis[2] == IDE_COMMAND_ATAPI_RESET) { ULONG TFD; @@ -1511,7 +1749,7 @@ } AtaReq->ahci.in_status = TFD; - return 0x00; + return IDE_STATUS_SUCCESS; } } @@ -1532,17 +1770,27 @@ PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; //ULONG Channel = deviceExtension->Channel + lChannel; //ULONG hIS; + ULONG CI; PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension); ULONG TFD; PUCHAR RCV_FIS = &(chan->AhciCtlBlock->rcv_fis.rfis[0]); + ULONG tag=0; + //ULONG i; + PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]); + PHW_LU_EXTENSION LunExt; KdPrint2(("UniataAhciEndTransaction: lChan %d\n", chan->lChannel)); + LunExt = chan->lun[DeviceNumber]; + TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); KdPrint2((" TFD %#x\n", TFD)); if(TFD & IDE_STATUS_ERROR) { - KdPrint2((" ERROR %#x\n", (UCHAR)(TFD >> 8))); + AtaReq->ahci.in_error = (UCHAR)(TFD >> 8); + KdPrint2((" ERROR %#x\n", AtaReq->ahci.in_error)); + } else { + AtaReq->ahci.in_error = 0; } AtaReq->ahci.in_status = TFD; @@ -1560,7 +1808,42 @@ ((ULONGLONG)(RCV_FIS[9]) << 32) | ((ULONGLONG)(RCV_FIS[7] & 0x0f) << 24); } + AtaReq->WordsTransfered = AHCI_CL->bytecount/2; + + if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) { + KdPrint2(("RCV:\n")); + KdDump(RCV_FIS, 24); + KdPrint2(("PIO:\n")); + KdDump(&(chan->AhciCtlBlock->rcv_fis.psfis[0]), 24); + KdPrint2(("len: %d vs %d\n", AHCI_CL->bytecount, (ULONG)RCV_FIS[5] | ((ULONG)RCV_FIS[6] << 8) )); + if(!AHCI_CL->bytecount) { + AtaReq->WordsTransfered = ((ULONG)RCV_FIS[5] | ((ULONG)RCV_FIS[6] << 8)) / 2; + } + } + + CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI); + if(CI & (1 << tag)) { + // clear CI + KdPrint2((" Incomplete command, CI %#x\n", CI)); + KdPrint2((" FIS status %#x, error %#x\n", RCV_FIS[2], RCV_FIS[3])); + +#if DBG + UniataDumpAhciPortRegs(chan); +#endif + UniataAhciStop(chan); + UniataAhciStart(chan); +#if DBG + UniataDumpAhciPortRegs(chan); +#endif + chan->AhciPrevCI = CI & ~((ULONG)1 << tag); + if(chan->AhciPrevCI) { + KdPrint2((" Need command list restart, CI %#x\n", chan->AhciPrevCI)); + } + } else { + chan->AhciPrevCI &= ~((ULONG)1 << tag); + RtlZeroMemory(AHCI_CL, sizeof(IDE_AHCI_CMD_LIST)); + } //} return 0; @@ -1578,7 +1861,7 @@ KdPrint2(("UniataAhciResume: lChan %d\n", chan->lChannel)); #ifdef DBG - UniataDumpAhciPortRegs(chan); + //UniataDumpAhciPortRegs(chan); #endif // DBG /* Disable port interrupts */ @@ -1617,7 +1900,7 @@ ); #ifdef DBG - UniataDumpAhciPortRegs(chan); + //UniataDumpAhciPortRegs(chan); #endif // DBG UniataAhciStartFR(chan); @@ -1710,7 +1993,7 @@ AHCI_CMD->cfis[7] = (UCHAR)(IDE_USE_LBA | DeviceNumber); AHCI_CMD->cfis[15] = IDE_DC_A_4BIT; - if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 10) == 0xff) { + if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 10) == IDE_STATUS_WRONG) { KdPrint2((" PM read failed\n")); return FALSE; } @@ -1755,7 +2038,7 @@ case IDX_SATA_SControl: Reg = 2; break; default: - return 0xff; + return IDE_STATUS_WRONG; } } @@ -1773,9 +2056,9 @@ AHCI_CMD->cfis[15] = IDE_DC_A_4BIT; - if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 100) == 0xff) { + if(UniataAhciSendCommand(chan->DeviceExtension, chan->lChannel, DeviceNumber, 0, 100) == IDE_STATUS_WRONG) { KdPrint2((" PM write failed\n")); - return 0xff; + return IDE_STATUS_WRONG; } TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD); @@ -1806,11 +2089,82 @@ prd_base = (PUCHAR)(&AtaReq->ahci_cmd0); prd_base0 = prd_base; - prd_base64 = (prd_base64 + max(FIELD_OFFSET(ATA_REQ, ahci_cmd0), AHCI_CMD_ALIGNEMENT_MASK)) & ~AHCI_CMD_ALIGNEMENT_MASK; + prd_base64 = (prd_base64 + max(FIELD_OFFSET(ATA_REQ, ahci_cmd0), AHCI_CMD_ALIGNEMENT_MASK+1)) & ~AHCI_CMD_ALIGNEMENT_MASK; d = (ULONG)(prd_base64 - prd_base64_0); - KdPrint2((PRINT_PREFIX " aligned %I64x, d=%x\n", prd_base64, d)); + KdPrint2((PRINT_PREFIX " AtaReq %#x: cmd aligned %I64x, d=%x\n", AtaReq, prd_base64, d)); AtaReq->ahci.ahci_cmd_ptr = (PIDE_AHCI_CMD)prd_base64; KdPrint2((PRINT_PREFIX " ahci_cmd_ptr %#x\n", AtaReq->ahci.ahci_cmd_ptr)); } // end UniataAhciSetupCmdPtr() + +PSCSI_REQUEST_BLOCK +NTAPI +BuildAhciInternalSrb ( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, + IN PUCHAR Buffer, + IN ULONG Length + ) +{ + PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension; + PHW_CHANNEL chan = &deviceExtension->chan[lChannel]; + PSCSI_REQUEST_BLOCK srb; +// PCDB cdb; + PATA_REQ AtaReq = chan->AhciInternalAtaReq; + + KdPrint(("BuildAhciInternalSrb: lChan %d [%#x]\n", lChannel, DeviceNumber)); + + if(!AtaReq) { + KdPrint2((PRINT_PREFIX " !chan->AhciInternalAtaReq\n")); + return NULL; + } + + //RtlZeroMemory((PCHAR) AtaReq, sizeof(ATA_REQ)); + //RtlZeroMemory((PCHAR) AtaReq, FIELD_OFFSET(ATA_REQ, ahci)); + UniAtaClearAtaReq(AtaReq); + + srb = chan->AhciInternalSrb; + + RtlZeroMemory((PCHAR) srb, sizeof(SCSI_REQUEST_BLOCK)); + + srb->PathId = (UCHAR)lChannel; + srb->TargetId = (UCHAR)DeviceNumber; + 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 = Buffer; + srb->DataTransferLength = Length; + srb->SrbExtension = AtaReq; + + AtaReq->Srb = srb; + AtaReq->DataBuffer = (PUSHORT)Buffer; + AtaReq->TransferLength = Length; + + //if(!AtaReq->ahci.ahci_cmd_ptr) { + //UniataAhciSetupCmdPtr(AtaReq); + //AtaReq->ahci.ahci_cmd_ptr = &(chan->AhciCtlBlock->cmd); + //AtaReq->ahci.ahci_base64 = chan->AHCI_CTL_PhAddr + FIELD_OFFSET(IDE_AHCI_CHANNEL_CTL_BLOCK, cmd); + //} + //AtaReq->ahci.ahci_cmd_ptr = &(AtaReq->ahci_cmd0); + //AtaReq->ahci.ahci_base64 = NULL; // indicate that we should copy command to proper place + + KdPrint2((PRINT_PREFIX " Srb %#x, AtaReq %#x, CMD %#x ph %I64x\n", srb, AtaReq, + AtaReq->ahci.ahci_cmd_ptr, AtaReq->ahci.ahci_base64)); + +/* // Set CDB operation code. + cdb = (PCDB)srb->Cdb; + cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE; + cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA); +*/ + return srb; +} // end BuildAhciInternalSrb() + Index: drivers/storage/ide/uniata/id_sata.h =================================================================== --- drivers/storage/ide/uniata/id_sata.h (revision 57016) +++ drivers/storage/ide/uniata/id_sata.h (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2008-2011 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2008-2012 Alexandr A. Telyatnikov (Alter) Module Name: id_probe.cpp @@ -123,6 +123,14 @@ IN PVOID HwDeviceExtension ); +#if DBG +VOID +NTAPI +UniataDumpAhciPortRegs( + IN PHW_CHANNEL chan + ); +#endif + BOOLEAN NTAPI UniataAhciDetect( @@ -149,16 +157,40 @@ IN UCHAR command, IN ULONGLONG lba, IN USHORT count, - IN USHORT feature, - IN ULONG flags + IN USHORT feature ); UCHAR NTAPI +UniataAhciWaitCommandReady( + IN PHW_CHANNEL chan, + IN ULONG timeout + ); + +UCHAR +NTAPI UniataAhciSendCommand( IN PVOID HwDeviceExtension, IN ULONG lChannel, IN ULONG DeviceNumber, + IN USHORT ahci_flags, + IN ULONG timeout + ); + +UCHAR +NTAPI +UniataAhciSendPIOCommand( + IN PVOID HwDeviceExtension, + IN ULONG lChannel, + IN ULONG DeviceNumber, + IN PSCSI_REQUEST_BLOCK Srb, + IN PUCHAR data, + IN ULONG length, + IN UCHAR command, + IN ULONGLONG lba, + IN USHORT count, + IN USHORT feature, + IN USHORT ahci_flags, IN ULONG flags, IN ULONG timeout ); @@ -289,8 +321,33 @@ (((ULONG)(RCV_FIS[5])) << 16) | (((ULONG)(RCV_FIS[4])) << 8) | ((ULONG)(RCV_FIS[12])) ); -} +} // end UniataAhciUlongFromRFIS() +__inline +USHORT +UniAtaAhciAdjustIoFlags( + IN UCHAR command, + IN USHORT ahci_flags, + IN ULONG fis_size, + IN ULONG DeviceNumber + ) +{ + ahci_flags |= (fis_size / sizeof(ULONG)) | (DeviceNumber << 12); + if(!command) { + return ahci_flags; + } + + if(AtaCommandFlags[command] & ATA_CMD_FLAG_Out) { + ahci_flags |= ATA_AHCI_CMD_WRITE; + } +/* + if(AtaCommandFlags[command] & ATA_CMD_FLAG_In) { + ahci_flags |= ATA_AHCI_CMD_READ; + } +*/ + return ahci_flags; +} // end UniAtaAhciAdjustIoFlags() + BOOLEAN NTAPI UniataAhciReadPM( @@ -314,4 +371,14 @@ IN OUT PATA_REQ AtaReq ); +PSCSI_REQUEST_BLOCK +NTAPI +BuildAhciInternalSrb ( + IN PVOID HwDeviceExtension, + IN ULONG DeviceNumber, + IN ULONG lChannel, + IN PUCHAR Buffer = NULL, + IN ULONG Length = 0 + ); + #endif //__UNIATA_SATA__H__ Index: drivers/storage/ide/uniata/scsi.h =================================================================== --- drivers/storage/ide/uniata/scsi.h (revision 57016) +++ drivers/storage/ide/uniata/scsi.h (working copy) @@ -98,6 +98,19 @@ UCHAR Control; } ERASE, *PERASE; + struct _ERASE10 { + UCHAR OperationCode; + UCHAR Reserved : 1; + UCHAR Immediate : 1; + UCHAR ERA : 1; + UCHAR Reserved1 : 2; + UCHAR Lun : 3; + UCHAR LBA[4]; + UCHAR Reserved2; + UCHAR TransferBlocks[2]; + UCHAR Control; + } ERASE10, *PERASE10; + #define FormatUnit_Code_Mask 0x07 #define FormatUnit_Cmp 0x08 #define FormatUnit_Fmt 0x10 Index: drivers/storage/ide/uniata/tools.h =================================================================== --- drivers/storage/ide/uniata/tools.h (revision 57016) +++ drivers/storage/ide/uniata/tools.h (working copy) @@ -1,6 +1,6 @@ /*++ -Copyright (c) 2002-2005 Alexandr A. Telyatnikov (Alter) +Copyright (c) 2002-2012 Alexandr A. Telyatnikov (Alter) Module Name: tools.h @@ -94,196 +94,7 @@ } #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) \ @@ -298,7 +109,7 @@ KdPrint(("\n")); \ } -#define BrutePoint() {} +#define BrutePoint() { ASSERT(0); } #define DbgAllocatePool(x,y) ExAllocatePool(x,y) #define DbgFreePool(x) ExFreePool(x) Index: drivers/storage/ide/uniata/uniata_ver.h =================================================================== --- drivers/storage/ide/uniata/uniata_ver.h (revision 57016) +++ drivers/storage/ide/uniata/uniata_ver.h (working copy) @@ -1,10 +1,10 @@ -#define UNIATA_VER_STR "41b5" -#define UNIATA_VER_DOT 0.41.2.5 +#define UNIATA_VER_STR "42e2" +#define UNIATA_VER_DOT 0.42.5.2 #define UNIATA_VER_MJ 0 -#define UNIATA_VER_MN 41 -#define UNIATA_VER_SUB_MJ 2 -#define UNIATA_VER_SUB_MN 5 -#define UNIATA_VER_DOT_COMMA 0,41,2,5 -#define UNIATA_VER_DOT_STR "0.41.2.5" +#define UNIATA_VER_MN 42 +#define UNIATA_VER_SUB_MJ 5 +#define UNIATA_VER_SUB_MN 2 +#define UNIATA_VER_DOT_COMMA 0,42,5,2 +#define UNIATA_VER_DOT_STR "0.42.5.2" #define UNIATA_VER_YEAR 2012 #define UNIATA_VER_YEAR_STR "2012"