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 status
, 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
= 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 %x %x\n", ssts
.DET
, PortExtension
->Port
->CMD
, PortExtension
->Port
->SSTS
);
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
297 ULONG ghc
, messageCount
, status
, cmd
, index
;
298 PAHCI_PORT_EXTENSION PortExtension
;
299 PAHCI_ADAPTER_EXTENSION adapterExtension
;
300 AHCI_SERIAL_ATA_STATUS ssts
;
302 DebugPrint("AhciHwInitialize()\n");
304 adapterExtension
= AdapterExtension
;
305 adapterExtension
->StateFlags
.MessagePerPort
= FALSE
;
307 // First check what type of interrupt/synchronization device is using
308 ghc
= StorPortReadRegisterUlong(adapterExtension
, &adapterExtension
->ABAR_Address
->GHC
);
310 // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector
311 // but has reverted to using the first vector only. When this bit is cleared to ‘0’,
312 // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
313 // software has allocated the number of messages requested
314 if ((ghc
& AHCI_Global_HBA_CONTROL_MRSM
) == 0)
316 adapterExtension
->StateFlags
.MessagePerPort
= TRUE
;
317 DebugPrint("\tMultiple MSI based message not supported\n");
320 for (index
= 0; index
< adapterExtension
->PortCount
; index
++)
322 if ((adapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
324 PortExtension
= &adapterExtension
->PortExtension
[index
];
325 PortExtension
->IsActive
= AhciStartPort(PortExtension
);
326 if (PortExtension
->IsActive
== FALSE
)
328 DebugPrint("\tPort Disabled: %d\n", index
);
334 }// -- AhciHwInitialize();
337 * @name AhciCompleteIssuedSrb
340 * Complete issued Srbs
342 * @param PortExtension
346 AhciCompleteIssuedSrb (
347 __in PAHCI_PORT_EXTENSION PortExtension
,
348 __in ULONG CommandsToComplete
352 PSCSI_REQUEST_BLOCK Srb
;
353 PAHCI_SRB_EXTENSION SrbExtension
;
354 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
355 PAHCI_COMPLETION_ROUTINE CompletionRoutine
;
357 DebugPrint("AhciCompleteIssuedSrb()\n");
359 NT_ASSERT(CommandsToComplete
!= 0);
361 DebugPrint("\tCompleted Commands: %d\n", CommandsToComplete
);
363 AdapterExtension
= PortExtension
->AdapterExtension
;
364 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
366 for (i
= 0; i
< NCS
; i
++)
368 if (((1 << i
) & CommandsToComplete
) != 0)
370 Srb
= PortExtension
->Slot
[i
];
371 NT_ASSERT(Srb
!= NULL
);
373 if (Srb
->SrbStatus
== SRB_STATUS_PENDING
)
375 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
378 SrbExtension
= GetSrbExtension(Srb
);
379 CompletionRoutine
= SrbExtension
->CompletionRoutine
;
381 if (CompletionRoutine
!= NULL
)
383 // now it's completion routine responsibility to set SrbStatus
384 CompletionRoutine(AdapterExtension
, PortExtension
, Srb
);
388 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
389 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
395 }// -- AhciCompleteIssuedSrb();
398 * @name AhciInterruptHandler
401 * Interrupt Handler for PortExtension
403 * @param PortExtension
407 AhciInterruptHandler (
408 __in PAHCI_PORT_EXTENSION PortExtension
411 ULONG is
, ci
, sact
, outstanding
;
412 AHCI_INTERRUPT_STATUS PxIS
;
413 AHCI_INTERRUPT_STATUS PxISMasked
;
414 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
416 DebugPrint("AhciInterruptHandler()\n");
417 DebugPrint("\tPort Number: %d\n", PortExtension
->PortNumber
);
419 AdapterExtension
= PortExtension
->AdapterExtension
;
420 NT_ASSERT(IsPortValid(AdapterExtension
, PortExtension
->PortNumber
));
423 // 1. Software determines the cause of the interrupt by reading the PxIS register.
424 // It is possible for multiple bits to be set
425 // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt.
426 // 3. Software clears the interrupt bit in IS.IPS corresponding to the port.
427 // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to
428 // the list of commands previously issued by software that are still outstanding.
429 // If executing native queued commands, software reads the PxSACT register and compares the current
430 // value to the list of commands previously issued by software.
431 // Software completes with success any outstanding command whose corresponding bit has been cleared in
432 // the respective register. PxCI and PxSACT are volatile registers; software should only use their values
433 // to determine commands that have completed, not to determine which commands have previously been issued.
434 // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2).
435 PxISMasked
.Status
= 0;
436 PxIS
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
);
440 // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES
441 if (PxIS
.HBFS
|| PxIS
.HBDS
|| PxIS
.IFS
|| PxIS
.TFES
)
443 // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process
444 // any native command queuing commands. To recover, the port must be restarted
445 // To detect an error that requires software recovery actions to be performed,
446 // software should check whether any of the following status bits are set on an interrupt:
447 // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set,
448 // software should perform the appropriate error recovery actions based on whether
449 // non-queued commands were being issued or native command queuing commands were being issued.
451 DebugPrint("\tFatal Error: %x\n", PxIS
.Status
);
454 // Normal Command Completion
456 // A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory.
457 PxISMasked
.DHRS
= PxIS
.DHRS
;
458 // A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory.
459 PxISMasked
.PSS
= PxIS
.PSS
;
460 // A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory.
461 PxISMasked
.DSS
= PxIS
.DSS
;
462 // A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/
463 PxISMasked
.SDBS
= PxIS
.SDBS
;
464 // A PRD with the ‘I’ bit set has transferred all of its data.
465 PxISMasked
.DPS
= PxIS
.DPS
;
467 if (PxISMasked
.Status
!= 0)
469 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
, PxISMasked
.Status
);
473 // Clear port interrupt
474 // It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software.
475 is
= (1 << PortExtension
->PortNumber
);
476 StorPortWriteRegisterUlong(AdapterExtension
, AdapterExtension
->IS
, is
);
478 ci
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
);
479 sact
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SACT
);
481 outstanding
= ci
| sact
; // NOTE: Including both non-NCQ and NCQ based commands
482 if ((PortExtension
->CommandIssuedSlots
& (~outstanding
)) != 0)
484 AhciCompleteIssuedSrb(PortExtension
, (PortExtension
->CommandIssuedSlots
& (~outstanding
)));
485 PortExtension
->CommandIssuedSlots
&= outstanding
;
489 }// -- AhciInterruptHandler();
492 * @name AhciHwInterrupt
495 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
497 * @param AdapterExtension
500 * return TRUE Indicates that an interrupt was pending on adapter.
501 * return FALSE Indicates the interrupt was not ours.
505 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
508 ULONG portPending
, nextPort
, i
, portCount
;
510 DebugPrint("AhciHwInterrupt()\n");
512 if (AdapterExtension
->StateFlags
.Removed
)
517 portPending
= StorPortReadRegisterUlong(AdapterExtension
, AdapterExtension
->IS
);
518 // we process interrupt for implemented ports only
519 portCount
= AdapterExtension
->PortCount
;
520 portPending
= portPending
& AdapterExtension
->PortImplemented
;
522 if (portPending
== 0)
527 for (i
= 1; i
<= portCount
; i
++)
529 nextPort
= (AdapterExtension
->LastInterruptPort
+ i
) % portCount
;
531 if ((portPending
& (0x1 << nextPort
)) == 0)
534 NT_ASSERT(IsPortValid(AdapterExtension
, nextPort
));
536 if (nextPort
== AdapterExtension
->LastInterruptPort
)
541 if (AdapterExtension
->PortExtension
[nextPort
].IsActive
== FALSE
)
546 // we can assign this interrupt to this port
547 AdapterExtension
->LastInterruptPort
= nextPort
;
548 AhciInterruptHandler(&AdapterExtension
->PortExtension
[nextPort
]);
550 // interrupt belongs to this device
551 // should always return TRUE
555 DebugPrint("\tSomething went wrong");
557 }// -- AhciHwInterrupt();
560 * @name AhciHwStartIo
563 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
565 * @param adapterExtension
569 * return TRUE if the request was accepted
570 * return FALSE if the request must be submitted later
574 __in PVOID AdapterExtension
,
575 __in PSCSI_REQUEST_BLOCK Srb
578 UCHAR function
, pathId
;
579 PAHCI_ADAPTER_EXTENSION adapterExtension
;
581 DebugPrint("AhciHwStartIo()\n");
583 pathId
= Srb
->PathId
;
584 function
= Srb
->Function
;
585 adapterExtension
= AdapterExtension
;
587 if (!IsPortValid(adapterExtension
, pathId
))
589 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
590 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
594 // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp
595 // If the function member of an SRB is set to SRB_FUNCTION_PNP,
596 // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK.
597 if (function
== SRB_FUNCTION_PNP
)
599 PSCSI_PNP_REQUEST_BLOCK pnpRequest
;
601 pnpRequest
= (PSCSI_PNP_REQUEST_BLOCK
)Srb
;
602 if ((pnpRequest
->SrbPnPFlags
& SRB_PNP_FLAGS_ADAPTER_REQUEST
) != 0)
604 if ((pnpRequest
->PnPAction
== StorRemoveDevice
) ||
605 (pnpRequest
->PnPAction
== StorSurpriseRemoval
))
607 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
608 adapterExtension
->StateFlags
.Removed
= 1;
609 DebugPrint("\tAdapter removed\n");
611 else if (pnpRequest
->PnPAction
== StorStopDevice
)
613 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
614 DebugPrint("\tRequested to Stop the adapter\n");
618 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
621 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
626 if (function
== SRB_FUNCTION_EXECUTE_SCSI
)
628 // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
629 // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
630 // routine does the following:
632 // - Gets and/or sets up whatever context the miniport driver maintains in its device,
633 // logical unit, and/or SRB extensions
634 // For example, a miniport driver might set up a logical unit extension with pointers
635 // to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value,
636 // and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be
637 // carried out on the HBA.
639 // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags,
640 // for the requested operation
641 // For a device I/O operation, such an internal routine generally selects the target device
642 // and sends the CDB over the bus to the target logical unit.
643 if (Srb
->CdbLength
> 0)
645 PCDB cdb
= (PCDB
)&Srb
->Cdb
;
646 if (cdb
->CDB10
.OperationCode
== SCSIOP_INQUIRY
)
648 Srb
->SrbStatus
= DeviceInquiryRequest(adapterExtension
, Srb
, cdb
);
652 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
657 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
660 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
664 DebugPrint("\tUnknown function code recieved: %x\n", function
);
665 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
666 StorPortNotification(RequestComplete
, adapterExtension
, Srb
);
668 }// -- AhciHwStartIo();
671 * @name AhciHwResetBus
674 * The HwStorResetBus routine is called by the port driver to clear error conditions.
676 * @param adapterExtension
680 * return TRUE if bus was successfully reset
684 __in PVOID AdapterExtension
,
688 STOR_LOCK_HANDLE lockhandle
;
689 PAHCI_ADAPTER_EXTENSION adapterExtension
;
691 DebugPrint("AhciHwResetBus()\n");
693 adapterExtension
= AdapterExtension
;
695 if (IsPortValid(AdapterExtension
, PathId
))
697 AhciZeroMemory(&lockhandle
, sizeof(lockhandle
));
700 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
702 // TODO: Perform port reset
705 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
709 }// -- AhciHwResetBus();
712 * @name AhciHwFindAdapter
715 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
716 * HBA is supported and, if it is, to return configuration information about that adapter.
718 * 10.1 Platform Communication
719 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
721 * @param DeviceExtension
723 * @param BusInformation
724 * @param ArgumentString
730 * 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.
733 * 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.
735 * SP_RETURN_BAD_CONFIG
736 * Indicates that the supplied configuration information was invalid for the adapter.
738 * SP_RETURN_NOT_FOUND
739 * Indicates that no supported HBA was found for the supplied configuration information.
741 * @remarks Called by Storport.
745 __in PVOID AdapterExtension
,
746 __in PVOID HwContext
,
747 __in PVOID BusInformation
,
748 __in PVOID ArgumentString
,
749 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
750 __in PBOOLEAN Reserved3
755 ULONG portCount
, portImplemented
;
757 UCHAR pci_cfg_buf
[sizeof(PCI_COMMON_CONFIG
)];
758 PACCESS_RANGE accessRange
;
760 PAHCI_MEMORY_REGISTERS abar
;
761 PPCI_COMMON_CONFIG pciConfigData
;
762 PAHCI_ADAPTER_EXTENSION adapterExtension
;
764 DebugPrint("AhciHwFindAdapter()\n");
766 adapterExtension
= AdapterExtension
;
767 adapterExtension
->SlotNumber
= ConfigInfo
->SlotNumber
;
768 adapterExtension
->SystemIoBusNumber
= ConfigInfo
->SystemIoBusNumber
;
770 // get PCI configuration header
771 pci_cfg_len
= StorPortGetBusData(
774 adapterExtension
->SystemIoBusNumber
,
775 adapterExtension
->SlotNumber
,
777 sizeof(PCI_COMMON_CONFIG
));
779 if (pci_cfg_len
!= sizeof(PCI_COMMON_CONFIG
))
781 DebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG
), pci_cfg_len
);
782 return SP_RETURN_ERROR
;//Not a valid device at the given bus number
785 pciConfigData
= pci_cfg_buf
;
786 adapterExtension
->VendorID
= pciConfigData
->VendorID
;
787 adapterExtension
->DeviceID
= pciConfigData
->DeviceID
;
788 adapterExtension
->RevisionID
= pciConfigData
->RevisionID
;
789 // 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).
790 adapterExtension
->AhciBaseAddress
= pciConfigData
->u
.type0
.BaseAddresses
[5] & (0xFFFFFFF0);
792 DebugPrint("\tVendorID:%d DeviceID:%d RevisionID:%d\n", adapterExtension
->VendorID
,
793 adapterExtension
->DeviceID
,
794 adapterExtension
->RevisionID
);
798 if (ConfigInfo
->NumberOfAccessRanges
> 0)
800 for (index
= 0; index
< ConfigInfo
->NumberOfAccessRanges
; index
++)
802 accessRange
= *ConfigInfo
->AccessRanges
;
803 if (accessRange
[index
].RangeStart
.QuadPart
== adapterExtension
->AhciBaseAddress
)
805 abar
= StorPortGetDeviceBase(adapterExtension
,
806 ConfigInfo
->AdapterInterfaceType
,
807 ConfigInfo
->SystemIoBusNumber
,
808 accessRange
[index
].RangeStart
,
809 accessRange
[index
].RangeLength
,
810 !accessRange
[index
].RangeInMemory
);
818 DebugPrint("\tabar == NULL\n");
819 return SP_RETURN_ERROR
; // corrupted information supplied
822 adapterExtension
->ABAR_Address
= abar
;
823 adapterExtension
->CAP
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP
);
824 adapterExtension
->CAP2
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP2
);
825 adapterExtension
->Version
= StorPortReadRegisterUlong(adapterExtension
, &abar
->VS
);
826 adapterExtension
->LastInterruptPort
= -1;
829 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
830 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
831 ghc
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
832 // AE := Highest Significant bit of GHC
833 if ((ghc
& AHCI_Global_HBA_CONTROL_AE
) != 0)// Hmm, controller was already in power state
835 // reset controller to have it in known state
836 DebugPrint("\tAE Already set, Reset()\n");
837 if (!AhciAdapterReset(adapterExtension
))
839 DebugPrint("\tReset Failed!\n");
840 return SP_RETURN_ERROR
;// reset failed
844 ghc
= AHCI_Global_HBA_CONTROL_AE
;// only AE=1
845 // tell the controller that we know about AHCI
846 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
);
848 adapterExtension
->IS
= &abar
->IS
;
849 adapterExtension
->PortImplemented
= StorPortReadRegisterUlong(adapterExtension
, &abar
->PI
);
851 if (adapterExtension
->PortImplemented
== 0)
853 DebugPrint("\tadapterExtension->PortImplemented == 0\n");
854 return SP_RETURN_ERROR
;
857 ConfigInfo
->MaximumTransferLength
= MAXIMUM_TRANSFER_LENGTH
;//128 KB
858 ConfigInfo
->NumberOfPhysicalBreaks
= 0x21;
859 ConfigInfo
->MaximumNumberOfTargets
= 1;
860 ConfigInfo
->MaximumNumberOfLogicalUnits
= 1;
861 ConfigInfo
->ResetTargetSupported
= TRUE
;
862 ConfigInfo
->NumberOfBuses
= MAXIMUM_AHCI_PORT_COUNT
;
863 ConfigInfo
->SynchronizationModel
= StorSynchronizeFullDuplex
;
864 ConfigInfo
->ScatterGather
= TRUE
;
866 // allocate necessary resource for each port
867 if (!AhciAllocateResourceForAdapter(adapterExtension
, ConfigInfo
))
869 DebugPrint("\tAhciAllocateResourceForAdapter() == FALSE\n");
870 return SP_RETURN_ERROR
;
873 for (index
= 0; index
< adapterExtension
->PortCount
; index
++)
875 if ((adapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
876 AhciPortInitialize(&adapterExtension
->PortExtension
[index
]);
879 // Turn IE -- Interrupt Enabled
880 ghc
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
881 ghc
|= AHCI_Global_HBA_CONTROL_IE
;
882 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
);
884 return SP_RETURN_FOUND
;
885 }// -- AhciHwFindAdapter();
891 * Initial Entrypoint for storahci miniport driver
893 * @param DriverObject
894 * @param RegistryPath
897 * NT_STATUS in case of driver loaded successfully.
901 __in PVOID DriverObject
,
902 __in PVOID RegistryPath
905 HW_INITIALIZATION_DATA hwInitializationData
;
908 DebugPrint("Storahci Loaded\n");
910 // initialize the hardware data structure
911 AhciZeroMemory(&hwInitializationData
, sizeof(HW_INITIALIZATION_DATA
));
913 // set size of hardware initialization structure
914 hwInitializationData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
916 // identity required miniport entry point routines
917 hwInitializationData
.HwStartIo
= AhciHwStartIo
;
918 hwInitializationData
.HwResetBus
= AhciHwResetBus
;
919 hwInitializationData
.HwInterrupt
= AhciHwInterrupt
;
920 hwInitializationData
.HwInitialize
= AhciHwInitialize
;
921 hwInitializationData
.HwFindAdapter
= AhciHwFindAdapter
;
923 // adapter specific information
924 hwInitializationData
.NeedPhysicalAddresses
= TRUE
;
925 hwInitializationData
.TaggedQueuing
= TRUE
;
926 hwInitializationData
.AutoRequestSense
= TRUE
;
927 hwInitializationData
.MultipleRequestPerLu
= TRUE
;
929 hwInitializationData
.NumberOfAccessRanges
= 6;
930 hwInitializationData
.AdapterInterfaceType
= PCIBus
;
931 hwInitializationData
.MapBuffers
= STOR_MAP_NON_READ_WRITE_BUFFERS
;
933 // set required extension sizes
934 hwInitializationData
.SrbExtensionSize
= sizeof(AHCI_SRB_EXTENSION
);
935 hwInitializationData
.DeviceExtensionSize
= sizeof(AHCI_ADAPTER_EXTENSION
);
937 // register our hw init data
938 status
= StorPortInitialize(DriverObject
,
940 &hwInitializationData
,
943 DebugPrint("\tstatus: %x\n", status
);
945 }// -- DriverEntry();
951 * create ATA CFIS from Srb
953 * @param PortExtension
959 __in PAHCI_PORT_EXTENSION PortExtension
,
960 __in PAHCI_SRB_EXTENSION SrbExtension
963 PAHCI_COMMAND_TABLE cmdTable
;
965 DebugPrint("AhciATA_CFIS()\n");
967 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
969 NT_ASSERT(sizeof(cmdTable
->CFIS
) == 64);
971 AhciZeroMemory(&cmdTable
->CFIS
, sizeof(cmdTable
->CFIS
));
973 cmdTable
->CFIS
[AHCI_ATA_CFIS_FisType
] = 0x27; // FIS Type
974 cmdTable
->CFIS
[AHCI_ATA_CFIS_PMPort_C
] = (1 << 7); // PM Port & C
975 cmdTable
->CFIS
[AHCI_ATA_CFIS_CommandReg
] = SrbExtension
->CommandReg
;
977 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesLow
] = SrbExtension
->FeaturesLow
;
978 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA0
] = SrbExtension
->LBA0
;
979 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA1
] = SrbExtension
->LBA1
;
980 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA2
] = SrbExtension
->LBA2
;
981 cmdTable
->CFIS
[AHCI_ATA_CFIS_Device
] = SrbExtension
->Device
;
982 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA3
] = SrbExtension
->LBA3
;
983 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA4
] = SrbExtension
->LBA4
;
984 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA5
] = SrbExtension
->LBA5
;
985 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesHigh
] = SrbExtension
->FeaturesHigh
;
986 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountLow
] = SrbExtension
->SectorCountLow
;
987 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountHigh
] = SrbExtension
->SectorCountHigh
;
990 }// -- AhciATA_CFIS();
993 * @name AhciATAPI_CFIS
996 * create ATAPI CFIS from Srb
998 * @param PortExtension
1004 __in PAHCI_PORT_EXTENSION PortExtension
,
1005 __in PAHCI_SRB_EXTENSION SrbExtension
1008 DebugPrint("AhciATAPI_CFIS()\n");
1010 }// -- AhciATAPI_CFIS();
1013 * @name AhciBuild_PRDT
1016 * Build PRDT for data transfer
1018 * @param PortExtension
1022 * Return number of entries in PRDT.
1026 __in PAHCI_PORT_EXTENSION PortExtension
,
1027 __in PAHCI_SRB_EXTENSION SrbExtension
1031 PAHCI_COMMAND_TABLE cmdTable
;
1032 PLOCAL_SCATTER_GATHER_LIST sgl
;
1033 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1035 DebugPrint("AhciBuild_PRDT()\n");
1037 sgl
= &SrbExtension
->Sgl
;
1038 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
1039 AdapterExtension
= PortExtension
->AdapterExtension
;
1041 NT_ASSERT(sgl
!= NULL
);
1042 NT_ASSERT(sgl
->NumberOfElements
< MAXIMUM_AHCI_PRDT_ENTRIES
);
1044 for (index
= 0; index
< sgl
->NumberOfElements
; index
++)
1046 NT_ASSERT(sgl
->List
[index
].Length
<= MAXIMUM_TRANSFER_LENGTH
);
1048 cmdTable
->PRDT
[index
].DBA
= sgl
->List
[index
].PhysicalAddress
.LowPart
;
1049 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1051 cmdTable
->PRDT
[index
].DBAU
= sgl
->List
[index
].PhysicalAddress
.HighPart
;
1055 return sgl
->NumberOfElements
;
1056 }// -- AhciBuild_PRDT();
1059 * @name AhciProcessSrb
1062 * Prepare Srb for IO processing
1064 * @param PortExtension
1071 __in PAHCI_PORT_EXTENSION PortExtension
,
1072 __in PSCSI_REQUEST_BLOCK Srb
,
1073 __in ULONG SlotIndex
1076 ULONG prdtlen
, sig
, length
;
1077 PAHCI_SRB_EXTENSION SrbExtension
;
1078 PAHCI_COMMAND_HEADER CommandHeader
;
1079 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1080 STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress
;
1082 DebugPrint("AhciProcessSrb()\n");
1084 NT_ASSERT(Srb
->PathId
== PortExtension
->PortNumber
);
1086 SrbExtension
= GetSrbExtension(Srb
);
1087 AdapterExtension
= PortExtension
->AdapterExtension
;
1089 NT_ASSERT(SrbExtension
!= NULL
);
1090 NT_ASSERT(SrbExtension
->AtaFunction
!= 0);
1092 if ((SrbExtension
->AtaFunction
== ATA_FUNCTION_ATA_IDENTIFY
) &&
1093 (SrbExtension
->CommandReg
== IDE_COMMAND_NOT_VALID
))
1095 // Here we are safe to check SIG register
1096 sig
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SIG
);
1099 SrbExtension
->CommandReg
= IDE_COMMAND_IDENTIFY
;
1103 SrbExtension
->CommandReg
= IDE_COMMAND_ATAPI_IDENTIFY
;
1107 NT_ASSERT(SlotIndex
< AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
1108 SrbExtension
->SlotIndex
= SlotIndex
;
1110 // program the CFIS in the CommandTable
1111 CommandHeader
= &PortExtension
->CommandList
[SlotIndex
];
1113 if (IsAtaCommand(SrbExtension
->AtaFunction
))
1115 AhciATA_CFIS(PortExtension
, SrbExtension
);
1117 else if (IsAtapiCommand(SrbExtension
->AtaFunction
))
1119 AhciATAPI_CFIS(PortExtension
, SrbExtension
);
1123 if (IsDataTransferNeeded(SrbExtension
))
1125 prdtlen
= AhciBuild_PRDT(PortExtension
, SrbExtension
);
1126 NT_ASSERT(prdtlen
!= -1);
1129 // Program the command header
1130 CommandHeader
->DI
.PRDTL
= prdtlen
; // number of entries in PRD table
1131 CommandHeader
->DI
.CFL
= 5;
1132 CommandHeader
->DI
.W
= (SrbExtension
->Flags
& ATA_FLAGS_DATA_OUT
) ? 1 : 0;
1133 CommandHeader
->DI
.P
= 0; // ATA Specifications says so
1134 CommandHeader
->DI
.PMP
= 0; // Port Multiplier
1136 // Reset -- Manual Configuation
1137 CommandHeader
->DI
.R
= 0;
1138 CommandHeader
->DI
.B
= 0;
1139 CommandHeader
->DI
.C
= 0;
1141 CommandHeader
->PRDBC
= 0;
1143 CommandHeader
->Reserved
[0] = 0;
1144 CommandHeader
->Reserved
[1] = 0;
1145 CommandHeader
->Reserved
[2] = 0;
1146 CommandHeader
->Reserved
[3] = 0;
1148 // set CommandHeader CTBA
1149 // I am really not sure if SrbExtension is 128 byte aligned or not
1150 // Command FIS will not work if it is not so.
1151 CommandTablePhysicalAddress
= StorPortGetPhysicalAddress(AdapterExtension
,
1156 // command table alignment
1157 NT_ASSERT((CommandTablePhysicalAddress
.LowPart
% 128) == 0);
1159 CommandHeader
->CTBA0
= CommandTablePhysicalAddress
.LowPart
;
1161 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1163 CommandHeader
->CTBA_U0
= CommandTablePhysicalAddress
.HighPart
;
1167 PortExtension
->Slot
[SlotIndex
] = Srb
;
1168 PortExtension
->QueueSlots
|= 1 << SlotIndex
;
1170 }// -- AhciProcessSrb();
1173 * @name AhciActivatePort
1176 * Program Port and populate command list
1178 * @param PortExtension
1183 __in PAHCI_PORT_EXTENSION PortExtension
1187 ULONG QueueSlots
, slotToActivate
, tmp
;
1188 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1190 DebugPrint("AhciActivatePort()\n");
1192 AdapterExtension
= PortExtension
->AdapterExtension
;
1193 QueueSlots
= PortExtension
->QueueSlots
;
1195 if (QueueSlots
== 0)
1199 // Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’
1200 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
1202 if (cmd
.ST
== 0) // PxCMD.ST == 0
1205 // get the lowest set bit
1206 tmp
= QueueSlots
& (QueueSlots
- 1);
1209 slotToActivate
= QueueSlots
;
1211 slotToActivate
= (QueueSlots
& (~tmp
));
1213 // mark that bit off in QueueSlots
1214 // so we can know we it is really needed to activate port or not
1215 PortExtension
->QueueSlots
&= ~slotToActivate
;
1216 // mark this CommandIssuedSlots
1217 // to validate in completeIssuedCommand
1218 PortExtension
->CommandIssuedSlots
|= slotToActivate
;
1220 // tell the HBA to issue this Command Slot to the given port
1221 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
, slotToActivate
);
1224 }// -- AhciActivatePort();
1227 * @name AhciProcessIO
1230 * Acquire Exclusive lock to port, populate pending commands to command List
1231 * program controller's port to process new commands in command list.
1233 * @param AdapterExtension
1240 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1242 __in PSCSI_REQUEST_BLOCK Srb
1245 STOR_LOCK_HANDLE lockhandle
;
1246 PSCSI_REQUEST_BLOCK tmpSrb
;
1247 PAHCI_PORT_EXTENSION PortExtension
;
1248 ULONG commandSlotMask
, occupiedSlots
, slotIndex
, NCS
;
1250 DebugPrint("AhciProcessIO()\n");
1251 DebugPrint("\tPathId: %d\n", PathId
);
1253 PortExtension
= &AdapterExtension
->PortExtension
[PathId
];
1255 NT_ASSERT(PathId
< AdapterExtension
->PortCount
);
1258 AddQueue(&PortExtension
->SrbQueue
, Srb
);
1260 if (PortExtension
->IsActive
== FALSE
)
1261 return; // we should wait for device to get active
1263 AhciZeroMemory(&lockhandle
, sizeof(lockhandle
));
1266 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
1268 occupiedSlots
= (PortExtension
->QueueSlots
| PortExtension
->CommandIssuedSlots
); // Busy command slots for given port
1269 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
1270 commandSlotMask
= (1 << NCS
) - 1; // available slots mask
1272 commandSlotMask
= (commandSlotMask
& ~occupiedSlots
);
1273 if(commandSlotMask
!= 0)
1275 // iterate over HBA port slots
1276 for (slotIndex
= 0; slotIndex
< NCS
; slotIndex
++)
1278 // find first free slot
1279 if ((commandSlotMask
& (1 << slotIndex
)) != 0)
1281 tmpSrb
= RemoveQueue(&PortExtension
->SrbQueue
);
1284 NT_ASSERT(tmpSrb
->PathId
== PathId
);
1285 AhciProcessSrb(PortExtension
, tmpSrb
, slotIndex
);
1300 AhciActivatePort(PortExtension
);
1303 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
1306 }// -- AhciProcessIO();
1309 * @name InquiryCompletion
1312 * InquiryCompletion routine should be called after device signals
1313 * for device inquiry request is completed (through interrupt)
1315 * @param PortExtension
1321 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1322 __in PAHCI_PORT_EXTENSION PortExtension
,
1323 __in PSCSI_REQUEST_BLOCK Srb
1327 PAHCI_SRB_EXTENSION SrbExtension
;
1329 DebugPrint("InquiryCompletion()\n");
1331 NT_ASSERT(PortExtension
!= NULL
);
1332 NT_ASSERT(Srb
!= NULL
);
1334 SrbStatus
= Srb
->SrbStatus
;
1335 SrbExtension
= GetSrbExtension(Srb
);
1337 if (SrbStatus
== SRB_STATUS_SUCCESS
)
1339 if (SrbExtension
->CommandReg
== IDE_COMMAND_IDENTIFY
)
1341 DebugPrint("Device: ATA\n");
1342 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATA
;
1346 DebugPrint("Device: ATAPI\n");
1347 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATAPI
;
1349 // TODO: Set Device Paramters
1351 else if (SrbStatus
== SRB_STATUS_NO_DEVICE
)
1353 DebugPrint("Device: No Device\n");
1354 AdapterExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_NODEVICE
;
1362 }// -- InquiryCompletion();
1365 * @name DeviceInquiryRequest
1368 * Tells wheather given port is implemented or not
1370 * @param AdapterExtension
1375 * return STOR status for DeviceInquiryRequest
1378 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
1381 DeviceInquiryRequest (
1382 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1383 __in PSCSI_REQUEST_BLOCK Srb
,
1388 ULONG DataBufferLength
;
1389 PAHCI_PORT_EXTENSION PortExtension
;
1390 PAHCI_SRB_EXTENSION SrbExtension
;
1392 DebugPrint("DeviceInquiryRequest()\n");
1394 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
1396 SrbExtension
= GetSrbExtension(Srb
);
1397 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1400 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
1401 if (Cdb
->CDB6INQUIRY3
.EnableVitalProductData
== 0)
1403 DebugPrint("\tEVPD Inquired\n");
1404 NT_ASSERT(SrbExtension
!= NULL
);
1406 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATA_IDENTIFY
;
1407 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
1408 SrbExtension
->CompletionRoutine
= InquiryCompletion
;
1409 SrbExtension
->CommandReg
= IDE_COMMAND_NOT_VALID
;
1411 // TODO: Should use AhciZeroMemory
1412 SrbExtension
->FeaturesLow
= 0;
1413 SrbExtension
->LBA0
= 0;
1414 SrbExtension
->LBA1
= 0;
1415 SrbExtension
->LBA2
= 0;
1416 SrbExtension
->Device
= 0;
1417 SrbExtension
->LBA3
= 0;
1418 SrbExtension
->LBA4
= 0;
1419 SrbExtension
->LBA5
= 0;
1420 SrbExtension
->FeaturesHigh
= 0;
1421 SrbExtension
->SectorCountLow
= 0;
1422 SrbExtension
->SectorCountHigh
= 0;
1424 SrbExtension
->Sgl
.NumberOfElements
= 1;
1425 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.LowPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.LowPart
;
1426 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.HighPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.HighPart
;
1427 SrbExtension
->Sgl
.List
[0].Length
= sizeof(IDENTIFY_DEVICE_DATA
);
1431 DebugPrint("\tVPD Inquired\n");
1433 DataBuffer
= Srb
->DataBuffer
;
1434 DataBufferLength
= Srb
->DataTransferLength
;
1436 if (DataBuffer
== NULL
)
1438 return SRB_STATUS_INVALID_REQUEST
;
1441 AhciZeroMemory(DataBuffer
, DataBufferLength
);
1444 return SRB_STATUS_BAD_FUNCTION
;
1447 AhciProcessIO(AdapterExtension
, Srb
->PathId
, Srb
);
1448 return SRB_STATUS_PENDING
;
1449 }// -- DeviceInquiryRequest();
1452 * @name AhciAdapterReset
1456 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
1457 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
1458 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
1459 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
1460 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
1461 * the HBA reset has completed.
1462 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
1463 * a hung or locked state.
1465 * @param AdapterExtension
1468 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
1472 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
1475 ULONG ghc
, ticks
, ghcStatus
;
1476 PAHCI_MEMORY_REGISTERS abar
= NULL
;
1478 DebugPrint("AhciAdapterReset()\n");
1480 abar
= AdapterExtension
->ABAR_Address
;
1481 if (abar
== NULL
) // basic sanity
1486 // HR -- Very first bit (lowest significant)
1487 ghc
= AHCI_Global_HBA_CONTROL_HR
;
1488 StorPortWriteRegisterUlong(AdapterExtension
, &abar
->GHC
, ghc
);
1490 for (ticks
= 0; ticks
< 50; ++ticks
)
1492 ghcStatus
= StorPortReadRegisterUlong(AdapterExtension
, &abar
->GHC
);
1493 if ((ghcStatus
& AHCI_Global_HBA_CONTROL_HR
) == 0)
1497 StorPortStallExecution(20000);
1500 if (ticks
== 50)// 1 second
1502 DebugPrint("\tDevice Timeout\n");
1507 }// -- AhciAdapterReset();
1510 * @name AhciZeroMemory
1513 * Clear buffer by filling zeros
1522 __in ULONG BufferSize
1526 for (i
= 0; i
< BufferSize
; i
++)
1532 }// -- AhciZeroMemory();
1538 * Tells wheather given port is implemented or not
1540 * @param AdapterExtension
1544 * return TRUE if provided port is valid (implemented) or not
1549 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1553 NT_ASSERT(pathId
>= 0);
1555 if (pathId
>= AdapterExtension
->PortCount
)
1560 return AdapterExtension
->PortExtension
[pathId
].IsActive
;
1561 }// -- IsPortValid()
1573 * return TRUE if Srb is successfully added to Queue
1579 __inout PAHCI_QUEUE Queue
,
1583 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1584 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1586 if (Queue
->Tail
== ((Queue
->Head
+ 1) % MAXIMUM_QUEUE_BUFFER_SIZE
))
1589 Queue
->Buffer
[Queue
->Head
++] = Srb
;
1590 Queue
->Head
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
1599 * Remove and return Srb from Queue
1610 __inout PAHCI_QUEUE Queue
1615 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1616 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
1618 if (Queue
->Head
== Queue
->Tail
)
1621 Srb
= Queue
->Buffer
[Queue
->Tail
++];
1622 Queue
->Tail
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
1625 }// -- RemoveQueue();
1628 * @name GetSrbExtension
1631 * GetSrbExtension from Srb make sure It is properly aligned
1636 * return SrbExtension
1642 __in PSCSI_REQUEST_BLOCK Srb
1646 ULONG_PTR SrbExtension
;
1648 SrbExtension
= Srb
->SrbExtension
;
1649 Offset
= SrbExtension
% 128;
1651 // CommandTable should be 128 byte aligned
1653 Offset
= 128 - Offset
;
1655 return (PAHCI_SRB_EXTENSION
)(SrbExtension
+ Offset
);
1656 }// -- PAHCI_SRB_EXTENSION();