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
27 ULONG mappedLength
, portNumber
;
28 PAHCI_MEMORY_REGISTERS abar
;
29 PAHCI_ADAPTER_EXTENSION adapterExtension
;
30 STOR_PHYSICAL_ADDRESS commandListPhysical
, receivedFISPhysical
;
32 DebugPrint("AhciPortInitialize()\n");
34 adapterExtension
= PortExtension
->AdapterExtension
;
35 abar
= adapterExtension
->ABAR_Address
;
36 portNumber
= PortExtension
->PortNumber
;
38 NT_ASSERT(abar
!= NULL
);
39 NT_ASSERT(portNumber
< adapterExtension
->PortCount
);
41 PortExtension
->Port
= &abar
->PortList
[portNumber
];
43 commandListPhysical
= StorPortGetPhysicalAddress(adapterExtension
,
45 PortExtension
->CommandList
,
48 if ((mappedLength
== 0) || ((commandListPhysical
.LowPart
% 1024) != 0))
50 DebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength
);
54 receivedFISPhysical
= StorPortGetPhysicalAddress(adapterExtension
,
56 PortExtension
->ReceivedFIS
,
59 if ((mappedLength
== 0) || ((receivedFISPhysical
.LowPart
% 256) != 0))
61 DebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength
);
65 // Ensure that the controller is not in the running state by reading and examining each
66 // implemented port’s PxCMD register. If PxCMD.ST, PxCMD.CR, PxCMD.FRE and
67 // PxCMD.FR are all cleared, the port is in an idle state. Otherwise, the port is not idle and
68 // should be placed in the idle state prior to manipulating HBA and port specific registers.
69 // System software places a port into the idle state by clearing PxCMD.ST and waiting for
70 // PxCMD.CR to return ‘0’ when read. Software should wait at least 500 milliseconds for
71 // this to occur. If PxCMD.FRE is set to ‘1’, software should clear it to ‘0’ and wait at least
72 // 500 milliseconds for PxCMD.FR to return ‘0’ when read. If PxCMD.CR or PxCMD.FR do
73 // not clear to ‘0’ correctly, then software may attempt a port reset or a full HBA reset to recove
75 // TODO: Check if port is in idle state or not, if not then restart port
76 cmd
.Status
= StorPortReadRegisterUlong(adapterExtension
, &PortExtension
->Port
->CMD
);
77 if ((cmd
.FR
!= 0) || (cmd
.CR
!= 0) || (cmd
.FRE
!= 0) || (cmd
.ST
!= 0))
79 DebugPrint("\tPort is not idle: %x\n", cmd
);
82 // 10.1.2 For each implemented port, system software shall allocate memory for and program:
83 // PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
84 // PxFB and PxFBU (if CAP.S64A is set to ‘1’)
85 // Note: Assuming 32bit support only
86 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->CLB
, commandListPhysical
.LowPart
);
87 if (IsAdapterCAPS64(adapterExtension
->CAP
))
89 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->CLBU
, commandListPhysical
.HighPart
);
92 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->FB
, receivedFISPhysical
.LowPart
);
93 if (IsAdapterCAPS64(adapterExtension
->CAP
))
95 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->FBU
, receivedFISPhysical
.HighPart
);
98 PortExtension
->IdentifyDeviceDataPhysicalAddress
= StorPortGetPhysicalAddress(adapterExtension
,
100 PortExtension
->IdentifyDeviceData
,
103 // set device power state flag to D0
104 PortExtension
->DevicePowerState
= StorPowerDeviceD0
;
106 // clear pending interrupts
107 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->SERR
, (ULONG
)~0);
108 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->IS
, (ULONG
)~0);
109 StorPortWriteRegisterUlong(adapterExtension
, adapterExtension
->IS
, (1 << PortExtension
->PortNumber
));
112 }// -- AhciPortInitialize();
115 * @name AhciAllocateResourceForAdapter
118 * Allocate memory from poll for required pointers
120 * @param AdapterExtension
124 * return TRUE if allocation was successful
127 AhciAllocateResourceForAdapter (
128 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
129 __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
132 PCHAR nonCachedExtension
, tmp
;
133 ULONG index
, NCS
, AlignedNCS
;
134 ULONG portCount
, portImplemented
, nonCachedExtensionSize
;
136 DebugPrint("AhciAllocateResourceForAdapter()\n");
138 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
139 AlignedNCS
= ROUND_UP(NCS
, 8);
141 // get port count -- Number of set bits in `AdapterExtension->PortImplemented`
143 portImplemented
= AdapterExtension
->PortImplemented
;
145 NT_ASSERT(portImplemented
!= 0);
146 for (index
= MAXIMUM_AHCI_PORT_COUNT
- 1; index
> 0; index
--)
147 if ((portImplemented
& (1 << index
)) != 0)
150 portCount
= index
+ 1;
151 DebugPrint("\tPort Count: %d\n", portCount
);
153 AdapterExtension
->PortCount
= portCount
;
154 nonCachedExtensionSize
= sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
+ //should be 1K aligned
155 sizeof(AHCI_RECEIVED_FIS
) +
156 sizeof(IDENTIFY_DEVICE_DATA
);
158 // align nonCachedExtensionSize to 1024
159 nonCachedExtensionSize
= ROUND_UP(nonCachedExtensionSize
, 1024);
161 AdapterExtension
->NonCachedExtension
= StorPortGetUncachedExtension(AdapterExtension
,
163 nonCachedExtensionSize
* portCount
);
165 if (AdapterExtension
->NonCachedExtension
== NULL
)
167 DebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
171 nonCachedExtension
= AdapterExtension
->NonCachedExtension
;
172 AhciZeroMemory(nonCachedExtension
, nonCachedExtensionSize
* portCount
);
174 for (index
= 0; index
< portCount
; index
++)
176 AdapterExtension
->PortExtension
[index
].IsActive
= FALSE
;
177 if ((AdapterExtension
->PortImplemented
& (1 << index
)) != 0)
179 AdapterExtension
->PortExtension
[index
].PortNumber
= index
;
180 AdapterExtension
->PortExtension
[index
].IsActive
= TRUE
;
181 AdapterExtension
->PortExtension
[index
].AdapterExtension
= AdapterExtension
;
182 AdapterExtension
->PortExtension
[index
].CommandList
= (PAHCI_COMMAND_HEADER
)nonCachedExtension
;
184 tmp
= (PCHAR
)(nonCachedExtension
+ sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
);
186 AdapterExtension
->PortExtension
[index
].ReceivedFIS
= (PAHCI_RECEIVED_FIS
)tmp
;
187 AdapterExtension
->PortExtension
[index
].IdentifyDeviceData
= (PIDENTIFY_DEVICE_DATA
)(tmp
+ sizeof(AHCI_RECEIVED_FIS
));
188 nonCachedExtension
+= nonCachedExtensionSize
;
193 }// -- AhciAllocateResourceForAdapter();
196 * @name AhciStartPort
199 * Try to start the port device
201 * @param AdapterExtension
202 * @param PortExtension
207 __in PAHCI_PORT_EXTENSION PortExtension
212 AHCI_SERIAL_ATA_STATUS ssts
;
213 AHCI_SERIAL_ATA_CONTROL sctl
;
214 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
216 DebugPrint("AhciStartPort()\n");
218 AdapterExtension
= PortExtension
->AdapterExtension
;
219 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
221 if ((cmd
.FR
== 1) && (cmd
.CR
== 1) && (cmd
.FRE
== 1) && (cmd
.ST
== 1))
228 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
, cmd
.Status
);
230 if (((cmd
.FR
== 1) && (cmd
.FRE
== 0)) ||
231 ((cmd
.CR
== 1) && (cmd
.ST
== 0)))
233 DebugPrint("\tCOMRESET\n");
237 // Software causes a port reset (COMRESET) by writing 1h to the PxSCTL.DET field to invoke a
238 // COMRESET on the interface and start a re-establishment of Phy layer communications. Software shall
239 // wait at least 1 millisecond before clearing PxSCTL.DET to 0h; this ensures that at least one COMRESET
240 // signal is sent over the interface. After clearing PxSCTL.DET to 0h, software should wait for
241 // communication to be re-established as indicated by PxSSTS.DET being set to 3h. Then software should
242 // write all 1s to the PxSERR register to clear any bits that were set as part of the port reset.
244 sctl
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
);
246 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
, sctl
.Status
);
248 StorPortStallExecution(1000);
250 sctl
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
);
252 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
, sctl
.Status
);
254 // Poll DET to verify if a device is attached to the port
258 StorPortStallExecution(1000);
259 ssts
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SSTS
);
270 ssts
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SSTS
);
277 DebugPrint("\tDET: %d %d\n", ssts
.DET
, cmd
.ST
);
279 }// -- AhciStartPort();
282 * @name AhciHwInitialize
285 * initializes the HBA and finds all devices that are of interest to the miniport driver.
287 * @param adapterExtension
290 * return TRUE if intialization was successful
294 __in PVOID AdapterExtension
298 PAHCI_PORT_EXTENSION PortExtension
;
299 PAHCI_ADAPTER_EXTENSION adapterExtension
;
301 DebugPrint("AhciHwInitialize()\n");
303 adapterExtension
= AdapterExtension
;
304 adapterExtension
->StateFlags
.MessagePerPort
= FALSE
;
306 // First check what type of interrupt/synchronization device is using
307 ghc
= StorPortReadRegisterUlong(adapterExtension
, &adapterExtension
->ABAR_Address
->GHC
);
309 // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector
310 // but has reverted to using the first vector only. When this bit is cleared to ‘0’,
311 // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
312 // software has allocated the number of messages requested
313 if ((ghc
& AHCI_Global_HBA_CONTROL_MRSM
) == 0)
315 adapterExtension
->StateFlags
.MessagePerPort
= TRUE
;
316 DebugPrint("\tMultiple MSI based message not supported\n");
319 for (index
= 0; index
< adapterExtension
->PortCount
; index
++)
321 if ((adapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
323 PortExtension
= &adapterExtension
->PortExtension
[index
];
324 PortExtension
->IsActive
= AhciStartPort(PortExtension
);
325 if (PortExtension
->IsActive
== FALSE
)
327 DebugPrint("\tPort Disabled: %d\n", index
);
333 }// -- AhciHwInitialize();
336 * @name AhciCompleteIssuedSrb
339 * Complete issued Srbs
341 * @param PortExtension
345 AhciCompleteIssuedSrb (
346 __in PAHCI_PORT_EXTENSION PortExtension
,
347 __in ULONG CommandsToComplete
351 PSCSI_REQUEST_BLOCK Srb
;
352 PAHCI_SRB_EXTENSION SrbExtension
;
353 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
354 PAHCI_COMPLETION_ROUTINE CompletionRoutine
;
356 DebugPrint("AhciCompleteIssuedSrb()\n");
358 NT_ASSERT(CommandsToComplete
!= 0);
360 DebugPrint("\tCompleted Commands: %d\n", CommandsToComplete
);
362 AdapterExtension
= PortExtension
->AdapterExtension
;
363 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
365 for (i
= 0; i
< NCS
; i
++)
367 if (((1 << i
) & CommandsToComplete
) != 0)
369 Srb
= PortExtension
->Slot
[i
];
370 NT_ASSERT(Srb
!= NULL
);
372 if (Srb
->SrbStatus
== SRB_STATUS_PENDING
)
374 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
377 SrbExtension
= GetSrbExtension(Srb
);
378 CompletionRoutine
= SrbExtension
->CompletionRoutine
;
380 if (CompletionRoutine
!= NULL
)
382 // now it's completion routine responsibility to set SrbStatus
383 CompletionRoutine(AdapterExtension
, PortExtension
, Srb
);
387 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
388 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
394 }// -- AhciCompleteIssuedSrb();
397 * @name AhciInterruptHandler
400 * Interrupt Handler for PortExtension
402 * @param PortExtension
406 AhciInterruptHandler (
407 __in PAHCI_PORT_EXTENSION PortExtension
410 ULONG is
, ci
, sact
, outstanding
;
411 AHCI_INTERRUPT_STATUS PxIS
;
412 AHCI_INTERRUPT_STATUS PxISMasked
;
413 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
415 DebugPrint("AhciInterruptHandler()\n");
416 DebugPrint("\tPort Number: %d\n", PortExtension
->PortNumber
);
418 AdapterExtension
= PortExtension
->AdapterExtension
;
419 NT_ASSERT(IsPortValid(AdapterExtension
, PortExtension
->PortNumber
));
422 // 1. Software determines the cause of the interrupt by reading the PxIS register.
423 // It is possible for multiple bits to be set
424 // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt.
425 // 3. Software clears the interrupt bit in IS.IPS corresponding to the port.
426 // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to
427 // the list of commands previously issued by software that are still outstanding.
428 // If executing native queued commands, software reads the PxSACT register and compares the current
429 // value to the list of commands previously issued by software.
430 // Software completes with success any outstanding command whose corresponding bit has been cleared in
431 // the respective register. PxCI and PxSACT are volatile registers; software should only use their values
432 // to determine commands that have completed, not to determine which commands have previously been issued.
433 // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2).
434 PxISMasked
.Status
= 0;
435 PxIS
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
);
439 // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES
440 if (PxIS
.HBFS
|| PxIS
.HBDS
|| PxIS
.IFS
|| PxIS
.TFES
)
442 // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process
443 // any native command queuing commands. To recover, the port must be restarted
444 // To detect an error that requires software recovery actions to be performed,
445 // software should check whether any of the following status bits are set on an interrupt:
446 // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set,
447 // software should perform the appropriate error recovery actions based on whether
448 // non-queued commands were being issued or native command queuing commands were being issued.
450 DebugPrint("\tFatal Error: %x\n", PxIS
.Status
);
453 // Normal Command Completion
455 // A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory.
456 PxISMasked
.DHRS
= PxIS
.DHRS
;
457 // A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory.
458 PxISMasked
.PSS
= PxIS
.PSS
;
459 // A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory.
460 PxISMasked
.DSS
= PxIS
.DSS
;
461 // A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/
462 PxISMasked
.SDBS
= PxIS
.SDBS
;
463 // A PRD with the ‘I’ bit set has transferred all of its data.
464 PxISMasked
.DPS
= PxIS
.DPS
;
466 if (PxISMasked
.Status
!= 0)
468 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
, PxISMasked
.Status
);
472 // Clear port interrupt
473 // It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software.
474 is
= (1 << PortExtension
->PortNumber
);
475 StorPortWriteRegisterUlong(AdapterExtension
, AdapterExtension
->IS
, is
);
477 ci
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
);
478 sact
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SACT
);
480 outstanding
= ci
| sact
; // NOTE: Including both non-NCQ and NCQ based commands
481 if ((PortExtension
->CommandIssuedSlots
& (~outstanding
)) != 0)
483 AhciCompleteIssuedSrb(PortExtension
, (PortExtension
->CommandIssuedSlots
& (~outstanding
)));
484 PortExtension
->CommandIssuedSlots
&= outstanding
;
488 }// -- AhciInterruptHandler();
491 * @name AhciHwInterrupt
494 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
496 * @param AdapterExtension
499 * return TRUE Indicates that an interrupt was pending on adapter.
500 * return FALSE Indicates the interrupt was not ours.
504 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
507 ULONG portPending
, nextPort
, i
, portCount
;
509 DebugPrint("AhciHwInterrupt()\n");
511 if (AdapterExtension
->StateFlags
.Removed
)
516 portPending
= StorPortReadRegisterUlong(AdapterExtension
, AdapterExtension
->IS
);
517 // we process interrupt for implemented ports only
518 portCount
= AdapterExtension
->PortCount
;
519 portPending
= portPending
& AdapterExtension
->PortImplemented
;
521 if (portPending
== 0)
526 for (i
= 1; i
<= portCount
; i
++)
528 nextPort
= (AdapterExtension
->LastInterruptPort
+ i
) % portCount
;
530 if ((portPending
& (0x1 << nextPort
)) == 0)
533 NT_ASSERT(IsPortValid(AdapterExtension
, nextPort
));
535 if (nextPort
== AdapterExtension
->LastInterruptPort
)
540 if (AdapterExtension
->PortExtension
[nextPort
].IsActive
== FALSE
)
545 // we can assign this interrupt to this port
546 AdapterExtension
->LastInterruptPort
= nextPort
;
547 AhciInterruptHandler(&AdapterExtension
->PortExtension
[nextPort
]);
549 // interrupt belongs to this device
550 // should always return TRUE
554 DebugPrint("\tSomething went wrong");
556 }// -- AhciHwInterrupt();
559 * @name AhciHwStartIo
562 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
564 * @param adapterExtension
568 * return TRUE if the request was accepted
569 * return FALSE if the request must be submitted later
573 __in PVOID AdapterExtension
,
574 __in PSCSI_REQUEST_BLOCK Srb
577 UCHAR function
, pathId
;
578 PAHCI_ADAPTER_EXTENSION adapterExtension
;
580 DebugPrint("AhciHwStartIo()\n");
582 pathId
= Srb
->PathId
;
583 function
= Srb
->Function
;
584 adapterExtension
= AdapterExtension
;
586 if (!IsPortValid(adapterExtension
, pathId
))
588 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
589 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
593 // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp
594 // If the function member of an SRB is set to SRB_FUNCTION_PNP,
595 // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK.
596 if (function
== SRB_FUNCTION_PNP
)
598 PSCSI_PNP_REQUEST_BLOCK pnpRequest
;
600 pnpRequest
= (PSCSI_PNP_REQUEST_BLOCK
)Srb
;
601 if ((pnpRequest
->SrbPnPFlags
& SRB_PNP_FLAGS_ADAPTER_REQUEST
) != 0)
603 if ((pnpRequest
->PnPAction
== StorRemoveDevice
) ||
604 (pnpRequest
->PnPAction
== StorSurpriseRemoval
))
606 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
607 adapterExtension
->StateFlags
.Removed
= 1;
608 DebugPrint("\tAdapter removed\n");
610 else if (pnpRequest
->PnPAction
== StorStopDevice
)
612 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
613 DebugPrint("\tRequested to Stop the adapter\n");
617 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
620 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
625 if (function
== SRB_FUNCTION_EXECUTE_SCSI
)
627 // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
628 // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
629 // routine does the following:
631 // - Gets and/or sets up whatever context the miniport driver maintains in its device,
632 // logical unit, and/or SRB extensions
633 // For example, a miniport driver might set up a logical unit extension with pointers
634 // to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value,
635 // and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be
636 // carried out on the HBA.
638 // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags,
639 // for the requested operation
640 // For a device I/O operation, such an internal routine generally selects the target device
641 // and sends the CDB over the bus to the target logical unit.
642 if (Srb
->CdbLength
> 0)
644 PCDB cdb
= (PCDB
)&Srb
->Cdb
;
645 if (cdb
->CDB10
.OperationCode
== SCSIOP_INQUIRY
)
647 Srb
->SrbStatus
= DeviceInquiryRequest(adapterExtension
, Srb
, cdb
);
651 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
656 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
659 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
663 DebugPrint("\tUnknown function code recieved: %x\n", function
);
664 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
665 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
667 }// -- AhciHwStartIo();
670 * @name AhciHwResetBus
673 * The HwStorResetBus routine is called by the port driver to clear error conditions.
675 * @param adapterExtension
679 * return TRUE if bus was successfully reset
683 __in PVOID AdapterExtension
,
687 STOR_LOCK_HANDLE lockhandle
;
688 PAHCI_ADAPTER_EXTENSION adapterExtension
;
690 DebugPrint("AhciHwResetBus()\n");
692 adapterExtension
= AdapterExtension
;
694 if (IsPortValid(AdapterExtension
, PathId
))
696 AhciZeroMemory(&lockhandle
, sizeof(lockhandle
));
699 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
701 // TODO: Perform port reset
704 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
708 }// -- AhciHwResetBus();
711 * @name AhciHwFindAdapter
714 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
715 * HBA is supported and, if it is, to return configuration information about that adapter.
717 * 10.1 Platform Communication
718 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
720 * @param DeviceExtension
722 * @param BusInformation
723 * @param ArgumentString
729 * 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.
732 * 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.
734 * SP_RETURN_BAD_CONFIG
735 * Indicates that the supplied configuration information was invalid for the adapter.
737 * SP_RETURN_NOT_FOUND
738 * Indicates that no supported HBA was found for the supplied configuration information.
740 * @remarks Called by Storport.
744 __in PVOID AdapterExtension
,
745 __in PVOID HwContext
,
746 __in PVOID BusInformation
,
747 __in PVOID ArgumentString
,
748 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
749 __in PBOOLEAN Reserved3
752 ULONG ghc
, index
, pci_cfg_len
;
753 UCHAR pci_cfg_buf
[sizeof(PCI_COMMON_CONFIG
)];
754 PACCESS_RANGE accessRange
;
756 PAHCI_MEMORY_REGISTERS abar
;
757 PPCI_COMMON_CONFIG pciConfigData
;
758 PAHCI_ADAPTER_EXTENSION adapterExtension
;
760 DebugPrint("AhciHwFindAdapter()\n");
762 UNREFERENCED_PARAMETER(HwContext
);
763 UNREFERENCED_PARAMETER(BusInformation
);
764 UNREFERENCED_PARAMETER(ArgumentString
);
765 UNREFERENCED_PARAMETER(Reserved3
);
767 adapterExtension
= AdapterExtension
;
768 adapterExtension
->SlotNumber
= ConfigInfo
->SlotNumber
;
769 adapterExtension
->SystemIoBusNumber
= ConfigInfo
->SystemIoBusNumber
;
771 // get PCI configuration header
772 pci_cfg_len
= StorPortGetBusData(
775 adapterExtension
->SystemIoBusNumber
,
776 adapterExtension
->SlotNumber
,
778 sizeof(PCI_COMMON_CONFIG
));
780 if (pci_cfg_len
!= sizeof(PCI_COMMON_CONFIG
))
782 DebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG
), pci_cfg_len
);
783 return SP_RETURN_ERROR
;//Not a valid device at the given bus number
786 pciConfigData
= pci_cfg_buf
;
787 adapterExtension
->VendorID
= pciConfigData
->VendorID
;
788 adapterExtension
->DeviceID
= pciConfigData
->DeviceID
;
789 adapterExtension
->RevisionID
= pciConfigData
->RevisionID
;
790 // 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).
791 adapterExtension
->AhciBaseAddress
= pciConfigData
->u
.type0
.BaseAddresses
[5] & (0xFFFFFFF0);
793 DebugPrint("\tVendorID:%d DeviceID:%d RevisionID:%d\n", adapterExtension
->VendorID
,
794 adapterExtension
->DeviceID
,
795 adapterExtension
->RevisionID
);
799 if (ConfigInfo
->NumberOfAccessRanges
> 0)
801 accessRange
= *(ConfigInfo
->AccessRanges
);
802 for (index
= 0; index
< ConfigInfo
->NumberOfAccessRanges
; index
++)
804 if (accessRange
[index
].RangeStart
.QuadPart
== adapterExtension
->AhciBaseAddress
)
806 abar
= StorPortGetDeviceBase(adapterExtension
,
807 ConfigInfo
->AdapterInterfaceType
,
808 ConfigInfo
->SystemIoBusNumber
,
809 accessRange
[index
].RangeStart
,
810 accessRange
[index
].RangeLength
,
811 !accessRange
[index
].RangeInMemory
);
819 DebugPrint("\tabar == NULL\n");
820 return SP_RETURN_ERROR
; // corrupted information supplied
823 adapterExtension
->ABAR_Address
= abar
;
824 adapterExtension
->CAP
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP
);
825 adapterExtension
->CAP2
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP2
);
826 adapterExtension
->Version
= StorPortReadRegisterUlong(adapterExtension
, &abar
->VS
);
827 adapterExtension
->LastInterruptPort
= -1;
830 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
831 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
832 ghc
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
833 // AE := Highest Significant bit of GHC
834 if ((ghc
& AHCI_Global_HBA_CONTROL_AE
) != 0)// Hmm, controller was already in power state
836 // reset controller to have it in known state
837 DebugPrint("\tAE Already set, Reset()\n");
838 if (!AhciAdapterReset(adapterExtension
))
840 DebugPrint("\tReset Failed!\n");
841 return SP_RETURN_ERROR
;// reset failed
845 ghc
= AHCI_Global_HBA_CONTROL_AE
;// only AE=1
846 // tell the controller that we know about AHCI
847 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
);
849 adapterExtension
->IS
= &abar
->IS
;
850 adapterExtension
->PortImplemented
= StorPortReadRegisterUlong(adapterExtension
, &abar
->PI
);
852 if (adapterExtension
->PortImplemented
== 0)
854 DebugPrint("\tadapterExtension->PortImplemented == 0\n");
855 return SP_RETURN_ERROR
;
858 ConfigInfo
->MaximumTransferLength
= MAXIMUM_TRANSFER_LENGTH
;//128 KB
859 ConfigInfo
->NumberOfPhysicalBreaks
= 0x21;
860 ConfigInfo
->MaximumNumberOfTargets
= 1;
861 ConfigInfo
->MaximumNumberOfLogicalUnits
= 1;
862 ConfigInfo
->ResetTargetSupported
= TRUE
;
863 ConfigInfo
->NumberOfBuses
= MAXIMUM_AHCI_PORT_COUNT
;
864 ConfigInfo
->SynchronizationModel
= StorSynchronizeFullDuplex
;
865 ConfigInfo
->ScatterGather
= TRUE
;
867 // allocate necessary resource for each port
868 if (!AhciAllocateResourceForAdapter(adapterExtension
, ConfigInfo
))
870 DebugPrint("\tAhciAllocateResourceForAdapter() == FALSE\n");
871 return SP_RETURN_ERROR
;
874 for (index
= 0; index
< adapterExtension
->PortCount
; index
++)
876 if ((adapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
877 AhciPortInitialize(&adapterExtension
->PortExtension
[index
]);
880 // Turn IE -- Interrupt Enabled
881 ghc
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
882 ghc
|= AHCI_Global_HBA_CONTROL_IE
;
883 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
);
885 return SP_RETURN_FOUND
;
886 }// -- AhciHwFindAdapter();
892 * Initial Entrypoint for storahci miniport driver
894 * @param DriverObject
895 * @param RegistryPath
898 * NT_STATUS in case of driver loaded successfully.
902 __in PVOID DriverObject
,
903 __in PVOID RegistryPath
907 HW_INITIALIZATION_DATA hwInitializationData
;
909 DebugPrint("Storahci Loaded\n");
911 // initialize the hardware data structure
912 AhciZeroMemory(&hwInitializationData
, sizeof(HW_INITIALIZATION_DATA
));
914 // set size of hardware initialization structure
915 hwInitializationData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
917 // identity required miniport entry point routines
918 hwInitializationData
.HwStartIo
= AhciHwStartIo
;
919 hwInitializationData
.HwResetBus
= AhciHwResetBus
;
920 hwInitializationData
.HwInterrupt
= AhciHwInterrupt
;
921 hwInitializationData
.HwInitialize
= AhciHwInitialize
;
922 hwInitializationData
.HwFindAdapter
= AhciHwFindAdapter
;
924 // adapter specific information
925 hwInitializationData
.NeedPhysicalAddresses
= TRUE
;
926 hwInitializationData
.TaggedQueuing
= TRUE
;
927 hwInitializationData
.AutoRequestSense
= TRUE
;
928 hwInitializationData
.MultipleRequestPerLu
= TRUE
;
930 hwInitializationData
.NumberOfAccessRanges
= 6;
931 hwInitializationData
.AdapterInterfaceType
= PCIBus
;
932 hwInitializationData
.MapBuffers
= STOR_MAP_NON_READ_WRITE_BUFFERS
;
934 // set required extension sizes
935 hwInitializationData
.SrbExtensionSize
= sizeof(AHCI_SRB_EXTENSION
);
936 hwInitializationData
.DeviceExtensionSize
= sizeof(AHCI_ADAPTER_EXTENSION
);
938 // register our hw init data
939 status
= StorPortInitialize(DriverObject
,
941 &hwInitializationData
,
944 DebugPrint("\tstatus: %x\n", status
);
946 }// -- DriverEntry();
952 * create ATA CFIS from Srb
954 * @param PortExtension
960 __in PAHCI_PORT_EXTENSION PortExtension
,
961 __in PAHCI_SRB_EXTENSION SrbExtension
964 PAHCI_COMMAND_TABLE cmdTable
;
966 UNREFERENCED_PARAMETER(PortExtension
);
968 DebugPrint("AhciATA_CFIS()\n");
970 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
972 NT_ASSERT(sizeof(cmdTable
->CFIS
) == 64);
974 AhciZeroMemory(&cmdTable
->CFIS
, sizeof(cmdTable
->CFIS
));
976 cmdTable
->CFIS
[AHCI_ATA_CFIS_FisType
] = 0x27; // FIS Type
977 cmdTable
->CFIS
[AHCI_ATA_CFIS_PMPort_C
] = (1 << 7); // PM Port & C
978 cmdTable
->CFIS
[AHCI_ATA_CFIS_CommandReg
] = SrbExtension
->CommandReg
;
980 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesLow
] = SrbExtension
->FeaturesLow
;
981 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA0
] = SrbExtension
->LBA0
;
982 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA1
] = SrbExtension
->LBA1
;
983 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA2
] = SrbExtension
->LBA2
;
984 cmdTable
->CFIS
[AHCI_ATA_CFIS_Device
] = SrbExtension
->Device
;
985 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA3
] = SrbExtension
->LBA3
;
986 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA4
] = SrbExtension
->LBA4
;
987 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA5
] = SrbExtension
->LBA5
;
988 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesHigh
] = SrbExtension
->FeaturesHigh
;
989 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountLow
] = SrbExtension
->SectorCountLow
;
990 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountHigh
] = SrbExtension
->SectorCountHigh
;
993 }// -- AhciATA_CFIS();
996 * @name AhciATAPI_CFIS
999 * create ATAPI CFIS from Srb
1001 * @param PortExtension
1007 __in PAHCI_PORT_EXTENSION PortExtension
,
1008 __in PAHCI_SRB_EXTENSION SrbExtension
1011 UNREFERENCED_PARAMETER(PortExtension
);
1012 UNREFERENCED_PARAMETER(SrbExtension
);
1014 DebugPrint("AhciATAPI_CFIS()\n");
1017 }// -- AhciATAPI_CFIS();
1020 * @name AhciBuild_PRDT
1023 * Build PRDT for data transfer
1025 * @param PortExtension
1029 * Return number of entries in PRDT.
1033 __in PAHCI_PORT_EXTENSION PortExtension
,
1034 __in PAHCI_SRB_EXTENSION SrbExtension
1038 PAHCI_COMMAND_TABLE cmdTable
;
1039 PLOCAL_SCATTER_GATHER_LIST sgl
;
1040 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1042 DebugPrint("AhciBuild_PRDT()\n");
1044 sgl
= &SrbExtension
->Sgl
;
1045 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
1046 AdapterExtension
= PortExtension
->AdapterExtension
;
1048 NT_ASSERT(sgl
!= NULL
);
1049 NT_ASSERT(sgl
->NumberOfElements
< MAXIMUM_AHCI_PRDT_ENTRIES
);
1051 for (index
= 0; index
< sgl
->NumberOfElements
; index
++)
1053 NT_ASSERT(sgl
->List
[index
].Length
<= MAXIMUM_TRANSFER_LENGTH
);
1055 cmdTable
->PRDT
[index
].DBA
= sgl
->List
[index
].PhysicalAddress
.LowPart
;
1056 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1058 cmdTable
->PRDT
[index
].DBAU
= sgl
->List
[index
].PhysicalAddress
.HighPart
;
1062 return sgl
->NumberOfElements
;
1063 }// -- AhciBuild_PRDT();
1066 * @name AhciProcessSrb
1069 * Prepare Srb for IO processing
1071 * @param PortExtension
1078 __in PAHCI_PORT_EXTENSION PortExtension
,
1079 __in PSCSI_REQUEST_BLOCK Srb
,
1080 __in ULONG SlotIndex
1083 ULONG prdtlen
, sig
, length
;
1084 PAHCI_SRB_EXTENSION SrbExtension
;
1085 PAHCI_COMMAND_HEADER CommandHeader
;
1086 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1087 STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress
;
1089 DebugPrint("AhciProcessSrb()\n");
1091 NT_ASSERT(Srb
->PathId
== PortExtension
->PortNumber
);
1093 SrbExtension
= GetSrbExtension(Srb
);
1094 AdapterExtension
= PortExtension
->AdapterExtension
;
1096 NT_ASSERT(SrbExtension
!= NULL
);
1097 NT_ASSERT(SrbExtension
->AtaFunction
!= 0);
1099 if ((SrbExtension
->AtaFunction
== ATA_FUNCTION_ATA_IDENTIFY
) &&
1100 (SrbExtension
->CommandReg
== IDE_COMMAND_NOT_VALID
))
1102 // Here we are safe to check SIG register
1103 sig
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SIG
);
1106 SrbExtension
->CommandReg
= IDE_COMMAND_IDENTIFY
;
1110 SrbExtension
->CommandReg
= IDE_COMMAND_ATAPI_IDENTIFY
;
1114 NT_ASSERT(SlotIndex
< AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
1115 SrbExtension
->SlotIndex
= SlotIndex
;
1117 // program the CFIS in the CommandTable
1118 CommandHeader
= &PortExtension
->CommandList
[SlotIndex
];
1120 if (IsAtaCommand(SrbExtension
->AtaFunction
))
1122 AhciATA_CFIS(PortExtension
, SrbExtension
);
1124 else if (IsAtapiCommand(SrbExtension
->AtaFunction
))
1126 AhciATAPI_CFIS(PortExtension
, SrbExtension
);
1130 if (IsDataTransferNeeded(SrbExtension
))
1132 prdtlen
= AhciBuild_PRDT(PortExtension
, SrbExtension
);
1133 NT_ASSERT(prdtlen
!= -1);
1136 // Program the command header
1137 CommandHeader
->DI
.PRDTL
= prdtlen
; // number of entries in PRD table
1138 CommandHeader
->DI
.CFL
= 5;
1139 CommandHeader
->DI
.W
= (SrbExtension
->Flags
& ATA_FLAGS_DATA_OUT
) ? 1 : 0;
1140 CommandHeader
->DI
.P
= 0; // ATA Specifications says so
1141 CommandHeader
->DI
.PMP
= 0; // Port Multiplier
1143 // Reset -- Manual Configuation
1144 CommandHeader
->DI
.R
= 0;
1145 CommandHeader
->DI
.B
= 0;
1146 CommandHeader
->DI
.C
= 0;
1148 CommandHeader
->PRDBC
= 0;
1150 CommandHeader
->Reserved
[0] = 0;
1151 CommandHeader
->Reserved
[1] = 0;
1152 CommandHeader
->Reserved
[2] = 0;
1153 CommandHeader
->Reserved
[3] = 0;
1155 // set CommandHeader CTBA
1156 // I am really not sure if SrbExtension is 128 byte aligned or not
1157 // Command FIS will not work if it is not so.
1158 CommandTablePhysicalAddress
= StorPortGetPhysicalAddress(AdapterExtension
,
1163 // command table alignment
1164 NT_ASSERT((CommandTablePhysicalAddress
.LowPart
% 128) == 0);
1166 CommandHeader
->CTBA0
= CommandTablePhysicalAddress
.LowPart
;
1168 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1170 CommandHeader
->CTBA_U0
= CommandTablePhysicalAddress
.HighPart
;
1174 PortExtension
->Slot
[SlotIndex
] = Srb
;
1175 PortExtension
->QueueSlots
|= 1 << SlotIndex
;
1177 }// -- AhciProcessSrb();
1180 * @name AhciActivatePort
1183 * Program Port and populate command list
1185 * @param PortExtension
1190 __in PAHCI_PORT_EXTENSION PortExtension
1194 ULONG QueueSlots
, slotToActivate
, tmp
;
1195 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1197 DebugPrint("AhciActivatePort()\n");
1199 AdapterExtension
= PortExtension
->AdapterExtension
;
1200 QueueSlots
= PortExtension
->QueueSlots
;
1202 if (QueueSlots
== 0)
1206 // Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’
1207 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
1209 if (cmd
.ST
== 0) // PxCMD.ST == 0
1212 // get the lowest set bit
1213 tmp
= QueueSlots
& (QueueSlots
- 1);
1216 slotToActivate
= QueueSlots
;
1218 slotToActivate
= (QueueSlots
& (~tmp
));
1220 // mark that bit off in QueueSlots
1221 // so we can know we it is really needed to activate port or not
1222 PortExtension
->QueueSlots
&= ~slotToActivate
;
1223 // mark this CommandIssuedSlots
1224 // to validate in completeIssuedCommand
1225 PortExtension
->CommandIssuedSlots
|= slotToActivate
;
1227 // tell the HBA to issue this Command Slot to the given port
1228 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
, slotToActivate
);
1231 }// -- AhciActivatePort();
1234 * @name AhciProcessIO
1237 * Acquire Exclusive lock to port, populate pending commands to command List
1238 * program controller's port to process new commands in command list.
1240 * @param AdapterExtension
1247 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1249 __in PSCSI_REQUEST_BLOCK Srb
1252 STOR_LOCK_HANDLE lockhandle
;
1253 PSCSI_REQUEST_BLOCK tmpSrb
;
1254 PAHCI_PORT_EXTENSION PortExtension
;
1255 ULONG commandSlotMask
, occupiedSlots
, slotIndex
, NCS
;
1257 DebugPrint("AhciProcessIO()\n");
1258 DebugPrint("\tPathId: %d\n", PathId
);
1260 PortExtension
= &AdapterExtension
->PortExtension
[PathId
];
1262 NT_ASSERT(PathId
< AdapterExtension
->PortCount
);
1265 AddQueue(&PortExtension
->SrbQueue
, Srb
);
1267 if (PortExtension
->IsActive
== FALSE
)
1268 return; // we should wait for device to get active
1270 AhciZeroMemory(&lockhandle
, sizeof(lockhandle
));
1273 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
1275 occupiedSlots
= (PortExtension
->QueueSlots
| PortExtension
->CommandIssuedSlots
); // Busy command slots for given port
1276 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
1277 commandSlotMask
= (1 << NCS
) - 1; // available slots mask
1279 commandSlotMask
= (commandSlotMask
& ~occupiedSlots
);
1280 if(commandSlotMask
!= 0)
1282 // iterate over HBA port slots
1283 for (slotIndex
= 0; slotIndex
< NCS
; slotIndex
++)
1285 // find first free slot
1286 if ((commandSlotMask
& (1 << slotIndex
)) != 0)
1288 tmpSrb
= RemoveQueue(&PortExtension
->SrbQueue
);
1291 NT_ASSERT(tmpSrb
->PathId
== PathId
);
1292 AhciProcessSrb(PortExtension
, tmpSrb
, slotIndex
);
1307 AhciActivatePort(PortExtension
);
1310 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
1313 }// -- AhciProcessIO();
1316 * @name InquiryCompletion
1319 * InquiryCompletion routine should be called after device signals
1320 * for device inquiry request is completed (through interrupt)
1322 * @param PortExtension
1328 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1329 __in PAHCI_PORT_EXTENSION PortExtension
,
1330 __in PSCSI_REQUEST_BLOCK Srb
1334 PAHCI_SRB_EXTENSION SrbExtension
;
1336 DebugPrint("InquiryCompletion()\n");
1338 NT_ASSERT(PortExtension
!= NULL
);
1339 NT_ASSERT(Srb
!= NULL
);
1341 SrbStatus
= Srb
->SrbStatus
;
1342 SrbExtension
= GetSrbExtension(Srb
);
1344 if (SrbStatus
== SRB_STATUS_SUCCESS
)
1346 if (SrbExtension
->CommandReg
== IDE_COMMAND_IDENTIFY
)
1348 DebugPrint("Device: ATA\n");
1349 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATA
;
1353 DebugPrint("Device: ATAPI\n");
1354 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATAPI
;
1356 // TODO: Set Device Paramters
1358 else if (SrbStatus
== SRB_STATUS_NO_DEVICE
)
1360 DebugPrint("Device: No Device\n");
1361 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_NODEVICE
;
1369 }// -- InquiryCompletion();
1372 * @name DeviceInquiryRequest
1375 * Tells wheather given port is implemented or not
1377 * @param AdapterExtension
1382 * return STOR status for DeviceInquiryRequest
1385 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
1388 DeviceInquiryRequest (
1389 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1390 __in PSCSI_REQUEST_BLOCK Srb
,
1395 ULONG DataBufferLength
;
1396 PAHCI_PORT_EXTENSION PortExtension
;
1397 PAHCI_SRB_EXTENSION SrbExtension
;
1399 DebugPrint("DeviceInquiryRequest()\n");
1401 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
1403 SrbExtension
= GetSrbExtension(Srb
);
1404 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1407 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
1408 if (Cdb
->CDB6INQUIRY3
.EnableVitalProductData
== 0)
1410 DebugPrint("\tEVPD Inquired\n");
1411 NT_ASSERT(SrbExtension
!= NULL
);
1413 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATA_IDENTIFY
;
1414 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
1415 SrbExtension
->CompletionRoutine
= InquiryCompletion
;
1416 SrbExtension
->CommandReg
= IDE_COMMAND_NOT_VALID
;
1418 // TODO: Should use AhciZeroMemory
1419 SrbExtension
->FeaturesLow
= 0;
1420 SrbExtension
->LBA0
= 0;
1421 SrbExtension
->LBA1
= 0;
1422 SrbExtension
->LBA2
= 0;
1423 SrbExtension
->Device
= 0;
1424 SrbExtension
->LBA3
= 0;
1425 SrbExtension
->LBA4
= 0;
1426 SrbExtension
->LBA5
= 0;
1427 SrbExtension
->FeaturesHigh
= 0;
1428 SrbExtension
->SectorCountLow
= 0;
1429 SrbExtension
->SectorCountHigh
= 0;
1431 SrbExtension
->Sgl
.NumberOfElements
= 1;
1432 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.LowPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.LowPart
;
1433 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.HighPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.HighPart
;
1434 SrbExtension
->Sgl
.List
[0].Length
= sizeof(IDENTIFY_DEVICE_DATA
);
1438 DebugPrint("\tVPD Inquired\n");
1440 DataBuffer
= Srb
->DataBuffer
;
1441 DataBufferLength
= Srb
->DataTransferLength
;
1443 if (DataBuffer
== NULL
)
1445 return SRB_STATUS_INVALID_REQUEST
;
1448 AhciZeroMemory(DataBuffer
, DataBufferLength
);
1451 return SRB_STATUS_BAD_FUNCTION
;
1454 AhciProcessIO(AdapterExtension
, Srb
->PathId
, Srb
);
1455 return SRB_STATUS_PENDING
;
1456 }// -- DeviceInquiryRequest();
1459 * @name AhciAdapterReset
1463 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
1464 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
1465 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
1466 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
1467 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
1468 * the HBA reset has completed.
1469 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
1470 * a hung or locked state.
1472 * @param AdapterExtension
1475 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
1479 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
1482 ULONG ghc
, ticks
, ghcStatus
;
1483 PAHCI_MEMORY_REGISTERS abar
= NULL
;
1485 DebugPrint("AhciAdapterReset()\n");
1487 abar
= AdapterExtension
->ABAR_Address
;
1488 if (abar
== NULL
) // basic sanity
1493 // HR -- Very first bit (lowest significant)
1494 ghc
= AHCI_Global_HBA_CONTROL_HR
;
1495 StorPortWriteRegisterUlong(AdapterExtension
, &abar
->GHC
, ghc
);
1497 for (ticks
= 0; ticks
< 50; ++ticks
)
1499 ghcStatus
= StorPortReadRegisterUlong(AdapterExtension
, &abar
->GHC
);
1500 if ((ghcStatus
& AHCI_Global_HBA_CONTROL_HR
) == 0)
1504 StorPortStallExecution(20000);
1507 if (ticks
== 50)// 1 second
1509 DebugPrint("\tDevice Timeout\n");
1514 }// -- AhciAdapterReset();
1517 * @name AhciZeroMemory
1520 * Clear buffer by filling zeros
1529 __in ULONG BufferSize
1533 for (i
= 0; i
< BufferSize
; i
++)
1539 }// -- AhciZeroMemory();
1545 * Tells wheather given port is implemented or not
1547 * @param AdapterExtension
1551 * return TRUE if provided port is valid (implemented) or not
1556 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1560 NT_ASSERT(pathId
< MAXIMUM_AHCI_PORT_COUNT
);
1562 if (pathId
>= AdapterExtension
->PortCount
)
1567 return AdapterExtension
->PortExtension
[pathId
].IsActive
;
1568 }// -- IsPortValid()
1580 * return TRUE if Srb is successfully added to Queue
1586 __inout PAHCI_QUEUE Queue
,
1590 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1591 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1593 if (Queue
->Tail
== ((Queue
->Head
+ 1) % MAXIMUM_QUEUE_BUFFER_SIZE
))
1596 Queue
->Buffer
[Queue
->Head
++] = Srb
;
1597 Queue
->Head
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
1606 * Remove and return Srb from Queue
1617 __inout PAHCI_QUEUE Queue
1622 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1623 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1625 if (Queue
->Head
== Queue
->Tail
)
1628 Srb
= Queue
->Buffer
[Queue
->Tail
++];
1629 Queue
->Tail
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
1632 }// -- RemoveQueue();
1635 * @name GetSrbExtension
1638 * GetSrbExtension from Srb make sure It is properly aligned
1643 * return SrbExtension
1649 __in PSCSI_REQUEST_BLOCK Srb
1653 ULONG_PTR SrbExtension
;
1655 SrbExtension
= (ULONG_PTR
)Srb
->SrbExtension
;
1656 Offset
= SrbExtension
% 128;
1658 // CommandTable should be 128 byte aligned
1660 Offset
= 128 - Offset
;
1662 return (PAHCI_SRB_EXTENSION
)(SrbExtension
+ Offset
);
1663 }// -- PAHCI_SRB_EXTENSION();