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 AhciDebugPrint("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 AhciDebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength
);
54 receivedFISPhysical
= StorPortGetPhysicalAddress(adapterExtension
,
56 PortExtension
->ReceivedFIS
,
59 if ((mappedLength
== 0) || ((receivedFISPhysical
.LowPart
% 256) != 0))
61 AhciDebugPrint("\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 AhciDebugPrint("\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
;
135 PAHCI_PORT_EXTENSION PortExtension
;
137 AhciDebugPrint("AhciAllocateResourceForAdapter()\n");
139 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
140 AlignedNCS
= ROUND_UP(NCS
, 8);
142 // get port count -- Number of set bits in `AdapterExtension->PortImplemented`
144 portImplemented
= AdapterExtension
->PortImplemented
;
146 NT_ASSERT(portImplemented
!= 0);
147 for (index
= MAXIMUM_AHCI_PORT_COUNT
- 1; index
> 0; index
--)
148 if ((portImplemented
& (1 << index
)) != 0)
151 portCount
= index
+ 1;
152 AhciDebugPrint("\tPort Count: %d\n", portCount
);
154 AdapterExtension
->PortCount
= portCount
;
155 nonCachedExtensionSize
= sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
+ //should be 1K aligned
156 sizeof(AHCI_RECEIVED_FIS
) +
157 sizeof(IDENTIFY_DEVICE_DATA
);
159 // align nonCachedExtensionSize to 1024
160 nonCachedExtensionSize
= ROUND_UP(nonCachedExtensionSize
, 1024);
162 AdapterExtension
->NonCachedExtension
= StorPortGetUncachedExtension(AdapterExtension
,
164 nonCachedExtensionSize
* portCount
);
166 if (AdapterExtension
->NonCachedExtension
== NULL
)
168 AhciDebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
172 nonCachedExtension
= AdapterExtension
->NonCachedExtension
;
173 AhciZeroMemory(nonCachedExtension
, nonCachedExtensionSize
* portCount
);
175 for (index
= 0; index
< portCount
; index
++)
177 PortExtension
= &AdapterExtension
->PortExtension
[index
];
179 PortExtension
->DeviceParams
.IsActive
= FALSE
;
180 if ((AdapterExtension
->PortImplemented
& (1 << index
)) != 0)
182 PortExtension
->PortNumber
= index
;
183 PortExtension
->DeviceParams
.IsActive
= TRUE
;
184 PortExtension
->AdapterExtension
= AdapterExtension
;
185 PortExtension
->CommandList
= (PAHCI_COMMAND_HEADER
)nonCachedExtension
;
187 tmp
= (PCHAR
)(nonCachedExtension
+ sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
);
189 PortExtension
->ReceivedFIS
= (PAHCI_RECEIVED_FIS
)tmp
;
190 PortExtension
->IdentifyDeviceData
= (PIDENTIFY_DEVICE_DATA
)(tmp
+ sizeof(AHCI_RECEIVED_FIS
));
191 PortExtension
->MaxPortQueueDepth
= NCS
;
192 nonCachedExtension
+= nonCachedExtensionSize
;
197 }// -- AhciAllocateResourceForAdapter();
200 * @name AhciStartPort
203 * Try to start the port device
205 * @param AdapterExtension
206 * @param PortExtension
211 __in PAHCI_PORT_EXTENSION PortExtension
216 AHCI_TASK_FILE_DATA tfd
;
217 AHCI_INTERRUPT_ENABLE ie
;
218 AHCI_SERIAL_ATA_STATUS ssts
;
219 AHCI_SERIAL_ATA_CONTROL sctl
;
220 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
222 AhciDebugPrint("AhciStartPort()\n");
224 AdapterExtension
= PortExtension
->AdapterExtension
;
225 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
227 if ((cmd
.FR
== 1) && (cmd
.CR
== 1) && (cmd
.FRE
== 1) && (cmd
.ST
== 1))
234 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
, cmd
.Status
);
236 if (((cmd
.FR
== 1) && (cmd
.FRE
== 0)) ||
237 ((cmd
.CR
== 1) && (cmd
.ST
== 0)))
239 AhciDebugPrint("\tCOMRESET\n");
243 // Software causes a port reset (COMRESET) by writing 1h to the PxSCTL.DET field to invoke a
244 // COMRESET on the interface and start a re-establishment of Phy layer communications. Software shall
245 // wait at least 1 millisecond before clearing PxSCTL.DET to 0h; this ensures that at least one COMRESET
246 // signal is sent over the interface. After clearing PxSCTL.DET to 0h, software should wait for
247 // communication to be re-established as indicated by PxSSTS.DET being set to 3h. Then software should
248 // write all 1s to the PxSERR register to clear any bits that were set as part of the port reset.
250 sctl
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
);
252 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
, sctl
.Status
);
254 StorPortStallExecution(1000);
256 sctl
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
);
258 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
, sctl
.Status
);
260 // Poll DET to verify if a device is attached to the port
264 StorPortStallExecution(1000);
265 ssts
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SSTS
);
276 ssts
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SSTS
);
281 NT_ASSERT(cmd
.ST
== 0);
283 // make sure FIS Recieve is enabled (cmd.FRE)
287 StorPortStallExecution(10000);
288 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
290 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
, cmd
.Status
);
293 while((cmd
.FR
!= 1) && (index
< 3));
297 // failed to start FIS DMA engine
298 // it can crash the driver later
299 // so better to turn this port off
303 // start port channel
306 NT_ASSERT(cmd
.FRE
== 1);
307 NT_ASSERT(cmd
.CR
== 0);
309 // why assert? well If we face such condition on DET = 0x3
310 // then we don't have port in idle state and hence before executing this part of code
311 // we must have restarted it.
312 tfd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->TFD
);
314 if ((tfd
.STS
.BSY
) || (tfd
.STS
.DRQ
))
316 AhciDebugPrint("\tUnhandled Case BSY-DRQ\n");
319 // clear pending interrupts
320 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SERR
, (ULONG
)~0);
321 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
, (ULONG
)~0);
322 StorPortWriteRegisterUlong(AdapterExtension
, AdapterExtension
->IS
, (1 << PortExtension
->PortNumber
));
325 ie
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IE
);
326 /* Device to Host Register FIS Interrupt Enable */
328 /* PIO Setup FIS Interrupt Enable */
330 /* DMA Setup FIS Interrupt Enable */
332 /* Set Device Bits FIS Interrupt Enable */
334 /* Unknown FIS Interrupt Enable */
336 /* Descriptor Processed Interrupt Enable */
338 /* Port Change Interrupt Enable */
340 /* Device Mechanical Presence Enable */
342 /* PhyRdy Change Interrupt Enable */
344 /* Incorrect Port Multiplier Enable */
346 /* Overflow Enable */
348 /* Interface Non-fatal Error Enable */
350 /* Interface Fatal Error Enable */
352 /* Host Bus Data Error Enable */
354 /* Host Bus Fatal Error Enable */
356 /* Task File Error Enable */
359 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
360 /* Cold Presence Detect Enable */
361 if (cmd
.CPD
) // does it support CPD?
363 // disable it for now
367 // should I replace this to single line?
368 // by directly setting ie.Status?
370 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IE
, ie
.Status
);
373 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
, cmd
.Status
);
374 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
378 AhciDebugPrint("\tFailed to start Port\n");
386 AhciDebugPrint("\tDET == %x Unsupported\n", ssts
.DET
);
390 }// -- AhciStartPort();
393 * @name AhciCommandCompletionDpcRoutine
396 * Handles Completed Commands
399 * @param AdapterExtension
400 * @param SystemArgument1
401 * @param SystemArgument2
404 AhciCommandCompletionDpcRoutine (
406 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
407 __in PAHCI_PORT_EXTENSION PortExtension
,
408 __in PVOID SystemArgument2
411 PSCSI_REQUEST_BLOCK Srb
;
412 PAHCI_SRB_EXTENSION SrbExtension
;
413 STOR_LOCK_HANDLE lockhandle
= {0};
414 PAHCI_COMPLETION_ROUTINE CompletionRoutine
;
416 UNREFERENCED_PARAMETER(Dpc
);
417 UNREFERENCED_PARAMETER(SystemArgument2
);
419 AhciDebugPrint("AhciCommandCompletionDpcRoutine()\n");
421 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
422 Srb
= RemoveQueue(&PortExtension
->CompletionQueue
);
423 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
425 NT_ASSERT(Srb
!= NULL
);
427 if (Srb
->SrbStatus
== SRB_STATUS_PENDING
)
429 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
436 SrbExtension
= GetSrbExtension(Srb
);
438 CompletionRoutine
= SrbExtension
->CompletionRoutine
;
439 NT_ASSERT(CompletionRoutine
!= NULL
);
441 // now it's completion routine responsibility to set SrbStatus
442 CompletionRoutine(PortExtension
, Srb
);
444 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
447 }// -- AhciCommandCompletionDpcRoutine();
450 * @name AhciHwPassiveInitialize
453 * initializes the HBA and finds all devices that are of interest to the miniport driver. (at PASSIVE LEVEL)
455 * @param adapterExtension
458 * return TRUE if intialization was successful
461 AhciHwPassiveInitialize (
462 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
466 PAHCI_PORT_EXTENSION PortExtension
;
468 AhciDebugPrint("AhciHwPassiveInitialize()\n");
470 for (index
= 0; index
< AdapterExtension
->PortCount
; index
++)
472 if ((AdapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
474 PortExtension
= &AdapterExtension
->PortExtension
[index
];
475 PortExtension
->DeviceParams
.IsActive
= AhciStartPort(PortExtension
);
476 StorPortInitializeDpc(AdapterExtension
, &PortExtension
->CommandCompletion
, AhciCommandCompletionDpcRoutine
);
481 }// -- AhciHwPassiveInitialize();
484 * @name AhciHwInitialize
487 * initializes the HBA and finds all devices that are of interest to the miniport driver.
489 * @param adapterExtension
492 * return TRUE if intialization was successful
496 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
501 AhciDebugPrint("AhciHwInitialize()\n");
503 AdapterExtension
->StateFlags
.MessagePerPort
= FALSE
;
505 // First check what type of interrupt/synchronization device is using
506 ghc
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &AdapterExtension
->ABAR_Address
->GHC
);
508 // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector
509 // but has reverted to using the first vector only. When this bit is cleared to ‘0’,
510 // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
511 // software has allocated the number of messages requested
514 AdapterExtension
->StateFlags
.MessagePerPort
= TRUE
;
515 AhciDebugPrint("\tMultiple MSI based message not supported\n");
518 StorPortEnablePassiveInitialization(AdapterExtension
, AhciHwPassiveInitialize
);
521 }// -- AhciHwInitialize();
524 * @name AhciCompleteIssuedSrb
527 * Complete issued Srbs
529 * @param PortExtension
533 AhciCompleteIssuedSrb (
534 __in PAHCI_PORT_EXTENSION PortExtension
,
535 __in ULONG CommandsToComplete
539 PSCSI_REQUEST_BLOCK Srb
;
540 PAHCI_SRB_EXTENSION SrbExtension
;
541 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
543 AhciDebugPrint("AhciCompleteIssuedSrb()\n");
545 NT_ASSERT(CommandsToComplete
!= 0);
547 AhciDebugPrint("\tCompleted Commands: %d\n", CommandsToComplete
);
549 AdapterExtension
= PortExtension
->AdapterExtension
;
550 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
552 for (i
= 0; i
< NCS
; i
++)
554 if (((1 << i
) & CommandsToComplete
) != 0)
556 Srb
= PortExtension
->Slot
[i
];
563 SrbExtension
= GetSrbExtension(Srb
);
564 NT_ASSERT(SrbExtension
!= NULL
);
566 if (SrbExtension
->CompletionRoutine
!= NULL
)
568 AddQueue(&PortExtension
->CompletionQueue
, Srb
);
569 StorPortIssueDpc(AdapterExtension
, &PortExtension
->CommandCompletion
, PortExtension
, Srb
);
573 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
574 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
580 }// -- AhciCompleteIssuedSrb();
583 * @name AhciInterruptHandler
586 * Interrupt Handler for PortExtension
588 * @param PortExtension
592 AhciInterruptHandler (
593 __in PAHCI_PORT_EXTENSION PortExtension
596 ULONG is
, ci
, sact
, outstanding
;
597 AHCI_INTERRUPT_STATUS PxIS
;
598 AHCI_INTERRUPT_STATUS PxISMasked
;
599 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
601 AhciDebugPrint("AhciInterruptHandler()\n");
602 AhciDebugPrint("\tPort Number: %d\n", PortExtension
->PortNumber
);
604 AdapterExtension
= PortExtension
->AdapterExtension
;
605 NT_ASSERT(IsPortValid(AdapterExtension
, PortExtension
->PortNumber
));
608 // 1. Software determines the cause of the interrupt by reading the PxIS register.
609 // It is possible for multiple bits to be set
610 // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt.
611 // 3. Software clears the interrupt bit in IS.IPS corresponding to the port.
612 // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to
613 // the list of commands previously issued by software that are still outstanding.
614 // If executing native queued commands, software reads the PxSACT register and compares the current
615 // value to the list of commands previously issued by software.
616 // Software completes with success any outstanding command whose corresponding bit has been cleared in
617 // the respective register. PxCI and PxSACT are volatile registers; software should only use their values
618 // to determine commands that have completed, not to determine which commands have previously been issued.
619 // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2).
620 PxISMasked
.Status
= 0;
621 PxIS
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
);
625 // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES
626 if (PxIS
.HBFS
|| PxIS
.HBDS
|| PxIS
.IFS
|| PxIS
.TFES
)
628 // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process
629 // any native command queuing commands. To recover, the port must be restarted
630 // To detect an error that requires software recovery actions to be performed,
631 // software should check whether any of the following status bits are set on an interrupt:
632 // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set,
633 // software should perform the appropriate error recovery actions based on whether
634 // non-queued commands were being issued or native command queuing commands were being issued.
636 AhciDebugPrint("\tFatal Error: %x\n", PxIS
.Status
);
639 // Normal Command Completion
641 // A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory.
642 PxISMasked
.DHRS
= PxIS
.DHRS
;
643 // A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory.
644 PxISMasked
.PSS
= PxIS
.PSS
;
645 // A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory.
646 PxISMasked
.DSS
= PxIS
.DSS
;
647 // A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/
648 PxISMasked
.SDBS
= PxIS
.SDBS
;
649 // A PRD with the ‘I’ bit set has transferred all of its data.
650 PxISMasked
.DPS
= PxIS
.DPS
;
652 if (PxISMasked
.Status
!= 0)
654 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
, PxISMasked
.Status
);
658 // Clear port interrupt
659 // It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software.
660 is
= (1 << PortExtension
->PortNumber
);
661 StorPortWriteRegisterUlong(AdapterExtension
, AdapterExtension
->IS
, is
);
663 ci
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
);
664 sact
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SACT
);
666 outstanding
= ci
| sact
; // NOTE: Including both non-NCQ and NCQ based commands
667 if ((PortExtension
->CommandIssuedSlots
& (~outstanding
)) != 0)
669 AhciCompleteIssuedSrb(PortExtension
, (PortExtension
->CommandIssuedSlots
& (~outstanding
)));
670 PortExtension
->CommandIssuedSlots
&= outstanding
;
674 }// -- AhciInterruptHandler();
677 * @name AhciHwInterrupt
680 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
682 * @param AdapterExtension
685 * return TRUE Indicates that an interrupt was pending on adapter.
686 * return FALSE Indicates the interrupt was not ours.
690 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
693 ULONG portPending
, nextPort
, i
, portCount
;
695 if (AdapterExtension
->StateFlags
.Removed
)
700 portPending
= StorPortReadRegisterUlong(AdapterExtension
, AdapterExtension
->IS
);
702 // we process interrupt for implemented ports only
703 portCount
= AdapterExtension
->PortCount
;
704 portPending
= portPending
& AdapterExtension
->PortImplemented
;
706 if (portPending
== 0)
711 for (i
= 1; i
<= portCount
; i
++)
713 nextPort
= (AdapterExtension
->LastInterruptPort
+ i
) % portCount
;
714 if ((portPending
& (0x1 << nextPort
)) == 0)
717 NT_ASSERT(IsPortValid(AdapterExtension
, nextPort
));
719 if (AdapterExtension
->PortExtension
[nextPort
].DeviceParams
.IsActive
== FALSE
)
724 // we can assign this interrupt to this port
725 AdapterExtension
->LastInterruptPort
= nextPort
;
726 AhciInterruptHandler(&AdapterExtension
->PortExtension
[nextPort
]);
728 portPending
&= ~(1 << nextPort
);
730 // interrupt belongs to this device
731 // should always return TRUE
735 AhciDebugPrint("\tSomething went wrong");
737 }// -- AhciHwInterrupt();
740 * @name AhciHwStartIo
743 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
745 * @param adapterExtension
749 * return TRUE if the request was accepted
750 * return FALSE if the request must be submitted later
754 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
755 __in PSCSI_REQUEST_BLOCK Srb
758 AhciDebugPrint("AhciHwStartIo()\n");
760 if (!IsPortValid(AdapterExtension
, Srb
->PathId
))
762 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
763 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
767 switch(Srb
->Function
)
769 case SRB_FUNCTION_PNP
:
771 // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp
772 // If the function member of an SRB is set to SRB_FUNCTION_PNP,
773 // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK.
775 PSCSI_PNP_REQUEST_BLOCK pnpRequest
;
776 pnpRequest
= (PSCSI_PNP_REQUEST_BLOCK
)Srb
;
777 if ((pnpRequest
->SrbPnPFlags
& SRB_PNP_FLAGS_ADAPTER_REQUEST
) != 0)
779 switch(pnpRequest
->PnPAction
)
781 case StorRemoveDevice
:
782 case StorSurpriseRemoval
:
784 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
785 AdapterExtension
->StateFlags
.Removed
= 1;
786 AhciDebugPrint("\tAdapter removed\n");
791 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
792 AhciDebugPrint("\tRequested to Stop the adapter\n");
796 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
802 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
806 case SRB_FUNCTION_EXECUTE_SCSI
:
808 // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
809 // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
810 // routine does the following:
812 // - Gets and/or sets up whatever context the miniport driver maintains in its device,
813 // logical unit, and/or SRB extensions
814 // For example, a miniport driver might set up a logical unit extension with pointers
815 // to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value,
816 // and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be
817 // carried out on the HBA.
819 // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags,
820 // for the requested operation
821 // For a device I/O operation, such an internal routine generally selects the target device
822 // and sends the CDB over the bus to the target logical unit.
823 PCDB cdb
= (PCDB
)&Srb
->Cdb
;
824 if (Srb
->CdbLength
== 0)
826 AhciDebugPrint("\tOperationCode: %d\n", cdb
->CDB10
.OperationCode
);
827 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
831 NT_ASSERT(cdb
!= NULL
);
833 switch(cdb
->CDB10
.OperationCode
)
836 Srb
->SrbStatus
= DeviceInquiryRequest(AdapterExtension
, Srb
, cdb
);
838 case SCSIOP_REPORT_LUNS
:
839 Srb
->SrbStatus
= DeviceReportLuns(AdapterExtension
, Srb
, cdb
);
841 case SCSIOP_READ_CAPACITY
:
842 case SCSIOP_READ_CAPACITY16
:
843 Srb
->SrbStatus
= DeviceRequestCapacity(AdapterExtension
, Srb
, cdb
);
847 Srb
->SrbStatus
= DeviceRequestReadWrite(AdapterExtension
, Srb
, cdb
);
850 AhciDebugPrint("\tOperationCode: %d\n", cdb
->CDB10
.OperationCode
);
851 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
857 AhciDebugPrint("\tUnknown function code recieved: %x\n", Srb
->Function
);
858 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
862 if (Srb
->SrbStatus
!= SRB_STATUS_PENDING
)
864 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
867 }// -- AhciHwStartIo();
870 * @name AhciHwResetBus
873 * The HwStorResetBus routine is called by the port driver to clear error conditions.
875 * @param adapterExtension
879 * return TRUE if bus was successfully reset
883 __in PVOID AdapterExtension
,
887 STOR_LOCK_HANDLE lockhandle
= {0};
888 PAHCI_ADAPTER_EXTENSION adapterExtension
;
890 AhciDebugPrint("AhciHwResetBus()\n");
892 adapterExtension
= AdapterExtension
;
894 if (IsPortValid(AdapterExtension
, PathId
))
897 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
899 // TODO: Perform port reset
902 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
906 }// -- AhciHwResetBus();
909 * @name AhciHwFindAdapter
912 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
913 * HBA is supported and, if it is, to return configuration information about that adapter.
915 * 10.1 Platform Communication
916 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
918 * @param DeviceExtension
920 * @param BusInformation
921 * @param ArgumentString
927 * 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.
930 * 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.
932 * SP_RETURN_BAD_CONFIG
933 * Indicates that the supplied configuration information was invalid for the adapter.
935 * SP_RETURN_NOT_FOUND
936 * Indicates that no supported HBA was found for the supplied configuration information.
938 * @remarks Called by Storport.
942 __in PVOID AdapterExtension
,
943 __in PVOID HwContext
,
944 __in PVOID BusInformation
,
945 __in PVOID ArgumentString
,
946 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
947 __in PBOOLEAN Reserved3
951 ULONG index
, pci_cfg_len
;
952 PACCESS_RANGE accessRange
;
953 UCHAR pci_cfg_buf
[sizeof(PCI_COMMON_CONFIG
)];
955 PAHCI_MEMORY_REGISTERS abar
;
956 PPCI_COMMON_CONFIG pciConfigData
;
957 PAHCI_ADAPTER_EXTENSION adapterExtension
;
959 AhciDebugPrint("AhciHwFindAdapter()\n");
961 UNREFERENCED_PARAMETER(HwContext
);
962 UNREFERENCED_PARAMETER(BusInformation
);
963 UNREFERENCED_PARAMETER(ArgumentString
);
964 UNREFERENCED_PARAMETER(Reserved3
);
966 adapterExtension
= AdapterExtension
;
967 adapterExtension
->SlotNumber
= ConfigInfo
->SlotNumber
;
968 adapterExtension
->SystemIoBusNumber
= ConfigInfo
->SystemIoBusNumber
;
970 // get PCI configuration header
971 pci_cfg_len
= StorPortGetBusData(
974 adapterExtension
->SystemIoBusNumber
,
975 adapterExtension
->SlotNumber
,
977 sizeof(PCI_COMMON_CONFIG
));
979 if (pci_cfg_len
!= sizeof(PCI_COMMON_CONFIG
))
981 AhciDebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG
), pci_cfg_len
);
982 return SP_RETURN_ERROR
;//Not a valid device at the given bus number
985 pciConfigData
= (PPCI_COMMON_CONFIG
)pci_cfg_buf
;
986 adapterExtension
->VendorID
= pciConfigData
->VendorID
;
987 adapterExtension
->DeviceID
= pciConfigData
->DeviceID
;
988 adapterExtension
->RevisionID
= pciConfigData
->RevisionID
;
989 // 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).
990 adapterExtension
->AhciBaseAddress
= pciConfigData
->u
.type0
.BaseAddresses
[5] & (0xFFFFFFF0);
992 AhciDebugPrint("\tVendorID:%d DeviceID:%d RevisionID:%d\n", adapterExtension
->VendorID
,
993 adapterExtension
->DeviceID
,
994 adapterExtension
->RevisionID
);
998 if (ConfigInfo
->NumberOfAccessRanges
> 0)
1000 accessRange
= *(ConfigInfo
->AccessRanges
);
1001 for (index
= 0; index
< ConfigInfo
->NumberOfAccessRanges
; index
++)
1003 if (accessRange
[index
].RangeStart
.QuadPart
== adapterExtension
->AhciBaseAddress
)
1005 abar
= StorPortGetDeviceBase(adapterExtension
,
1006 ConfigInfo
->AdapterInterfaceType
,
1007 ConfigInfo
->SystemIoBusNumber
,
1008 accessRange
[index
].RangeStart
,
1009 accessRange
[index
].RangeLength
,
1010 !accessRange
[index
].RangeInMemory
);
1018 AhciDebugPrint("\tabar == NULL\n");
1019 return SP_RETURN_ERROR
; // corrupted information supplied
1022 adapterExtension
->ABAR_Address
= abar
;
1023 adapterExtension
->CAP
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP
);
1024 adapterExtension
->CAP2
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP2
);
1025 adapterExtension
->Version
= StorPortReadRegisterUlong(adapterExtension
, &abar
->VS
);
1026 adapterExtension
->LastInterruptPort
= (ULONG
)-1;
1029 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
1030 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
1031 ghc
.Status
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
1032 // AE := Highest Significant bit of GHC
1033 if (ghc
.AE
!= 0)// Hmm, controller was already in power state
1035 // reset controller to have it in known state
1036 AhciDebugPrint("\tAE Already set, Reset()\n");
1037 if (!AhciAdapterReset(adapterExtension
))
1039 AhciDebugPrint("\tReset Failed!\n");
1040 return SP_RETURN_ERROR
;// reset failed
1045 ghc
.AE
= 1;// only AE=1
1046 // tell the controller that we know about AHCI
1047 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
.Status
);
1049 adapterExtension
->IS
= &abar
->IS
;
1050 adapterExtension
->PortImplemented
= StorPortReadRegisterUlong(adapterExtension
, &abar
->PI
);
1052 if (adapterExtension
->PortImplemented
== 0)
1054 AhciDebugPrint("\tadapterExtension->PortImplemented == 0\n");
1055 return SP_RETURN_ERROR
;
1058 ConfigInfo
->Master
= TRUE
;
1059 ConfigInfo
->AlignmentMask
= 0x3;
1060 ConfigInfo
->ScatterGather
= TRUE
;
1061 ConfigInfo
->DmaWidth
= Width32Bits
;
1062 ConfigInfo
->WmiDataProvider
= FALSE
;
1063 ConfigInfo
->Dma32BitAddresses
= TRUE
;
1065 if (IsAdapterCAPS64(adapterExtension
->CAP
))
1067 ConfigInfo
->Dma64BitAddresses
= TRUE
;
1070 ConfigInfo
->MaximumNumberOfTargets
= 1;
1071 ConfigInfo
->ResetTargetSupported
= TRUE
;
1072 ConfigInfo
->NumberOfPhysicalBreaks
= 0x21;
1073 ConfigInfo
->MaximumNumberOfLogicalUnits
= 1;
1074 ConfigInfo
->NumberOfBuses
= MAXIMUM_AHCI_PORT_COUNT
;
1075 ConfigInfo
->MaximumTransferLength
= MAXIMUM_TRANSFER_LENGTH
;
1076 ConfigInfo
->SynchronizationModel
= StorSynchronizeFullDuplex
;
1078 // Turn IE -- Interrupt Enabled
1079 ghc
.Status
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
1081 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
.Status
);
1083 // allocate necessary resource for each port
1084 if (!AhciAllocateResourceForAdapter(adapterExtension
, ConfigInfo
))
1087 return SP_RETURN_ERROR
;
1090 for (index
= 0; index
< adapterExtension
->PortCount
; index
++)
1092 if ((adapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
1093 AhciPortInitialize(&adapterExtension
->PortExtension
[index
]);
1096 return SP_RETURN_FOUND
;
1097 }// -- AhciHwFindAdapter();
1103 * Initial Entrypoint for storahci miniport driver
1105 * @param DriverObject
1106 * @param RegistryPath
1109 * NT_STATUS in case of driver loaded successfully.
1113 __in PVOID DriverObject
,
1114 __in PVOID RegistryPath
1118 // initialize the hardware data structure
1119 HW_INITIALIZATION_DATA hwInitializationData
= {0};
1121 // set size of hardware initialization structure
1122 hwInitializationData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
1124 // identity required miniport entry point routines
1125 hwInitializationData
.HwStartIo
= AhciHwStartIo
;
1126 hwInitializationData
.HwResetBus
= AhciHwResetBus
;
1127 hwInitializationData
.HwInterrupt
= AhciHwInterrupt
;
1128 hwInitializationData
.HwInitialize
= AhciHwInitialize
;
1129 hwInitializationData
.HwFindAdapter
= AhciHwFindAdapter
;
1131 // adapter specific information
1132 hwInitializationData
.TaggedQueuing
= TRUE
;
1133 hwInitializationData
.AutoRequestSense
= TRUE
;
1134 hwInitializationData
.MultipleRequestPerLu
= TRUE
;
1135 hwInitializationData
.NeedPhysicalAddresses
= TRUE
;
1137 hwInitializationData
.NumberOfAccessRanges
= 6;
1138 hwInitializationData
.AdapterInterfaceType
= PCIBus
;
1139 hwInitializationData
.MapBuffers
= STOR_MAP_NON_READ_WRITE_BUFFERS
;
1141 // set required extension sizes
1142 hwInitializationData
.SrbExtensionSize
= sizeof(AHCI_SRB_EXTENSION
);
1143 hwInitializationData
.DeviceExtensionSize
= sizeof(AHCI_ADAPTER_EXTENSION
);
1145 // register our hw init data
1146 status
= StorPortInitialize(DriverObject
,
1148 &hwInitializationData
,
1151 NT_ASSERT(status
== STATUS_SUCCESS
);
1153 }// -- DriverEntry();
1156 * @name AhciATA_CFIS
1159 * create ATA CFIS from Srb
1161 * @param PortExtension
1165 * Number of CFIS fields used in DWORD
1169 __in PAHCI_PORT_EXTENSION PortExtension
,
1170 __in PAHCI_SRB_EXTENSION SrbExtension
1173 PAHCI_COMMAND_TABLE cmdTable
;
1175 UNREFERENCED_PARAMETER(PortExtension
);
1177 AhciDebugPrint("AhciATA_CFIS()\n");
1179 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
1181 AhciZeroMemory((PCHAR
)cmdTable
->CFIS
, sizeof(cmdTable
->CFIS
));
1183 cmdTable
->CFIS
[AHCI_ATA_CFIS_FisType
] = FIS_TYPE_REG_H2D
; // FIS Type
1184 cmdTable
->CFIS
[AHCI_ATA_CFIS_PMPort_C
] = (1 << 7); // PM Port & C
1185 cmdTable
->CFIS
[AHCI_ATA_CFIS_CommandReg
] = SrbExtension
->CommandReg
;
1187 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesLow
] = SrbExtension
->FeaturesLow
;
1188 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA0
] = SrbExtension
->LBA0
;
1189 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA1
] = SrbExtension
->LBA1
;
1190 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA2
] = SrbExtension
->LBA2
;
1191 cmdTable
->CFIS
[AHCI_ATA_CFIS_Device
] = SrbExtension
->Device
;
1192 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA3
] = SrbExtension
->LBA3
;
1193 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA4
] = SrbExtension
->LBA4
;
1194 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA5
] = SrbExtension
->LBA5
;
1195 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesHigh
] = SrbExtension
->FeaturesHigh
;
1196 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountLow
] = SrbExtension
->SectorCountLow
;
1197 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountHigh
] = SrbExtension
->SectorCountHigh
;
1200 }// -- AhciATA_CFIS();
1203 * @name AhciATAPI_CFIS
1206 * create ATAPI CFIS from Srb
1208 * @param PortExtension
1212 * Number of CFIS fields used in DWORD
1216 __in PAHCI_PORT_EXTENSION PortExtension
,
1217 __in PAHCI_SRB_EXTENSION SrbExtension
1220 UNREFERENCED_PARAMETER(PortExtension
);
1221 UNREFERENCED_PARAMETER(SrbExtension
);
1223 AhciDebugPrint("AhciATAPI_CFIS()\n");
1226 }// -- AhciATAPI_CFIS();
1229 * @name AhciBuild_PRDT
1232 * Build PRDT for data transfer
1234 * @param PortExtension
1238 * Return number of entries in PRDT.
1242 __in PAHCI_PORT_EXTENSION PortExtension
,
1243 __in PAHCI_SRB_EXTENSION SrbExtension
1247 PAHCI_COMMAND_TABLE cmdTable
;
1248 PLOCAL_SCATTER_GATHER_LIST sgl
;
1249 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1251 AhciDebugPrint("AhciBuild_PRDT()\n");
1253 sgl
= SrbExtension
->pSgl
;
1254 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
1255 AdapterExtension
= PortExtension
->AdapterExtension
;
1257 NT_ASSERT(sgl
!= NULL
);
1258 NT_ASSERT(sgl
->NumberOfElements
< MAXIMUM_AHCI_PRDT_ENTRIES
);
1260 for (index
= 0; index
< sgl
->NumberOfElements
; index
++)
1262 NT_ASSERT(sgl
->List
[index
].Length
<= MAXIMUM_TRANSFER_LENGTH
);
1264 cmdTable
->PRDT
[index
].DBA
= sgl
->List
[index
].PhysicalAddress
.LowPart
;
1265 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1267 cmdTable
->PRDT
[index
].DBAU
= sgl
->List
[index
].PhysicalAddress
.HighPart
;
1270 // Data Byte Count (DBC): A ‘0’ based value that Indicates the length, in bytes, of the data block.
1271 // A maximum of length of 4MB may exist for any entry. Bit ‘0’ of this field must always be ‘1’ to
1272 // indicate an even byte count. A value of ‘1’ indicates 2 bytes, ‘3’ indicates 4 bytes, etc.
1273 cmdTable
->PRDT
[index
].DBC
= sgl
->List
[index
].Length
- 1;
1276 return sgl
->NumberOfElements
;
1277 }// -- AhciBuild_PRDT();
1280 * @name AhciProcessSrb
1283 * Prepare Srb for IO processing
1285 * @param PortExtension
1292 __in PAHCI_PORT_EXTENSION PortExtension
,
1293 __in PSCSI_REQUEST_BLOCK Srb
,
1294 __in ULONG SlotIndex
1297 ULONG prdtlen
, sig
, length
, cfl
;
1298 PAHCI_SRB_EXTENSION SrbExtension
;
1299 PAHCI_COMMAND_HEADER CommandHeader
;
1300 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1301 STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress
;
1303 AhciDebugPrint("AhciProcessSrb()\n");
1305 NT_ASSERT(Srb
->PathId
== PortExtension
->PortNumber
);
1307 SrbExtension
= GetSrbExtension(Srb
);
1308 AdapterExtension
= PortExtension
->AdapterExtension
;
1310 NT_ASSERT(SrbExtension
!= NULL
);
1311 NT_ASSERT(SrbExtension
->AtaFunction
!= 0);
1313 if ((SrbExtension
->AtaFunction
== ATA_FUNCTION_ATA_IDENTIFY
) &&
1314 (SrbExtension
->CommandReg
== IDE_COMMAND_NOT_VALID
))
1316 // Here we are safe to check SIG register
1317 sig
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SIG
);
1320 AhciDebugPrint("\tATA Device Found!\n");
1321 SrbExtension
->CommandReg
= IDE_COMMAND_IDENTIFY
;
1325 AhciDebugPrint("\tATAPI Device Found!\n");
1326 SrbExtension
->CommandReg
= IDE_COMMAND_ATAPI_IDENTIFY
;
1330 NT_ASSERT(SlotIndex
< AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
1331 SrbExtension
->SlotIndex
= SlotIndex
;
1333 // program the CFIS in the CommandTable
1334 CommandHeader
= &PortExtension
->CommandList
[SlotIndex
];
1337 if (IsAtapiCommand(SrbExtension
->AtaFunction
))
1339 cfl
= AhciATAPI_CFIS(PortExtension
, SrbExtension
);
1341 else if (IsAtaCommand(SrbExtension
->AtaFunction
))
1343 cfl
= AhciATA_CFIS(PortExtension
, SrbExtension
);
1351 if (IsDataTransferNeeded(SrbExtension
))
1353 prdtlen
= AhciBuild_PRDT(PortExtension
, SrbExtension
);
1354 NT_ASSERT(prdtlen
!= -1);
1357 // Program the command header
1358 CommandHeader
->DI
.PRDTL
= prdtlen
; // number of entries in PRD table
1359 CommandHeader
->DI
.CFL
= cfl
;
1360 CommandHeader
->DI
.A
= (SrbExtension
->AtaFunction
& ATA_FUNCTION_ATAPI_COMMAND
) ? 1 : 0;
1361 CommandHeader
->DI
.W
= (SrbExtension
->Flags
& ATA_FLAGS_DATA_OUT
) ? 1 : 0;
1362 CommandHeader
->DI
.P
= 0; // ATA Specifications says so
1363 CommandHeader
->DI
.PMP
= 0; // Port Multiplier
1365 // Reset -- Manual Configuation
1366 CommandHeader
->DI
.R
= 0;
1367 CommandHeader
->DI
.B
= 0;
1368 CommandHeader
->DI
.C
= 0;
1370 CommandHeader
->PRDBC
= 0;
1372 CommandHeader
->Reserved
[0] = 0;
1373 CommandHeader
->Reserved
[1] = 0;
1374 CommandHeader
->Reserved
[2] = 0;
1375 CommandHeader
->Reserved
[3] = 0;
1377 // set CommandHeader CTBA
1378 CommandTablePhysicalAddress
= StorPortGetPhysicalAddress(AdapterExtension
,
1383 NT_ASSERT(length
!= 0);
1385 // command table alignment
1386 NT_ASSERT((CommandTablePhysicalAddress
.LowPart
% 128) == 0);
1388 CommandHeader
->CTBA
= CommandTablePhysicalAddress
.LowPart
;
1390 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1392 CommandHeader
->CTBA_U
= CommandTablePhysicalAddress
.HighPart
;
1396 PortExtension
->Slot
[SlotIndex
] = Srb
;
1397 PortExtension
->QueueSlots
|= 1 << SlotIndex
;
1399 }// -- AhciProcessSrb();
1402 * @name AhciActivatePort
1405 * Program Port and populate command list
1407 * @param PortExtension
1412 __in PAHCI_PORT_EXTENSION PortExtension
1416 ULONG QueueSlots
, slotToActivate
, tmp
;
1417 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1419 AhciDebugPrint("AhciActivatePort()\n");
1421 AdapterExtension
= PortExtension
->AdapterExtension
;
1422 QueueSlots
= PortExtension
->QueueSlots
;
1424 if (QueueSlots
== 0)
1430 // Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’
1431 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
1433 if (cmd
.ST
== 0) // PxCMD.ST == 0
1438 // get the lowest set bit
1439 tmp
= QueueSlots
& (QueueSlots
- 1);
1442 slotToActivate
= QueueSlots
;
1444 slotToActivate
= (QueueSlots
& (~tmp
));
1446 // mark that bit off in QueueSlots
1447 // so we can know we it is really needed to activate port or not
1448 PortExtension
->QueueSlots
&= ~slotToActivate
;
1449 // mark this CommandIssuedSlots
1450 // to validate in completeIssuedCommand
1451 PortExtension
->CommandIssuedSlots
|= slotToActivate
;
1453 // tell the HBA to issue this Command Slot to the given port
1454 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
, slotToActivate
);
1457 }// -- AhciActivatePort();
1460 * @name AhciProcessIO
1463 * Acquire Exclusive lock to port, populate pending commands to command List
1464 * program controller's port to process new commands in command list.
1466 * @param AdapterExtension
1473 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1475 __in PSCSI_REQUEST_BLOCK Srb
1478 PSCSI_REQUEST_BLOCK tmpSrb
;
1479 STOR_LOCK_HANDLE lockhandle
= {0};
1480 PAHCI_PORT_EXTENSION PortExtension
;
1481 ULONG commandSlotMask
, occupiedSlots
, slotIndex
, NCS
;
1483 AhciDebugPrint("AhciProcessIO()\n");
1484 AhciDebugPrint("\tPathId: %d\n", PathId
);
1486 PortExtension
= &AdapterExtension
->PortExtension
[PathId
];
1488 NT_ASSERT(PathId
< AdapterExtension
->PortCount
);
1491 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
1494 AddQueue(&PortExtension
->SrbQueue
, Srb
);
1496 if (PortExtension
->DeviceParams
.IsActive
== FALSE
)
1499 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
1500 return; // we should wait for device to get active
1503 occupiedSlots
= (PortExtension
->QueueSlots
| PortExtension
->CommandIssuedSlots
); // Busy command slots for given port
1504 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
1505 commandSlotMask
= (1 << NCS
) - 1; // available slots mask
1507 commandSlotMask
= (commandSlotMask
& ~occupiedSlots
);
1508 if(commandSlotMask
!= 0)
1510 // iterate over HBA port slots
1511 for (slotIndex
= 0; slotIndex
< NCS
; slotIndex
++)
1513 // find first free slot
1514 if ((commandSlotMask
& (1 << slotIndex
)) != 0)
1516 tmpSrb
= RemoveQueue(&PortExtension
->SrbQueue
);
1519 NT_ASSERT(tmpSrb
->PathId
== PathId
);
1520 AhciProcessSrb(PortExtension
, tmpSrb
, slotIndex
);
1535 AhciActivatePort(PortExtension
);
1538 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
1541 }// -- AhciProcessIO();
1544 * @name InquiryCompletion
1547 * InquiryCompletion routine should be called after device signals
1548 * for device inquiry request is completed (through interrupt)
1550 * @param PortExtension
1556 __in PAHCI_PORT_EXTENSION PortExtension
,
1557 __in PSCSI_REQUEST_BLOCK Srb
1562 PINQUIRYDATA InquiryData
;
1563 PAHCI_SRB_EXTENSION SrbExtension
;
1564 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1565 PIDENTIFY_DEVICE_DATA IdentifyDeviceData
;
1567 AhciDebugPrint("InquiryCompletion()\n");
1569 NT_ASSERT(Srb
!= NULL
);
1570 NT_ASSERT(PortExtension
!= NULL
);
1572 cdb
= (PCDB
)&Srb
->Cdb
;
1573 InquiryData
= Srb
->DataBuffer
;
1574 SrbExtension
= GetSrbExtension(Srb
);
1575 AdapterExtension
= PortExtension
->AdapterExtension
;
1576 IdentifyDeviceData
= PortExtension
->IdentifyDeviceData
;
1578 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
1580 if (Srb
->SrbStatus
== SRB_STATUS_NO_DEVICE
)
1582 PortExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_NODEVICE
;
1587 NT_ASSERT(InquiryData
!= NULL
);
1588 NT_ASSERT(Srb
->SrbStatus
== SRB_STATUS_SUCCESS
);
1590 // Device specific data
1591 PortExtension
->DeviceParams
.MaxLba
.QuadPart
= 0;
1593 if (SrbExtension
->CommandReg
== IDE_COMMAND_IDENTIFY
)
1595 PortExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATA
;
1596 if (IdentifyDeviceData
->GeneralConfiguration
.RemovableMedia
)
1598 PortExtension
->DeviceParams
.RemovableDevice
= 1;
1601 if (IdentifyDeviceData
->CommandSetSupport
.BigLba
&& IdentifyDeviceData
->CommandSetActive
.BigLba
)
1603 PortExtension
->DeviceParams
.Lba48BitMode
= 1;
1606 PortExtension
->DeviceParams
.AccessType
= DIRECT_ACCESS_DEVICE
;
1608 /* Device max address lba */
1609 if (PortExtension
->DeviceParams
.Lba48BitMode
)
1611 PortExtension
->DeviceParams
.MaxLba
.LowPart
= IdentifyDeviceData
->Max48BitLBA
[0];
1612 PortExtension
->DeviceParams
.MaxLba
.HighPart
= IdentifyDeviceData
->Max48BitLBA
[1];
1616 PortExtension
->DeviceParams
.MaxLba
.LowPart
= IdentifyDeviceData
->UserAddressableSectors
;
1619 /* Bytes Per Logical Sector */
1620 if (IdentifyDeviceData
->PhysicalLogicalSectorSize
.LogicalSectorLongerThan256Words
)
1622 AhciDebugPrint("\tBytesPerLogicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1626 PortExtension
->DeviceParams
.BytesPerLogicalSector
= DEVICE_ATA_BLOCK_SIZE
;
1628 /* Bytes Per Physical Sector */
1629 if (IdentifyDeviceData
->PhysicalLogicalSectorSize
.MultipleLogicalSectorsPerPhysicalSector
)
1631 AhciDebugPrint("\tBytesPerPhysicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1635 PortExtension
->DeviceParams
.BytesPerPhysicalSector
= DEVICE_ATA_BLOCK_SIZE
;
1637 // TODO: Add other device params
1638 AhciDebugPrint("\tATA Device\n");
1642 AhciDebugPrint("\tATAPI Device\n");
1643 PortExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATAPI
;
1644 PortExtension
->DeviceParams
.AccessType
= READ_ONLY_DIRECT_ACCESS_DEVICE
;
1647 // INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h
1648 if (Srb
->DataTransferLength
< INQUIRYDATABUFFERSIZE
)
1650 AhciDebugPrint("\tDataBufferLength < sizeof(INQUIRYDATA), Could crash the driver.\n");
1653 // update data transfer length
1654 Srb
->DataTransferLength
= INQUIRYDATABUFFERSIZE
;
1656 // prepare data to send
1657 InquiryData
->Versions
= 2;
1658 InquiryData
->Wide32Bit
= 1;
1659 InquiryData
->CommandQueue
= 0; // NCQ not supported
1660 InquiryData
->ResponseDataFormat
= 0x2;
1661 InquiryData
->DeviceTypeModifier
= 0;
1662 InquiryData
->DeviceTypeQualifier
= DEVICE_CONNECTED
;
1663 InquiryData
->AdditionalLength
= INQUIRYDATABUFFERSIZE
- 5;
1664 InquiryData
->DeviceType
= PortExtension
->DeviceParams
.AccessType
;
1665 InquiryData
->RemovableMedia
= PortExtension
->DeviceParams
.RemovableDevice
;
1667 // TODO: Fill VendorID, Product Revision Level and other string fields
1668 InquiryData
->VendorId
[0] = '2';
1669 InquiryData
->ProductId
[0] = '3';
1670 InquiryData
->ProductRevisionLevel
[0] = '4';
1673 status
= StorPortSetDeviceQueueDepth(PortExtension
->AdapterExtension
,
1677 AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
1679 NT_ASSERT(status
== TRUE
);
1681 }// -- InquiryCompletion();
1684 * @name DeviceRequestReadWrite
1687 * Handle SCSIOP_READ SCSIOP_WRITE OperationCode
1689 * @param AdapterExtension
1694 * return STOR status for DeviceReportLuns
1696 UCHAR
DeviceRequestReadWrite (
1697 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1698 __in PSCSI_REQUEST_BLOCK Srb
,
1704 PAHCI_SRB_EXTENSION SrbExtension
;
1705 PAHCI_PORT_EXTENSION PortExtension
;
1706 ULONG DataTransferLength
, BytesPerSector
, SectorCount
;
1708 AhciDebugPrint("DeviceRequestReadWrite()\n");
1710 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
1711 NT_ASSERT((Cdb
->CDB10
.OperationCode
== SCSIOP_READ
) || (Cdb
->CDB10
.OperationCode
== SCSIOP_WRITE
));
1713 SrbExtension
= GetSrbExtension(Srb
);
1714 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1716 DataTransferLength
= Srb
->DataTransferLength
;
1717 BytesPerSector
= PortExtension
->DeviceParams
.BytesPerLogicalSector
;
1719 NT_ASSERT(BytesPerSector
> 0);
1721 ROUND_UP(DataTransferLength
, BytesPerSector
);
1723 SectorCount
= DataTransferLength
/ BytesPerSector
;
1724 SectorNo
= AhciGetLba(Cdb
);
1725 IsReading
= (Cdb
->CDB10
.OperationCode
== SCSIOP_READ
);
1727 NT_ASSERT(SectorCount
> 0);
1729 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATA_READ
;
1730 SrbExtension
->Flags
|= ATA_FLAGS_USE_DMA
;
1731 SrbExtension
->CompletionRoutine
= NULL
;
1735 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
1736 SrbExtension
->CommandReg
= IDE_COMMAND_READ_DMA
;
1740 SrbExtension
->Flags
|= ATA_FLAGS_DATA_OUT
;
1744 SrbExtension
->FeaturesLow
= 0;
1745 SrbExtension
->LBA0
= (SectorNo
>> 0) & 0xFF;
1746 SrbExtension
->LBA1
= (SectorNo
>> 8) & 0xFF;
1747 SrbExtension
->LBA2
= (SectorNo
>> 16) & 0xFF;
1749 SrbExtension
->Device
= (0xA0 | IDE_LBA_MODE
);
1751 if (PortExtension
->DeviceParams
.Lba48BitMode
)
1753 SrbExtension
->Flags
|= ATA_FLAGS_48BIT_COMMAND
;
1754 SrbExtension
->CommandReg
= IDE_COMMAND_READ_DMA_EXT
;
1756 SrbExtension
->LBA3
= (SectorNo
>> 24) & 0xFF;
1757 SrbExtension
->LBA4
= (SectorNo
>> 32) & 0xFF;
1758 SrbExtension
->LBA5
= (SectorNo
>> 40) & 0xFF;
1765 SrbExtension
->FeaturesHigh
= 0;
1766 SrbExtension
->SectorCountLow
= (SectorCount
>> 0) & 0xFF;
1767 SrbExtension
->SectorCountHigh
= (SectorCount
>> 8) & 0xFF;
1769 NT_ASSERT(SectorCount
< 0x100);
1771 SrbExtension
->pSgl
= (PLOCAL_SCATTER_GATHER_LIST
)StorPortGetScatterGatherList(AdapterExtension
, Srb
);
1773 AhciProcessIO(AdapterExtension
, Srb
->PathId
, Srb
);
1774 return SRB_STATUS_PENDING
;
1775 }// -- DeviceRequestReadWrite();
1778 * @name DeviceRequestCapacity
1781 * Handle SCSIOP_READ_CAPACITY OperationCode
1783 * @param AdapterExtension
1788 * return STOR status for DeviceReportLuns
1790 UCHAR
DeviceRequestCapacity (
1791 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1792 __in PSCSI_REQUEST_BLOCK Srb
,
1796 ULONG MaxLba
, BytesPerLogicalSector
;
1797 PREAD_CAPACITY_DATA ReadCapacity
;
1798 PAHCI_PORT_EXTENSION PortExtension
;
1800 AhciDebugPrint("DeviceRequestCapacity()\n");
1802 UNREFERENCED_PARAMETER(AdapterExtension
);
1803 UNREFERENCED_PARAMETER(Cdb
);
1805 NT_ASSERT(Srb
->DataBuffer
!= NULL
);
1806 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
1808 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1810 if (Cdb
->CDB10
.OperationCode
== SCSIOP_READ_CAPACITY
)
1812 ReadCapacity
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1815 BytesPerLogicalSector
= PortExtension
->DeviceParams
.BytesPerLogicalSector
;
1816 MaxLba
= (ULONG
)PortExtension
->DeviceParams
.MaxLba
.QuadPart
;
1818 // I trust you windows :D
1819 NT_ASSERT(Srb
->DataTransferLength
>= sizeof(READ_CAPACITY_DATA
));
1821 // I trust you user :D
1822 NT_ASSERT(PortExtension
->DeviceParams
.MaxLba
.QuadPart
< (ULONG
)-1);
1824 // Actually I don't trust anyone :p
1825 Srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
1827 REVERSE_BYTES(&ReadCapacity
->BytesPerBlock
, &BytesPerLogicalSector
);
1828 REVERSE_BYTES(&ReadCapacity
->LogicalBlockAddress
, &MaxLba
);
1832 AhciDebugPrint("\tSCSIOP_READ_CAPACITY16 not supported\n");
1836 return SRB_STATUS_SUCCESS
;
1837 }// -- DeviceRequestCapacity();
1840 * @name DeviceReportLuns
1843 * Handle SCSIOP_REPORT_LUNS OperationCode
1845 * @param AdapterExtension
1850 * return STOR status for DeviceReportLuns
1852 UCHAR
DeviceReportLuns (
1853 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1854 __in PSCSI_REQUEST_BLOCK Srb
,
1860 AhciDebugPrint("DeviceReportLuns()\n");
1862 UNREFERENCED_PARAMETER(AdapterExtension
);
1863 UNREFERENCED_PARAMETER(Cdb
);
1865 NT_ASSERT(Srb
->DataTransferLength
>= sizeof(LUN_LIST
));
1866 NT_ASSERT(Cdb
->CDB10
.OperationCode
== SCSIOP_REPORT_LUNS
);
1868 LunList
= (PLUN_LIST
)Srb
->DataBuffer
;
1870 NT_ASSERT(LunList
!= NULL
);
1872 AhciZeroMemory((PCHAR
)LunList
, sizeof(LUN_LIST
));
1874 LunList
->LunListLength
[3] = 8;
1876 Srb
->ScsiStatus
= SCSISTAT_GOOD
;
1877 Srb
->DataTransferLength
= sizeof(LUN_LIST
);
1879 return SRB_STATUS_SUCCESS
;
1880 }// -- DeviceReportLuns();
1883 * @name DeviceInquiryRequest
1886 * Tells wheather given port is implemented or not
1888 * @param AdapterExtension
1893 * return STOR status for DeviceInquiryRequest
1896 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
1899 DeviceInquiryRequest (
1900 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1901 __in PSCSI_REQUEST_BLOCK Srb
,
1906 PAHCI_SRB_EXTENSION SrbExtension
;
1907 PAHCI_PORT_EXTENSION PortExtension
;
1908 PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer
;
1909 ULONG DataBufferLength
, RequiredDataBufferLength
;
1911 AhciDebugPrint("DeviceInquiryRequest()\n");
1913 NT_ASSERT(Cdb
->CDB10
.OperationCode
== SCSIOP_INQUIRY
);
1914 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
1916 SrbExtension
= GetSrbExtension(Srb
);
1917 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1921 return SRB_STATUS_SELECTION_TIMEOUT
;
1923 else if (Cdb
->CDB6INQUIRY3
.EnableVitalProductData
== 0)
1926 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
1927 AhciDebugPrint("\tEVPD Inquired\n");
1928 NT_ASSERT(SrbExtension
!= NULL
);
1930 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATA_IDENTIFY
;
1931 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
1932 SrbExtension
->CompletionRoutine
= InquiryCompletion
;
1933 SrbExtension
->CommandReg
= IDE_COMMAND_NOT_VALID
;
1935 // TODO: Should use AhciZeroMemory
1936 SrbExtension
->FeaturesLow
= 0;
1937 SrbExtension
->LBA0
= 0;
1938 SrbExtension
->LBA1
= 0;
1939 SrbExtension
->LBA2
= 0;
1940 SrbExtension
->Device
= 0xA0;
1941 SrbExtension
->LBA3
= 0;
1942 SrbExtension
->LBA4
= 0;
1943 SrbExtension
->LBA5
= 0;
1944 SrbExtension
->FeaturesHigh
= 0;
1945 SrbExtension
->SectorCountLow
= 0;
1946 SrbExtension
->SectorCountHigh
= 0;
1948 SrbExtension
->Sgl
.NumberOfElements
= 1;
1949 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.LowPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.LowPart
;
1950 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.HighPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.HighPart
;
1951 SrbExtension
->Sgl
.List
[0].Length
= sizeof(IDENTIFY_DEVICE_DATA
);
1953 SrbExtension
->pSgl
= &SrbExtension
->Sgl
;
1955 AhciProcessIO(AdapterExtension
, Srb
->PathId
, Srb
);
1956 return SRB_STATUS_PENDING
;
1960 AhciDebugPrint("\tVPD Inquired\n");
1962 DataBuffer
= Srb
->DataBuffer
;
1963 DataBufferLength
= Srb
->DataTransferLength
;
1964 RequiredDataBufferLength
= DataBufferLength
; // make the compiler happy :p
1966 if (DataBuffer
== NULL
)
1968 return SRB_STATUS_INVALID_REQUEST
;
1971 AhciZeroMemory(DataBuffer
, DataBufferLength
);
1973 switch(Cdb
->CDB6INQUIRY3
.PageCode
)
1975 case VPD_SUPPORTED_PAGES
:
1977 AhciDebugPrint("\tVPD_SUPPORTED_PAGES\n");
1978 RequiredDataBufferLength
= sizeof(VPD_SUPPORTED_PAGES_PAGE
) + 1;
1980 if (DataBufferLength
< RequiredDataBufferLength
)
1982 AhciDebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength
, RequiredDataBufferLength
);
1983 return SRB_STATUS_INVALID_REQUEST
;
1986 VpdOutputBuffer
= (PVPD_SUPPORTED_PAGES_PAGE
)DataBuffer
;
1988 VpdOutputBuffer
->DeviceType
= PortExtension
->DeviceParams
.AccessType
;
1989 VpdOutputBuffer
->DeviceTypeQualifier
= 0;
1990 VpdOutputBuffer
->PageCode
= VPD_SUPPORTED_PAGES
;
1991 VpdOutputBuffer
->PageLength
= 1;
1992 VpdOutputBuffer
->SupportedPageList
[0] = VPD_SUPPORTED_PAGES
;
1993 //VpdOutputBuffer->SupportedPageList[1] = VPD_SERIAL_NUMBER;
1994 //VpdOutputBuffer->SupportedPageList[2] = VPD_DEVICE_IDENTIFIERS;
1996 NT_ASSERT(VpdOutputBuffer
->DeviceType
== DIRECT_ACCESS_DEVICE
);
1999 case VPD_SERIAL_NUMBER
:
2001 AhciDebugPrint("\tVPD_SERIAL_NUMBER\n");
2004 case VPD_DEVICE_IDENTIFIERS
:
2006 AhciDebugPrint("\tVPD_DEVICE_IDENTIFIERS\n");
2010 AhciDebugPrint("\tPageCode: %x\n", Cdb
->CDB6INQUIRY3
.PageCode
);
2011 return SRB_STATUS_INVALID_REQUEST
;
2014 Srb
->DataTransferLength
= RequiredDataBufferLength
;
2015 return SRB_STATUS_SUCCESS
;
2017 }// -- DeviceInquiryRequest();
2020 * @name AhciAdapterReset
2024 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
2025 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
2026 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
2027 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
2028 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
2029 * the HBA reset has completed.
2030 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
2031 * a hung or locked state.
2033 * @param AdapterExtension
2036 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
2040 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
2045 PAHCI_MEMORY_REGISTERS abar
= NULL
;
2047 AhciDebugPrint("AhciAdapterReset()\n");
2049 abar
= AdapterExtension
->ABAR_Address
;
2050 if (abar
== NULL
) // basic sanity
2055 // HR -- Very first bit (lowest significant)
2057 StorPortWriteRegisterUlong(AdapterExtension
, &abar
->GHC
, ghc
.Status
);
2059 for (ticks
= 0; ticks
< 50; ++ticks
)
2061 ghc
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &abar
->GHC
);
2066 StorPortStallExecution(20000);
2069 if (ticks
== 50)// 1 second
2071 AhciDebugPrint("\tDevice Timeout\n");
2076 }// -- AhciAdapterReset();
2079 * @name AhciZeroMemory
2082 * Clear buffer by filling zeros
2091 __in ULONG BufferSize
2095 for (i
= 0; i
< BufferSize
; i
++)
2101 }// -- AhciZeroMemory();
2107 * Tells wheather given port is implemented or not
2109 * @param AdapterExtension
2113 * return TRUE if provided port is valid (implemented) or not
2118 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
2122 NT_ASSERT(pathId
< MAXIMUM_AHCI_PORT_COUNT
);
2124 if (pathId
>= AdapterExtension
->PortCount
)
2129 return AdapterExtension
->PortExtension
[pathId
].DeviceParams
.IsActive
;
2130 }// -- IsPortValid()
2142 * return TRUE if Srb is successfully added to Queue
2148 __inout PAHCI_QUEUE Queue
,
2152 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2153 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2155 if (Queue
->Tail
== ((Queue
->Head
+ 1) % MAXIMUM_QUEUE_BUFFER_SIZE
))
2158 Queue
->Buffer
[Queue
->Head
++] = Srb
;
2159 Queue
->Head
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
2168 * Remove and return Srb from Queue
2179 __inout PAHCI_QUEUE Queue
2184 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2185 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2187 if (Queue
->Head
== Queue
->Tail
)
2190 Srb
= Queue
->Buffer
[Queue
->Tail
++];
2191 Queue
->Tail
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
2194 }// -- RemoveQueue();
2197 * @name GetSrbExtension
2200 * GetSrbExtension from Srb make sure It is properly aligned
2205 * return SrbExtension
2211 __in PSCSI_REQUEST_BLOCK Srb
2215 ULONG_PTR SrbExtension
;
2217 SrbExtension
= (ULONG_PTR
)Srb
->SrbExtension
;
2218 Offset
= SrbExtension
% 128;
2220 // CommandTable should be 128 byte aligned
2222 Offset
= 128 - Offset
;
2224 return (PAHCI_SRB_EXTENSION
)(SrbExtension
+ Offset
);
2225 }// -- PAHCI_SRB_EXTENSION();
2236 NT_ASSERT(Cdb
!= NULL
);
2238 lba
|= Cdb
->CDB10
.LogicalBlockByte3
<< 0;
2239 lba
|= Cdb
->CDB10
.LogicalBlockByte2
<< 8;
2240 lba
|= Cdb
->CDB10
.LogicalBlockByte1
<< 16;
2241 lba
|= Cdb
->CDB10
.LogicalBlockByte0
<< 24;
2244 }// -- AhciGetLba();