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
24 __in PVOID DeviceExtension
27 PAHCI_PORT_EXTENSION PortExtension
;
29 PAHCI_MEMORY_REGISTERS abar
;
30 ULONG mappedLength
, portNumber
, ticks
;
31 PAHCI_ADAPTER_EXTENSION adapterExtension
;
32 STOR_PHYSICAL_ADDRESS commandListPhysical
, receivedFISPhysical
;
34 AhciDebugPrint("AhciPortInitialize()\n");
36 PortExtension
= (PAHCI_PORT_EXTENSION
)DeviceExtension
;
37 adapterExtension
= PortExtension
->AdapterExtension
;
38 abar
= adapterExtension
->ABAR_Address
;
39 portNumber
= PortExtension
->PortNumber
;
41 NT_ASSERT(abar
!= NULL
);
42 NT_ASSERT(portNumber
< adapterExtension
->PortCount
);
44 PortExtension
->Port
= &abar
->PortList
[portNumber
];
46 commandListPhysical
= StorPortGetPhysicalAddress(adapterExtension
,
48 PortExtension
->CommandList
,
51 if ((mappedLength
== 0) || ((commandListPhysical
.LowPart
% 1024) != 0))
53 AhciDebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength
);
57 receivedFISPhysical
= StorPortGetPhysicalAddress(adapterExtension
,
59 PortExtension
->ReceivedFIS
,
62 if ((mappedLength
== 0) || ((receivedFISPhysical
.LowPart
% 256) != 0))
64 AhciDebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength
);
68 // Ensure that the controller is not in the running state by reading and examining each
69 // implemented port’s PxCMD register. If PxCMD.ST, PxCMD.CR, PxCMD.FRE and
70 // PxCMD.FR are all cleared, the port is in an idle state. Otherwise, the port is not idle and
71 // should be placed in the idle state prior to manipulating HBA and port specific registers.
72 // System software places a port into the idle state by clearing PxCMD.ST and waiting for
73 // PxCMD.CR to return ‘0’ when read. Software should wait at least 500 milliseconds for
74 // this to occur. If PxCMD.FRE is set to ‘1’, software should clear it to ‘0’ and wait at least
75 // 500 milliseconds for PxCMD.FR to return ‘0’ when read. If PxCMD.CR or PxCMD.FR do
76 // not clear to ‘0’ correctly, then software may attempt a port reset or a full HBA reset to recove
78 // TODO: Check if port is in idle state or not, if not then restart port
79 cmd
.Status
= StorPortReadRegisterUlong(adapterExtension
, &PortExtension
->Port
->CMD
);
80 if ((cmd
.FR
!= 0) || (cmd
.CR
!= 0) || (cmd
.FRE
!= 0) || (cmd
.ST
!= 0))
88 StorPortStallExecution(50000);
89 cmd
.Status
= StorPortReadRegisterUlong(adapterExtension
, &PortExtension
->Port
->CMD
);
92 AhciDebugPrint("\tAttempt to reset port failed: %x\n", cmd
);
97 while(cmd
.CR
!= 0 || cmd
.FR
!= 0);
100 // 10.1.2 For each implemented port, system software shall allocate memory for and program:
101 // ? PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
102 // ? PxFB and PxFBU (if CAP.S64A is set to ‘1’)
103 // Note: Assuming 32bit support only
104 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->CLB
, commandListPhysical
.LowPart
);
105 if (IsAdapterCAPS64(adapterExtension
->CAP
))
107 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->CLBU
, commandListPhysical
.HighPart
);
110 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->FB
, receivedFISPhysical
.LowPart
);
111 if (IsAdapterCAPS64(adapterExtension
->CAP
))
113 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->FBU
, receivedFISPhysical
.HighPart
);
116 PortExtension
->IdentifyDeviceDataPhysicalAddress
= StorPortGetPhysicalAddress(adapterExtension
,
118 PortExtension
->IdentifyDeviceData
,
121 // set device power state flag to D0
122 PortExtension
->DevicePowerState
= StorPowerDeviceD0
;
124 // clear pending interrupts
125 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->SERR
, (ULONG
)~0);
126 StorPortWriteRegisterUlong(adapterExtension
, &PortExtension
->Port
->IS
, (ULONG
)~0);
127 StorPortWriteRegisterUlong(adapterExtension
, adapterExtension
->IS
, (1 << PortExtension
->PortNumber
));
130 }// -- AhciPortInitialize();
133 * @name AhciAllocateResourceForAdapter
136 * Allocate memory from poll for required pointers
138 * @param AdapterExtension
142 * return TRUE if allocation was successful
145 AhciAllocateResourceForAdapter (
146 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
147 __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
150 PCHAR nonCachedExtension
, tmp
;
151 ULONG index
, NCS
, AlignedNCS
;
152 ULONG portCount
, portImplemented
, nonCachedExtensionSize
;
153 PAHCI_PORT_EXTENSION PortExtension
;
155 AhciDebugPrint("AhciAllocateResourceForAdapter()\n");
157 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
158 AlignedNCS
= ROUND_UP(NCS
, 8);
160 // get port count -- Number of set bits in `AdapterExtension->PortImplemented`
162 portImplemented
= AdapterExtension
->PortImplemented
;
164 NT_ASSERT(portImplemented
!= 0);
165 for (index
= MAXIMUM_AHCI_PORT_COUNT
- 1; index
> 0; index
--)
166 if ((portImplemented
& (1 << index
)) != 0)
169 portCount
= index
+ 1;
170 AhciDebugPrint("\tPort Count: %d\n", portCount
);
172 AdapterExtension
->PortCount
= portCount
;
173 nonCachedExtensionSize
= sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
+ //should be 1K aligned
174 sizeof(AHCI_RECEIVED_FIS
) +
175 sizeof(IDENTIFY_DEVICE_DATA
);
177 // align nonCachedExtensionSize to 1024
178 nonCachedExtensionSize
= ROUND_UP(nonCachedExtensionSize
, 1024);
180 AdapterExtension
->NonCachedExtension
= StorPortGetUncachedExtension(AdapterExtension
,
182 nonCachedExtensionSize
* portCount
);
184 if (AdapterExtension
->NonCachedExtension
== NULL
)
186 AhciDebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
190 nonCachedExtension
= AdapterExtension
->NonCachedExtension
;
191 AhciZeroMemory(nonCachedExtension
, nonCachedExtensionSize
* portCount
);
193 for (index
= 0; index
< portCount
; index
++)
195 PortExtension
= &AdapterExtension
->PortExtension
[index
];
197 PortExtension
->DeviceParams
.IsActive
= FALSE
;
198 if ((AdapterExtension
->PortImplemented
& (1 << index
)) != 0)
200 PortExtension
->PortNumber
= index
;
201 PortExtension
->DeviceParams
.IsActive
= TRUE
;
202 PortExtension
->AdapterExtension
= AdapterExtension
;
203 PortExtension
->CommandList
= (PAHCI_COMMAND_HEADER
)nonCachedExtension
;
205 tmp
= (PCHAR
)(nonCachedExtension
+ sizeof(AHCI_COMMAND_HEADER
) * AlignedNCS
);
207 PortExtension
->ReceivedFIS
= (PAHCI_RECEIVED_FIS
)tmp
;
208 PortExtension
->IdentifyDeviceData
= (PIDENTIFY_DEVICE_DATA
)(tmp
+ sizeof(AHCI_RECEIVED_FIS
));
209 PortExtension
->MaxPortQueueDepth
= NCS
;
210 nonCachedExtension
+= nonCachedExtensionSize
;
215 }// -- AhciAllocateResourceForAdapter();
218 * @name AhciStartPort
221 * Try to start the port device
223 * @param AdapterExtension
224 * @param PortExtension
229 __in PAHCI_PORT_EXTENSION PortExtension
234 AHCI_TASK_FILE_DATA tfd
;
235 AHCI_INTERRUPT_ENABLE ie
;
236 AHCI_SERIAL_ATA_STATUS ssts
;
237 AHCI_SERIAL_ATA_CONTROL sctl
;
238 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
240 AhciDebugPrint("AhciStartPort()\n");
242 AdapterExtension
= PortExtension
->AdapterExtension
;
243 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
245 if ((cmd
.FR
== 1) && (cmd
.CR
== 1) && (cmd
.FRE
== 1) && (cmd
.ST
== 1))
252 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
, cmd
.Status
);
254 if (((cmd
.FR
== 1) && (cmd
.FRE
== 0)) ||
255 ((cmd
.CR
== 1) && (cmd
.ST
== 0)))
257 AhciDebugPrint("\tCOMRESET\n");
261 // Software causes a port reset (COMRESET) by writing 1h to the PxSCTL.DET field to invoke a
262 // COMRESET on the interface and start a re-establishment of Phy layer communications. Software shall
263 // wait at least 1 millisecond before clearing PxSCTL.DET to 0h; this ensures that at least one COMRESET
264 // signal is sent over the interface. After clearing PxSCTL.DET to 0h, software should wait for
265 // communication to be re-established as indicated by PxSSTS.DET being set to 3h. Then software should
266 // write all 1s to the PxSERR register to clear any bits that were set as part of the port reset.
268 sctl
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
);
270 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
, sctl
.Status
);
272 StorPortStallExecution(1000);
274 sctl
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
);
276 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SCTL
, sctl
.Status
);
278 // Poll DET to verify if a device is attached to the port
282 StorPortStallExecution(1000);
283 ssts
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SSTS
);
294 ssts
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SSTS
);
299 NT_ASSERT(cmd
.ST
== 0);
301 // make sure FIS Recieve is enabled (cmd.FRE)
305 StorPortStallExecution(10000);
306 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
308 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
, cmd
.Status
);
311 while((cmd
.FR
!= 1) && (index
< 3));
315 // failed to start FIS DMA engine
316 // it can crash the driver later
317 // so better to turn this port off
321 // start port channel
324 NT_ASSERT(cmd
.FRE
== 1);
325 NT_ASSERT(cmd
.CR
== 0);
327 // why assert? well If we face such condition on DET = 0x3
328 // then we don't have port in idle state and hence before executing this part of code
329 // we must have restarted it.
330 tfd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->TFD
);
332 if ((tfd
.STS
.BSY
) || (tfd
.STS
.DRQ
))
334 AhciDebugPrint("\tUnhandled Case BSY-DRQ\n");
337 // clear pending interrupts
338 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SERR
, (ULONG
)~0);
339 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
, (ULONG
)~0);
340 StorPortWriteRegisterUlong(AdapterExtension
, AdapterExtension
->IS
, (1 << PortExtension
->PortNumber
));
343 ie
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IE
);
344 /* Device to Host Register FIS Interrupt Enable */
346 /* PIO Setup FIS Interrupt Enable */
348 /* DMA Setup FIS Interrupt Enable */
350 /* Set Device Bits FIS Interrupt Enable */
352 /* Unknown FIS Interrupt Enable */
354 /* Descriptor Processed Interrupt Enable */
356 /* Port Change Interrupt Enable */
358 /* Device Mechanical Presence Enable */
360 /* PhyRdy Change Interrupt Enable */
362 /* Incorrect Port Multiplier Enable */
364 /* Overflow Enable */
366 /* Interface Non-fatal Error Enable */
368 /* Interface Fatal Error Enable */
370 /* Host Bus Data Error Enable */
372 /* Host Bus Fatal Error Enable */
374 /* Task File Error Enable */
377 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
378 /* Cold Presence Detect Enable */
379 if (cmd
.CPD
) // does it support CPD?
381 // disable it for now
385 // should I replace this to single line?
386 // by directly setting ie.Status?
388 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IE
, ie
.Status
);
391 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
, cmd
.Status
);
392 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
396 AhciDebugPrint("\tFailed to start Port\n");
404 AhciDebugPrint("\tDET == %x Unsupported\n", ssts
.DET
);
407 }// -- AhciStartPort();
410 * @name AhciCommandCompletionDpcRoutine
413 * Handles Completed Commands
416 * @param AdapterExtension
417 * @param SystemArgument1
418 * @param SystemArgument2
421 AhciCommandCompletionDpcRoutine (
423 __in PVOID HwDeviceExtension
,
424 __in PVOID SystemArgument1
,
425 __in PVOID SystemArgument2
428 PSCSI_REQUEST_BLOCK Srb
;
429 PAHCI_SRB_EXTENSION SrbExtension
;
430 STOR_LOCK_HANDLE lockhandle
= {0};
431 PAHCI_COMPLETION_ROUTINE CompletionRoutine
;
432 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
433 PAHCI_PORT_EXTENSION PortExtension
;
435 UNREFERENCED_PARAMETER(Dpc
);
436 UNREFERENCED_PARAMETER(SystemArgument2
);
438 AhciDebugPrint("AhciCommandCompletionDpcRoutine()\n");
440 AdapterExtension
= (PAHCI_ADAPTER_EXTENSION
)HwDeviceExtension
;
441 PortExtension
= (PAHCI_PORT_EXTENSION
)SystemArgument1
;
443 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
444 Srb
= RemoveQueue(&PortExtension
->CompletionQueue
);
445 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
447 NT_ASSERT(Srb
!= NULL
);
449 if (Srb
->SrbStatus
== SRB_STATUS_PENDING
)
451 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
458 SrbExtension
= GetSrbExtension(Srb
);
460 CompletionRoutine
= SrbExtension
->CompletionRoutine
;
461 NT_ASSERT(CompletionRoutine
!= NULL
);
463 // now it's completion routine responsibility to set SrbStatus
464 CompletionRoutine(PortExtension
, Srb
);
466 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
469 }// -- AhciCommandCompletionDpcRoutine();
472 * @name AhciHwPassiveInitialize
475 * initializes the HBA and finds all devices that are of interest to the miniport driver. (at PASSIVE LEVEL)
477 * @param adapterExtension
480 * return TRUE if intialization was successful
483 AhciHwPassiveInitialize (
484 __in PVOID DeviceExtension
488 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
489 PAHCI_PORT_EXTENSION PortExtension
;
491 AhciDebugPrint("AhciHwPassiveInitialize()\n");
493 AdapterExtension
= (PAHCI_ADAPTER_EXTENSION
)DeviceExtension
;
495 for (index
= 0; index
< AdapterExtension
->PortCount
; index
++)
497 if ((AdapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
499 PortExtension
= &AdapterExtension
->PortExtension
[index
];
500 PortExtension
->DeviceParams
.IsActive
= AhciStartPort(PortExtension
);
501 StorPortInitializeDpc(AdapterExtension
, &PortExtension
->CommandCompletion
, AhciCommandCompletionDpcRoutine
);
506 }// -- AhciHwPassiveInitialize();
509 * @name AhciHwInitialize
512 * initializes the HBA and finds all devices that are of interest to the miniport driver.
514 * @param adapterExtension
517 * return TRUE if intialization was successful
522 __in PVOID DeviceExtension
525 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
528 AhciDebugPrint("AhciHwInitialize()\n");
530 AdapterExtension
= (PAHCI_ADAPTER_EXTENSION
)DeviceExtension
;
531 AdapterExtension
->StateFlags
.MessagePerPort
= FALSE
;
533 // First check what type of interrupt/synchronization device is using
534 ghc
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &AdapterExtension
->ABAR_Address
->GHC
);
536 // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector
537 // but has reverted to using the first vector only. When this bit is cleared to ‘0’,
538 // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
539 // software has allocated the number of messages requested
542 AdapterExtension
->StateFlags
.MessagePerPort
= TRUE
;
543 AhciDebugPrint("\tMultiple MSI based message not supported\n");
546 StorPortEnablePassiveInitialization(AdapterExtension
, AhciHwPassiveInitialize
);
549 }// -- AhciHwInitialize();
552 * @name AhciCompleteIssuedSrb
555 * Complete issued Srbs
557 * @param PortExtension
561 AhciCompleteIssuedSrb (
562 __in PAHCI_PORT_EXTENSION PortExtension
,
563 __in ULONG CommandsToComplete
567 PSCSI_REQUEST_BLOCK Srb
;
568 PAHCI_SRB_EXTENSION SrbExtension
;
569 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
571 AhciDebugPrint("AhciCompleteIssuedSrb()\n");
573 NT_ASSERT(CommandsToComplete
!= 0);
575 AhciDebugPrint("\tCompleted Commands: %d\n", CommandsToComplete
);
577 AdapterExtension
= PortExtension
->AdapterExtension
;
578 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
580 for (i
= 0; i
< NCS
; i
++)
582 if (((1 << i
) & CommandsToComplete
) != 0)
584 Srb
= PortExtension
->Slot
[i
];
591 SrbExtension
= GetSrbExtension(Srb
);
592 NT_ASSERT(SrbExtension
!= NULL
);
594 if (SrbExtension
->CompletionRoutine
!= NULL
)
596 AddQueue(&PortExtension
->CompletionQueue
, Srb
);
597 StorPortIssueDpc(AdapterExtension
, &PortExtension
->CommandCompletion
, PortExtension
, Srb
);
601 NT_ASSERT(Srb
->SrbStatus
== SRB_STATUS_PENDING
);
602 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
603 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
609 }// -- AhciCompleteIssuedSrb();
612 * @name AhciInterruptHandler
615 * Interrupt Handler for PortExtension
617 * @param PortExtension
621 AhciInterruptHandler (
622 __in PAHCI_PORT_EXTENSION PortExtension
625 ULONG is
, ci
, sact
, outstanding
;
626 AHCI_INTERRUPT_STATUS PxIS
;
627 AHCI_INTERRUPT_STATUS PxISMasked
;
628 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
630 AhciDebugPrint("AhciInterruptHandler()\n");
631 AhciDebugPrint("\tPort Number: %d\n", PortExtension
->PortNumber
);
633 AdapterExtension
= PortExtension
->AdapterExtension
;
634 NT_ASSERT(IsPortValid(AdapterExtension
, PortExtension
->PortNumber
));
637 // 1. Software determines the cause of the interrupt by reading the PxIS register.
638 // It is possible for multiple bits to be set
639 // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt.
640 // 3. Software clears the interrupt bit in IS.IPS corresponding to the port.
641 // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to
642 // the list of commands previously issued by software that are still outstanding.
643 // If executing native queued commands, software reads the PxSACT register and compares the current
644 // value to the list of commands previously issued by software.
645 // Software completes with success any outstanding command whose corresponding bit has been cleared in
646 // the respective register. PxCI and PxSACT are volatile registers; software should only use their values
647 // to determine commands that have completed, not to determine which commands have previously been issued.
648 // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2).
649 PxISMasked
.Status
= 0;
650 PxIS
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
);
654 // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES
655 if (PxIS
.HBFS
|| PxIS
.HBDS
|| PxIS
.IFS
|| PxIS
.TFES
)
657 // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process
658 // any native command queuing commands. To recover, the port must be restarted
659 // To detect an error that requires software recovery actions to be performed,
660 // software should check whether any of the following status bits are set on an interrupt:
661 // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set,
662 // software should perform the appropriate error recovery actions based on whether
663 // non-queued commands were being issued or native command queuing commands were being issued.
665 AhciDebugPrint("\tFatal Error: %x\n", PxIS
.Status
);
668 // Normal Command Completion
670 // A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory.
671 PxISMasked
.DHRS
= PxIS
.DHRS
;
672 // A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory.
673 PxISMasked
.PSS
= PxIS
.PSS
;
674 // A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory.
675 PxISMasked
.DSS
= PxIS
.DSS
;
676 // A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/
677 PxISMasked
.SDBS
= PxIS
.SDBS
;
678 // A PRD with the ‘I’ bit set has transferred all of its data.
679 PxISMasked
.DPS
= PxIS
.DPS
;
681 if (PxISMasked
.Status
!= 0)
683 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->IS
, PxISMasked
.Status
);
687 // Clear port interrupt
688 // It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software.
689 is
= (1 << PortExtension
->PortNumber
);
690 StorPortWriteRegisterUlong(AdapterExtension
, AdapterExtension
->IS
, is
);
692 ci
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
);
693 sact
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SACT
);
695 outstanding
= ci
| sact
; // NOTE: Including both non-NCQ and NCQ based commands
696 if ((PortExtension
->CommandIssuedSlots
& (~outstanding
)) != 0)
698 AhciCompleteIssuedSrb(PortExtension
, (PortExtension
->CommandIssuedSlots
& (~outstanding
)));
699 PortExtension
->CommandIssuedSlots
&= outstanding
;
703 }// -- AhciInterruptHandler();
706 * @name AhciHwInterrupt
709 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
711 * @param AdapterExtension
714 * return TRUE Indicates that an interrupt was pending on adapter.
715 * return FALSE Indicates the interrupt was not ours.
720 __in PVOID DeviceExtension
723 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
724 ULONG portPending
, nextPort
, i
, portCount
;
726 AdapterExtension
= (PAHCI_ADAPTER_EXTENSION
)DeviceExtension
;
728 if (AdapterExtension
->StateFlags
.Removed
)
733 portPending
= StorPortReadRegisterUlong(AdapterExtension
, AdapterExtension
->IS
);
735 // we process interrupt for implemented ports only
736 portCount
= AdapterExtension
->PortCount
;
737 portPending
= portPending
& AdapterExtension
->PortImplemented
;
739 if (portPending
== 0)
744 for (i
= 1; i
<= portCount
; i
++)
746 nextPort
= (AdapterExtension
->LastInterruptPort
+ i
) % portCount
;
747 if ((portPending
& (0x1 << nextPort
)) == 0)
750 NT_ASSERT(IsPortValid(AdapterExtension
, nextPort
));
752 if (AdapterExtension
->PortExtension
[nextPort
].DeviceParams
.IsActive
== FALSE
)
757 // we can assign this interrupt to this port
758 AdapterExtension
->LastInterruptPort
= nextPort
;
759 AhciInterruptHandler(&AdapterExtension
->PortExtension
[nextPort
]);
761 portPending
&= ~(1 << nextPort
);
763 // interrupt belongs to this device
764 // should always return TRUE
768 AhciDebugPrint("\tSomething went wrong");
770 }// -- AhciHwInterrupt();
773 * @name AhciHwStartIo
776 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
778 * @param adapterExtension
782 * return TRUE if the request was accepted
783 * return FALSE if the request must be submitted later
788 __in PVOID DeviceExtension
,
789 __in PSCSI_REQUEST_BLOCK Srb
792 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
794 AhciDebugPrint("AhciHwStartIo()\n");
796 AdapterExtension
= (PAHCI_ADAPTER_EXTENSION
)DeviceExtension
;
798 if (!IsPortValid(AdapterExtension
, Srb
->PathId
))
800 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
801 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
805 switch(Srb
->Function
)
807 case SRB_FUNCTION_PNP
:
809 // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp
810 // If the function member of an SRB is set to SRB_FUNCTION_PNP,
811 // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK.
813 PSCSI_PNP_REQUEST_BLOCK pnpRequest
;
814 pnpRequest
= (PSCSI_PNP_REQUEST_BLOCK
)Srb
;
815 if ((pnpRequest
->SrbPnPFlags
& SRB_PNP_FLAGS_ADAPTER_REQUEST
) != 0)
817 switch(pnpRequest
->PnPAction
)
819 case StorRemoveDevice
:
820 case StorSurpriseRemoval
:
822 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
823 AdapterExtension
->StateFlags
.Removed
= 1;
824 AhciDebugPrint("\tAdapter removed\n");
829 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
830 AhciDebugPrint("\tRequested to Stop the adapter\n");
834 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
840 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
844 case SRB_FUNCTION_EXECUTE_SCSI
:
846 // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
847 // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
848 // routine does the following:
850 // - Gets and/or sets up whatever context the miniport driver maintains in its device,
851 // logical unit, and/or SRB extensions
852 // For example, a miniport driver might set up a logical unit extension with pointers
853 // to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value,
854 // and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be
855 // carried out on the HBA.
857 // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags,
858 // for the requested operation
859 // For a device I/O operation, such an internal routine generally selects the target device
860 // and sends the CDB over the bus to the target logical unit.
861 PCDB cdb
= (PCDB
)&Srb
->Cdb
;
862 if (Srb
->CdbLength
== 0)
864 AhciDebugPrint("\tOperationCode: %d\n", cdb
->CDB10
.OperationCode
);
865 Srb
->SrbStatus
= SRB_STATUS_BAD_FUNCTION
;
869 NT_ASSERT(cdb
!= NULL
);
871 switch(cdb
->CDB10
.OperationCode
)
874 Srb
->SrbStatus
= DeviceInquiryRequest(AdapterExtension
, Srb
, cdb
);
876 case SCSIOP_REPORT_LUNS
:
877 Srb
->SrbStatus
= DeviceReportLuns(AdapterExtension
, Srb
, cdb
);
879 case SCSIOP_READ_CAPACITY
:
880 Srb
->SrbStatus
= DeviceRequestCapacity(AdapterExtension
, Srb
, cdb
);
882 case SCSIOP_TEST_UNIT_READY
:
883 Srb
->SrbStatus
= DeviceRequestComplete(AdapterExtension
, Srb
, cdb
);
885 case SCSIOP_MODE_SENSE
:
886 Srb
->SrbStatus
= DeviceRequestSense(AdapterExtension
, Srb
, cdb
);
890 Srb
->SrbStatus
= DeviceRequestReadWrite(AdapterExtension
, Srb
, cdb
);
893 AhciDebugPrint("\tOperationCode: %d\n", cdb
->CDB10
.OperationCode
);
894 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
900 AhciDebugPrint("\tUnknown function code recieved: %x\n", Srb
->Function
);
901 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
905 if (Srb
->SrbStatus
!= SRB_STATUS_PENDING
)
907 StorPortNotification(RequestComplete
, AdapterExtension
, Srb
);
911 AhciProcessIO(AdapterExtension
, Srb
->PathId
, Srb
);
914 }// -- AhciHwStartIo();
917 * @name AhciHwResetBus
920 * The HwStorResetBus routine is called by the port driver to clear error conditions.
922 * @param adapterExtension
926 * return TRUE if bus was successfully reset
931 __in PVOID AdapterExtension
,
935 STOR_LOCK_HANDLE lockhandle
= {0};
936 // PAHCI_ADAPTER_EXTENSION adapterExtension;
938 AhciDebugPrint("AhciHwResetBus()\n");
940 // adapterExtension = AdapterExtension;
942 if (IsPortValid(AdapterExtension
, PathId
))
945 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
947 // TODO: Perform port reset
950 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
954 }// -- AhciHwResetBus();
957 * @name AhciHwFindAdapter
960 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
961 * HBA is supported and, if it is, to return configuration information about that adapter.
963 * 10.1 Platform Communication
964 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
966 * @param DeviceExtension
968 * @param BusInformation
969 * @param ArgumentString
975 * 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.
978 * 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.
980 * SP_RETURN_BAD_CONFIG
981 * Indicates that the supplied configuration information was invalid for the adapter.
983 * SP_RETURN_NOT_FOUND
984 * Indicates that no supported HBA was found for the supplied configuration information.
986 * @remarks Called by Storport.
991 __in PVOID DeviceExtension
,
992 __in PVOID HwContext
,
993 __in PVOID BusInformation
,
994 __in PCHAR ArgumentString
,
995 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
996 __in PBOOLEAN Reserved3
1000 ULONG index
, pci_cfg_len
;
1001 PACCESS_RANGE accessRange
;
1002 UCHAR pci_cfg_buf
[sizeof(PCI_COMMON_CONFIG
)];
1004 PAHCI_MEMORY_REGISTERS abar
;
1005 PPCI_COMMON_CONFIG pciConfigData
;
1006 PAHCI_ADAPTER_EXTENSION adapterExtension
;
1008 AhciDebugPrint("AhciHwFindAdapter()\n");
1010 UNREFERENCED_PARAMETER(HwContext
);
1011 UNREFERENCED_PARAMETER(BusInformation
);
1012 UNREFERENCED_PARAMETER(ArgumentString
);
1013 UNREFERENCED_PARAMETER(Reserved3
);
1015 adapterExtension
= DeviceExtension
;
1016 adapterExtension
->SlotNumber
= ConfigInfo
->SlotNumber
;
1017 adapterExtension
->SystemIoBusNumber
= ConfigInfo
->SystemIoBusNumber
;
1019 // get PCI configuration header
1020 pci_cfg_len
= StorPortGetBusData(
1023 adapterExtension
->SystemIoBusNumber
,
1024 adapterExtension
->SlotNumber
,
1026 sizeof(PCI_COMMON_CONFIG
));
1028 if (pci_cfg_len
!= sizeof(PCI_COMMON_CONFIG
))
1030 AhciDebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG
), pci_cfg_len
);
1031 return SP_RETURN_ERROR
;//Not a valid device at the given bus number
1034 pciConfigData
= (PPCI_COMMON_CONFIG
)pci_cfg_buf
;
1035 adapterExtension
->VendorID
= pciConfigData
->VendorID
;
1036 adapterExtension
->DeviceID
= pciConfigData
->DeviceID
;
1037 adapterExtension
->RevisionID
= pciConfigData
->RevisionID
;
1038 // 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).
1039 adapterExtension
->AhciBaseAddress
= pciConfigData
->u
.type0
.BaseAddresses
[5] & (0xFFFFFFF0);
1041 AhciDebugPrint("\tVendorID: %04x DeviceID: %04x RevisionID: %02x\n",
1042 adapterExtension
->VendorID
,
1043 adapterExtension
->DeviceID
,
1044 adapterExtension
->RevisionID
);
1048 if (ConfigInfo
->NumberOfAccessRanges
> 0)
1050 accessRange
= *(ConfigInfo
->AccessRanges
);
1051 for (index
= 0; index
< ConfigInfo
->NumberOfAccessRanges
; index
++)
1053 if (accessRange
[index
].RangeStart
.QuadPart
== adapterExtension
->AhciBaseAddress
)
1055 abar
= StorPortGetDeviceBase(adapterExtension
,
1056 ConfigInfo
->AdapterInterfaceType
,
1057 ConfigInfo
->SystemIoBusNumber
,
1058 accessRange
[index
].RangeStart
,
1059 accessRange
[index
].RangeLength
,
1060 !accessRange
[index
].RangeInMemory
);
1068 AhciDebugPrint("\tabar == NULL\n");
1069 return SP_RETURN_ERROR
; // corrupted information supplied
1072 adapterExtension
->ABAR_Address
= abar
;
1073 adapterExtension
->CAP
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP
);
1074 adapterExtension
->CAP2
= StorPortReadRegisterUlong(adapterExtension
, &abar
->CAP2
);
1075 adapterExtension
->Version
= StorPortReadRegisterUlong(adapterExtension
, &abar
->VS
);
1076 adapterExtension
->LastInterruptPort
= (ULONG
)-1;
1079 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
1080 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
1081 ghc
.Status
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
1082 // AE := Highest Significant bit of GHC
1083 if (ghc
.AE
!= 0)// Hmm, controller was already in power state
1085 // reset controller to have it in known state
1086 AhciDebugPrint("\tAE Already set, Reset()\n");
1087 if (!AhciAdapterReset(adapterExtension
))
1089 AhciDebugPrint("\tReset Failed!\n");
1090 return SP_RETURN_ERROR
;// reset failed
1095 ghc
.AE
= 1;// only AE=1
1096 // tell the controller that we know about AHCI
1097 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
.Status
);
1099 adapterExtension
->IS
= &abar
->IS
;
1100 adapterExtension
->PortImplemented
= StorPortReadRegisterUlong(adapterExtension
, &abar
->PI
);
1102 if (adapterExtension
->PortImplemented
== 0)
1104 AhciDebugPrint("\tadapterExtension->PortImplemented == 0\n");
1105 return SP_RETURN_ERROR
;
1108 ConfigInfo
->Master
= TRUE
;
1109 ConfigInfo
->AlignmentMask
= 0x3;
1110 ConfigInfo
->ScatterGather
= TRUE
;
1111 ConfigInfo
->DmaWidth
= Width32Bits
;
1112 ConfigInfo
->WmiDataProvider
= FALSE
;
1113 ConfigInfo
->Dma32BitAddresses
= TRUE
;
1115 if (IsAdapterCAPS64(adapterExtension
->CAP
))
1117 ConfigInfo
->Dma64BitAddresses
= TRUE
;
1120 ConfigInfo
->MaximumNumberOfTargets
= 1;
1121 ConfigInfo
->ResetTargetSupported
= TRUE
;
1122 ConfigInfo
->NumberOfPhysicalBreaks
= 0x21;
1123 ConfigInfo
->MaximumNumberOfLogicalUnits
= 1;
1124 ConfigInfo
->NumberOfBuses
= MAXIMUM_AHCI_PORT_COUNT
;
1125 ConfigInfo
->MaximumTransferLength
= MAXIMUM_TRANSFER_LENGTH
;
1126 ConfigInfo
->SynchronizationModel
= StorSynchronizeFullDuplex
;
1128 // Turn IE -- Interrupt Enabled
1129 ghc
.Status
= StorPortReadRegisterUlong(adapterExtension
, &abar
->GHC
);
1131 StorPortWriteRegisterUlong(adapterExtension
, &abar
->GHC
, ghc
.Status
);
1133 // allocate necessary resource for each port
1134 if (!AhciAllocateResourceForAdapter(adapterExtension
, ConfigInfo
))
1137 return SP_RETURN_ERROR
;
1140 for (index
= 0; index
< adapterExtension
->PortCount
; index
++)
1142 if ((adapterExtension
->PortImplemented
& (0x1 << index
)) != 0)
1143 AhciPortInitialize(&adapterExtension
->PortExtension
[index
]);
1146 return SP_RETURN_FOUND
;
1147 }// -- AhciHwFindAdapter();
1153 * Initial Entrypoint for storahci miniport driver
1155 * @param DriverObject
1156 * @param RegistryPath
1159 * NT_STATUS in case of driver loaded successfully.
1164 __in PVOID DriverObject
,
1165 __in PVOID RegistryPath
1169 // initialize the hardware data structure
1170 HW_INITIALIZATION_DATA hwInitializationData
= {0};
1172 // set size of hardware initialization structure
1173 hwInitializationData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
1175 // identity required miniport entry point routines
1176 hwInitializationData
.HwStartIo
= AhciHwStartIo
;
1177 hwInitializationData
.HwResetBus
= AhciHwResetBus
;
1178 hwInitializationData
.HwInterrupt
= AhciHwInterrupt
;
1179 hwInitializationData
.HwInitialize
= AhciHwInitialize
;
1180 hwInitializationData
.HwFindAdapter
= AhciHwFindAdapter
;
1182 // adapter specific information
1183 hwInitializationData
.TaggedQueuing
= TRUE
;
1184 hwInitializationData
.AutoRequestSense
= TRUE
;
1185 hwInitializationData
.MultipleRequestPerLu
= TRUE
;
1186 hwInitializationData
.NeedPhysicalAddresses
= TRUE
;
1188 hwInitializationData
.NumberOfAccessRanges
= 6;
1189 hwInitializationData
.AdapterInterfaceType
= PCIBus
;
1190 hwInitializationData
.MapBuffers
= STOR_MAP_NON_READ_WRITE_BUFFERS
;
1192 // set required extension sizes
1193 hwInitializationData
.SrbExtensionSize
= sizeof(AHCI_SRB_EXTENSION
);
1194 hwInitializationData
.DeviceExtensionSize
= sizeof(AHCI_ADAPTER_EXTENSION
);
1196 // register our hw init data
1197 status
= StorPortInitialize(DriverObject
,
1199 &hwInitializationData
,
1202 NT_ASSERT(status
== STATUS_SUCCESS
);
1204 }// -- DriverEntry();
1207 * @name AhciATA_CFIS
1210 * create ATA CFIS from Srb
1212 * @param PortExtension
1216 * Number of CFIS fields used in DWORD
1220 __in PAHCI_PORT_EXTENSION PortExtension
,
1221 __in PAHCI_SRB_EXTENSION SrbExtension
1224 PAHCI_COMMAND_TABLE cmdTable
;
1226 UNREFERENCED_PARAMETER(PortExtension
);
1228 AhciDebugPrint("AhciATA_CFIS()\n");
1230 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
1232 AhciZeroMemory((PCHAR
)cmdTable
->CFIS
, sizeof(cmdTable
->CFIS
));
1234 cmdTable
->CFIS
[AHCI_ATA_CFIS_FisType
] = FIS_TYPE_REG_H2D
; // FIS Type
1235 cmdTable
->CFIS
[AHCI_ATA_CFIS_PMPort_C
] = (1 << 7); // PM Port & C
1236 cmdTable
->CFIS
[AHCI_ATA_CFIS_CommandReg
] = SrbExtension
->CommandReg
;
1238 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesLow
] = SrbExtension
->FeaturesLow
;
1239 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA0
] = SrbExtension
->LBA0
;
1240 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA1
] = SrbExtension
->LBA1
;
1241 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA2
] = SrbExtension
->LBA2
;
1242 cmdTable
->CFIS
[AHCI_ATA_CFIS_Device
] = SrbExtension
->Device
;
1243 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA3
] = SrbExtension
->LBA3
;
1244 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA4
] = SrbExtension
->LBA4
;
1245 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA5
] = SrbExtension
->LBA5
;
1246 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesHigh
] = SrbExtension
->FeaturesHigh
;
1247 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountLow
] = SrbExtension
->SectorCountLow
;
1248 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountHigh
] = SrbExtension
->SectorCountHigh
;
1251 }// -- AhciATA_CFIS();
1254 * @name AhciATAPI_CFIS
1257 * create ATAPI CFIS from Srb
1259 * @param PortExtension
1263 * Number of CFIS fields used in DWORD
1267 __in PAHCI_PORT_EXTENSION PortExtension
,
1268 __in PAHCI_SRB_EXTENSION SrbExtension
1271 PAHCI_COMMAND_TABLE cmdTable
;
1272 UNREFERENCED_PARAMETER(PortExtension
);
1274 AhciDebugPrint("AhciATAPI_CFIS()\n");
1276 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
1278 NT_ASSERT(SrbExtension
->CommandReg
== IDE_COMMAND_ATAPI_PACKET
);
1280 AhciZeroMemory((PCHAR
)cmdTable
->CFIS
, sizeof(cmdTable
->CFIS
));
1282 cmdTable
->CFIS
[AHCI_ATA_CFIS_FisType
] = FIS_TYPE_REG_H2D
; // FIS Type
1283 cmdTable
->CFIS
[AHCI_ATA_CFIS_PMPort_C
] = (1 << 7); // PM Port & C
1284 cmdTable
->CFIS
[AHCI_ATA_CFIS_CommandReg
] = SrbExtension
->CommandReg
;
1286 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesLow
] = SrbExtension
->FeaturesLow
;
1287 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA0
] = SrbExtension
->LBA0
;
1288 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA1
] = SrbExtension
->LBA1
;
1289 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA2
] = SrbExtension
->LBA2
;
1290 cmdTable
->CFIS
[AHCI_ATA_CFIS_Device
] = SrbExtension
->Device
;
1291 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA3
] = SrbExtension
->LBA3
;
1292 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA4
] = SrbExtension
->LBA4
;
1293 cmdTable
->CFIS
[AHCI_ATA_CFIS_LBA5
] = SrbExtension
->LBA5
;
1294 cmdTable
->CFIS
[AHCI_ATA_CFIS_FeaturesHigh
] = SrbExtension
->FeaturesHigh
;
1295 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountLow
] = SrbExtension
->SectorCountLow
;
1296 cmdTable
->CFIS
[AHCI_ATA_CFIS_SectorCountHigh
] = SrbExtension
->SectorCountHigh
;
1299 }// -- AhciATAPI_CFIS();
1302 * @name AhciBuild_PRDT
1305 * Build PRDT for data transfer
1307 * @param PortExtension
1311 * Return number of entries in PRDT.
1315 __in PAHCI_PORT_EXTENSION PortExtension
,
1316 __in PAHCI_SRB_EXTENSION SrbExtension
1320 PAHCI_COMMAND_TABLE cmdTable
;
1321 PLOCAL_SCATTER_GATHER_LIST sgl
;
1322 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1324 AhciDebugPrint("AhciBuild_PRDT()\n");
1326 sgl
= SrbExtension
->pSgl
;
1327 cmdTable
= (PAHCI_COMMAND_TABLE
)SrbExtension
;
1328 AdapterExtension
= PortExtension
->AdapterExtension
;
1330 NT_ASSERT(sgl
!= NULL
);
1331 NT_ASSERT(sgl
->NumberOfElements
< MAXIMUM_AHCI_PRDT_ENTRIES
);
1333 for (index
= 0; index
< sgl
->NumberOfElements
; index
++)
1335 NT_ASSERT(sgl
->List
[index
].Length
<= MAXIMUM_TRANSFER_LENGTH
);
1337 cmdTable
->PRDT
[index
].DBA
= sgl
->List
[index
].PhysicalAddress
.LowPart
;
1338 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1340 cmdTable
->PRDT
[index
].DBAU
= sgl
->List
[index
].PhysicalAddress
.HighPart
;
1343 // Data Byte Count (DBC): A ‘0’ based value that Indicates the length, in bytes, of the data block.
1344 // A maximum of length of 4MB may exist for any entry. Bit ‘0’ of this field must always be ‘1’ to
1345 // indicate an even byte count. A value of ‘1’ indicates 2 bytes, ‘3’ indicates 4 bytes, etc.
1346 cmdTable
->PRDT
[index
].DBC
= sgl
->List
[index
].Length
- 1;
1349 return sgl
->NumberOfElements
;
1350 }// -- AhciBuild_PRDT();
1353 * @name AhciProcessSrb
1356 * Prepare Srb for IO processing
1358 * @param PortExtension
1365 __in PAHCI_PORT_EXTENSION PortExtension
,
1366 __in PSCSI_REQUEST_BLOCK Srb
,
1367 __in ULONG SlotIndex
1370 ULONG prdtlen
, sig
, length
, cfl
;
1371 PAHCI_SRB_EXTENSION SrbExtension
;
1372 PAHCI_COMMAND_HEADER CommandHeader
;
1373 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1374 STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress
;
1376 AhciDebugPrint("AhciProcessSrb()\n");
1378 NT_ASSERT(Srb
->PathId
== PortExtension
->PortNumber
);
1380 SrbExtension
= GetSrbExtension(Srb
);
1381 AdapterExtension
= PortExtension
->AdapterExtension
;
1383 NT_ASSERT(SrbExtension
!= NULL
);
1384 NT_ASSERT(SrbExtension
->AtaFunction
!= 0);
1386 if ((SrbExtension
->AtaFunction
== ATA_FUNCTION_ATA_IDENTIFY
) &&
1387 (SrbExtension
->CommandReg
== IDE_COMMAND_NOT_VALID
))
1389 // Here we are safe to check SIG register
1390 sig
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->SIG
);
1393 AhciDebugPrint("\tATA Device Found!\n");
1394 SrbExtension
->CommandReg
= IDE_COMMAND_IDENTIFY
;
1398 AhciDebugPrint("\tATAPI Device Found!\n");
1399 SrbExtension
->CommandReg
= IDE_COMMAND_ATAPI_IDENTIFY
;
1403 NT_ASSERT(SlotIndex
< AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
1404 SrbExtension
->SlotIndex
= SlotIndex
;
1406 // program the CFIS in the CommandTable
1407 CommandHeader
= &PortExtension
->CommandList
[SlotIndex
];
1410 if (IsAtapiCommand(SrbExtension
->AtaFunction
))
1412 cfl
= AhciATAPI_CFIS(PortExtension
, SrbExtension
);
1414 else if (IsAtaCommand(SrbExtension
->AtaFunction
))
1416 cfl
= AhciATA_CFIS(PortExtension
, SrbExtension
);
1424 if (IsDataTransferNeeded(SrbExtension
))
1426 prdtlen
= AhciBuild_PRDT(PortExtension
, SrbExtension
);
1427 NT_ASSERT(prdtlen
!= -1);
1430 // Program the command header
1431 CommandHeader
->DI
.PRDTL
= prdtlen
; // number of entries in PRD table
1432 CommandHeader
->DI
.CFL
= cfl
;
1433 CommandHeader
->DI
.A
= (SrbExtension
->AtaFunction
& ATA_FUNCTION_ATAPI_COMMAND
) ? 1 : 0;
1434 CommandHeader
->DI
.W
= (SrbExtension
->Flags
& ATA_FLAGS_DATA_OUT
) ? 1 : 0;
1435 CommandHeader
->DI
.P
= 0; // ATA Specifications says so
1436 CommandHeader
->DI
.PMP
= 0; // Port Multiplier
1438 // Reset -- Manual Configuation
1439 CommandHeader
->DI
.R
= 0;
1440 CommandHeader
->DI
.B
= 0;
1441 CommandHeader
->DI
.C
= 0;
1443 CommandHeader
->PRDBC
= 0;
1445 CommandHeader
->Reserved
[0] = 0;
1446 CommandHeader
->Reserved
[1] = 0;
1447 CommandHeader
->Reserved
[2] = 0;
1448 CommandHeader
->Reserved
[3] = 0;
1450 // set CommandHeader CTBA
1451 CommandTablePhysicalAddress
= StorPortGetPhysicalAddress(AdapterExtension
,
1456 NT_ASSERT(length
!= 0);
1458 // command table alignment
1459 NT_ASSERT((CommandTablePhysicalAddress
.LowPart
% 128) == 0);
1461 CommandHeader
->CTBA
= CommandTablePhysicalAddress
.LowPart
;
1463 if (IsAdapterCAPS64(AdapterExtension
->CAP
))
1465 CommandHeader
->CTBA_U
= CommandTablePhysicalAddress
.HighPart
;
1469 PortExtension
->Slot
[SlotIndex
] = Srb
;
1470 PortExtension
->QueueSlots
|= 1 << SlotIndex
;
1472 }// -- AhciProcessSrb();
1475 * @name AhciActivatePort
1478 * Program Port and populate command list
1480 * @param PortExtension
1484 #ifdef _MSC_VER // avoid MSVC C4700
1485 #pragma warning(push)
1486 #pragma warning(disable: 4700)
1491 __in PAHCI_PORT_EXTENSION PortExtension
1495 ULONG QueueSlots
, slotToActivate
, tmp
;
1496 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1498 AhciDebugPrint("AhciActivatePort()\n");
1500 AdapterExtension
= PortExtension
->AdapterExtension
;
1501 QueueSlots
= PortExtension
->QueueSlots
;
1503 if (QueueSlots
== 0)
1509 // Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’
1510 cmd
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CMD
);
1512 if (cmd
.ST
== 0) // PxCMD.ST == 0
1517 // get the lowest set bit
1518 tmp
= QueueSlots
& (QueueSlots
- 1);
1521 slotToActivate
= QueueSlots
;
1523 slotToActivate
= (QueueSlots
& (~tmp
));
1525 // mark that bit off in QueueSlots
1526 // so we can know we it is really needed to activate port or not
1527 PortExtension
->QueueSlots
&= ~slotToActivate
;
1528 // mark this CommandIssuedSlots
1529 // to validate in completeIssuedCommand
1530 PortExtension
->CommandIssuedSlots
|= slotToActivate
;
1532 // tell the HBA to issue this Command Slot to the given port
1533 StorPortWriteRegisterUlong(AdapterExtension
, &PortExtension
->Port
->CI
, slotToActivate
);
1536 }// -- AhciActivatePort();
1538 #ifdef _MSC_VER // avoid MSVC C4700
1539 #pragma warning(pop)
1543 * @name AhciProcessIO
1546 * Acquire Exclusive lock to port, populate pending commands to command List
1547 * program controller's port to process new commands in command list.
1549 * @param AdapterExtension
1556 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1558 __in PSCSI_REQUEST_BLOCK Srb
1561 PSCSI_REQUEST_BLOCK tmpSrb
;
1562 STOR_LOCK_HANDLE lockhandle
= {0};
1563 PAHCI_PORT_EXTENSION PortExtension
;
1564 ULONG commandSlotMask
, occupiedSlots
, slotIndex
, NCS
;
1566 AhciDebugPrint("AhciProcessIO()\n");
1567 AhciDebugPrint("\tPathId: %d\n", PathId
);
1569 PortExtension
= &AdapterExtension
->PortExtension
[PathId
];
1571 NT_ASSERT(PathId
< AdapterExtension
->PortCount
);
1574 StorPortAcquireSpinLock(AdapterExtension
, InterruptLock
, NULL
, &lockhandle
);
1577 AddQueue(&PortExtension
->SrbQueue
, Srb
);
1579 if (PortExtension
->DeviceParams
.IsActive
== FALSE
)
1582 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
1583 return; // we should wait for device to get active
1586 occupiedSlots
= (PortExtension
->QueueSlots
| PortExtension
->CommandIssuedSlots
); // Busy command slots for given port
1587 NCS
= AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
);
1588 commandSlotMask
= (1 << NCS
) - 1; // available slots mask
1590 commandSlotMask
= (commandSlotMask
& ~occupiedSlots
);
1591 if(commandSlotMask
!= 0)
1593 // iterate over HBA port slots
1594 for (slotIndex
= 0; slotIndex
< NCS
; slotIndex
++)
1596 // find first free slot
1597 if ((commandSlotMask
& (1 << slotIndex
)) != 0)
1599 tmpSrb
= RemoveQueue(&PortExtension
->SrbQueue
);
1602 NT_ASSERT(tmpSrb
->PathId
== PathId
);
1603 AhciProcessSrb(PortExtension
, tmpSrb
, slotIndex
);
1618 AhciActivatePort(PortExtension
);
1621 StorPortReleaseSpinLock(AdapterExtension
, &lockhandle
);
1624 }// -- AhciProcessIO();
1627 * @name AtapiInquiryCompletion
1630 * AtapiInquiryCompletion routine should be called after device signals
1631 * for device inquiry request is completed (through interrupt) -- ATAPI Device only
1633 * @param PortExtension
1638 AtapiInquiryCompletion (
1639 __in PVOID _Extension
,
1643 PAHCI_PORT_EXTENSION PortExtension
;
1644 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1645 PSCSI_REQUEST_BLOCK Srb
;
1648 AhciDebugPrint("AtapiInquiryCompletion()\n");
1650 PortExtension
= (PAHCI_PORT_EXTENSION
)_Extension
;
1651 Srb
= (PSCSI_REQUEST_BLOCK
)_Srb
;
1653 NT_ASSERT(Srb
!= NULL
);
1654 NT_ASSERT(PortExtension
!= NULL
);
1656 AdapterExtension
= PortExtension
->AdapterExtension
;
1659 status
= StorPortSetDeviceQueueDepth(PortExtension
->AdapterExtension
,
1663 AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
1665 NT_ASSERT(status
== TRUE
);
1667 }// -- AtapiInquiryCompletion();
1670 * @name InquiryCompletion
1673 * InquiryCompletion routine should be called after device signals
1674 * for device inquiry request is completed (through interrupt)
1676 * @param PortExtension
1682 __in PVOID _Extension
,
1686 PAHCI_PORT_EXTENSION PortExtension
;
1687 PSCSI_REQUEST_BLOCK Srb
;
1691 PINQUIRYDATA InquiryData
;
1692 PAHCI_SRB_EXTENSION SrbExtension
;
1693 PAHCI_ADAPTER_EXTENSION AdapterExtension
;
1694 PIDENTIFY_DEVICE_DATA IdentifyDeviceData
;
1696 AhciDebugPrint("InquiryCompletion()\n");
1698 PortExtension
= (PAHCI_PORT_EXTENSION
)_Extension
;
1699 Srb
= (PSCSI_REQUEST_BLOCK
)_Srb
;
1701 NT_ASSERT(Srb
!= NULL
);
1702 NT_ASSERT(PortExtension
!= NULL
);
1704 // cdb = (PCDB)&Srb->Cdb;
1705 InquiryData
= Srb
->DataBuffer
;
1706 SrbExtension
= GetSrbExtension(Srb
);
1707 AdapterExtension
= PortExtension
->AdapterExtension
;
1708 IdentifyDeviceData
= PortExtension
->IdentifyDeviceData
;
1710 if (Srb
->SrbStatus
!= SRB_STATUS_SUCCESS
)
1712 if (Srb
->SrbStatus
== SRB_STATUS_NO_DEVICE
)
1714 PortExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_NODEVICE
;
1719 NT_ASSERT(InquiryData
!= NULL
);
1720 NT_ASSERT(Srb
->SrbStatus
== SRB_STATUS_SUCCESS
);
1722 // Device specific data
1723 PortExtension
->DeviceParams
.MaxLba
.QuadPart
= 0;
1725 if (SrbExtension
->CommandReg
== IDE_COMMAND_IDENTIFY
)
1727 PortExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATA
;
1728 if (IdentifyDeviceData
->GeneralConfiguration
.RemovableMedia
)
1730 PortExtension
->DeviceParams
.RemovableDevice
= 1;
1733 if ((IdentifyDeviceData
->CommandSetSupport
.BigLba
) && (IdentifyDeviceData
->CommandSetActive
.BigLba
))
1735 PortExtension
->DeviceParams
.Lba48BitMode
= 1;
1738 PortExtension
->DeviceParams
.AccessType
= DIRECT_ACCESS_DEVICE
;
1740 /* Device max address lba */
1741 if (PortExtension
->DeviceParams
.Lba48BitMode
)
1743 PortExtension
->DeviceParams
.MaxLba
.LowPart
= IdentifyDeviceData
->Max48BitLBA
[0];
1744 PortExtension
->DeviceParams
.MaxLba
.HighPart
= IdentifyDeviceData
->Max48BitLBA
[1];
1748 PortExtension
->DeviceParams
.MaxLba
.LowPart
= IdentifyDeviceData
->UserAddressableSectors
;
1751 /* Bytes Per Logical Sector */
1752 if (IdentifyDeviceData
->PhysicalLogicalSectorSize
.LogicalSectorLongerThan256Words
)
1754 AhciDebugPrint("\tBytesPerLogicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1758 PortExtension
->DeviceParams
.BytesPerLogicalSector
= DEVICE_ATA_BLOCK_SIZE
;
1760 /* Bytes Per Physical Sector */
1761 if (IdentifyDeviceData
->PhysicalLogicalSectorSize
.MultipleLogicalSectorsPerPhysicalSector
)
1763 AhciDebugPrint("\tBytesPerPhysicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1767 PortExtension
->DeviceParams
.BytesPerPhysicalSector
= DEVICE_ATA_BLOCK_SIZE
;
1769 // last byte should be NULL
1770 StorPortCopyMemory(PortExtension
->DeviceParams
.VendorId
, IdentifyDeviceData
->ModelNumber
, sizeof(PortExtension
->DeviceParams
.VendorId
) - 1);
1771 StorPortCopyMemory(PortExtension
->DeviceParams
.RevisionID
, IdentifyDeviceData
->FirmwareRevision
, sizeof(PortExtension
->DeviceParams
.RevisionID
) - 1);
1772 StorPortCopyMemory(PortExtension
->DeviceParams
.SerialNumber
, IdentifyDeviceData
->SerialNumber
, sizeof(PortExtension
->DeviceParams
.SerialNumber
) - 1);
1774 PortExtension
->DeviceParams
.VendorId
[sizeof(PortExtension
->DeviceParams
.VendorId
) - 1] = '\0';
1775 PortExtension
->DeviceParams
.RevisionID
[sizeof(PortExtension
->DeviceParams
.RevisionID
) - 1] = '\0';
1776 PortExtension
->DeviceParams
.SerialNumber
[sizeof(PortExtension
->DeviceParams
.SerialNumber
) - 1] = '\0';
1778 // TODO: Add other device params
1779 AhciDebugPrint("\tATA Device\n");
1783 AhciDebugPrint("\tATAPI Device\n");
1784 PortExtension
->DeviceParams
.DeviceType
= AHCI_DEVICE_TYPE_ATAPI
;
1785 PortExtension
->DeviceParams
.AccessType
= READ_ONLY_DIRECT_ACCESS_DEVICE
;
1788 // INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h
1789 if (Srb
->DataTransferLength
< INQUIRYDATABUFFERSIZE
)
1791 AhciDebugPrint("\tDataBufferLength < sizeof(INQUIRYDATA), Could crash the driver.\n");
1795 // update data transfer length
1796 Srb
->DataTransferLength
= INQUIRYDATABUFFERSIZE
;
1798 // prepare data to send
1799 InquiryData
->Versions
= 2;
1800 InquiryData
->Wide32Bit
= 1;
1801 InquiryData
->CommandQueue
= 0; // NCQ not supported
1802 InquiryData
->ResponseDataFormat
= 0x2;
1803 InquiryData
->DeviceTypeModifier
= 0;
1804 InquiryData
->DeviceTypeQualifier
= DEVICE_CONNECTED
;
1805 InquiryData
->AdditionalLength
= INQUIRYDATABUFFERSIZE
- 5;
1806 InquiryData
->DeviceType
= PortExtension
->DeviceParams
.AccessType
;
1807 InquiryData
->RemovableMedia
= PortExtension
->DeviceParams
.RemovableDevice
;
1809 // Fill VendorID, Product Revision Level and other string fields
1810 StorPortCopyMemory(InquiryData
->VendorId
, PortExtension
->DeviceParams
.VendorId
, sizeof(InquiryData
->VendorId
) - 1);
1811 StorPortCopyMemory(InquiryData
->ProductId
, PortExtension
->DeviceParams
.RevisionID
, sizeof(PortExtension
->DeviceParams
.RevisionID
));
1812 StorPortCopyMemory(InquiryData
->ProductRevisionLevel
, PortExtension
->DeviceParams
.SerialNumber
, sizeof(InquiryData
->ProductRevisionLevel
) - 1);
1814 InquiryData
->VendorId
[sizeof(InquiryData
->VendorId
) - 1] = '\0';
1815 InquiryData
->ProductId
[sizeof(InquiryData
->ProductId
) - 1] = '\0';
1816 InquiryData
->ProductRevisionLevel
[sizeof(InquiryData
->ProductRevisionLevel
) - 1] = '\0';
1819 status
= StorPortSetDeviceQueueDepth(PortExtension
->AdapterExtension
,
1823 AHCI_Global_Port_CAP_NCS(AdapterExtension
->CAP
));
1825 NT_ASSERT(status
== TRUE
);
1827 }// -- InquiryCompletion();
1830 * @name AhciATAPICommand
1833 * Handles ATAPI Requests commands
1835 * @param AdapterExtension
1840 * return STOR status for AhciATAPICommand
1844 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1845 __in PSCSI_REQUEST_BLOCK Srb
,
1849 ULONG SrbFlags
, DataBufferLength
;
1850 PAHCI_SRB_EXTENSION SrbExtension
;
1851 PAHCI_PORT_EXTENSION PortExtension
;
1853 AhciDebugPrint("AhciATAPICommand()\n");
1855 SrbFlags
= Srb
->SrbFlags
;
1856 SrbExtension
= GetSrbExtension(Srb
);
1857 DataBufferLength
= Srb
->DataTransferLength
;
1858 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1860 NT_ASSERT(PortExtension
->DeviceParams
.DeviceType
== AHCI_DEVICE_TYPE_ATAPI
);
1862 NT_ASSERT(SrbExtension
!= NULL
);
1864 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATAPI_COMMAND
;
1865 SrbExtension
->Flags
= 0;
1867 if (SrbFlags
& SRB_FLAGS_DATA_IN
)
1869 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
1872 if (SrbFlags
& SRB_FLAGS_DATA_OUT
)
1874 SrbExtension
->Flags
|= ATA_FLAGS_DATA_OUT
;
1877 SrbExtension
->FeaturesLow
= 0;
1879 SrbExtension
->CompletionRoutine
= NULL
;
1881 NT_ASSERT(Cdb
!= NULL
);
1882 switch(Cdb
->CDB10
.OperationCode
)
1884 case SCSIOP_INQUIRY
:
1885 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
1886 SrbExtension
->CompletionRoutine
= AtapiInquiryCompletion
;
1889 SrbExtension
->Flags
|= ATA_FLAGS_USE_DMA
;
1890 SrbExtension
->FeaturesLow
= 0x5;
1893 SrbExtension
->Flags
|= ATA_FLAGS_USE_DMA
;
1894 SrbExtension
->FeaturesLow
= 0x1;
1898 SrbExtension
->CommandReg
= IDE_COMMAND_ATAPI_PACKET
;
1900 SrbExtension
->LBA0
= 0;
1901 SrbExtension
->LBA1
= (UCHAR
)(DataBufferLength
>> 0);
1902 SrbExtension
->LBA2
= (UCHAR
)(DataBufferLength
>> 8);
1903 SrbExtension
->Device
= 0;
1904 SrbExtension
->LBA3
= 0;
1905 SrbExtension
->LBA4
= 0;
1906 SrbExtension
->LBA5
= 0;
1907 SrbExtension
->FeaturesHigh
= 0;
1908 SrbExtension
->SectorCountLow
= 0;
1909 SrbExtension
->SectorCountHigh
= 0;
1911 if ((SrbExtension
->Flags
& ATA_FLAGS_DATA_IN
) || (SrbExtension
->Flags
& ATA_FLAGS_DATA_OUT
))
1913 SrbExtension
->pSgl
= (PLOCAL_SCATTER_GATHER_LIST
)StorPortGetScatterGatherList(AdapterExtension
, Srb
);
1916 return SRB_STATUS_PENDING
;
1917 }// -- AhciATAPICommand();
1920 * @name DeviceRequestSense
1923 * Handle SCSIOP_MODE_SENSE OperationCode
1925 * @param AdapterExtension
1930 * return STOR status for DeviceRequestSense
1933 DeviceRequestSense (
1934 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1935 __in PSCSI_REQUEST_BLOCK Srb
,
1939 PMODE_PARAMETER_HEADER ModeHeader
;
1940 PAHCI_PORT_EXTENSION PortExtension
;
1942 AhciDebugPrint("DeviceRequestSense()\n");
1944 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
1945 NT_ASSERT(Cdb
->CDB10
.OperationCode
== SCSIOP_MODE_SENSE
);
1947 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
1949 if (PortExtension
->DeviceParams
.DeviceType
== AHCI_DEVICE_TYPE_ATAPI
)
1951 return AhciATAPICommand(AdapterExtension
, Srb
, Cdb
);
1954 ModeHeader
= (PMODE_PARAMETER_HEADER
)Srb
->DataBuffer
;
1956 NT_ASSERT(ModeHeader
!= NULL
);
1958 AhciZeroMemory((PCHAR
)ModeHeader
, Srb
->DataTransferLength
);
1960 ModeHeader
->ModeDataLength
= sizeof(MODE_PARAMETER_HEADER
);
1961 ModeHeader
->MediumType
= 0;
1962 ModeHeader
->DeviceSpecificParameter
= 0;
1963 ModeHeader
->BlockDescriptorLength
= 0;
1965 if (Cdb
->MODE_SENSE
.PageCode
== MODE_SENSE_CURRENT_VALUES
)
1967 ModeHeader
->ModeDataLength
= sizeof(MODE_PARAMETER_HEADER
) + sizeof(MODE_PARAMETER_BLOCK
);
1968 ModeHeader
->BlockDescriptorLength
= sizeof(MODE_PARAMETER_BLOCK
);
1971 return SRB_STATUS_SUCCESS
;
1972 }// -- DeviceRequestSense();
1975 * @name DeviceRequestReadWrite
1978 * Handle SCSIOP_READ SCSIOP_WRITE OperationCode
1980 * @param AdapterExtension
1985 * return STOR status for DeviceRequestReadWrite
1988 DeviceRequestReadWrite (
1989 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
1990 __in PSCSI_REQUEST_BLOCK Srb
,
1995 ULONG64 StartOffset
;
1996 PAHCI_SRB_EXTENSION SrbExtension
;
1997 PAHCI_PORT_EXTENSION PortExtension
;
1998 ULONG DataTransferLength
, BytesPerSector
, SectorCount
;
2000 AhciDebugPrint("DeviceRequestReadWrite()\n");
2002 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
2003 NT_ASSERT((Cdb
->CDB10
.OperationCode
== SCSIOP_READ
) || (Cdb
->CDB10
.OperationCode
== SCSIOP_WRITE
));
2005 SrbExtension
= GetSrbExtension(Srb
);
2006 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
2008 if (PortExtension
->DeviceParams
.DeviceType
== AHCI_DEVICE_TYPE_ATAPI
)
2010 return AhciATAPICommand(AdapterExtension
, Srb
, Cdb
);
2013 DataTransferLength
= Srb
->DataTransferLength
;
2014 BytesPerSector
= PortExtension
->DeviceParams
.BytesPerLogicalSector
;
2016 NT_ASSERT(BytesPerSector
> 0);
2018 //ROUND_UP(DataTransferLength, BytesPerSector);
2020 SectorCount
= DataTransferLength
/ BytesPerSector
;
2022 Srb
->DataTransferLength
= SectorCount
* BytesPerSector
;
2024 StartOffset
= AhciGetLba(Cdb
, Srb
->CdbLength
);
2025 IsReading
= (Cdb
->CDB10
.OperationCode
== SCSIOP_READ
);
2027 NT_ASSERT(SectorCount
> 0);
2029 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATA_READ
;
2030 SrbExtension
->Flags
|= ATA_FLAGS_USE_DMA
;
2031 SrbExtension
->CompletionRoutine
= NULL
;
2035 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
2036 SrbExtension
->CommandReg
= IDE_COMMAND_READ_DMA
;
2040 SrbExtension
->Flags
|= ATA_FLAGS_DATA_OUT
;
2041 SrbExtension
->CommandReg
= IDE_COMMAND_WRITE_DMA
;
2044 SrbExtension
->FeaturesLow
= 0;
2045 SrbExtension
->LBA0
= (StartOffset
>> 0) & 0xFF;
2046 SrbExtension
->LBA1
= (StartOffset
>> 8) & 0xFF;
2047 SrbExtension
->LBA2
= (StartOffset
>> 16) & 0xFF;
2049 SrbExtension
->Device
= (0xA0 | IDE_LBA_MODE
);
2051 if (PortExtension
->DeviceParams
.Lba48BitMode
)
2053 SrbExtension
->Flags
|= ATA_FLAGS_48BIT_COMMAND
;
2057 SrbExtension
->CommandReg
= IDE_COMMAND_READ_DMA_EXT
;
2061 SrbExtension
->CommandReg
= IDE_COMMAND_WRITE_DMA_EXT
;
2064 SrbExtension
->LBA3
= (StartOffset
>> 24) & 0xFF;
2065 SrbExtension
->LBA4
= (StartOffset
>> 32) & 0xFF;
2066 SrbExtension
->LBA5
= (StartOffset
>> 40) & 0xFF;
2073 SrbExtension
->FeaturesHigh
= 0;
2074 SrbExtension
->SectorCountLow
= (SectorCount
>> 0) & 0xFF;
2075 SrbExtension
->SectorCountHigh
= (SectorCount
>> 8) & 0xFF;
2077 NT_ASSERT(SectorCount
< 0x100);
2079 SrbExtension
->pSgl
= (PLOCAL_SCATTER_GATHER_LIST
)StorPortGetScatterGatherList(AdapterExtension
, Srb
);
2081 return SRB_STATUS_PENDING
;
2082 }// -- DeviceRequestReadWrite();
2085 * @name DeviceRequestCapacity
2088 * Handle SCSIOP_READ_CAPACITY OperationCode
2090 * @param AdapterExtension
2095 * return STOR status for DeviceRequestCapacity
2098 DeviceRequestCapacity (
2099 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
2100 __in PSCSI_REQUEST_BLOCK Srb
,
2104 ULONG MaxLba
, BytesPerLogicalSector
;
2105 PREAD_CAPACITY_DATA ReadCapacity
;
2106 PAHCI_PORT_EXTENSION PortExtension
;
2108 AhciDebugPrint("DeviceRequestCapacity()\n");
2110 UNREFERENCED_PARAMETER(AdapterExtension
);
2111 UNREFERENCED_PARAMETER(Cdb
);
2113 NT_ASSERT(Srb
->DataBuffer
!= NULL
);
2114 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
2117 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
2119 if (PortExtension
->DeviceParams
.DeviceType
== AHCI_DEVICE_TYPE_ATAPI
)
2121 return AhciATAPICommand(AdapterExtension
, Srb
, Cdb
);
2124 if (Cdb
->CDB10
.OperationCode
== SCSIOP_READ_CAPACITY
)
2126 ReadCapacity
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
2128 BytesPerLogicalSector
= PortExtension
->DeviceParams
.BytesPerLogicalSector
;
2129 MaxLba
= (ULONG
)PortExtension
->DeviceParams
.MaxLba
.QuadPart
- 1;
2131 // I trust you windows :D
2132 NT_ASSERT(Srb
->DataTransferLength
>= sizeof(READ_CAPACITY_DATA
));
2134 // I trust you user :D
2135 NT_ASSERT(PortExtension
->DeviceParams
.MaxLba
.QuadPart
< (ULONG
)-1);
2137 // Actually I don't trust anyone :p
2138 Srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2140 REVERSE_BYTES(&ReadCapacity
->BytesPerBlock
, &BytesPerLogicalSector
);
2141 REVERSE_BYTES(&ReadCapacity
->LogicalBlockAddress
, &MaxLba
);
2145 AhciDebugPrint("\tSCSIOP_READ_CAPACITY16 not supported\n");
2149 return SRB_STATUS_SUCCESS
;
2150 }// -- DeviceRequestCapacity();
2153 * @name DeviceRequestComplete
2156 * Handle UnHandled Requests
2158 * @param AdapterExtension
2163 * return STOR status for DeviceRequestComplete
2166 DeviceRequestComplete (
2167 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
2168 __in PSCSI_REQUEST_BLOCK Srb
,
2172 AhciDebugPrint("DeviceRequestComplete()\n");
2174 UNREFERENCED_PARAMETER(AdapterExtension
);
2175 UNREFERENCED_PARAMETER(Cdb
);
2177 Srb
->ScsiStatus
= SCSISTAT_GOOD
;
2179 return SRB_STATUS_SUCCESS
;
2180 }// -- DeviceRequestComplete();
2183 * @name DeviceReportLuns
2186 * Handle SCSIOP_REPORT_LUNS OperationCode
2188 * @param AdapterExtension
2193 * return STOR status for DeviceReportLuns
2197 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
2198 __in PSCSI_REQUEST_BLOCK Srb
,
2203 PAHCI_PORT_EXTENSION PortExtension
;
2205 AhciDebugPrint("DeviceReportLuns()\n");
2207 UNREFERENCED_PARAMETER(Cdb
);
2209 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
2211 NT_ASSERT(Srb
->DataTransferLength
>= sizeof(LUN_LIST
));
2212 NT_ASSERT(Cdb
->CDB10
.OperationCode
== SCSIOP_REPORT_LUNS
);
2214 if (PortExtension
->DeviceParams
.DeviceType
== AHCI_DEVICE_TYPE_ATAPI
)
2216 return AhciATAPICommand(AdapterExtension
, Srb
, Cdb
);
2219 LunList
= (PLUN_LIST
)Srb
->DataBuffer
;
2221 NT_ASSERT(LunList
!= NULL
);
2223 AhciZeroMemory((PCHAR
)LunList
, sizeof(LUN_LIST
));
2225 LunList
->LunListLength
[3] = 8;
2227 Srb
->ScsiStatus
= SCSISTAT_GOOD
;
2228 Srb
->DataTransferLength
= sizeof(LUN_LIST
);
2230 return SRB_STATUS_SUCCESS
;
2231 }// -- DeviceReportLuns();
2234 * @name DeviceInquiryRequest
2237 * Tells wheather given port is implemented or not
2239 * @param AdapterExtension
2244 * return STOR status for DeviceInquiryRequest
2247 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
2250 DeviceInquiryRequest (
2251 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
2252 __in PSCSI_REQUEST_BLOCK Srb
,
2257 PAHCI_SRB_EXTENSION SrbExtension
;
2258 PAHCI_PORT_EXTENSION PortExtension
;
2259 PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer
;
2260 ULONG DataBufferLength
, RequiredDataBufferLength
;
2262 AhciDebugPrint("DeviceInquiryRequest()\n");
2264 NT_ASSERT(Cdb
->CDB10
.OperationCode
== SCSIOP_INQUIRY
);
2265 NT_ASSERT(IsPortValid(AdapterExtension
, Srb
->PathId
));
2267 SrbExtension
= GetSrbExtension(Srb
);
2268 PortExtension
= &AdapterExtension
->PortExtension
[Srb
->PathId
];
2270 if (PortExtension
->DeviceParams
.DeviceType
== AHCI_DEVICE_TYPE_ATAPI
)
2272 return AhciATAPICommand(AdapterExtension
, Srb
, Cdb
);
2277 return SRB_STATUS_SELECTION_TIMEOUT
;
2279 else if (Cdb
->CDB6INQUIRY3
.EnableVitalProductData
== 0)
2282 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
2283 AhciDebugPrint("\tEVPD Inquired\n");
2284 NT_ASSERT(SrbExtension
!= NULL
);
2286 SrbExtension
->AtaFunction
= ATA_FUNCTION_ATA_IDENTIFY
;
2287 SrbExtension
->Flags
|= ATA_FLAGS_DATA_IN
;
2288 SrbExtension
->CompletionRoutine
= InquiryCompletion
;
2289 SrbExtension
->CommandReg
= IDE_COMMAND_NOT_VALID
;
2291 // TODO: Should use AhciZeroMemory
2292 SrbExtension
->FeaturesLow
= 0;
2293 SrbExtension
->LBA0
= 0;
2294 SrbExtension
->LBA1
= 0;
2295 SrbExtension
->LBA2
= 0;
2296 SrbExtension
->Device
= 0xA0;
2297 SrbExtension
->LBA3
= 0;
2298 SrbExtension
->LBA4
= 0;
2299 SrbExtension
->LBA5
= 0;
2300 SrbExtension
->FeaturesHigh
= 0;
2301 SrbExtension
->SectorCountLow
= 0;
2302 SrbExtension
->SectorCountHigh
= 0;
2304 SrbExtension
->Sgl
.NumberOfElements
= 1;
2305 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.LowPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.LowPart
;
2306 SrbExtension
->Sgl
.List
[0].PhysicalAddress
.HighPart
= PortExtension
->IdentifyDeviceDataPhysicalAddress
.HighPart
;
2307 SrbExtension
->Sgl
.List
[0].Length
= sizeof(IDENTIFY_DEVICE_DATA
);
2309 SrbExtension
->pSgl
= &SrbExtension
->Sgl
;
2310 return SRB_STATUS_PENDING
;
2314 AhciDebugPrint("\tVPD Inquired\n");
2316 DataBuffer
= Srb
->DataBuffer
;
2317 DataBufferLength
= Srb
->DataTransferLength
;
2318 RequiredDataBufferLength
= DataBufferLength
; // make the compiler happy :p
2320 if (DataBuffer
== NULL
)
2322 return SRB_STATUS_INVALID_REQUEST
;
2325 AhciZeroMemory(DataBuffer
, DataBufferLength
);
2327 switch(Cdb
->CDB6INQUIRY3
.PageCode
)
2329 case VPD_SUPPORTED_PAGES
:
2331 AhciDebugPrint("\tVPD_SUPPORTED_PAGES\n");
2332 RequiredDataBufferLength
= sizeof(VPD_SUPPORTED_PAGES_PAGE
) + 1;
2334 if (DataBufferLength
< RequiredDataBufferLength
)
2336 AhciDebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength
, RequiredDataBufferLength
);
2337 return SRB_STATUS_INVALID_REQUEST
;
2340 VpdOutputBuffer
= (PVPD_SUPPORTED_PAGES_PAGE
)DataBuffer
;
2342 VpdOutputBuffer
->DeviceType
= PortExtension
->DeviceParams
.AccessType
;
2343 VpdOutputBuffer
->DeviceTypeQualifier
= 0;
2344 VpdOutputBuffer
->PageCode
= VPD_SUPPORTED_PAGES
;
2345 VpdOutputBuffer
->PageLength
= 1;
2346 VpdOutputBuffer
->SupportedPageList
[0] = VPD_SUPPORTED_PAGES
;
2347 //VpdOutputBuffer->SupportedPageList[1] = VPD_SERIAL_NUMBER;
2348 //VpdOutputBuffer->SupportedPageList[2] = VPD_DEVICE_IDENTIFIERS;
2350 NT_ASSERT(VpdOutputBuffer
->DeviceType
== DIRECT_ACCESS_DEVICE
);
2353 case VPD_SERIAL_NUMBER
:
2355 AhciDebugPrint("\tVPD_SERIAL_NUMBER\n");
2358 case VPD_DEVICE_IDENTIFIERS
:
2360 AhciDebugPrint("\tVPD_DEVICE_IDENTIFIERS\n");
2364 AhciDebugPrint("\tPageCode: %x\n", Cdb
->CDB6INQUIRY3
.PageCode
);
2365 return SRB_STATUS_INVALID_REQUEST
;
2368 Srb
->DataTransferLength
= RequiredDataBufferLength
;
2369 return SRB_STATUS_SUCCESS
;
2371 }// -- DeviceInquiryRequest();
2374 * @name AhciAdapterReset
2378 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
2379 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
2380 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
2381 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
2382 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
2383 * the HBA reset has completed.
2384 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
2385 * a hung or locked state.
2387 * @param AdapterExtension
2390 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
2394 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
2399 PAHCI_MEMORY_REGISTERS abar
= NULL
;
2401 AhciDebugPrint("AhciAdapterReset()\n");
2403 abar
= AdapterExtension
->ABAR_Address
;
2404 if (abar
== NULL
) // basic sanity
2409 // HR -- Very first bit (lowest significant)
2411 StorPortWriteRegisterUlong(AdapterExtension
, &abar
->GHC
, ghc
.Status
);
2413 for (ticks
= 0; ticks
< 50; ++ticks
)
2415 ghc
.Status
= StorPortReadRegisterUlong(AdapterExtension
, &abar
->GHC
);
2420 StorPortStallExecution(20000);
2423 if (ticks
== 50)// 1 second
2425 AhciDebugPrint("\tDevice Timeout\n");
2430 }// -- AhciAdapterReset();
2433 * @name AhciZeroMemory
2436 * Clear buffer by filling zeros
2445 __in ULONG BufferSize
2449 for (i
= 0; i
< BufferSize
; i
++)
2455 }// -- AhciZeroMemory();
2461 * Tells wheather given port is implemented or not
2463 * @param AdapterExtension
2467 * return TRUE if provided port is valid (implemented) or not
2472 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
,
2476 NT_ASSERT(pathId
< MAXIMUM_AHCI_PORT_COUNT
);
2478 if (pathId
>= AdapterExtension
->PortCount
)
2483 return AdapterExtension
->PortExtension
[pathId
].DeviceParams
.IsActive
;
2484 }// -- IsPortValid()
2496 * return TRUE if Srb is successfully added to Queue
2502 __inout PAHCI_QUEUE Queue
,
2506 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2507 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2509 if (Queue
->Tail
== ((Queue
->Head
+ 1) % MAXIMUM_QUEUE_BUFFER_SIZE
))
2512 Queue
->Buffer
[Queue
->Head
++] = Srb
;
2513 Queue
->Head
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
2522 * Remove and return Srb from Queue
2533 __inout PAHCI_QUEUE Queue
2538 NT_ASSERT(Queue
->Head
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2539 NT_ASSERT(Queue
->Tail
< MAXIMUM_QUEUE_BUFFER_SIZE
);
2541 if (Queue
->Head
== Queue
->Tail
)
2544 Srb
= Queue
->Buffer
[Queue
->Tail
++];
2545 Queue
->Tail
%= MAXIMUM_QUEUE_BUFFER_SIZE
;
2548 }// -- RemoveQueue();
2551 * @name GetSrbExtension
2554 * GetSrbExtension from Srb make sure It is properly aligned
2559 * return SrbExtension
2565 __in PSCSI_REQUEST_BLOCK Srb
2569 ULONG_PTR SrbExtension
;
2571 SrbExtension
= (ULONG_PTR
)Srb
->SrbExtension
;
2572 Offset
= SrbExtension
% 128;
2574 // CommandTable should be 128 byte aligned
2576 Offset
= 128 - Offset
;
2578 return (PAHCI_SRB_EXTENSION
)(SrbExtension
+ Offset
);
2579 }// -- PAHCI_SRB_EXTENSION();
2585 * Find the logical address of demand block from Cdb
2590 * return Logical Address of the block
2597 __in ULONG CdbLength
2602 NT_ASSERT(Cdb
!= NULL
);
2603 NT_ASSERT(CdbLength
!= 0);
2605 if (CdbLength
== 0x10)
2607 REVERSE_BYTES_QUAD(&lba
, Cdb
->CDB16
.LogicalBlock
);
2611 lba
|= Cdb
->CDB10
.LogicalBlockByte3
<< 0;
2612 lba
|= Cdb
->CDB10
.LogicalBlockByte2
<< 8;
2613 lba
|= Cdb
->CDB10
.LogicalBlockByte1
<< 16;
2614 lba
|= Cdb
->CDB10
.LogicalBlockByte0
<< 24;
2618 }// -- AhciGetLba();