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)
11 * @name AhciPortInitialize
14 * Initialize port by setting up PxCLB & PxFB Registers
16 * @param PortExtension
19 * Return true if intialization was successful
23 __in PAHCI_PORT_EXTENSION PortExtension
26 ULONG mappedLength
, portNumber
;
27 PAHCI_MEMORY_REGISTERS abar
;
28 PAHCI_ADAPTER_EXTENSION adapterExtension
;
29 STOR_PHYSICAL_ADDRESS commandListPhysical
, receivedFISPhysical
;
31 DebugPrint("AhciPortInitialize()\n");
33 adapterExtension
= PortExtension
->AdapterExtension
;
34 abar
= adapterExtension
->ABAR_Address
;
35 portNumber
= PortExtension
->PortNumber
;
37 NT_ASSERT(abar
!= NULL
);
38 NT_ASSERT(portNumber
< adapterExtension
->PortCount
);
40 PortExtension
->Port
= &abar
->PortList
[portNumber
];
42 commandListPhysical
= StorPortGetPhysicalAddress(adapterExtension
,
44 PortExtension
->CommandList
,
47 if ((mappedLength
== 0) || ((commandListPhysical
.LowPart
% 1024) != 0))
49 DebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength
);
53 receivedFISPhysical
= StorPortGetPhysicalAddress(adapterExtension
,
55 PortExtension
->ReceivedFIS
,
58 if ((mappedLength
== 0) || ((receivedFISPhysical
.LowPart
% 256) != 0))
60 DebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength
);
64 // 10.1.2 For each implemented port, system software shall allocate memory for and program:
65 // PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
66 // PxFB and PxFBU (if CAP.S64A is set to ‘1’)
67 // Note: Assuming 32bit support only
68 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->CLB
, commandListPhysical
.LowPart
);
69 if (IsAdapterCAPS64(adapterExtension
->CAP
))
71 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->CLBU
, commandListPhysical
.HighPart
);
74 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->FB
, receivedFISPhysical
.LowPart
);
75 if (IsAdapterCAPS64(adapterExtension
->CAP
))
77 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->FBU
, receivedFISPhysical
.HighPart
);
80 PortExtension
->IdentifyDeviceDataPhysicalAddress
= StorPortGetPhysicalAddress(adapterExtension
,
82 PortExtension
->IdentifyDeviceData
,
85 NT_ASSERT(mappedLength
== sizeof(IDENTIFY_DEVICE_DATA
));
87 // set device power state flag to D0
88 PortExtension
->DevicePowerState
= StorPowerDeviceD0
;
90 // clear pending interrupts
91 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->SERR
, (ULONG
)-1);
92 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->IS
, (ULONG
)-1);
93 StorPortWriteRegisterUlong(adapterExtension
, PortExtension
->AdapterExtension
->IS
, (1 << PortExtension
->PortNumber
));
96 }// -- AhciPortInitialize();
99 * @name AhciAllocateResourceForAdapter
102 * Allocate memory from poll for required pointers
104 * @param AdapterExtension
108 * return TRUE if allocation was successful
111 AhciAllocateResourceForAdapter (
112 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
113 __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
116 PVOID portsExtension
= NULL
;
117 PCHAR nonCachedExtension
, tmp
;
118 ULONG status
, index
, NCS
, AlignedNCS
;
119 ULONG portCount
, portImplemented
, nonCachedExtensionSize
;
121 DebugPrint("AhciAllocateResourceForAdapter()\n");
123 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
124 AlignedNCS
= ROUND_UP(NCS
, 8);
126 // get port count -- Number of set bits in `AdapterExtension->PortImplemented`
128 portImplemented
= AdapterExtension
->PortImplemented
;
130 NT_ASSERT(portImplemented
!= 0);
131 for (index
= MAXIMUM_AHCI_PORT_COUNT
- 1; index
> 0; index
--)
132 if ((portImplemented
& (1 << index
)) != 0)
135 portCount
= index
+ 1;
136 DebugPrint("\tPort Count: %d\n", portCount
);
138 AdapterExtension
->PortCount
= portCount
;
139 nonCachedExtensionSize
= sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
+ //should be 1K aligned
140 sizeof(AHCI_RECEIVED_FIS
) +
141 sizeof(IDENTIFY_DEVICE_DATA
);
143 // align nonCachedExtensionSize to 1024
144 nonCachedExtensionSize
= ROUND_UP(nonCachedExtensionSize
, 1024);
146 AdapterExtension
->NonCachedExtension
= StorPortGetUncachedExtension(AdapterExtension
,
148 nonCachedExtensionSize
* portCount
);
150 if (AdapterExtension
->NonCachedExtension
== NULL
)
152 DebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
156 nonCachedExtension
= AdapterExtension
->NonCachedExtension
;
157 AhciZeroMemory(nonCachedExtension
, nonCachedExtensionSize
* portCount
);
159 for (index
= 0; index
< portCount
; index
++)
161 AdapterExtension
->PortExtension
[index
].IsActive
= FALSE
;
162 if ((AdapterExtension
->PortImplemented
& (1 << index
)) != 0)
164 AdapterExtension
->PortExtension
[index
].PortNumber
= index
;
165 AdapterExtension
->PortExtension
[index
].IsActive
= TRUE
;
166 AdapterExtension
->PortExtension
[index
].AdapterExtension
= AdapterExtension
;
167 AdapterExtension
->PortExtension
[index
].CommandList
= nonCachedExtension
;
169 tmp
= (PCHAR
)(nonCachedExtension
+ sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
);
171 AdapterExtension
->PortExtension
[index
].ReceivedFIS
= (PAHCI_RECEIVED_FIS
)tmp
;
172 AdapterExtension
->PortExtension
[index
].IdentifyDeviceData
= (PIDENTIFY_DEVICE_DATA
)(tmp
+ sizeof(AHCI_RECEIVED_FIS
));
173 nonCachedExtension
+= nonCachedExtensionSize
;
178 }// -- AhciAllocateResourceForAdapter();
181 * @name AhciHwInitialize
184 * initializes the HBA and finds all devices that are of interest to the miniport driver.
186 * @param adapterExtension
189 * return TRUE if intialization was successful
193 __in PVOID AdapterExtension
196 ULONG ghc
, messageCount
, status
;
197 PAHCI_ADAPTER_EXTENSION adapterExtension
;
199 DebugPrint("AhciHwInitialize()\n");
201 adapterExtension
= AdapterExtension
;
202 adapterExtension
->StateFlags
.MessagePerPort
= FALSE
;
204 // First check what type of interrupt/synchronization device is using
205 ghc
= StorPortReadRegisterUlong(adapterExtension
, &adapterExtension
->ABAR_Address
->GHC
);
207 // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector
208 // but has reverted to using the first vector only. When this bit is cleared to ‘0’,
209 // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
210 // software has allocated the number of messages requested
211 if ((ghc
& AHCI_Global_HBA_CONTROL_MRSM
) == 0)
213 adapterExtension
->StateFlags
.MessagePerPort
= TRUE
;
214 DebugPrint("\tMultiple MSI based message not supported\n");
218 }// -- AhciHwInitialize();
221 * @name AhciCompleteIssuedSrb
224 * Complete issued Srbs
226 * @param PortExtension
230 AhciCompleteIssuedSrb (
231 __in PAHCI_PORT_EXTENSION PortExtension
,
232 __in ULONG CommandsToComplete
236 PSCSI_REQUEST_BLOCK Srb
;
237 PAHCI_SRB_EXTENSION SrbExtension
;
238 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
239 PAHCI_COMPLETION_ROUTINE CompletionRoutine
;
241 DebugPrint("AhciCompleteIssuedSrb()\n");
243 NT_ASSERT(CommandsToComplete
!= 0);
245 DebugPrint("\tCompleted Commands: %d\n", CommandsToComplete
);
247 AdapterExtension
= PortExtension
->AdapterExtension
;
248 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
250 for (i
= 0; i
< NCS
; i
++)
252 if (((1 << i
) & CommandsToComplete
) != 0)
254 Srb
= &PortExtension
->Slot
[i
];
255 NT_ASSERT(Srb
!= NULL
);
257 if (Srb
->SrbStatus
== SRB_STATUS_PENDING
)
259 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
262 SrbExtension
= GetSrbExtension(Srb
);
263 CompletionRoutine
= SrbExtension
->CompletionRoutine
;
265 if (CompletionRoutine
!= NULL
)
267 // now it's completion routine responsibility to set SrbStatus
268 CompletionRoutine(AdapterExtension
, PortExtension
, Srb
);
272 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
273 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
279 }// -- AhciCompleteIssuedSrb();
282 * @name AhciInterruptHandler
285 * Interrupt Handler for PortExtension
287 * @param PortExtension
291 AhciInterruptHandler (
292 __in PAHCI_PORT_EXTENSION PortExtension
295 ULONG is
, ci
, sact
, outstanding
;
296 AHCI_INTERRUPT_STATUS PxIS
;
297 AHCI_INTERRUPT_STATUS PxISMasked
;
298 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
300 DebugPrint("AhciInterruptHandler()\n");
301 DebugPrint("\tPort Number: %d\n", PortExtension
->PortNumber
);
303 AdapterExtension
= PortExtension
->AdapterExtension
;
304 NT_ASSERT(IsPortValid(AdapterExtension
, PortExtension
->PortNumber
));
307 // 1. Software determines the cause of the interrupt by reading the PxIS register.
308 // It is possible for multiple bits to be set
309 // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt.
310 // 3. Software clears the interrupt bit in IS.IPS corresponding to the port.
311 // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to
312 // the list of commands previously issued by software that are still outstanding.
313 // If executing native queued commands, software reads the PxSACT register and compares the current
314 // value to the list of commands previously issued by software.
315 // Software completes with success any outstanding command whose corresponding bit has been cleared in
316 // the respective register. PxCI and PxSACT are volatile registers; software should only use their values
317 // to determine commands that have completed, not to determine which commands have previously been issued.
318 // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2).
319 PxISMasked
.Status
= 0;
320 PxIS
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
);
324 // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES
325 if (PxIS
.HBFS
|| PxIS
.HBDS
|| PxIS
.IFS
|| PxIS
.TFES
)
327 // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process
328 // any native command queuing commands. To recover, the port must be restarted
329 // To detect an error that requires software recovery actions to be performed,
330 // software should check whether any of the following status bits are set on an interrupt:
331 // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set,
332 // software should perform the appropriate error recovery actions based on whether
333 // non-queued commands were being issued or native command queuing commands were being issued.
335 DebugPrint("\tFatal Error: %x\n", PxIS
.Status
);
338 // Normal Command Completion
340 // A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory.
341 PxISMasked
.DHRS
= PxIS
.DHRS
;
342 // A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory.
343 PxISMasked
.PSS
= PxIS
.PSS
;
344 // A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory.
345 PxISMasked
.DSS
= PxIS
.DSS
;
346 // A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/
347 PxISMasked
.SDBS
= PxIS
.SDBS
;
348 // A PRD with the ‘I’ bit set has transferred all of its data.
349 PxISMasked
.DPS
= PxIS
.DPS
;
351 if (PxISMasked
.Status
!= 0)
353 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
, PxISMasked
.Status
);
357 // Clear port interrupt
358 // It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software.
359 is
= (1 << PortExtension
->PortNumber
);
360 StorPortWriteRegisterUlong(AdapterExtension
, AdapterExtension
->IS
, is
);
362 ci
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
);
363 sact
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SACT
);
365 outstanding
= ci
| sact
; // NOTE: Including both non-NCQ and NCQ based commands
366 if ((PortExtension
->CommandIssuedSlots
& (~outstanding
)) != 0)
368 AhciCompleteIssuedSrb(PortExtension
, (PortExtension
->CommandIssuedSlots
& (~outstanding
)));
369 PortExtension
->CommandIssuedSlots
&= outstanding
;
373 }// -- AhciInterruptHandler();
376 * @name AhciHwInterrupt
379 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
381 * @param AdapterExtension
384 * return TRUE Indicates that an interrupt was pending on adapter.
385 * return FALSE Indicates the interrupt was not ours.
389 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
392 ULONG portPending
, nextPort
, i
, portCount
;
394 DebugPrint("AhciHwInterrupt()\n");
396 if (AdapterExtension
->StateFlags
.Removed
)
401 portPending
= StorPortReadRegisterUlong(AdapterExtension
, AdapterExtension
->IS
);
402 // we process interrupt for implemented ports only
403 portCount
= AdapterExtension
->PortCount
;
404 portPending
= portPending
& AdapterExtension
->PortImplemented
;
406 if (portPending
== 0)
411 for (i
= 1; i
<= portCount
; i
++)
413 nextPort
= (AdapterExtension
->LastInterruptPort
+ i
) % portCount
;
415 if ((portPending
& (0x1 << nextPort
)) == 0)
418 NT_ASSERT(IsPortValid(AdapterExtension
, nextPort
));
420 if ((nextPort
== AdapterExtension
->LastInterruptPort
) ||
421 (AdapterExtension
->PortExtension
[nextPort
].IsActive
== FALSE
))
426 // we can assign this interrupt to this port
427 AdapterExtension
->LastInterruptPort
= nextPort
;
428 AhciInterruptHandler(&AdapterExtension
->PortExtension
[nextPort
]);
430 // interrupt belongs to this device
431 // should always return TRUE
435 DebugPrint("\tSomething went wrong");
437 }// -- AhciHwInterrupt();
440 * @name AhciHwStartIo
443 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
445 * @param adapterExtension
449 * return TRUE if the request was accepted
450 * return FALSE if the request must be submitted later
454 __in PVOID AdapterExtension
,
455 __in PSCSI_REQUEST_BLOCK Srb
458 UCHAR function
, pathId
;
459 PAHCI_ADAPTER_EXTENSION adapterExtension
;
461 DebugPrint("AhciHwStartIo()\n");
463 pathId
= Srb
->PathId
;
464 function
= Srb
->Function
;
465 adapterExtension
= AdapterExtension
;
467 if (!IsPortValid(adapterExtension
, pathId
))
469 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
470 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
474 // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp
475 // If the function member of an SRB is set to SRB_FUNCTION_PNP,
476 // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK.
477 if (function
== SRB_FUNCTION_PNP
)
479 PSCSI_PNP_REQUEST_BLOCK pnpRequest
;
481 pnpRequest
= (PSCSI_PNP_REQUEST_BLOCK
)Srb
;
482 if ((pnpRequest
->SrbPnPFlags
& SRB_PNP_FLAGS_ADAPTER_REQUEST
) != 0)
484 if ((pnpRequest
->PnPAction
== StorRemoveDevice
) ||
485 (pnpRequest
->PnPAction
== StorSurpriseRemoval
))
487 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
488 adapterExtension
->StateFlags
.Removed
= 1;
489 DebugPrint("\tAdapter removed\n");
491 else if (pnpRequest
->PnPAction
== StorStopDevice
)
493 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
494 DebugPrint("\tRequested to Stop the adapter\n");
498 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
501 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
506 if (function
== SRB_FUNCTION_EXECUTE_SCSI
)
508 // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
509 // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
510 // routine does the following:
512 // - Gets and/or sets up whatever context the miniport driver maintains in its device,
513 // logical unit, and/or SRB extensions
514 // For example, a miniport driver might set up a logical unit extension with pointers
515 // to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value,
516 // and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be
517 // carried out on the HBA.
519 // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags,
520 // for the requested operation
521 // For a device I/O operation, such an internal routine generally selects the target device
522 // and sends the CDB over the bus to the target logical unit.
523 if (Srb
->CdbLength
> 0)
525 PCDB cdb
= (PCDB
)&Srb
->Cdb
;
526 if (cdb
->CDB10
.OperationCode
== SCSIOP_INQUIRY
)
528 Srb
->SrbStatus
= DeviceInquiryRequest(adapterExtension
, Srb
, cdb
);
532 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
537 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
540 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
544 DebugPrint("\tUnknown function code recieved: %x\n", function
);
545 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
546 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
548 }// -- AhciHwStartIo();
551 * @name AhciHwResetBus
554 * The HwStorResetBus routine is called by the port driver to clear error conditions.
556 * @param adapterExtension
560 * return TRUE if bus was successfully reset
564 __in PVOID AdapterExtension
,
568 STOR_LOCK_HANDLE lockhandle
;
569 PAHCI_ADAPTER_EXTENSION adapterExtension
;
571 DebugPrint("AhciHwResetBus()\n");
573 adapterExtension
= AdapterExtension
;
575 if (IsPortValid(AdapterExtension
, PathId
))
577 AhciZeroMemory(&lockhandle
, sizeof(lockhandle
));
580 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
582 // TODO: Perform port reset
585 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
589 }// -- AhciHwResetBus();
592 * @name AhciHwFindAdapter
595 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
596 * HBA is supported and, if it is, to return configuration information about that adapter.
598 * 10.1 Platform Communication
599 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
601 * @param DeviceExtension
603 * @param BusInformation
604 * @param ArgumentString
610 * Indicates that a supported HBA was found and that the HBA-relevant configuration information was successfully determined and set in the PORT_CONFIGURATION_INFORMATION structure.
613 * Indicates that an HBA was found but there was an error obtaining the configuration information. If possible, such an error should be logged with StorPortLogError.
615 * SP_RETURN_BAD_CONFIG
616 * Indicates that the supplied configuration information was invalid for the adapter.
618 * SP_RETURN_NOT_FOUND
619 * Indicates that no supported HBA was found for the supplied configuration information.
621 * @remarks Called by Storport.
625 __in PVOID AdapterExtension
,
626 __in PVOID HwContext
,
627 __in PVOID BusInformation
,
628 __in PVOID ArgumentString
,
629 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
630 __in PBOOLEAN Reserved3
635 ULONG portCount
, portImplemented
;
637 UCHAR pci_cfg_buf
[sizeof(PCI_COMMON_CONFIG
)];
638 PACCESS_RANGE accessRange
;
640 PAHCI_MEMORY_REGISTERS abar
;
641 PPCI_COMMON_CONFIG pciConfigData
;
642 PAHCI_ADAPTER_EXTENSION adapterExtension
;
644 DebugPrint("AhciHwFindAdapter()\n");
646 adapterExtension
= AdapterExtension
;
647 adapterExtension
->SlotNumber
= ConfigInfo
->SlotNumber
;
648 adapterExtension
->SystemIoBusNumber
= ConfigInfo
->SystemIoBusNumber
;
650 // get PCI configuration header
651 pci_cfg_len
= StorPortGetBusData(
654 adapterExtension
->SystemIoBusNumber
,
655 adapterExtension
->SlotNumber
,
657 sizeof(PCI_COMMON_CONFIG
));
659 if (pci_cfg_len
!= sizeof(PCI_COMMON_CONFIG
))
661 DebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG
), pci_cfg_len
);
662 return SP_RETURN_ERROR
;//Not a valid device at the given bus number
665 pciConfigData
= pci_cfg_buf
;
666 adapterExtension
->VendorID
= pciConfigData
->VendorID
;
667 adapterExtension
->DeviceID
= pciConfigData
->DeviceID
;
668 adapterExtension
->RevisionID
= pciConfigData
->RevisionID
;
669 // The last PCI base address register (BAR[5], header offset 0x24) points to the AHCI base memory, it’s called ABAR (AHCI Base Memory Register).
670 adapterExtension
->AhciBaseAddress
= pciConfigData
->u
.type0
.BaseAddresses
[5] & (0xFFFFFFF0);
672 DebugPrint("\tVendorID:%d DeviceID:%d RevisionID:%d\n", adapterExtension
->VendorID
,
673 adapterExtension
->DeviceID
,
674 adapterExtension
->RevisionID
);
678 if (ConfigInfo
->NumberOfAccessRanges
> 0)
680 for (index
= 0; index
< ConfigInfo
->NumberOfAccessRanges
; index
++)
682 accessRange
= *ConfigInfo
->AccessRanges
;
683 if (accessRange
[index
].RangeStart
.QuadPart
== adapterExtension
->AhciBaseAddress
)
685 abar
= StorPortGetDeviceBase(adapterExtension
,
686 ConfigInfo
->AdapterInterfaceType
,
687 ConfigInfo
->SystemIoBusNumber
,
688 accessRange
[index
].RangeStart
,
689 accessRange
[index
].RangeLength
,
690 !accessRange
[index
].RangeInMemory
);
698 DebugPrint("\tabar == NULL\n");
699 return SP_RETURN_ERROR
; // corrupted information supplied
702 adapterExtension
->ABAR_Address
= abar
;
703 adapterExtension
->CAP
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP
);
704 adapterExtension
->CAP2
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP2
);
705 adapterExtension
->Version
= StorPortReadRegisterUlong(adapterExtension
, &abar
->VS
);
706 adapterExtension
->LastInterruptPort
= -1;
709 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
710 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
711 ghc
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
712 // AE := Highest Significant bit of GHC
713 if ((ghc
& AHCI_Global_HBA_CONTROL_AE
) != 0)// Hmm, controller was already in power state
715 // reset controller to have it in known state
716 DebugPrint("\tAE Already set, Reset()\n");
717 if (!AhciAdapterReset(adapterExtension
))
719 DebugPrint("\tReset Failed!\n");
720 return SP_RETURN_ERROR
;// reset failed
724 ghc
= AHCI_Global_HBA_CONTROL_AE
;// only AE=1
725 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
);
727 adapterExtension
->IS
= &abar
->IS
;
728 adapterExtension
->PortImplemented
= StorPortReadRegisterUlong(adapterExtension
, &abar
->PI
);
730 if (adapterExtension
->PortImplemented
== 0)
732 DebugPrint("\tadapterExtension->PortImplemented == 0\n");
733 return SP_RETURN_ERROR
;
736 ConfigInfo
->MaximumTransferLength
= MAXIMUM_TRANSFER_LENGTH
;//128 KB
737 ConfigInfo
->NumberOfPhysicalBreaks
= 0x21;
738 ConfigInfo
->MaximumNumberOfTargets
= 1;
739 ConfigInfo
->MaximumNumberOfLogicalUnits
= 1;
740 ConfigInfo
->ResetTargetSupported
= TRUE
;
741 ConfigInfo
->NumberOfBuses
= MAXIMUM_AHCI_PORT_COUNT
;
742 ConfigInfo
->SynchronizationModel
= StorSynchronizeFullDuplex
;
743 ConfigInfo
->ScatterGather
= TRUE
;
745 // Turn IE -- Interrupt Enabled
746 ghc
|= AHCI_Global_HBA_CONTROL_IE
;
747 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
);
749 // allocate necessary resource for each port
750 if (!AhciAllocateResourceForAdapter(adapterExtension
, ConfigInfo
))
752 DebugPrint("\tAhciAllocateResourceForAdapter() == FALSE\n");
753 return SP_RETURN_ERROR
;
756 for (index
= 0; index
< adapterExtension
->PortCount
; index
++)
758 if ((adapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
759 AhciPortInitialize(&adapterExtension
->PortExtension
[index
]);
762 return SP_RETURN_FOUND
;
763 }// -- AhciHwFindAdapter();
769 * Initial Entrypoint for storahci miniport driver
771 * @param DriverObject
772 * @param RegistryPath
775 * NT_STATUS in case of driver loaded successfully.
779 __in PVOID DriverObject
,
780 __in PVOID RegistryPath
783 HW_INITIALIZATION_DATA hwInitializationData
;
786 DebugPrint("Storahci Loaded\n");
788 // initialize the hardware data structure
789 AhciZeroMemory(&hwInitializationData
, sizeof(HW_INITIALIZATION_DATA
));
791 // set size of hardware initialization structure
792 hwInitializationData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
794 // identity required miniport entry point routines
795 hwInitializationData
.HwStartIo
= AhciHwStartIo
;
796 hwInitializationData
.HwResetBus
= AhciHwResetBus
;
797 hwInitializationData
.HwInterrupt
= AhciHwInterrupt
;
798 hwInitializationData
.HwInitialize
= AhciHwInitialize
;
799 hwInitializationData
.HwFindAdapter
= AhciHwFindAdapter
;
801 // adapter specific information
802 hwInitializationData
.NeedPhysicalAddresses
= TRUE
;
803 hwInitializationData
.TaggedQueuing
= TRUE
;
804 hwInitializationData
.AutoRequestSense
= TRUE
;
805 hwInitializationData
.MultipleRequestPerLu
= TRUE
;
807 hwInitializationData
.NumberOfAccessRanges
= 6;
808 hwInitializationData
.AdapterInterfaceType
= PCIBus
;
809 hwInitializationData
.MapBuffers
= STOR_MAP_NON_READ_WRITE_BUFFERS
;
811 // set required extension sizes
812 hwInitializationData
.SrbExtensionSize
= sizeof(AHCI_SRB_EXTENSION
);
813 hwInitializationData
.DeviceExtensionSize
= sizeof(AHCI_ADAPTER_EXTENSION
);
815 // register our hw init data
816 status
= StorPortInitialize(DriverObject
,
818 &hwInitializationData
,
821 DebugPrint("\tstatus:%x\n", status
);
823 }// -- DriverEntry();
829 * create ATA CFIS from Srb
831 * @param PortExtension
837 __in PAHCI_PORT_EXTENSION PortExtension
,
838 __in PAHCI_SRB_EXTENSION SrbExtension
841 PAHCI_COMMAND_TABLE cmdTable
;
843 DebugPrint("AhciATA_CFIS()\n");
845 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
847 NT_ASSERT(sizeof(cmdTable
->CFIS
) == 64);
849 AhciZeroMemory(&cmdTable
->CFIS
, sizeof(cmdTable
->CFIS
));
851 cmdTable
->CFIS
[AHCI_ATA_CFIS_FisType
] = 0x27; // FIS Type
852 cmdTable
->CFIS
[AHCI_ATA_CFIS_PMPort_C
] = (1 << 7); // PM Port & C
853 cmdTable
->CFIS
[AHCI_ATA_CFIS_CommandReg
] = SrbExtension
->CommandReg
;
855 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesLow
] = SrbExtension
->FeaturesLow
;
856 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA0
] = SrbExtension
->LBA0
;
857 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA1
] = SrbExtension
->LBA1
;
858 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA2
] = SrbExtension
->LBA2
;
859 cmdTable
->CFIS
[AHCI_ATA_CFIS_Device
] = SrbExtension
->Device
;
860 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA3
] = SrbExtension
->LBA3
;
861 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA4
] = SrbExtension
->LBA4
;
862 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA5
] = SrbExtension
->LBA5
;
863 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesHigh
] = SrbExtension
->FeaturesHigh
;
864 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountLow
] = SrbExtension
->SectorCountLow
;
865 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountHigh
] = SrbExtension
->SectorCountHigh
;
868 }// -- AhciATA_CFIS();
871 * @name AhciATAPI_CFIS
874 * create ATAPI CFIS from Srb
876 * @param PortExtension
882 __in PAHCI_PORT_EXTENSION PortExtension
,
883 __in PAHCI_SRB_EXTENSION SrbExtension
886 DebugPrint("AhciATAPI_CFIS()\n");
888 }// -- AhciATAPI_CFIS();
891 * @name AhciBuild_PRDT
894 * Build PRDT for data transfer
896 * @param PortExtension
900 * Return number of entries in PRDT.
904 __in PAHCI_PORT_EXTENSION PortExtension
,
905 __in PAHCI_SRB_EXTENSION SrbExtension
909 PAHCI_COMMAND_TABLE cmdTable
;
910 PLOCAL_SCATTER_GATHER_LIST sgl
;
911 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
913 DebugPrint("AhciBuild_PRDT()\n");
915 sgl
= &SrbExtension
->Sgl
;
916 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
917 AdapterExtension
= PortExtension
->AdapterExtension
;
919 NT_ASSERT(sgl
!= NULL
);
920 NT_ASSERT(sgl
->NumberOfElements
< MAXIMUM_AHCI_PRDT_ENTRIES
);
922 for (index
= 0; index
< sgl
->NumberOfElements
; index
++)
924 NT_ASSERT(sgl
->List
[index
].Length
<= MAXIMUM_TRANSFER_LENGTH
);
926 cmdTable
->PRDT
[index
].DBA
= sgl
->List
[index
].PhysicalAddress
.LowPart
;
927 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
929 cmdTable
->PRDT
[index
].DBAU
= sgl
->List
[index
].PhysicalAddress
.HighPart
;
933 return sgl
->NumberOfElements
;
934 }// -- AhciBuild_PRDT();
937 * @name AhciProcessSrb
940 * Prepare Srb for IO processing
942 * @param PortExtension
949 __in PAHCI_PORT_EXTENSION PortExtension
,
950 __in PSCSI_REQUEST_BLOCK Srb
,
954 ULONG prdtlen
, sig
, length
;
955 PAHCI_SRB_EXTENSION SrbExtension
;
956 PAHCI_COMMAND_HEADER CommandHeader
;
957 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
958 STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress
;
960 DebugPrint("AhciProcessSrb()\n");
962 NT_ASSERT(Srb
->PathId
== PortExtension
->PortNumber
);
964 SrbExtension
= GetSrbExtension(Srb
);
965 AdapterExtension
= PortExtension
->AdapterExtension
;
967 NT_ASSERT(SrbExtension
!= NULL
);
968 NT_ASSERT(SrbExtension
->AtaFunction
!= 0);
970 if ((SrbExtension
->AtaFunction
== ATA_FUNCTION_ATA_IDENTIFY
) &&
971 (SrbExtension
->CommandReg
== IDE_COMMAND_NOT_VALID
))
973 // Here we are safe to check SIG register
974 sig
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SIG
);
977 SrbExtension
->CommandReg
= IDE_COMMAND_IDENTIFY
;
981 SrbExtension
->CommandReg
= IDE_COMMAND_ATAPI_IDENTIFY
;
985 NT_ASSERT(SlotIndex
< AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
986 SrbExtension
->SlotIndex
= SlotIndex
;
988 // program the CFIS in the CommandTable
989 CommandHeader
= &PortExtension
->CommandList
[SlotIndex
];
991 if (IsAtaCommand(SrbExtension
->AtaFunction
))
993 AhciATA_CFIS(PortExtension
, SrbExtension
);
995 else if (IsAtapiCommand(SrbExtension
->AtaFunction
))
997 AhciATAPI_CFIS(PortExtension
, SrbExtension
);
1001 if (IsDataTransferNeeded(SrbExtension
))
1003 prdtlen
= AhciBuild_PRDT(PortExtension
, SrbExtension
);
1004 NT_ASSERT(prdtlen
!= -1);
1007 // Program the command header
1008 CommandHeader
->DI
.PRDTL
= prdtlen
; // number of entries in PRD table
1009 CommandHeader
->DI
.CFL
= 5;
1010 CommandHeader
->DI
.W
= (SrbExtension
->Flags
& ATA_FLAGS_DATA_OUT
) ? 1 : 0;
1011 CommandHeader
->DI
.P
= 0; // ATA Specifications says so
1012 CommandHeader
->DI
.PMP
= 0; // Port Multiplier
1014 // Reset -- Manual Configuation
1015 CommandHeader
->DI
.R
= 0;
1016 CommandHeader
->DI
.B
= 0;
1017 CommandHeader
->DI
.C
= 0;
1019 CommandHeader
->PRDBC
= 0;
1021 CommandHeader
->Reserved
[0] = 0;
1022 CommandHeader
->Reserved
[1] = 0;
1023 CommandHeader
->Reserved
[2] = 0;
1024 CommandHeader
->Reserved
[3] = 0;
1026 // set CommandHeader CTBA
1027 // I am really not sure if SrbExtension is 128 byte aligned or not
1028 // Command FIS will not work if it is not so.
1029 CommandTablePhysicalAddress
= StorPortGetPhysicalAddress(AdapterExtension
,
1034 // command table alignment
1035 NT_ASSERT((CommandTablePhysicalAddress
.LowPart
% 128) == 0);
1037 CommandHeader
->CTBA0
= CommandTablePhysicalAddress
.LowPart
;
1039 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1041 CommandHeader
->CTBA_U0
= CommandTablePhysicalAddress
.HighPart
;
1045 PortExtension
->Slot
[SlotIndex
] = Srb
;
1046 PortExtension
->QueueSlots
|= SlotIndex
;
1048 }// -- AhciProcessSrb();
1051 * @name AhciActivatePort
1054 * Program Port and populate command list
1056 * @param PortExtension
1061 __in PAHCI_PORT_EXTENSION PortExtension
1064 ULONG cmd
, QueueSlots
, slotToActivate
, tmp
;
1065 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1067 DebugPrint("AhciActivatePort()\n");
1069 AdapterExtension
= PortExtension
->AdapterExtension
;
1070 QueueSlots
= PortExtension
->QueueSlots
;
1072 if (QueueSlots
== 0)
1076 // Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’
1077 cmd
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
1079 if ((cmd
&1) == 0) // PxCMD.ST == 0
1082 // get the lowest set bit
1083 tmp
= QueueSlots
& (QueueSlots
- 1);
1086 slotToActivate
= QueueSlots
;
1088 slotToActivate
= (QueueSlots
& (~tmp
));
1090 // mark that bit off in QueueSlots
1091 // so we can know we it is really needed to activate port or not
1092 PortExtension
->QueueSlots
&= ~slotToActivate
;
1093 // mark this CommandIssuedSlots
1094 // to validate in completeIssuedCommand
1095 PortExtension
->CommandIssuedSlots
|= slotToActivate
;
1097 // tell the HBA to issue this Command Slot to the given port
1098 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
, slotToActivate
);
1101 }// -- AhciActivatePort();
1104 * @name AhciProcessIO
1107 * Acquire Exclusive lock to port, populate pending commands to command List
1108 * program controller's port to process new commands in command list.
1110 * @param AdapterExtension
1117 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1119 __in PSCSI_REQUEST_BLOCK Srb
1122 STOR_LOCK_HANDLE lockhandle
;
1123 PSCSI_REQUEST_BLOCK tmpSrb
;
1124 PAHCI_PORT_EXTENSION PortExtension
;
1125 ULONG commandSlotMask
, occupiedSlots
, slotIndex
, NCS
;
1127 DebugPrint("AhciProcessIO()\n");
1128 DebugPrint("\tPathId: %d\n", PathId
);
1130 PortExtension
= &AdapterExtension
->PortExtension
[PathId
];
1132 NT_ASSERT(PathId
< AdapterExtension
->PortCount
);
1135 AddQueue(&PortExtension
->SrbQueue
, Srb
);
1137 if (PortExtension
->IsActive
== FALSE
)
1138 return; // we should wait for device to get active
1140 AhciZeroMemory(&lockhandle
, sizeof(lockhandle
));
1143 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
1145 occupiedSlots
= (PortExtension
->QueueSlots
| PortExtension
->CommandIssuedSlots
); // Busy command slots for given port
1146 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
1147 commandSlotMask
= (1 << NCS
) - 1; // available slots mask
1149 commandSlotMask
= (commandSlotMask
& ~occupiedSlots
);
1150 if(commandSlotMask
!= 0)
1152 // iterate over HBA port slots
1153 for (slotIndex
= 0; slotIndex
< NCS
; slotIndex
++)
1155 // find first free slot
1156 if ((commandSlotMask
& (1 << slotIndex
)) != 0)
1158 tmpSrb
= RemoveQueue(&PortExtension
->SrbQueue
);
1161 NT_ASSERT(tmpSrb
->PathId
== PathId
);
1162 AhciProcessSrb(PortExtension
, tmpSrb
, slotIndex
);
1177 AhciActivatePort(PortExtension
);
1180 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
1183 }// -- AhciProcessIO();
1186 * @name InquiryCompletion
1189 * InquiryCompletion routine should be called after device signals
1190 * for device inquiry request is completed (through interrupt)
1192 * @param PortExtension
1198 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1199 __in PAHCI_PORT_EXTENSION PortExtension
,
1200 __in PSCSI_REQUEST_BLOCK Srb
1204 PAHCI_SRB_EXTENSION SrbExtension
;
1206 DebugPrint("InquiryCompletion()\n");
1208 NT_ASSERT(PortExtension
!= NULL
);
1209 NT_ASSERT(Srb
!= NULL
);
1211 SrbStatus
= Srb
->SrbStatus
;
1212 SrbExtension
= GetSrbExtension(Srb
);
1214 if (SrbStatus
== SRB_STATUS_SUCCESS
)
1216 if (SrbExtension
->CommandReg
== IDE_COMMAND_IDENTIFY
)
1218 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATA
;
1222 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATAPI
;
1224 // TODO: Set Device Paramters
1226 else if (SrbStatus
== SRB_STATUS_NO_DEVICE
)
1228 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_NODEVICE
;
1236 }// -- InquiryCompletion();
1239 * @name DeviceInquiryRequest
1242 * Tells wheather given port is implemented or not
1244 * @param AdapterExtension
1249 * return STOR status for DeviceInquiryRequest
1252 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
1255 DeviceInquiryRequest (
1256 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1257 __in PSCSI_REQUEST_BLOCK Srb
,
1262 ULONG DataBufferLength
;
1263 PAHCI_PORT_EXTENSION PortExtension
;
1264 PAHCI_SRB_EXTENSION SrbExtension
;
1266 DebugPrint("DeviceInquiryRequest()\n");
1268 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
1270 SrbExtension
= GetSrbExtension(Srb
);
1271 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1274 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
1275 if (Cdb
->CDB6INQUIRY3
.EnableVitalProductData
== 0)
1277 DebugPrint("\tEVPD Inquired\n");
1278 NT_ASSERT(SrbExtension
!= NULL
);
1280 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATA_IDENTIFY
;
1281 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
1282 SrbExtension
->CompletionRoutine
= InquiryCompletion
;
1283 SrbExtension
->CommandReg
= IDE_COMMAND_NOT_VALID
;
1285 // TODO: Should use AhciZeroMemory
1286 SrbExtension
->FeaturesLow
= 0;
1287 SrbExtension
->LBA0
= 0;
1288 SrbExtension
->LBA1
= 0;
1289 SrbExtension
->LBA2
= 0;
1290 SrbExtension
->Device
= 0;
1291 SrbExtension
->LBA3
= 0;
1292 SrbExtension
->LBA4
= 0;
1293 SrbExtension
->LBA5
= 0;
1294 SrbExtension
->FeaturesHigh
= 0;
1295 SrbExtension
->SectorCountLow
= 0;
1296 SrbExtension
->SectorCountHigh
= 0;
1298 SrbExtension
->Sgl
.NumberOfElements
= 1;
1299 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.LowPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.LowPart
;
1300 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.HighPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.HighPart
;
1301 SrbExtension
->Sgl
.List
[0].Length
= sizeof(IDENTIFY_DEVICE_DATA
);
1305 DebugPrint("\tVPD Inquired\n");
1307 DataBuffer
= Srb
->DataBuffer
;
1308 DataBufferLength
= Srb
->DataTransferLength
;
1310 if (DataBuffer
== NULL
)
1312 return SRB_STATUS_INVALID_REQUEST
;
1315 AhciZeroMemory(DataBuffer
, DataBufferLength
);
1318 return SRB_STATUS_BAD_FUNCTION
;
1321 AhciProcessIO(AdapterExtension
, Srb
->PathId
, Srb
);
1322 return SRB_STATUS_PENDING
;
1323 }// -- DeviceInquiryRequest();
1326 * @name AhciAdapterReset
1330 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
1331 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
1332 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
1333 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
1334 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
1335 * the HBA reset has completed.
1336 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
1337 * a hung or locked state.
1339 * @param AdapterExtension
1342 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
1346 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
1349 ULONG ghc
, ticks
, ghcStatus
;
1350 PAHCI_MEMORY_REGISTERS abar
= NULL
;
1352 DebugPrint("AhciAdapterReset()\n");
1354 abar
= AdapterExtension
->ABAR_Address
;
1355 if (abar
== NULL
) // basic sanity
1360 // HR -- Very first bit (lowest significant)
1361 ghc
= AHCI_Global_HBA_CONTROL_HR
;
1362 StorPortWriteRegisterUlong(AdapterExtension
, &abar
->GHC
, ghc
);
1364 for (ticks
= 0; ticks
< 50; ++ticks
)
1366 ghcStatus
= StorPortReadRegisterUlong(AdapterExtension
, &abar
->GHC
);
1367 if ((ghcStatus
& AHCI_Global_HBA_CONTROL_HR
) == 0)
1371 StorPortStallExecution(20000);
1374 if (ticks
== 50)// 1 second
1376 DebugPrint("\tDevice Timeout\n");
1381 }// -- AhciAdapterReset();
1384 * @name AhciZeroMemory
1387 * Clear buffer by filling zeros
1396 __in ULONG BufferSize
1400 for (i
= 0; i
< BufferSize
; i
++)
1406 }// -- AhciZeroMemory();
1412 * Tells wheather given port is implemented or not
1414 * @param AdapterExtension
1418 * return TRUE if provided port is valid (implemented) or not
1423 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1427 NT_ASSERT(pathId
>= 0);
1429 if (pathId
>= AdapterExtension
->PortCount
)
1434 return AdapterExtension
->PortExtension
[pathId
].IsActive
;
1435 }// -- IsPortValid()
1447 * return TRUE if Srb is successfully added to Queue
1453 __inout PAHCI_QUEUE Queue
,
1457 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1458 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1460 if (Queue
->Tail
== ((Queue
->Head
+ 1) % MAXIMUM_QUEUE_BUFFER_SIZE
))
1463 Queue
->Buffer
[Queue
->Head
++] = Srb
;
1464 Queue
->Head
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
1473 * Remove and return Srb from Queue
1484 __inout PAHCI_QUEUE Queue
1489 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1490 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1492 if (Queue
->Head
== Queue
->Tail
)
1495 Srb
= Queue
->Buffer
[Queue
->Tail
++];
1496 Queue
->Tail
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
1499 }// -- RemoveQueue();
1502 * @name GetSrbExtension
1505 * GetSrbExtension from Srb make sure It is properly aligned
1510 * return SrbExtension
1516 __in PSCSI_REQUEST_BLOCK Srb
1520 ULONG_PTR SrbExtension
;
1522 SrbExtension
= Srb
->SrbExtension
;
1523 Offset
= SrbExtension
% 128;
1525 // CommandTable should be 128 byte aligned
1527 Offset
= 128 - Offset
;
1529 return (PAHCI_SRB_EXTENSION
)(SrbExtension
+ Offset
);
1530 }// -- PAHCI_SRB_EXTENSION();