1 /*
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)
6  */
7 
8 #include "storahci.h"
9 
10 /**
11  * @name AhciPortInitialize
12  * @implemented
13  *
14  * Initialize port by setting up PxCLB & PxFB Registers
15  *
16  * @param PortExtension
17  *
18  * @return
19  * Return true if intialization was successful
20  */
21 BOOLEAN
22 NTAPI
23 AhciPortInitialize (
24     __in PVOID DeviceExtension
25     )
26 {
27     PAHCI_PORT_EXTENSION PortExtension;
28     AHCI_PORT_CMD cmd;
29     PAHCI_MEMORY_REGISTERS abar;
30     ULONG mappedLength, portNumber, ticks;
31     PAHCI_ADAPTER_EXTENSION adapterExtension;
32     STOR_PHYSICAL_ADDRESS commandListPhysical, receivedFISPhysical;
33 
34     AhciDebugPrint("AhciPortInitialize()\n");
35 
36     PortExtension = (PAHCI_PORT_EXTENSION)DeviceExtension;
37     adapterExtension = PortExtension->AdapterExtension;
38     abar = adapterExtension->ABAR_Address;
39     portNumber = PortExtension->PortNumber;
40 
41     NT_ASSERT(abar != NULL);
42     NT_ASSERT(portNumber < adapterExtension->PortCount);
43 
44     PortExtension->Port = &abar->PortList[portNumber];
45 
46     commandListPhysical = StorPortGetPhysicalAddress(adapterExtension,
47                                                      NULL,
48                                                      PortExtension->CommandList,
49                                                      &mappedLength);
50 
51     if ((mappedLength == 0) || ((commandListPhysical.LowPart % 1024) != 0))
52     {
53         AhciDebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength);
54         return FALSE;
55     }
56 
57     receivedFISPhysical = StorPortGetPhysicalAddress(adapterExtension,
58                                                      NULL,
59                                                      PortExtension->ReceivedFIS,
60                                                      &mappedLength);
61 
62     if ((mappedLength == 0) || ((receivedFISPhysical.LowPart % 256) != 0))
63     {
64         AhciDebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength);
65         return FALSE;
66     }
67 
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
77 
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))
81     {
82         cmd.ST = 0;
83         cmd.FRE = 0;
84 
85         ticks = 3;
86         do
87         {
88             StorPortStallExecution(50000);
89             cmd.Status = StorPortReadRegisterUlong(adapterExtension, &PortExtension->Port->CMD);
90             if (ticks == 0)
91             {
92                 AhciDebugPrint("\tAttempt to reset port failed: %x\n", cmd);
93                 return FALSE;
94             }
95             ticks--;
96         }
97         while(cmd.CR != 0 || cmd.FR != 0);
98     }
99 
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))
106     {
107         StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLBU, commandListPhysical.HighPart);
108     }
109 
110     StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FB, receivedFISPhysical.LowPart);
111     if (IsAdapterCAPS64(adapterExtension->CAP))
112     {
113         StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FBU, receivedFISPhysical.HighPart);
114     }
115 
116     PortExtension->IdentifyDeviceDataPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension,
117                                                                                   NULL,
118                                                                                   PortExtension->IdentifyDeviceData,
119                                                                                   &mappedLength);
120 
121     // set device power state flag to D0
122     PortExtension->DevicePowerState = StorPowerDeviceD0;
123 
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));
128 
129     return TRUE;
130 }// -- AhciPortInitialize();
131 
132 /**
133  * @name AhciAllocateResourceForAdapter
134  * @implemented
135  *
136  * Allocate memory from poll for required pointers
137  *
138  * @param AdapterExtension
139  * @param ConfigInfo
140  *
141  * @return
142  * return TRUE if allocation was successful
143  */
144 BOOLEAN
145 AhciAllocateResourceForAdapter (
146     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
147     __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
148     )
149 {
150     PCHAR nonCachedExtension, tmp;
151     ULONG index, NCS, AlignedNCS;
152     ULONG portCount, portImplemented, nonCachedExtensionSize;
153     PAHCI_PORT_EXTENSION PortExtension;
154 
155     AhciDebugPrint("AhciAllocateResourceForAdapter()\n");
156 
157     NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
158     AlignedNCS = ROUND_UP(NCS, 8);
159 
160     // get port count -- Number of set bits in `AdapterExtension->PortImplemented`
161     portCount = 0;
162     portImplemented = AdapterExtension->PortImplemented;
163 
164     NT_ASSERT(portImplemented != 0);
165     for (index = MAXIMUM_AHCI_PORT_COUNT - 1; index > 0; index--)
166         if ((portImplemented & (1 << index)) != 0)
167             break;
168 
169     portCount = index + 1;
170     AhciDebugPrint("\tPort Count: %d\n", portCount);
171 
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);
176 
177     // align nonCachedExtensionSize to 1024
178     nonCachedExtensionSize = ROUND_UP(nonCachedExtensionSize, 1024);
179 
180     AdapterExtension->NonCachedExtension = StorPortGetUncachedExtension(AdapterExtension,
181                                                                         ConfigInfo,
182                                                                         nonCachedExtensionSize * portCount);
183 
184     if (AdapterExtension->NonCachedExtension == NULL)
185     {
186         AhciDebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
187         return FALSE;
188     }
189 
190     nonCachedExtension = AdapterExtension->NonCachedExtension;
191     AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize * portCount);
192 
193     for (index = 0; index < portCount; index++)
194     {
195         PortExtension = &AdapterExtension->PortExtension[index];
196 
197         PortExtension->DeviceParams.IsActive = FALSE;
198         if ((AdapterExtension->PortImplemented & (1 << index)) != 0)
199         {
200             PortExtension->PortNumber = index;
201             PortExtension->DeviceParams.IsActive = TRUE;
202             PortExtension->AdapterExtension = AdapterExtension;
203             PortExtension->CommandList = (PAHCI_COMMAND_HEADER)nonCachedExtension;
204 
205             tmp = (PCHAR)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
206 
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;
211         }
212     }
213 
214     return TRUE;
215 }// -- AhciAllocateResourceForAdapter();
216 
217 /**
218  * @name AhciStartPort
219  * @implemented
220  *
221  * Try to start the port device
222  *
223  * @param AdapterExtension
224  * @param PortExtension
225  *
226  */
227 BOOLEAN
228 AhciStartPort (
229     __in PAHCI_PORT_EXTENSION PortExtension
230     )
231 {
232     ULONG index;
233     AHCI_PORT_CMD cmd;
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;
239 
240     AhciDebugPrint("AhciStartPort()\n");
241 
242     AdapterExtension = PortExtension->AdapterExtension;
243     cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
244 
245     if ((cmd.FR == 1) && (cmd.CR == 1) && (cmd.FRE == 1) && (cmd.ST == 1))
246     {
247         // Already Running
248         return TRUE;
249     }
250 
251     cmd.SUD = 1;
252     StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
253 
254     if (((cmd.FR == 1) && (cmd.FRE == 0)) ||
255         ((cmd.CR == 1) && (cmd.ST == 0)))
256     {
257         AhciDebugPrint("\tCOMRESET\n");
258         // perform COMRESET
259         // section 10.4.2
260 
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.
267 
268         sctl.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL);
269         sctl.DET = 1;
270         StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL, sctl.Status);
271 
272         StorPortStallExecution(1000);
273 
274         sctl.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL);
275         sctl.DET = 0;
276         StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL, sctl.Status);
277 
278         // Poll DET to verify if a device is attached to the port
279         index = 0;
280         do
281         {
282             StorPortStallExecution(1000);
283             ssts.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SSTS);
284 
285             index++;
286             if (ssts.DET != 0)
287             {
288                 break;
289             }
290         }
291         while(index < 30);
292     }
293 
294     ssts.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SSTS);
295     switch (ssts.DET)
296     {
297         case 0x3:
298             {
299                 NT_ASSERT(cmd.ST == 0);
300 
301                 // make sure FIS Recieve is enabled (cmd.FRE)
302                 index = 0;
303                 do
304                 {
305                     StorPortStallExecution(10000);
306                     cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
307                     cmd.FRE = 1;
308                     StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
309                     index++;
310                 }
311                 while((cmd.FR != 1) && (index < 3));
312 
313                 if (cmd.FR != 1)
314                 {
315                     // failed to start FIS DMA engine
316                     // it can crash the driver later
317                     // so better to turn this port off
318                     return FALSE;
319                 }
320 
321                 // start port channel
322                 // set cmd.ST
323 
324                 NT_ASSERT(cmd.FRE == 1);
325                 NT_ASSERT(cmd.CR == 0);
326 
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);
331 
332                 if ((tfd.STS.BSY) || (tfd.STS.DRQ))
333                 {
334                     AhciDebugPrint("\tUnhandled Case BSY-DRQ\n");
335                 }
336 
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));
341 
342                 // set IE
343                 ie.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IE);
344                 /* Device to Host Register FIS Interrupt Enable */
345                 ie.DHRE = 1;
346                 /* PIO Setup FIS Interrupt Enable */
347                 ie.PSE = 1;
348                 /* DMA Setup FIS Interrupt Enable  */
349                 ie.DSE = 1;
350                 /* Set Device Bits FIS Interrupt Enable */
351                 ie.SDBE = 1;
352                 /* Unknown FIS Interrupt Enable */
353                 ie.UFE = 0;
354                 /* Descriptor Processed Interrupt Enable */
355                 ie.DPE = 0;
356                 /* Port Change Interrupt Enable */
357                 ie.PCE = 1;
358                 /* Device Mechanical Presence Enable */
359                 ie.DMPE = 0;
360                 /* PhyRdy Change Interrupt Enable */
361                 ie.PRCE = 1;
362                 /* Incorrect Port Multiplier Enable */
363                 ie.IPME = 0;
364                 /* Overflow Enable */
365                 ie.OFE = 1;
366                 /* Interface Non-fatal Error Enable */
367                 ie.INFE = 1;
368                 /* Interface Fatal Error Enable */
369                 ie.IFE = 1;
370                 /* Host Bus Data Error Enable */
371                 ie.HBDE = 1;
372                 /* Host Bus Fatal Error Enable */
373                 ie.HBFE = 1;
374                 /* Task File Error Enable */
375                 ie.TFEE = 1;
376 
377                 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
378                 /* Cold Presence Detect Enable */
379                 if (cmd.CPD) // does it support CPD?
380                 {
381                     // disable it for now
382                     ie.CPDE = 0;
383                 }
384 
385                 // should I replace this to single line?
386                 // by directly setting ie.Status?
387 
388                 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IE, ie.Status);
389 
390                 cmd.ST = 1;
391                 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
392                 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
393 
394                 if (cmd.ST != 1)
395                 {
396                     AhciDebugPrint("\tFailed to start Port\n");
397                     return FALSE;
398                 }
399 
400                 return TRUE;
401             }
402         default:
403             // unhandled case
404             AhciDebugPrint("\tDET == %x Unsupported\n", ssts.DET);
405             return FALSE;
406     }
407 }// -- AhciStartPort();
408 
409 /**
410  * @name AhciCommandCompletionDpcRoutine
411  * @implemented
412  *
413  * Handles Completed Commands
414  *
415  * @param Dpc
416  * @param AdapterExtension
417  * @param SystemArgument1
418  * @param SystemArgument2
419  */
420 VOID
421 AhciCommandCompletionDpcRoutine (
422     __in PSTOR_DPC Dpc,
423     __in PVOID HwDeviceExtension,
424     __in PVOID SystemArgument1,
425     __in PVOID SystemArgument2
426   )
427 {
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;
434 
435     UNREFERENCED_PARAMETER(Dpc);
436     UNREFERENCED_PARAMETER(SystemArgument2);
437 
438     AhciDebugPrint("AhciCommandCompletionDpcRoutine()\n");
439 
440     AdapterExtension = (PAHCI_ADAPTER_EXTENSION)HwDeviceExtension;
441     PortExtension = (PAHCI_PORT_EXTENSION)SystemArgument1;
442 
443     StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
444     Srb = RemoveQueue(&PortExtension->CompletionQueue);
445     StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
446 
447     NT_ASSERT(Srb != NULL);
448 
449     if (Srb->SrbStatus == SRB_STATUS_PENDING)
450     {
451         Srb->SrbStatus = SRB_STATUS_SUCCESS;
452     }
453     else
454     {
455         return;
456     }
457 
458     SrbExtension = GetSrbExtension(Srb);
459 
460     CompletionRoutine = SrbExtension->CompletionRoutine;
461     NT_ASSERT(CompletionRoutine != NULL);
462 
463     // now it's completion routine responsibility to set SrbStatus
464     CompletionRoutine(PortExtension, Srb);
465 
466     StorPortNotification(RequestComplete, AdapterExtension, Srb);
467 
468     return;
469 }// -- AhciCommandCompletionDpcRoutine();
470 
471 /**
472  * @name AhciHwPassiveInitialize
473  * @implemented
474  *
475  * initializes the HBA and finds all devices that are of interest to the miniport driver. (at PASSIVE LEVEL)
476  *
477  * @param adapterExtension
478  *
479  * @return
480  * return TRUE if intialization was successful
481  */
482 BOOLEAN
483 AhciHwPassiveInitialize (
484     __in PVOID DeviceExtension
485     )
486 {
487     ULONG index;
488     PAHCI_ADAPTER_EXTENSION AdapterExtension;
489     PAHCI_PORT_EXTENSION PortExtension;
490 
491     AhciDebugPrint("AhciHwPassiveInitialize()\n");
492 
493     AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
494 
495     for (index = 0; index < AdapterExtension->PortCount; index++)
496     {
497         if ((AdapterExtension->PortImplemented & (0x1 << index)) != 0)
498         {
499             PortExtension = &AdapterExtension->PortExtension[index];
500             PortExtension->DeviceParams.IsActive = AhciStartPort(PortExtension);
501             StorPortInitializeDpc(AdapterExtension, &PortExtension->CommandCompletion, AhciCommandCompletionDpcRoutine);
502         }
503     }
504 
505     return TRUE;
506 }// -- AhciHwPassiveInitialize();
507 
508 /**
509  * @name AhciHwInitialize
510  * @implemented
511  *
512  * initializes the HBA and finds all devices that are of interest to the miniport driver.
513  *
514  * @param adapterExtension
515  *
516  * @return
517  * return TRUE if intialization was successful
518  */
519 BOOLEAN
520 NTAPI
521 AhciHwInitialize (
522     __in PVOID DeviceExtension
523     )
524 {
525     PAHCI_ADAPTER_EXTENSION AdapterExtension;
526     AHCI_GHC ghc;
527 
528     AhciDebugPrint("AhciHwInitialize()\n");
529 
530     AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
531     AdapterExtension->StateFlags.MessagePerPort = FALSE;
532 
533     // First check what type of interrupt/synchronization device is using
534     ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &AdapterExtension->ABAR_Address->GHC);
535 
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
540     if (ghc.MRSM == 0)
541     {
542         AdapterExtension->StateFlags.MessagePerPort = TRUE;
543         AhciDebugPrint("\tMultiple MSI based message not supported\n");
544     }
545 
546     StorPortEnablePassiveInitialization(AdapterExtension, AhciHwPassiveInitialize);
547 
548     return TRUE;
549 }// -- AhciHwInitialize();
550 
551 /**
552  * @name AhciCompleteIssuedSrb
553  * @implemented
554  *
555  * Complete issued Srbs
556  *
557  * @param PortExtension
558  *
559  */
560 VOID
561 AhciCompleteIssuedSrb (
562     __in PAHCI_PORT_EXTENSION PortExtension,
563     __in ULONG CommandsToComplete
564     )
565 {
566     ULONG NCS, i;
567     PSCSI_REQUEST_BLOCK Srb;
568     PAHCI_SRB_EXTENSION SrbExtension;
569     PAHCI_ADAPTER_EXTENSION AdapterExtension;
570 
571     AhciDebugPrint("AhciCompleteIssuedSrb()\n");
572 
573     NT_ASSERT(CommandsToComplete != 0);
574 
575     AhciDebugPrint("\tCompleted Commands: %d\n", CommandsToComplete);
576 
577     AdapterExtension = PortExtension->AdapterExtension;
578     NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
579 
580     for (i = 0; i < NCS; i++)
581     {
582         if (((1 << i) & CommandsToComplete) != 0)
583         {
584             Srb = PortExtension->Slot[i];
585 
586             if (Srb == NULL)
587             {
588                 continue;
589             }
590 
591             SrbExtension = GetSrbExtension(Srb);
592             NT_ASSERT(SrbExtension != NULL);
593 
594             if (SrbExtension->CompletionRoutine != NULL)
595             {
596                 AddQueue(&PortExtension->CompletionQueue, Srb);
597                 StorPortIssueDpc(AdapterExtension, &PortExtension->CommandCompletion, PortExtension, Srb);
598             }
599             else
600             {
601                 NT_ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
602                 Srb->SrbStatus = SRB_STATUS_SUCCESS;
603                 StorPortNotification(RequestComplete, AdapterExtension, Srb);
604             }
605         }
606     }
607 
608     return;
609 }// -- AhciCompleteIssuedSrb();
610 
611 /**
612  * @name AhciInterruptHandler
613  * @not_implemented
614  *
615  * Interrupt Handler for PortExtension
616  *
617  * @param PortExtension
618  *
619  */
620 VOID
621 AhciInterruptHandler (
622     __in PAHCI_PORT_EXTENSION PortExtension
623     )
624 {
625     ULONG is, ci, sact, outstanding;
626     AHCI_INTERRUPT_STATUS PxIS;
627     AHCI_INTERRUPT_STATUS PxISMasked;
628     PAHCI_ADAPTER_EXTENSION AdapterExtension;
629 
630     AhciDebugPrint("AhciInterruptHandler()\n");
631     AhciDebugPrint("\tPort Number: %d\n", PortExtension->PortNumber);
632 
633     AdapterExtension = PortExtension->AdapterExtension;
634     NT_ASSERT(IsPortValid(AdapterExtension, PortExtension->PortNumber));
635 
636     // 5.5.3
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);
651 
652     // 6.2.2
653     // Fatal Error
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)
656     {
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.
664 
665         AhciDebugPrint("\tFatal Error: %x\n", PxIS.Status);
666     }
667 
668     // Normal Command Completion
669     // 3.3.5
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;
680 
681     if (PxISMasked.Status != 0)
682     {
683         StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IS, PxISMasked.Status);
684     }
685 
686     // 10.7.1.1
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);
691 
692     ci = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CI);
693     sact = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SACT);
694 
695     outstanding = ci | sact; // NOTE: Including both non-NCQ and NCQ based commands
696     if ((PortExtension->CommandIssuedSlots & (~outstanding)) != 0)
697     {
698         AhciCompleteIssuedSrb(PortExtension, (PortExtension->CommandIssuedSlots & (~outstanding)));
699         PortExtension->CommandIssuedSlots &= outstanding;
700     }
701 
702     return;
703 }// -- AhciInterruptHandler();
704 
705 /**
706  * @name AhciHwInterrupt
707  * @implemented
708  *
709  * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
710  *
711  * @param AdapterExtension
712  *
713  * @return
714  * return TRUE Indicates that an interrupt was pending on adapter.
715  * return FALSE Indicates the interrupt was not ours.
716  */
717 BOOLEAN
718 NTAPI
719 AhciHwInterrupt (
720     __in PVOID DeviceExtension
721     )
722 {
723     PAHCI_ADAPTER_EXTENSION AdapterExtension;
724     ULONG portPending, nextPort, i, portCount;
725 
726     AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
727 
728     if (AdapterExtension->StateFlags.Removed)
729     {
730         return FALSE;
731     }
732 
733     portPending = StorPortReadRegisterUlong(AdapterExtension, AdapterExtension->IS);
734 
735     // we process interrupt for implemented ports only
736     portCount = AdapterExtension->PortCount;
737     portPending = portPending & AdapterExtension->PortImplemented;
738 
739     if (portPending == 0)
740     {
741         return FALSE;
742     }
743 
744     for (i = 1; i <= portCount; i++)
745     {
746         nextPort = (AdapterExtension->LastInterruptPort + i) % portCount;
747         if ((portPending & (0x1 << nextPort)) == 0)
748             continue;
749 
750         NT_ASSERT(IsPortValid(AdapterExtension, nextPort));
751 
752         if (AdapterExtension->PortExtension[nextPort].DeviceParams.IsActive == FALSE)
753         {
754             continue;
755         }
756 
757         // we can assign this interrupt to this port
758         AdapterExtension->LastInterruptPort = nextPort;
759         AhciInterruptHandler(&AdapterExtension->PortExtension[nextPort]);
760 
761         portPending &= ~(1 << nextPort);
762 
763         // interrupt belongs to this device
764         // should always return TRUE
765         return TRUE;
766     }
767 
768     AhciDebugPrint("\tSomething went wrong");
769     return FALSE;
770 }// -- AhciHwInterrupt();
771 
772 /**
773  * @name AhciHwStartIo
774  * @not_implemented
775  *
776  * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
777  *
778  * @param adapterExtension
779  * @param Srb
780  *
781  * @return
782  * return TRUE if the request was accepted
783  * return FALSE if the request must be submitted later
784  */
785 BOOLEAN
786 NTAPI
787 AhciHwStartIo (
788     __in PVOID DeviceExtension,
789     __in PSCSI_REQUEST_BLOCK Srb
790     )
791 {
792     PAHCI_ADAPTER_EXTENSION AdapterExtension;
793 
794     AhciDebugPrint("AhciHwStartIo()\n");
795 
796     AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
797 
798     if (!IsPortValid(AdapterExtension, Srb->PathId))
799     {
800         Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
801         StorPortNotification(RequestComplete, AdapterExtension, Srb);
802         return TRUE;
803     }
804 
805     switch(Srb->Function)
806     {
807         case SRB_FUNCTION_PNP:
808             {
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.
812 
813                 PSCSI_PNP_REQUEST_BLOCK pnpRequest;
814                 pnpRequest = (PSCSI_PNP_REQUEST_BLOCK)Srb;
815                 if ((pnpRequest->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST) != 0)
816                 {
817                     switch(pnpRequest->PnPAction)
818                     {
819                         case StorRemoveDevice:
820                         case StorSurpriseRemoval:
821                             {
822                                 Srb->SrbStatus = SRB_STATUS_SUCCESS;
823                                 AdapterExtension->StateFlags.Removed = 1;
824                                 AhciDebugPrint("\tAdapter removed\n");
825                             }
826                             break;
827                         case StorStopDevice:
828                             {
829                                 Srb->SrbStatus = SRB_STATUS_SUCCESS;
830                                 AhciDebugPrint("\tRequested to Stop the adapter\n");
831                             }
832                             break;
833                         default:
834                             Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
835                             break;
836                     }
837                 }
838                 else
839                 {
840                     Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
841                 }
842             }
843             break;
844         case SRB_FUNCTION_EXECUTE_SCSI:
845             {
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:
849                 //
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.
856                 //
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)
863                 {
864                     AhciDebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode);
865                     Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
866                     break;
867                 }
868 
869                 NT_ASSERT(cdb != NULL);
870 
871                 switch(cdb->CDB10.OperationCode)
872                 {
873                     case SCSIOP_INQUIRY:
874                         Srb->SrbStatus = DeviceInquiryRequest(AdapterExtension, Srb, cdb);
875                         break;
876                     case SCSIOP_REPORT_LUNS:
877                         Srb->SrbStatus = DeviceReportLuns(AdapterExtension, Srb, cdb);
878                         break;
879                     case SCSIOP_READ_CAPACITY:
880                         Srb->SrbStatus = DeviceRequestCapacity(AdapterExtension, Srb, cdb);
881                         break;
882                     case SCSIOP_TEST_UNIT_READY:
883                         Srb->SrbStatus = DeviceRequestComplete(AdapterExtension, Srb, cdb);
884                         break;
885                     case SCSIOP_MODE_SENSE:
886                         Srb->SrbStatus = DeviceRequestSense(AdapterExtension, Srb, cdb);
887                         break;
888                     case SCSIOP_READ:
889                     case SCSIOP_WRITE:
890                         Srb->SrbStatus = DeviceRequestReadWrite(AdapterExtension, Srb, cdb);
891                         break;
892                     default:
893                         AhciDebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode);
894                         Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
895                         break;
896                 }
897             }
898             break;
899         default:
900             AhciDebugPrint("\tUnknown function code recieved: %x\n", Srb->Function);
901             Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
902             break;
903     }
904 
905     if (Srb->SrbStatus != SRB_STATUS_PENDING)
906     {
907         StorPortNotification(RequestComplete, AdapterExtension, Srb);
908     }
909     else
910     {
911         AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
912     }
913     return TRUE;
914 }// -- AhciHwStartIo();
915 
916 /**
917  * @name AhciHwResetBus
918  * @not_implemented
919  *
920  * The HwStorResetBus routine is called by the port driver to clear error conditions.
921  *
922  * @param adapterExtension
923  * @param PathId
924  *
925  * @return
926  * return TRUE if bus was successfully reset
927  */
928 BOOLEAN
929 NTAPI
930 AhciHwResetBus (
931     __in PVOID AdapterExtension,
932     __in ULONG PathId
933     )
934 {
935     STOR_LOCK_HANDLE lockhandle = {0};
936 //    PAHCI_ADAPTER_EXTENSION adapterExtension;
937 
938     AhciDebugPrint("AhciHwResetBus()\n");
939 
940 //    adapterExtension = AdapterExtension;
941 
942     if (IsPortValid(AdapterExtension, PathId))
943     {
944         // Acquire Lock
945         StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
946 
947         // TODO: Perform port reset
948 
949         // Release lock
950         StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
951     }
952 
953     return FALSE;
954 }// -- AhciHwResetBus();
955 
956 /**
957  * @name AhciHwFindAdapter
958  * @implemented
959  *
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.
962  *
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
965 
966  * @param DeviceExtension
967  * @param HwContext
968  * @param BusInformation
969  * @param ArgumentString
970  * @param ConfigInfo
971  * @param Reserved3
972  *
973  * @return
974  *      SP_RETURN_FOUND
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.
976  *
977  *      SP_RETURN_ERROR
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.
979  *
980  *      SP_RETURN_BAD_CONFIG
981  *          Indicates that the supplied configuration information was invalid for the adapter.
982  *
983  *      SP_RETURN_NOT_FOUND
984  *          Indicates that no supported HBA was found for the supplied configuration information.
985  *
986  * @remarks Called by Storport.
987  */
988 ULONG
989 NTAPI
990 AhciHwFindAdapter (
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
997     )
998 {
999     AHCI_GHC ghc;
1000     ULONG index, pci_cfg_len;
1001     PACCESS_RANGE accessRange;
1002     UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
1003 
1004     PAHCI_MEMORY_REGISTERS abar;
1005     PPCI_COMMON_CONFIG pciConfigData;
1006     PAHCI_ADAPTER_EXTENSION adapterExtension;
1007 
1008     AhciDebugPrint("AhciHwFindAdapter()\n");
1009 
1010     UNREFERENCED_PARAMETER(HwContext);
1011     UNREFERENCED_PARAMETER(BusInformation);
1012     UNREFERENCED_PARAMETER(ArgumentString);
1013     UNREFERENCED_PARAMETER(Reserved3);
1014 
1015     adapterExtension = DeviceExtension;
1016     adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
1017     adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
1018 
1019     // get PCI configuration header
1020     pci_cfg_len = StorPortGetBusData(
1021                         adapterExtension,
1022                         PCIConfiguration,
1023                         adapterExtension->SystemIoBusNumber,
1024                         adapterExtension->SlotNumber,
1025                         pci_cfg_buf,
1026                         sizeof(PCI_COMMON_CONFIG));
1027 
1028     if (pci_cfg_len != sizeof(PCI_COMMON_CONFIG))
1029     {
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
1032     }
1033 
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);
1040 
1041     AhciDebugPrint("\tVendorID: %04x  DeviceID: %04x  RevisionID: %02x\n",
1042                    adapterExtension->VendorID,
1043                    adapterExtension->DeviceID,
1044                    adapterExtension->RevisionID);
1045 
1046     // 2.1.11
1047     abar = NULL;
1048     if (ConfigInfo->NumberOfAccessRanges > 0)
1049     {
1050         accessRange = *(ConfigInfo->AccessRanges);
1051         for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++)
1052         {
1053             if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
1054             {
1055                 abar = StorPortGetDeviceBase(adapterExtension,
1056                                              ConfigInfo->AdapterInterfaceType,
1057                                              ConfigInfo->SystemIoBusNumber,
1058                                              accessRange[index].RangeStart,
1059                                              accessRange[index].RangeLength,
1060                                              !accessRange[index].RangeInMemory);
1061                 break;
1062             }
1063         }
1064     }
1065 
1066     if (abar == NULL)
1067     {
1068         AhciDebugPrint("\tabar == NULL\n");
1069         return SP_RETURN_ERROR; // corrupted information supplied
1070     }
1071 
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;
1077 
1078     // 10.1.2
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
1084     {
1085         // reset controller to have it in known state
1086         AhciDebugPrint("\tAE Already set, Reset()\n");
1087         if (!AhciAdapterReset(adapterExtension))
1088         {
1089             AhciDebugPrint("\tReset Failed!\n");
1090             return SP_RETURN_ERROR;// reset failed
1091         }
1092     }
1093 
1094     ghc.Status = 0;
1095     ghc.AE = 1;// only AE=1
1096     // tell the controller that we know about AHCI
1097     StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status);
1098 
1099     adapterExtension->IS = &abar->IS;
1100     adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
1101 
1102     if (adapterExtension->PortImplemented == 0)
1103     {
1104         AhciDebugPrint("\tadapterExtension->PortImplemented == 0\n");
1105         return SP_RETURN_ERROR;
1106     }
1107 
1108     ConfigInfo->Master = TRUE;
1109     ConfigInfo->AlignmentMask = 0x3;
1110     ConfigInfo->ScatterGather = TRUE;
1111     ConfigInfo->DmaWidth = Width32Bits;
1112     ConfigInfo->WmiDataProvider = FALSE;
1113     ConfigInfo->Dma32BitAddresses = TRUE;
1114 
1115     if (IsAdapterCAPS64(adapterExtension->CAP))
1116     {
1117         ConfigInfo->Dma64BitAddresses = TRUE;
1118     }
1119 
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;
1127 
1128     // Turn IE -- Interrupt Enabled
1129     ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
1130     ghc.IE = 1;
1131     StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status);
1132 
1133     // allocate necessary resource for each port
1134     if (!AhciAllocateResourceForAdapter(adapterExtension, ConfigInfo))
1135     {
1136         NT_ASSERT(FALSE);
1137         return SP_RETURN_ERROR;
1138     }
1139 
1140     for (index = 0; index < adapterExtension->PortCount; index++)
1141     {
1142         if ((adapterExtension->PortImplemented & (0x1 << index)) != 0)
1143             AhciPortInitialize(&adapterExtension->PortExtension[index]);
1144     }
1145 
1146     return SP_RETURN_FOUND;
1147 }// -- AhciHwFindAdapter();
1148 
1149 /**
1150  * @name DriverEntry
1151  * @implemented
1152  *
1153  * Initial Entrypoint for storahci miniport driver
1154  *
1155  * @param DriverObject
1156  * @param RegistryPath
1157  *
1158  * @return
1159  * NT_STATUS in case of driver loaded successfully.
1160  */
1161 ULONG
1162 NTAPI
1163 DriverEntry (
1164     __in PVOID DriverObject,
1165     __in PVOID RegistryPath
1166     )
1167 {
1168     ULONG status;
1169     // initialize the hardware data structure
1170     HW_INITIALIZATION_DATA hwInitializationData = {0};
1171 
1172     // set size of hardware initialization structure
1173     hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
1174 
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;
1181 
1182     // adapter specific information
1183     hwInitializationData.TaggedQueuing = TRUE;
1184     hwInitializationData.AutoRequestSense = TRUE;
1185     hwInitializationData.MultipleRequestPerLu = TRUE;
1186     hwInitializationData.NeedPhysicalAddresses = TRUE;
1187 
1188     hwInitializationData.NumberOfAccessRanges = 6;
1189     hwInitializationData.AdapterInterfaceType = PCIBus;
1190     hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
1191 
1192     // set required extension sizes
1193     hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION);
1194     hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION);
1195 
1196     // register our hw init data
1197     status = StorPortInitialize(DriverObject,
1198                                 RegistryPath,
1199                                 &hwInitializationData,
1200                                 NULL);
1201 
1202     NT_ASSERT(status == STATUS_SUCCESS);
1203     return status;
1204 }// -- DriverEntry();
1205 
1206 /**
1207  * @name AhciATA_CFIS
1208  * @implemented
1209  *
1210  * create ATA CFIS from Srb
1211  *
1212  * @param PortExtension
1213  * @param Srb
1214  *
1215  * @return
1216  * Number of CFIS fields used in DWORD
1217  */
1218 ULONG
1219 AhciATA_CFIS (
1220     __in PAHCI_PORT_EXTENSION PortExtension,
1221     __in PAHCI_SRB_EXTENSION SrbExtension
1222     )
1223 {
1224     PAHCI_COMMAND_TABLE cmdTable;
1225 
1226     UNREFERENCED_PARAMETER(PortExtension);
1227 
1228     AhciDebugPrint("AhciATA_CFIS()\n");
1229 
1230     cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
1231 
1232     AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS));
1233 
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;
1237 
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;
1249 
1250     return 5;
1251 }// -- AhciATA_CFIS();
1252 
1253 /**
1254  * @name AhciATAPI_CFIS
1255  * @not_implemented
1256  *
1257  * create ATAPI CFIS from Srb
1258  *
1259  * @param PortExtension
1260  * @param Srb
1261  *
1262  * @return
1263  * Number of CFIS fields used in DWORD
1264  */
1265 ULONG
1266 AhciATAPI_CFIS (
1267     __in PAHCI_PORT_EXTENSION PortExtension,
1268     __in PAHCI_SRB_EXTENSION SrbExtension
1269     )
1270 {
1271     PAHCI_COMMAND_TABLE cmdTable;
1272     UNREFERENCED_PARAMETER(PortExtension);
1273 
1274     AhciDebugPrint("AhciATAPI_CFIS()\n");
1275 
1276     cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
1277 
1278     NT_ASSERT(SrbExtension->CommandReg == IDE_COMMAND_ATAPI_PACKET);
1279 
1280     AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS));
1281 
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;
1285 
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;
1297 
1298     return 5;
1299 }// -- AhciATAPI_CFIS();
1300 
1301 /**
1302  * @name AhciBuild_PRDT
1303  * @implemented
1304  *
1305  * Build PRDT for data transfer
1306  *
1307  * @param PortExtension
1308  * @param Srb
1309  *
1310  * @return
1311  * Return number of entries in PRDT.
1312  */
1313 ULONG
1314 AhciBuild_PRDT (
1315     __in PAHCI_PORT_EXTENSION PortExtension,
1316     __in PAHCI_SRB_EXTENSION SrbExtension
1317     )
1318 {
1319     ULONG index;
1320     PAHCI_COMMAND_TABLE cmdTable;
1321     PLOCAL_SCATTER_GATHER_LIST sgl;
1322     PAHCI_ADAPTER_EXTENSION AdapterExtension;
1323 
1324     AhciDebugPrint("AhciBuild_PRDT()\n");
1325 
1326     sgl = SrbExtension->pSgl;
1327     cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
1328     AdapterExtension = PortExtension->AdapterExtension;
1329 
1330     NT_ASSERT(sgl != NULL);
1331     NT_ASSERT(sgl->NumberOfElements < MAXIMUM_AHCI_PRDT_ENTRIES);
1332 
1333     for (index = 0; index < sgl->NumberOfElements; index++)
1334     {
1335         NT_ASSERT(sgl->List[index].Length <= MAXIMUM_TRANSFER_LENGTH);
1336 
1337         cmdTable->PRDT[index].DBA = sgl->List[index].PhysicalAddress.LowPart;
1338         if (IsAdapterCAPS64(AdapterExtension->CAP))
1339         {
1340             cmdTable->PRDT[index].DBAU = sgl->List[index].PhysicalAddress.HighPart;
1341         }
1342 
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;
1347     }
1348 
1349     return sgl->NumberOfElements;
1350 }// -- AhciBuild_PRDT();
1351 
1352 /**
1353  * @name AhciProcessSrb
1354  * @implemented
1355  *
1356  * Prepare Srb for IO processing
1357  *
1358  * @param PortExtension
1359  * @param Srb
1360  * @param SlotIndex
1361  *
1362  */
1363 VOID
1364 AhciProcessSrb (
1365     __in PAHCI_PORT_EXTENSION PortExtension,
1366     __in PSCSI_REQUEST_BLOCK Srb,
1367     __in ULONG SlotIndex
1368     )
1369 {
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;
1375 
1376     AhciDebugPrint("AhciProcessSrb()\n");
1377 
1378     NT_ASSERT(Srb->PathId == PortExtension->PortNumber);
1379 
1380     SrbExtension = GetSrbExtension(Srb);
1381     AdapterExtension = PortExtension->AdapterExtension;
1382 
1383     NT_ASSERT(SrbExtension != NULL);
1384     NT_ASSERT(SrbExtension->AtaFunction != 0);
1385 
1386     if ((SrbExtension->AtaFunction == ATA_FUNCTION_ATA_IDENTIFY) &&
1387         (SrbExtension->CommandReg == IDE_COMMAND_NOT_VALID))
1388     {
1389         // Here we are safe to check SIG register
1390         sig = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SIG);
1391         if (sig == 0x101)
1392         {
1393             AhciDebugPrint("\tATA Device Found!\n");
1394             SrbExtension->CommandReg = IDE_COMMAND_IDENTIFY;
1395         }
1396         else
1397         {
1398             AhciDebugPrint("\tATAPI Device Found!\n");
1399             SrbExtension->CommandReg = IDE_COMMAND_ATAPI_IDENTIFY;
1400         }
1401     }
1402 
1403     NT_ASSERT(SlotIndex < AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
1404     SrbExtension->SlotIndex = SlotIndex;
1405 
1406     // program the CFIS in the CommandTable
1407     CommandHeader = &PortExtension->CommandList[SlotIndex];
1408 
1409     cfl = 0;
1410     if (IsAtapiCommand(SrbExtension->AtaFunction))
1411     {
1412         cfl = AhciATAPI_CFIS(PortExtension, SrbExtension);
1413     }
1414     else if (IsAtaCommand(SrbExtension->AtaFunction))
1415     {
1416         cfl = AhciATA_CFIS(PortExtension, SrbExtension);
1417     }
1418     else
1419     {
1420         NT_ASSERT(FALSE);
1421     }
1422 
1423     prdtlen = 0;
1424     if (IsDataTransferNeeded(SrbExtension))
1425     {
1426         prdtlen = AhciBuild_PRDT(PortExtension, SrbExtension);
1427         NT_ASSERT(prdtlen != -1);
1428     }
1429 
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
1437 
1438     // Reset -- Manual Configuation
1439     CommandHeader->DI.R = 0;
1440     CommandHeader->DI.B = 0;
1441     CommandHeader->DI.C = 0;
1442 
1443     CommandHeader->PRDBC = 0;
1444 
1445     CommandHeader->Reserved[0] = 0;
1446     CommandHeader->Reserved[1] = 0;
1447     CommandHeader->Reserved[2] = 0;
1448     CommandHeader->Reserved[3] = 0;
1449 
1450     // set CommandHeader CTBA
1451     CommandTablePhysicalAddress = StorPortGetPhysicalAddress(AdapterExtension,
1452                                                              NULL,
1453                                                              SrbExtension,
1454                                                              &length);
1455 
1456     NT_ASSERT(length != 0);
1457 
1458     // command table alignment
1459     NT_ASSERT((CommandTablePhysicalAddress.LowPart % 128) == 0);
1460 
1461     CommandHeader->CTBA = CommandTablePhysicalAddress.LowPart;
1462 
1463     if (IsAdapterCAPS64(AdapterExtension->CAP))
1464     {
1465         CommandHeader->CTBA_U = CommandTablePhysicalAddress.HighPart;
1466     }
1467 
1468     // mark this slot
1469     PortExtension->Slot[SlotIndex] = Srb;
1470     PortExtension->QueueSlots |= 1 << SlotIndex;
1471     return;
1472 }// -- AhciProcessSrb();
1473 
1474 /**
1475  * @name AhciActivatePort
1476  * @implemented
1477  *
1478  * Program Port and populate command list
1479  *
1480  * @param PortExtension
1481  *
1482  */
1483 
1484 #ifdef _MSC_VER     // avoid MSVC C4700
1485     #pragma warning(push)
1486     #pragma warning(disable: 4700)
1487 #endif
1488 
1489 VOID
1490 AhciActivatePort (
1491     __in PAHCI_PORT_EXTENSION PortExtension
1492     )
1493 {
1494     AHCI_PORT_CMD cmd;
1495     ULONG QueueSlots, slotToActivate, tmp;
1496     PAHCI_ADAPTER_EXTENSION AdapterExtension;
1497 
1498     AhciDebugPrint("AhciActivatePort()\n");
1499 
1500     AdapterExtension = PortExtension->AdapterExtension;
1501     QueueSlots = PortExtension->QueueSlots;
1502 
1503     if (QueueSlots == 0)
1504     {
1505         return;
1506     }
1507 
1508     // section 3.3.14
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);
1511 
1512     if (cmd.ST == 0) // PxCMD.ST == 0
1513     {
1514         return;
1515     }
1516 
1517     // get the lowest set bit
1518     tmp = QueueSlots & (QueueSlots - 1);
1519 
1520     if (tmp == 0)
1521         slotToActivate = QueueSlots;
1522     else
1523         slotToActivate = (QueueSlots & (~tmp));
1524 
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;
1531 
1532     // tell the HBA to issue this Command Slot to the given port
1533     StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CI, slotToActivate);
1534 
1535     return;
1536 }// -- AhciActivatePort();
1537 
1538 #ifdef _MSC_VER     // avoid MSVC C4700
1539     #pragma warning(pop)
1540 #endif
1541 
1542 /**
1543  * @name AhciProcessIO
1544  * @implemented
1545  *
1546  * Acquire Exclusive lock to port, populate pending commands to command List
1547  * program controller's port to process new commands in command list.
1548  *
1549  * @param AdapterExtension
1550  * @param PathId
1551  * @param Srb
1552  *
1553  */
1554 VOID
1555 AhciProcessIO (
1556     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1557     __in UCHAR PathId,
1558     __in PSCSI_REQUEST_BLOCK Srb
1559     )
1560 {
1561     PSCSI_REQUEST_BLOCK tmpSrb;
1562     STOR_LOCK_HANDLE lockhandle = {0};
1563     PAHCI_PORT_EXTENSION PortExtension;
1564     ULONG commandSlotMask, occupiedSlots, slotIndex, NCS;
1565 
1566     AhciDebugPrint("AhciProcessIO()\n");
1567     AhciDebugPrint("\tPathId: %d\n", PathId);
1568 
1569     PortExtension = &AdapterExtension->PortExtension[PathId];
1570 
1571     NT_ASSERT(PathId < AdapterExtension->PortCount);
1572 
1573     // Acquire Lock
1574     StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
1575 
1576     // add Srb to queue
1577     AddQueue(&PortExtension->SrbQueue, Srb);
1578 
1579     if (PortExtension->DeviceParams.IsActive == FALSE)
1580     {
1581         // Release Lock
1582         StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
1583         return; // we should wait for device to get active
1584     }
1585 
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
1589 
1590     commandSlotMask = (commandSlotMask & ~occupiedSlots);
1591     if(commandSlotMask != 0)
1592     {
1593         // iterate over HBA port slots
1594         for (slotIndex = 0; slotIndex < NCS; slotIndex++)
1595         {
1596             // find first free slot
1597             if ((commandSlotMask & (1 << slotIndex)) != 0)
1598             {
1599                 tmpSrb = RemoveQueue(&PortExtension->SrbQueue);
1600                 if (tmpSrb != NULL)
1601                 {
1602                     NT_ASSERT(tmpSrb->PathId == PathId);
1603                     AhciProcessSrb(PortExtension, tmpSrb, slotIndex);
1604                 }
1605                 else
1606                 {
1607                     break;
1608                 }
1609             }
1610             else
1611             {
1612                 break;
1613             }
1614         }
1615     }
1616 
1617     // program HBA port
1618     AhciActivatePort(PortExtension);
1619 
1620     // Release Lock
1621     StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
1622 
1623     return;
1624 }// -- AhciProcessIO();
1625 
1626 /**
1627  * @name AtapiInquiryCompletion
1628  * @implemented
1629  *
1630  * AtapiInquiryCompletion routine should be called after device signals
1631  * for device inquiry request is completed (through interrupt) -- ATAPI Device only
1632  *
1633  * @param PortExtension
1634  * @param Srb
1635  *
1636  */
1637 VOID
1638 AtapiInquiryCompletion (
1639     __in PVOID _Extension,
1640     __in PVOID _Srb
1641     )
1642 {
1643     PAHCI_PORT_EXTENSION PortExtension;
1644     PAHCI_ADAPTER_EXTENSION AdapterExtension;
1645     PSCSI_REQUEST_BLOCK Srb;
1646     BOOLEAN status;
1647 
1648     AhciDebugPrint("AtapiInquiryCompletion()\n");
1649 
1650     PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
1651     Srb = (PSCSI_REQUEST_BLOCK)_Srb;
1652 
1653     NT_ASSERT(Srb != NULL);
1654     NT_ASSERT(PortExtension != NULL);
1655 
1656     AdapterExtension = PortExtension->AdapterExtension;
1657 
1658     // send queue depth
1659     status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension,
1660                                          Srb->PathId,
1661                                          Srb->TargetId,
1662                                          Srb->Lun,
1663                                          AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
1664 
1665     NT_ASSERT(status == TRUE);
1666     return;
1667 }// -- AtapiInquiryCompletion();
1668 
1669 /**
1670  * @name InquiryCompletion
1671  * @implemented
1672  *
1673  * InquiryCompletion routine should be called after device signals
1674  * for device inquiry request is completed (through interrupt)
1675  *
1676  * @param PortExtension
1677  * @param Srb
1678  *
1679  */
1680 VOID
1681 InquiryCompletion (
1682     __in PVOID _Extension,
1683     __in PVOID _Srb
1684     )
1685 {
1686     PAHCI_PORT_EXTENSION PortExtension;
1687     PSCSI_REQUEST_BLOCK Srb;
1688 
1689 //    PCDB cdb;
1690     BOOLEAN status;
1691     PINQUIRYDATA InquiryData;
1692     PAHCI_SRB_EXTENSION SrbExtension;
1693     PAHCI_ADAPTER_EXTENSION AdapterExtension;
1694     PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
1695 
1696     AhciDebugPrint("InquiryCompletion()\n");
1697 
1698     PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
1699     Srb = (PSCSI_REQUEST_BLOCK)_Srb;
1700 
1701     NT_ASSERT(Srb != NULL);
1702     NT_ASSERT(PortExtension != NULL);
1703 
1704 //    cdb = (PCDB)&Srb->Cdb;
1705     InquiryData = Srb->DataBuffer;
1706     SrbExtension = GetSrbExtension(Srb);
1707     AdapterExtension = PortExtension->AdapterExtension;
1708     IdentifyDeviceData = PortExtension->IdentifyDeviceData;
1709 
1710     if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
1711     {
1712         if (Srb->SrbStatus == SRB_STATUS_NO_DEVICE)
1713         {
1714             PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
1715         }
1716         return;
1717     }
1718 
1719     NT_ASSERT(InquiryData != NULL);
1720     NT_ASSERT(Srb->SrbStatus == SRB_STATUS_SUCCESS);
1721 
1722     // Device specific data
1723     PortExtension->DeviceParams.MaxLba.QuadPart = 0;
1724 
1725     if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY)
1726     {
1727         PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA;
1728         if (IdentifyDeviceData->GeneralConfiguration.RemovableMedia)
1729         {
1730             PortExtension->DeviceParams.RemovableDevice = 1;
1731         }
1732 
1733         if ((IdentifyDeviceData->CommandSetSupport.BigLba) && (IdentifyDeviceData->CommandSetActive.BigLba))
1734         {
1735             PortExtension->DeviceParams.Lba48BitMode = 1;
1736         }
1737 
1738         PortExtension->DeviceParams.AccessType = DIRECT_ACCESS_DEVICE;
1739 
1740         /* Device max address lba */
1741         if (PortExtension->DeviceParams.Lba48BitMode)
1742         {
1743             PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->Max48BitLBA[0];
1744             PortExtension->DeviceParams.MaxLba.HighPart = IdentifyDeviceData->Max48BitLBA[1];
1745         }
1746         else
1747         {
1748             PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->UserAddressableSectors;
1749         }
1750 
1751         /* Bytes Per Logical Sector */
1752         if (IdentifyDeviceData->PhysicalLogicalSectorSize.LogicalSectorLongerThan256Words)
1753         {
1754             AhciDebugPrint("\tBytesPerLogicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1755             NT_ASSERT(FALSE);
1756         }
1757 
1758         PortExtension->DeviceParams.BytesPerLogicalSector = DEVICE_ATA_BLOCK_SIZE;
1759 
1760         /* Bytes Per Physical Sector */
1761         if (IdentifyDeviceData->PhysicalLogicalSectorSize.MultipleLogicalSectorsPerPhysicalSector)
1762         {
1763             AhciDebugPrint("\tBytesPerPhysicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1764             NT_ASSERT(FALSE);
1765         }
1766 
1767         PortExtension->DeviceParams.BytesPerPhysicalSector = DEVICE_ATA_BLOCK_SIZE;
1768 
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);
1773 
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';
1777 
1778         // TODO: Add other device params
1779         AhciDebugPrint("\tATA Device\n");
1780     }
1781     else
1782     {
1783         AhciDebugPrint("\tATAPI Device\n");
1784         PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
1785         PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE;
1786     }
1787 
1788     // INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h
1789     if (Srb->DataTransferLength < INQUIRYDATABUFFERSIZE)
1790     {
1791         AhciDebugPrint("\tDataBufferLength < sizeof(INQUIRYDATA), Could crash the driver.\n");
1792         NT_ASSERT(FALSE);
1793     }
1794 
1795     // update data transfer length
1796     Srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
1797 
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;
1808 
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);
1813 
1814     InquiryData->VendorId[sizeof(InquiryData->VendorId) - 1] = '\0';
1815     InquiryData->ProductId[sizeof(InquiryData->ProductId) - 1] = '\0';
1816     InquiryData->ProductRevisionLevel[sizeof(InquiryData->ProductRevisionLevel) - 1] = '\0';
1817 
1818     // send queue depth
1819     status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension,
1820                                          Srb->PathId,
1821                                          Srb->TargetId,
1822                                          Srb->Lun,
1823                                          AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
1824 
1825     NT_ASSERT(status == TRUE);
1826     return;
1827 }// -- InquiryCompletion();
1828 
1829  /**
1830  * @name AhciATAPICommand
1831  * @implemented
1832  *
1833  * Handles ATAPI Requests commands
1834  *
1835  * @param AdapterExtension
1836  * @param Srb
1837  * @param Cdb
1838  *
1839  * @return
1840  * return STOR status for AhciATAPICommand
1841  */
1842 UCHAR
1843 AhciATAPICommand (
1844     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1845     __in PSCSI_REQUEST_BLOCK Srb,
1846     __in PCDB Cdb
1847     )
1848 {
1849     ULONG SrbFlags, DataBufferLength;
1850     PAHCI_SRB_EXTENSION SrbExtension;
1851     PAHCI_PORT_EXTENSION PortExtension;
1852 
1853     AhciDebugPrint("AhciATAPICommand()\n");
1854 
1855     SrbFlags = Srb->SrbFlags;
1856     SrbExtension = GetSrbExtension(Srb);
1857     DataBufferLength = Srb->DataTransferLength;
1858     PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
1859 
1860     NT_ASSERT(PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI);
1861 
1862     NT_ASSERT(SrbExtension != NULL);
1863 
1864     SrbExtension->AtaFunction = ATA_FUNCTION_ATAPI_COMMAND;
1865     SrbExtension->Flags = 0;
1866 
1867     if (SrbFlags & SRB_FLAGS_DATA_IN)
1868     {
1869         SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
1870     }
1871 
1872     if (SrbFlags & SRB_FLAGS_DATA_OUT)
1873     {
1874         SrbExtension->Flags |= ATA_FLAGS_DATA_OUT;
1875     }
1876 
1877     SrbExtension->FeaturesLow = 0;
1878 
1879     SrbExtension->CompletionRoutine = NULL;
1880 
1881     NT_ASSERT(Cdb != NULL);
1882     switch(Cdb->CDB10.OperationCode)
1883     {
1884         case SCSIOP_INQUIRY:
1885             SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
1886             SrbExtension->CompletionRoutine = AtapiInquiryCompletion;
1887             break;
1888         case SCSIOP_READ:
1889             SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
1890             SrbExtension->FeaturesLow = 0x5;
1891             break;
1892         case SCSIOP_WRITE:
1893             SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
1894             SrbExtension->FeaturesLow = 0x1;
1895             break;
1896     }
1897 
1898     SrbExtension->CommandReg = IDE_COMMAND_ATAPI_PACKET;
1899 
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;
1910 
1911     if ((SrbExtension->Flags & ATA_FLAGS_DATA_IN) || (SrbExtension->Flags & ATA_FLAGS_DATA_OUT))
1912     {
1913         SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb);
1914     }
1915 
1916     return SRB_STATUS_PENDING;
1917 }// -- AhciATAPICommand();
1918 
1919 /**
1920  * @name DeviceRequestSense
1921  * @implemented
1922  *
1923  * Handle SCSIOP_MODE_SENSE OperationCode
1924  *
1925  * @param AdapterExtension
1926  * @param Srb
1927  * @param Cdb
1928  *
1929  * @return
1930  * return STOR status for DeviceRequestSense
1931  */
1932 UCHAR
1933 DeviceRequestSense (
1934     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1935     __in PSCSI_REQUEST_BLOCK Srb,
1936     __in PCDB Cdb
1937     )
1938 {
1939     PMODE_PARAMETER_HEADER ModeHeader;
1940     PAHCI_PORT_EXTENSION PortExtension;
1941 
1942     AhciDebugPrint("DeviceRequestSense()\n");
1943 
1944     NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
1945     NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_MODE_SENSE);
1946 
1947     PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
1948 
1949     if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
1950     {
1951         return AhciATAPICommand(AdapterExtension, Srb, Cdb);
1952     }
1953 
1954     ModeHeader = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;
1955 
1956     NT_ASSERT(ModeHeader != NULL);
1957 
1958     AhciZeroMemory((PCHAR)ModeHeader, Srb->DataTransferLength);
1959 
1960     ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER);
1961     ModeHeader->MediumType = 0;
1962     ModeHeader->DeviceSpecificParameter = 0;
1963     ModeHeader->BlockDescriptorLength = 0;
1964 
1965     if (Cdb->MODE_SENSE.PageCode == MODE_SENSE_CURRENT_VALUES)
1966     {
1967         ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1968         ModeHeader->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
1969     }
1970 
1971     return SRB_STATUS_SUCCESS;
1972 }// -- DeviceRequestSense();
1973 
1974 /**
1975  * @name DeviceRequestReadWrite
1976  * @implemented
1977  *
1978  * Handle SCSIOP_READ SCSIOP_WRITE OperationCode
1979  *
1980  * @param AdapterExtension
1981  * @param Srb
1982  * @param Cdb
1983  *
1984  * @return
1985  * return STOR status for DeviceRequestReadWrite
1986  */
1987 UCHAR
1988 DeviceRequestReadWrite (
1989     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1990     __in PSCSI_REQUEST_BLOCK Srb,
1991     __in PCDB Cdb
1992     )
1993 {
1994     BOOLEAN IsReading;
1995     ULONG64 StartOffset;
1996     PAHCI_SRB_EXTENSION SrbExtension;
1997     PAHCI_PORT_EXTENSION PortExtension;
1998     ULONG DataTransferLength, BytesPerSector, SectorCount;
1999 
2000     AhciDebugPrint("DeviceRequestReadWrite()\n");
2001 
2002     NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
2003     NT_ASSERT((Cdb->CDB10.OperationCode == SCSIOP_READ) || (Cdb->CDB10.OperationCode == SCSIOP_WRITE));
2004 
2005     SrbExtension = GetSrbExtension(Srb);
2006     PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
2007 
2008     if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
2009     {
2010         return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2011     }
2012 
2013     DataTransferLength = Srb->DataTransferLength;
2014     BytesPerSector = PortExtension->DeviceParams.BytesPerLogicalSector;
2015 
2016     NT_ASSERT(BytesPerSector > 0);
2017 
2018     //ROUND_UP(DataTransferLength, BytesPerSector);
2019 
2020     SectorCount = DataTransferLength / BytesPerSector;
2021 
2022     Srb->DataTransferLength = SectorCount * BytesPerSector;
2023 
2024     StartOffset = AhciGetLba(Cdb, Srb->CdbLength);
2025     IsReading = (Cdb->CDB10.OperationCode == SCSIOP_READ);
2026 
2027     NT_ASSERT(SectorCount > 0);
2028 
2029     SrbExtension->AtaFunction = ATA_FUNCTION_ATA_READ;
2030     SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
2031     SrbExtension->CompletionRoutine = NULL;
2032 
2033     if (IsReading)
2034     {
2035         SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
2036         SrbExtension->CommandReg = IDE_COMMAND_READ_DMA;
2037     }
2038     else
2039     {
2040         SrbExtension->Flags |= ATA_FLAGS_DATA_OUT;
2041         SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA;
2042     }
2043 
2044     SrbExtension->FeaturesLow = 0;
2045     SrbExtension->LBA0 = (StartOffset >> 0) & 0xFF;
2046     SrbExtension->LBA1 = (StartOffset >> 8) & 0xFF;
2047     SrbExtension->LBA2 = (StartOffset >> 16) & 0xFF;
2048 
2049     SrbExtension->Device = (0xA0 | IDE_LBA_MODE);
2050 
2051     if (PortExtension->DeviceParams.Lba48BitMode)
2052     {
2053         SrbExtension->Flags |= ATA_FLAGS_48BIT_COMMAND;
2054 
2055         if (IsReading)
2056         {
2057             SrbExtension->CommandReg = IDE_COMMAND_READ_DMA_EXT;
2058         }
2059         else
2060         {
2061             SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA_EXT;
2062         }
2063 
2064         SrbExtension->LBA3 = (StartOffset >> 24) & 0xFF;
2065         SrbExtension->LBA4 = (StartOffset >> 32) & 0xFF;
2066         SrbExtension->LBA5 = (StartOffset >> 40) & 0xFF;
2067     }
2068     else
2069     {
2070         NT_ASSERT(FALSE);
2071     }
2072 
2073     SrbExtension->FeaturesHigh = 0;
2074     SrbExtension->SectorCountLow = (SectorCount >> 0) & 0xFF;
2075     SrbExtension->SectorCountHigh = (SectorCount >> 8) & 0xFF;
2076 
2077     NT_ASSERT(SectorCount < 0x100);
2078 
2079     SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb);
2080 
2081     return SRB_STATUS_PENDING;
2082 }// -- DeviceRequestReadWrite();
2083 
2084 /**
2085  * @name DeviceRequestCapacity
2086  * @implemented
2087  *
2088  * Handle SCSIOP_READ_CAPACITY OperationCode
2089  *
2090  * @param AdapterExtension
2091  * @param Srb
2092  * @param Cdb
2093  *
2094  * @return
2095  * return STOR status for DeviceRequestCapacity
2096  */
2097 UCHAR
2098 DeviceRequestCapacity (
2099     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2100     __in PSCSI_REQUEST_BLOCK Srb,
2101     __in PCDB Cdb
2102     )
2103 {
2104     ULONG MaxLba, BytesPerLogicalSector;
2105     PREAD_CAPACITY_DATA ReadCapacity;
2106     PAHCI_PORT_EXTENSION PortExtension;
2107 
2108     AhciDebugPrint("DeviceRequestCapacity()\n");
2109 
2110     UNREFERENCED_PARAMETER(AdapterExtension);
2111     UNREFERENCED_PARAMETER(Cdb);
2112 
2113     NT_ASSERT(Srb->DataBuffer != NULL);
2114     NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
2115 
2116 
2117     PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
2118 
2119     if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
2120     {
2121         return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2122     }
2123 
2124     if (Cdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY)
2125     {
2126         ReadCapacity = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
2127 
2128         BytesPerLogicalSector = PortExtension->DeviceParams.BytesPerLogicalSector;
2129         MaxLba = (ULONG)PortExtension->DeviceParams.MaxLba.QuadPart - 1;
2130 
2131         // I trust you windows :D
2132         NT_ASSERT(Srb->DataTransferLength >= sizeof(READ_CAPACITY_DATA));
2133 
2134         // I trust you user :D
2135         NT_ASSERT(PortExtension->DeviceParams.MaxLba.QuadPart < (ULONG)-1);
2136 
2137         // Actually I don't trust anyone :p
2138         Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2139 
2140         REVERSE_BYTES(&ReadCapacity->BytesPerBlock, &BytesPerLogicalSector);
2141         REVERSE_BYTES(&ReadCapacity->LogicalBlockAddress, &MaxLba);
2142     }
2143     else
2144     {
2145         AhciDebugPrint("\tSCSIOP_READ_CAPACITY16 not supported\n");
2146         NT_ASSERT(FALSE);
2147     }
2148 
2149     return SRB_STATUS_SUCCESS;
2150 }// -- DeviceRequestCapacity();
2151 
2152 /**
2153  * @name DeviceRequestComplete
2154  * @implemented
2155  *
2156  * Handle UnHandled Requests
2157  *
2158  * @param AdapterExtension
2159  * @param Srb
2160  * @param Cdb
2161  *
2162  * @return
2163  * return STOR status for DeviceRequestComplete
2164  */
2165 UCHAR
2166 DeviceRequestComplete (
2167     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2168     __in PSCSI_REQUEST_BLOCK Srb,
2169     __in PCDB Cdb
2170     )
2171 {
2172     AhciDebugPrint("DeviceRequestComplete()\n");
2173 
2174     UNREFERENCED_PARAMETER(AdapterExtension);
2175     UNREFERENCED_PARAMETER(Cdb);
2176 
2177     Srb->ScsiStatus = SCSISTAT_GOOD;
2178 
2179     return SRB_STATUS_SUCCESS;
2180 }// -- DeviceRequestComplete();
2181 
2182 /**
2183  * @name DeviceReportLuns
2184  * @implemented
2185  *
2186  * Handle SCSIOP_REPORT_LUNS OperationCode
2187  *
2188  * @param AdapterExtension
2189  * @param Srb
2190  * @param Cdb
2191  *
2192  * @return
2193  * return STOR status for DeviceReportLuns
2194  */
2195 UCHAR
2196 DeviceReportLuns (
2197     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2198     __in PSCSI_REQUEST_BLOCK Srb,
2199     __in PCDB Cdb
2200     )
2201 {
2202     PLUN_LIST LunList;
2203     PAHCI_PORT_EXTENSION PortExtension;
2204 
2205     AhciDebugPrint("DeviceReportLuns()\n");
2206 
2207     UNREFERENCED_PARAMETER(Cdb);
2208 
2209     PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
2210 
2211     NT_ASSERT(Srb->DataTransferLength >= sizeof(LUN_LIST));
2212     NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_REPORT_LUNS);
2213 
2214     if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
2215     {
2216         return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2217     }
2218 
2219     LunList = (PLUN_LIST)Srb->DataBuffer;
2220 
2221     NT_ASSERT(LunList != NULL);
2222 
2223     AhciZeroMemory((PCHAR)LunList, sizeof(LUN_LIST));
2224 
2225     LunList->LunListLength[3] = 8;
2226 
2227     Srb->ScsiStatus = SCSISTAT_GOOD;
2228     Srb->DataTransferLength = sizeof(LUN_LIST);
2229 
2230     return SRB_STATUS_SUCCESS;
2231 }// -- DeviceReportLuns();
2232 
2233 /**
2234  * @name DeviceInquiryRequest
2235  * @implemented
2236  *
2237  * Tells wheather given port is implemented or not
2238  *
2239  * @param AdapterExtension
2240  * @param Srb
2241  * @param Cdb
2242  *
2243  * @return
2244  * return STOR status for DeviceInquiryRequest
2245  *
2246  * @remark
2247  * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
2248  */
2249 UCHAR
2250 DeviceInquiryRequest (
2251     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2252     __in PSCSI_REQUEST_BLOCK Srb,
2253     __in PCDB Cdb
2254     )
2255 {
2256     PVOID DataBuffer;
2257     PAHCI_SRB_EXTENSION SrbExtension;
2258     PAHCI_PORT_EXTENSION PortExtension;
2259     PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer;
2260     ULONG DataBufferLength, RequiredDataBufferLength;
2261 
2262     AhciDebugPrint("DeviceInquiryRequest()\n");
2263 
2264     NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_INQUIRY);
2265     NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
2266 
2267     SrbExtension = GetSrbExtension(Srb);
2268     PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
2269 
2270     if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
2271     {
2272         return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2273     }
2274 
2275     if (Srb->Lun != 0)
2276     {
2277         return SRB_STATUS_SELECTION_TIMEOUT;
2278     }
2279     else if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
2280     {
2281         // 3.6.1
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);
2285 
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;
2290 
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;
2303 
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);
2308 
2309         SrbExtension->pSgl = &SrbExtension->Sgl;
2310         return SRB_STATUS_PENDING;
2311     }
2312     else
2313     {
2314         AhciDebugPrint("\tVPD Inquired\n");
2315 
2316         DataBuffer = Srb->DataBuffer;
2317         DataBufferLength = Srb->DataTransferLength;
2318         RequiredDataBufferLength = DataBufferLength; // make the compiler happy :p
2319 
2320         if (DataBuffer == NULL)
2321         {
2322             return SRB_STATUS_INVALID_REQUEST;
2323         }
2324 
2325         AhciZeroMemory(DataBuffer, DataBufferLength);
2326 
2327         switch(Cdb->CDB6INQUIRY3.PageCode)
2328         {
2329             case VPD_SUPPORTED_PAGES:
2330                 {
2331                     AhciDebugPrint("\tVPD_SUPPORTED_PAGES\n");
2332                     RequiredDataBufferLength = sizeof(VPD_SUPPORTED_PAGES_PAGE) + 1;
2333 
2334                     if (DataBufferLength < RequiredDataBufferLength)
2335                     {
2336                         AhciDebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength, RequiredDataBufferLength);
2337                         return SRB_STATUS_INVALID_REQUEST;
2338                     }
2339 
2340                     VpdOutputBuffer = (PVPD_SUPPORTED_PAGES_PAGE)DataBuffer;
2341 
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;
2349 
2350                     NT_ASSERT(VpdOutputBuffer->DeviceType == DIRECT_ACCESS_DEVICE);
2351                 }
2352                 break;
2353             case VPD_SERIAL_NUMBER:
2354                 {
2355                     AhciDebugPrint("\tVPD_SERIAL_NUMBER\n");
2356                 }
2357                 break;
2358             case VPD_DEVICE_IDENTIFIERS:
2359                 {
2360                     AhciDebugPrint("\tVPD_DEVICE_IDENTIFIERS\n");
2361                 }
2362                 break;
2363             default:
2364                 AhciDebugPrint("\tPageCode: %x\n", Cdb->CDB6INQUIRY3.PageCode);
2365                 return SRB_STATUS_INVALID_REQUEST;
2366         }
2367 
2368         Srb->DataTransferLength = RequiredDataBufferLength;
2369         return SRB_STATUS_SUCCESS;
2370     }
2371 }// -- DeviceInquiryRequest();
2372 
2373 /**
2374  * @name AhciAdapterReset
2375  * @implemented
2376  *
2377  * 10.4.3 HBA Reset
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.
2386  *
2387  * @param AdapterExtension
2388  *
2389  * @return
2390  * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
2391  */
2392 BOOLEAN
2393 AhciAdapterReset (
2394     __in PAHCI_ADAPTER_EXTENSION AdapterExtension
2395     )
2396 {
2397     ULONG ticks;
2398     AHCI_GHC ghc;
2399     PAHCI_MEMORY_REGISTERS abar = NULL;
2400 
2401     AhciDebugPrint("AhciAdapterReset()\n");
2402 
2403     abar = AdapterExtension->ABAR_Address;
2404     if (abar == NULL) // basic sanity
2405     {
2406         return FALSE;
2407     }
2408 
2409     // HR -- Very first bit (lowest significant)
2410     ghc.HR = 1;
2411     StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc.Status);
2412 
2413     for (ticks = 0; ticks < 50; ++ticks)
2414     {
2415         ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
2416         if (ghc.HR == 0)
2417         {
2418             break;
2419         }
2420         StorPortStallExecution(20000);
2421     }
2422 
2423     if (ticks == 50)// 1 second
2424     {
2425         AhciDebugPrint("\tDevice Timeout\n");
2426         return FALSE;
2427     }
2428 
2429     return TRUE;
2430 }// -- AhciAdapterReset();
2431 
2432 /**
2433  * @name AhciZeroMemory
2434  * @implemented
2435  *
2436  * Clear buffer by filling zeros
2437  *
2438  * @param Buffer
2439  * @param BufferSize
2440  */
2441 FORCEINLINE
2442 VOID
2443 AhciZeroMemory (
2444     __out PCHAR Buffer,
2445     __in ULONG BufferSize
2446     )
2447 {
2448     ULONG i;
2449     for (i = 0; i < BufferSize; i++)
2450     {
2451         Buffer[i] = 0;
2452     }
2453 
2454     return;
2455 }// -- AhciZeroMemory();
2456 
2457 /**
2458  * @name IsPortValid
2459  * @implemented
2460  *
2461  * Tells wheather given port is implemented or not
2462  *
2463  * @param AdapterExtension
2464  * @param PathId
2465  *
2466  * @return
2467  * return TRUE if provided port is valid (implemented) or not
2468  */
2469 FORCEINLINE
2470 BOOLEAN
2471 IsPortValid (
2472     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2473     __in ULONG pathId
2474     )
2475 {
2476     NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT);
2477 
2478     if (pathId >= AdapterExtension->PortCount)
2479     {
2480         return FALSE;
2481     }
2482 
2483     return AdapterExtension->PortExtension[pathId].DeviceParams.IsActive;
2484 }// -- IsPortValid()
2485 
2486 /**
2487  * @name AddQueue
2488  * @implemented
2489  *
2490  * Add Srb to Queue
2491  *
2492  * @param Queue
2493  * @param Srb
2494  *
2495  * @return
2496  * return TRUE if Srb is successfully added to Queue
2497  *
2498  */
2499 FORCEINLINE
2500 BOOLEAN
2501 AddQueue (
2502     __inout PAHCI_QUEUE Queue,
2503     __in PVOID Srb
2504     )
2505 {
2506     NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
2507     NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
2508 
2509     if (Queue->Tail == ((Queue->Head + 1) % MAXIMUM_QUEUE_BUFFER_SIZE))
2510         return FALSE;
2511 
2512     Queue->Buffer[Queue->Head++] = Srb;
2513     Queue->Head %= MAXIMUM_QUEUE_BUFFER_SIZE;
2514 
2515     return TRUE;
2516 }// -- AddQueue();
2517 
2518 /**
2519  * @name RemoveQueue
2520  * @implemented
2521  *
2522  * Remove and return Srb from Queue
2523  *
2524  * @param Queue
2525  *
2526  * @return
2527  * return Srb
2528  *
2529  */
2530 FORCEINLINE
2531 PVOID
2532 RemoveQueue (
2533     __inout PAHCI_QUEUE Queue
2534     )
2535 {
2536     PVOID Srb;
2537 
2538     NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
2539     NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
2540 
2541     if (Queue->Head == Queue->Tail)
2542         return NULL;
2543 
2544     Srb = Queue->Buffer[Queue->Tail++];
2545     Queue->Tail %= MAXIMUM_QUEUE_BUFFER_SIZE;
2546 
2547     return Srb;
2548 }// -- RemoveQueue();
2549 
2550 /**
2551  * @name GetSrbExtension
2552  * @implemented
2553  *
2554  * GetSrbExtension from Srb make sure It is properly aligned
2555  *
2556  * @param Srb
2557  *
2558  * @return
2559  * return SrbExtension
2560  *
2561  */
2562 FORCEINLINE
2563 PAHCI_SRB_EXTENSION
2564 GetSrbExtension (
2565     __in PSCSI_REQUEST_BLOCK Srb
2566     )
2567 {
2568     ULONG Offset;
2569     ULONG_PTR SrbExtension;
2570 
2571     SrbExtension = (ULONG_PTR)Srb->SrbExtension;
2572     Offset = SrbExtension % 128;
2573 
2574     // CommandTable should be 128 byte aligned
2575     if (Offset != 0)
2576         Offset = 128 - Offset;
2577 
2578     return (PAHCI_SRB_EXTENSION)(SrbExtension + Offset);
2579 }// -- PAHCI_SRB_EXTENSION();
2580 
2581 /**
2582  * @name AhciGetLba
2583  * @implemented
2584  *
2585  * Find the logical address of demand block from Cdb
2586  *
2587  * @param Srb
2588  *
2589  * @return
2590  * return Logical Address of the block
2591  *
2592  */
2593 FORCEINLINE
2594 ULONG64
2595 AhciGetLba (
2596     __in PCDB Cdb,
2597     __in ULONG CdbLength
2598     )
2599 {
2600     ULONG64 lba = 0;
2601 
2602     NT_ASSERT(Cdb != NULL);
2603     NT_ASSERT(CdbLength != 0);
2604 
2605     if (CdbLength == 0x10)
2606     {
2607         REVERSE_BYTES_QUAD(&lba, Cdb->CDB16.LogicalBlock);
2608     }
2609     else
2610     {
2611         lba |= Cdb->CDB10.LogicalBlockByte3 << 0;
2612         lba |= Cdb->CDB10.LogicalBlockByte2 << 8;
2613         lba |= Cdb->CDB10.LogicalBlockByte1 << 16;
2614         lba |= Cdb->CDB10.LogicalBlockByte0 << 24;
2615     }
2616 
2617     return lba;
2618 }// -- AhciGetLba();
2619