2 * PROJECT: ReactOS Kernel
3 * LICENSE: GNU GPLv2 only as published by the Free Software Foundation
4 * PURPOSE: To Implement AHCI Miniport driver targeting storport NT 5.2
5 * PROGRAMMERS: Aman Priyadarshi (aman.eureka@gmail.com)
17 #pragma warning(disable:4214) // bit field types other than int
18 #pragma warning(disable:4201) // nameless struct/union
21 #define MAXIMUM_AHCI_PORT_COUNT 32
22 #define MAXIMUM_AHCI_PRDT_ENTRIES 32
23 #define MAXIMUM_AHCI_PORT_NCS 30
24 #define MAXIMUM_QUEUE_BUFFER_SIZE 255
25 #define MAXIMUM_TRANSFER_LENGTH (128*1024) // 128 KB
27 #define DEVICE_ATA_BLOCK_SIZE 512
29 // device type (DeviceParams)
30 #define AHCI_DEVICE_TYPE_ATA 1
31 #define AHCI_DEVICE_TYPE_ATAPI 2
32 #define AHCI_DEVICE_TYPE_NODEVICE 3
35 #define AHCI_Global_HBA_CAP_S64A (1 << 31)
37 // FIS Types : http://wiki.osdev.org/AHCI
38 #define FIS_TYPE_REG_H2D 0x27 // Register FIS - host to device
39 #define FIS_TYPE_REG_D2H 0x34 // Register FIS - device to host
40 #define FIS_TYPE_DMA_ACT 0x39 // DMA activate FIS - device to host
41 #define FIS_TYPE_DMA_SETUP 0x41 // DMA setup FIS - bidirectional
42 #define FIS_TYPE_BIST 0x58 // BIST activate FIS - bidirectional
43 #define FIS_TYPE_PIO_SETUP 0x5F // PIO setup FIS - device to host
44 #define FIS_TYPE_DEV_BITS 0xA1 // Set device bits FIS - device to host
46 #define AHCI_ATA_CFIS_FisType 0
47 #define AHCI_ATA_CFIS_PMPort_C 1
48 #define AHCI_ATA_CFIS_CommandReg 2
49 #define AHCI_ATA_CFIS_FeaturesLow 3
50 #define AHCI_ATA_CFIS_LBA0 4
51 #define AHCI_ATA_CFIS_LBA1 5
52 #define AHCI_ATA_CFIS_LBA2 6
53 #define AHCI_ATA_CFIS_Device 7
54 #define AHCI_ATA_CFIS_LBA3 8
55 #define AHCI_ATA_CFIS_LBA4 9
56 #define AHCI_ATA_CFIS_LBA5 10
57 #define AHCI_ATA_CFIS_FeaturesHigh 11
58 #define AHCI_ATA_CFIS_SectorCountLow 12
59 #define AHCI_ATA_CFIS_SectorCountHigh 13
62 #define ATA_FUNCTION_ATA_COMMAND 0x100
63 #define ATA_FUNCTION_ATA_IDENTIFY 0x101
64 #define ATA_FUNCTION_ATA_READ 0x102
67 #define ATA_FUNCTION_ATAPI_COMMAND 0x200
70 #define ATA_FLAGS_DATA_IN (1 << 1)
71 #define ATA_FLAGS_DATA_OUT (1 << 2)
72 #define ATA_FLAGS_48BIT_COMMAND (1 << 3)
73 #define ATA_FLAGS_USE_DMA (1 << 4)
75 #define IsAtaCommand(AtaFunction) (AtaFunction & ATA_FUNCTION_ATA_COMMAND)
76 #define IsAtapiCommand(AtaFunction) (AtaFunction & ATA_FUNCTION_ATAPI_COMMAND)
77 #define IsDataTransferNeeded(SrbExtension) (SrbExtension->Flags & (ATA_FLAGS_DATA_IN | ATA_FLAGS_DATA_OUT))
78 #define IsAdapterCAPS64(CAP) (CAP & AHCI_Global_HBA_CAP_S64A)
80 // 3.1.1 NCS = CAP[12:08] -> Align
81 #define AHCI_Global_Port_CAP_NCS(x) (((x) & 0xF00) >> 8)
83 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
84 //#define AhciDebugPrint(format, ...) StorPortDebugPrint(0, format, __VA_ARGS__)
85 #define AhciDebugPrint(format, ...) DbgPrint("(%s:%d) " format, __RELFILE__, __LINE__, ##__VA_ARGS__)
89 (*PAHCI_COMPLETION_ROUTINE
) (
90 __in PVOID PortExtension
,
94 //////////////////////////////////////////////////////////////
95 // ---- Support Structures --- //
96 //////////////////////////////////////////////////////////////
99 typedef union _AHCI_INTERRUPT_STATUS
103 ULONG DHRS
:1; //Device to Host Register FIS Interrupt
104 ULONG PSS
:1; //PIO Setup FIS Interrupt
105 ULONG DSS
:1; //DMA Setup FIS Interrupt
106 ULONG SDBS
:1; //Set Device Bits Interrupt
107 ULONG UFS
:1; //Unknown FIS Interrupt
108 ULONG DPS
:1; //Descriptor Processed
109 ULONG PCS
:1; //Port Connect Change Status
110 ULONG DMPS
:1; //Device Mechanical Presence Status (DMPS)
112 ULONG PRCS
:1; //PhyRdy Change Status
113 ULONG IPMS
:1; //Incorrect Port Multiplier Status
114 ULONG OFS
:1; //Overflow Status
116 ULONG INFS
:1; //Interface Non-fatal Error Status
117 ULONG IFS
:1; //Interface Fatal Error Status
118 ULONG HBDS
:1; //Host Bus Data Error Status
119 ULONG HBFS
:1; //Host Bus Fatal Error Status
120 ULONG TFES
:1; //Task File Error Status
121 ULONG CPDS
:1; //Cold Port Detect Status
125 } AHCI_INTERRUPT_STATUS
;
127 typedef struct _AHCI_FIS_DMA_SETUP
129 ULONG ULONG0_1
; // FIS_TYPE_DMA_SETUP
132 // Data transfer direction, 1 - device to host
134 // Auto-activate. Specifies if DMA Activate FIS is needed
135 UCHAR Reserved
[2]; // Reserved
136 ULONG DmaBufferLow
; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
138 ULONG Reserved2
; // More reserved
139 ULONG DmaBufferOffset
; // Byte offset into buffer. First 2 bits must be 0
140 ULONG TranferCount
; // Number of bytes to transfer. Bit 0 must be 0
141 ULONG Reserved3
; // Reserved
142 } AHCI_FIS_DMA_SETUP
;
144 typedef struct _AHCI_PIO_SETUP_FIS
159 UCHAR SectorNumb_Exp
;
165 UCHAR SectorCount_Exp
;
169 USHORT TransferCount
;
171 } AHCI_PIO_SETUP_FIS
;
173 typedef struct _AHCI_D2H_REGISTER_FIS
193 UCHAR SectorCount_Exp
;
197 } AHCI_D2H_REGISTER_FIS
;
199 typedef struct _AHCI_SET_DEVICE_BITS_FIS
216 } AHCI_SET_DEVICE_BITS_FIS
;
218 typedef struct _AHCI_QUEUE
220 PVOID Buffer
[MAXIMUM_QUEUE_BUFFER_SIZE
]; // because Storahci hold Srb queue of 255 size
223 } AHCI_QUEUE
, *PAHCI_QUEUE
;
225 //////////////////////////////////////////////////////////////
226 // --------------------------- //
227 //////////////////////////////////////////////////////////////
229 typedef union _AHCI_COMMAND_HEADER_DESCRIPTION
233 ULONG CFL
: 5; // Command FIS Length
234 ULONG A
: 1; // IsATAPI
235 ULONG W
: 1; // Write
236 ULONG P
: 1; // Prefetchable
238 ULONG R
: 1; // Reset
240 ULONG C
: 1; //Clear Busy upon R_OK
242 ULONG PMP
: 4; //Port Multiplier Port
244 ULONG PRDTL
: 16; //Physical Region Descriptor Table Length
248 } AHCI_COMMAND_HEADER_DESCRIPTION
;
250 typedef union _AHCI_GHC
265 typedef union _AHCI_PORT_CMD
297 typedef union _AHCI_SERIAL_ATA_CONTROL
306 ULONG DW11_Reserved
:12;
310 } AHCI_SERIAL_ATA_CONTROL
;
312 typedef union _AHCI_SERIAL_ATA_STATUS
323 } AHCI_SERIAL_ATA_STATUS
;
325 typedef union _AHCI_TASK_FILE_DATA
342 } AHCI_TASK_FILE_DATA
;
344 typedef struct _AHCI_PRDT
353 } AHCI_PRDT
, *PAHCI_PRDT
;
355 // 4.2.3 Command Table
356 typedef struct _AHCI_COMMAND_TABLE
358 // (16 * 32) + 64 + 16 + 48 = 648
359 // 128 byte aligned :D
363 AHCI_PRDT PRDT
[MAXIMUM_AHCI_PRDT_ENTRIES
];
364 } AHCI_COMMAND_TABLE
, *PAHCI_COMMAND_TABLE
;
366 // 4.2.2 Command Header
367 typedef struct _AHCI_COMMAND_HEADER
369 AHCI_COMMAND_HEADER_DESCRIPTION DI
; // DW 0
372 ULONG CTBA_U
; // DW 3
373 ULONG Reserved
[4]; // DW 4-7
374 } AHCI_COMMAND_HEADER
, *PAHCI_COMMAND_HEADER
;
377 typedef struct _AHCI_RECEIVED_FIS
379 struct _AHCI_FIS_DMA_SETUP DmaSetupFIS
; // 0x00 -- DMA Setup FIS
380 ULONG pad0
; // 4 BYTE padding
381 struct _AHCI_PIO_SETUP_FIS PioSetupFIS
; // 0x20 -- PIO Setup FIS
382 ULONG pad1
[3]; // 12 BYTE padding
383 struct _AHCI_D2H_REGISTER_FIS RegisterFIS
; // 0x40 -- Register – Device to Host FIS
384 ULONG pad2
; // 4 BYTE padding
385 struct _AHCI_SET_DEVICE_BITS_FIS SetDeviceFIS
; // 0x58 -- Set Device Bit FIS
386 ULONG UnknowFIS
[16]; // 0x60 -- Unknown FIS
387 ULONG Reserved
[24]; // 0xA0 -- Reserved
388 } AHCI_RECEIVED_FIS
, *PAHCI_RECEIVED_FIS
;
390 // Holds Port Information
391 typedef struct _AHCI_PORT
393 ULONG CLB
; // 0x00, command list base address, 1K-byte aligned
394 ULONG CLBU
; // 0x04, command list base address upper 32 bits
395 ULONG FB
; // 0x08, FIS base address, 256-byte aligned
396 ULONG FBU
; // 0x0C, FIS base address upper 32 bits
397 ULONG IS
; // 0x10, interrupt status
398 ULONG IE
; // 0x14, interrupt enable
399 ULONG CMD
; // 0x18, command and status
400 ULONG RSV0
; // 0x1C, Reserved
401 ULONG TFD
; // 0x20, task file data
402 ULONG SIG
; // 0x24, signature
403 ULONG SSTS
; // 0x28, SATA status (SCR0:SStatus)
404 ULONG SCTL
; // 0x2C, SATA control (SCR2:SControl)
405 ULONG SERR
; // 0x30, SATA error (SCR1:SError)
406 ULONG SACT
; // 0x34, SATA active (SCR3:SActive)
407 ULONG CI
; // 0x38, command issue
408 ULONG SNTF
; // 0x3C, SATA notification (SCR4:SNotification)
409 ULONG FBS
; // 0x40, FIS-based switch control
410 ULONG RSV1
[11]; // 0x44 ~ 0x6F, Reserved
411 ULONG Vendor
[4]; // 0x70 ~ 0x7F, vendor specific
412 } AHCI_PORT
, *PAHCI_PORT
;
414 typedef union _AHCI_INTERRUPT_ENABLE
426 ULONG DW5_Reserved
:14;
430 ULONG DW5_Reserved2
:1;
440 } AHCI_INTERRUPT_ENABLE
;
442 typedef struct _AHCI_MEMORY_REGISTERS
444 // 0x00 - 0x2B, Generic Host Control
445 ULONG CAP
; // 0x00, Host capability
446 ULONG GHC
; // 0x04, Global host control
447 ULONG IS
; // 0x08, Interrupt status
448 ULONG PI
; // 0x0C, Port implemented
449 ULONG VS
; // 0x10, Version
450 ULONG CCC_CTL
; // 0x14, Command completion coalescing control
451 ULONG CCC_PTS
; // 0x18, Command completion coalescing ports
452 ULONG EM_LOC
; // 0x1C, Enclosure management location
453 ULONG EM_CTL
; // 0x20, Enclosure management control
454 ULONG CAP2
; // 0x24, Host capabilities extended
455 ULONG BOHC
; // 0x28, BIOS/OS handoff control and status
456 ULONG Reserved
[0x1d]; // 0x2C - 0x9F, Reserved
457 ULONG VendorSpecific
[0x18]; // 0xA0 - 0xFF, Vendor specific registers
458 AHCI_PORT PortList
[MAXIMUM_AHCI_PORT_COUNT
];
459 } AHCI_MEMORY_REGISTERS
, *PAHCI_MEMORY_REGISTERS
;
461 // Holds information for each attached attached port to a given adapter.
462 typedef struct _AHCI_PORT_EXTENSION
465 ULONG QueueSlots
; // slots which we have already assigned task (Slot)
466 ULONG CommandIssuedSlots
; // slots which has been programmed
467 ULONG MaxPortQueueDepth
;
471 UCHAR RemovableDevice
;
476 LARGE_INTEGER MaxLba
;
477 ULONG BytesPerLogicalSector
;
478 ULONG BytesPerPhysicalSector
;
481 UCHAR SerialNumber
[21];
484 STOR_DPC CommandCompletion
;
485 PAHCI_PORT Port
; // AHCI Port Infomation
486 AHCI_QUEUE SrbQueue
; // pending Srbs
487 AHCI_QUEUE CompletionQueue
;
488 PSCSI_REQUEST_BLOCK Slot
[MAXIMUM_AHCI_PORT_NCS
]; // Srbs which has been alloted a port
489 PAHCI_RECEIVED_FIS ReceivedFIS
;
490 PAHCI_COMMAND_HEADER CommandList
;
491 STOR_DEVICE_POWER_STATE DevicePowerState
; // Device Power State
492 PIDENTIFY_DEVICE_DATA IdentifyDeviceData
;
493 STOR_PHYSICAL_ADDRESS IdentifyDeviceDataPhysicalAddress
;
494 struct _AHCI_ADAPTER_EXTENSION
* AdapterExtension
; // Port's Adapter Information
495 } AHCI_PORT_EXTENSION
, *PAHCI_PORT_EXTENSION
;
497 // Holds Adapter Information
498 typedef struct _AHCI_ADAPTER_EXTENSION
500 ULONG SystemIoBusNumber
;
502 ULONG AhciBaseAddress
;
503 PULONG IS
;// Interrupt Status, In case of MSIM == `1`
504 ULONG PortImplemented
;// bit-mapping of ports which are implemented
514 ULONG LastInterruptPort
;
515 ULONG CurrentCommandSlot
;
517 PVOID NonCachedExtension
; // holds virtual address to noncached buffer allocated for Port Extension
521 // Message per port or shared port?
522 ULONG MessagePerPort
: 1;
524 ULONG Reserved
: 30; // not in use -- maintain 4 byte alignment
527 PAHCI_MEMORY_REGISTERS ABAR_Address
;
528 AHCI_PORT_EXTENSION PortExtension
[MAXIMUM_AHCI_PORT_COUNT
];
529 } AHCI_ADAPTER_EXTENSION
, *PAHCI_ADAPTER_EXTENSION
;
531 typedef struct _LOCAL_SCATTER_GATHER_LIST
533 ULONG NumberOfElements
;
535 STOR_SCATTER_GATHER_ELEMENT List
[MAXIMUM_AHCI_PRDT_ENTRIES
];
536 } LOCAL_SCATTER_GATHER_LIST
, *PLOCAL_SCATTER_GATHER_LIST
;
538 typedef struct _AHCI_SRB_EXTENSION
540 AHCI_COMMAND_TABLE CommandTable
;
555 UCHAR SectorCountLow
;
556 UCHAR SectorCountHigh
;
559 LOCAL_SCATTER_GATHER_LIST Sgl
;
560 PLOCAL_SCATTER_GATHER_LIST pSgl
;
561 PAHCI_COMPLETION_ROUTINE CompletionRoutine
;
563 // for alignment purpose -- 128 byte alignment
564 // do not try to access (R/W) this field
566 } AHCI_SRB_EXTENSION
, *PAHCI_SRB_EXTENSION
;
568 //////////////////////////////////////////////////////////////
570 //////////////////////////////////////////////////////////////
574 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
576 __in PSCSI_REQUEST_BLOCK Srb
581 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
588 __in ULONG BufferSize
594 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
598 UCHAR
DeviceRequestSense (
599 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
600 __in PSCSI_REQUEST_BLOCK Srb
,
604 UCHAR
DeviceRequestReadWrite (
605 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
606 __in PSCSI_REQUEST_BLOCK Srb
,
610 UCHAR
DeviceRequestCapacity (
611 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
612 __in PSCSI_REQUEST_BLOCK Srb
,
617 DeviceInquiryRequest (
618 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
619 __in PSCSI_REQUEST_BLOCK Srb
,
623 UCHAR
DeviceRequestComplete (
624 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
625 __in PSCSI_REQUEST_BLOCK Srb
,
629 UCHAR
DeviceReportLuns (
630 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
631 __in PSCSI_REQUEST_BLOCK Srb
,
638 __inout PAHCI_QUEUE Queue
,
645 __inout PAHCI_QUEUE Queue
651 __in PSCSI_REQUEST_BLOCK Srb
661 //////////////////////////////////////////////////////////////
663 //////////////////////////////////////////////////////////////
665 // I assert every silly mistake I can do while coding
666 // because god never help me debugging the code
667 // but these asserts do :')
669 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, CAP
) == 0x00);
670 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, GHC
) == 0x04);
671 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, IS
) == 0x08);
672 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, PI
) == 0x0C);
673 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, VS
) == 0x10);
674 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, CCC_CTL
) == 0x14);
675 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, CCC_PTS
) == 0x18);
676 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, EM_LOC
) == 0x1C);
677 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, EM_CTL
) == 0x20);
678 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, CAP2
) == 0x24);
679 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, BOHC
) == 0x28);
680 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, Reserved
) == 0x2C);
681 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, VendorSpecific
) == 0xA0);
682 C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS
, PortList
) == 0x100);
684 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, CLB
) == 0x00);
685 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, CLBU
) == 0x04);
686 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, FB
) == 0x08);
687 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, FBU
) == 0x0C);
688 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, IS
) == 0x10);
689 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, IE
) == 0x14);
690 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, CMD
) == 0x18);
691 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, RSV0
) == 0x1C);
692 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, TFD
) == 0x20);
693 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, SIG
) == 0x24);
694 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, SSTS
) == 0x28);
695 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, SCTL
) == 0x2C);
696 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, SERR
) == 0x30);
697 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, SACT
) == 0x34);
698 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, CI
) == 0x38);
699 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, SNTF
) == 0x3C);
700 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, FBS
) == 0x40);
701 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, RSV1
) == 0x44);
702 C_ASSERT(FIELD_OFFSET(AHCI_PORT
, Vendor
) == 0x70);
704 C_ASSERT((sizeof(AHCI_COMMAND_TABLE
) % 128) == 0);
706 C_ASSERT(sizeof(AHCI_GHC
) == sizeof(ULONG
));
707 C_ASSERT(sizeof(AHCI_PORT_CMD
) == sizeof(ULONG
));
708 C_ASSERT(sizeof(AHCI_TASK_FILE_DATA
) == sizeof(ULONG
));
709 C_ASSERT(sizeof(AHCI_INTERRUPT_ENABLE
) == sizeof(ULONG
));
710 C_ASSERT(sizeof(AHCI_SERIAL_ATA_STATUS
) == sizeof(ULONG
));
711 C_ASSERT(sizeof(AHCI_SERIAL_ATA_CONTROL
) == sizeof(ULONG
));
712 C_ASSERT(sizeof(AHCI_COMMAND_HEADER_DESCRIPTION
) == sizeof(ULONG
));
714 C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE
, CFIS
) == 0x00);
715 C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE
, ACMD
) == 0x40);
716 C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE
, RSV0
) == 0x50);
717 C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE
, PRDT
) == 0x80);