[STORAHCI] Make the storahci driver build on gcc and add it to the build.
[reactos.git] / drivers / storage / storahci / storahci.c
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 VOID
1484 AhciActivatePort (
1485 __in PAHCI_PORT_EXTENSION PortExtension
1486 )
1487 {
1488 AHCI_PORT_CMD cmd;
1489 ULONG QueueSlots, slotToActivate, tmp;
1490 PAHCI_ADAPTER_EXTENSION AdapterExtension;
1491
1492 AhciDebugPrint("AhciActivatePort()\n");
1493
1494 AdapterExtension = PortExtension->AdapterExtension;
1495 QueueSlots = PortExtension->QueueSlots;
1496
1497 if (QueueSlots == 0)
1498 {
1499 return;
1500 }
1501
1502 // section 3.3.14
1503 // Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’
1504 cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
1505
1506 if (cmd.ST == 0) // PxCMD.ST == 0
1507 {
1508 return;
1509 }
1510
1511 // get the lowest set bit
1512 tmp = QueueSlots & (QueueSlots - 1);
1513
1514 if (tmp == 0)
1515 slotToActivate = QueueSlots;
1516 else
1517 slotToActivate = (QueueSlots & (~tmp));
1518
1519 // mark that bit off in QueueSlots
1520 // so we can know we it is really needed to activate port or not
1521 PortExtension->QueueSlots &= ~slotToActivate;
1522 // mark this CommandIssuedSlots
1523 // to validate in completeIssuedCommand
1524 PortExtension->CommandIssuedSlots |= slotToActivate;
1525
1526 // tell the HBA to issue this Command Slot to the given port
1527 StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CI, slotToActivate);
1528
1529 return;
1530 }// -- AhciActivatePort();
1531
1532 /**
1533 * @name AhciProcessIO
1534 * @implemented
1535 *
1536 * Acquire Exclusive lock to port, populate pending commands to command List
1537 * program controller's port to process new commands in command list.
1538 *
1539 * @param AdapterExtension
1540 * @param PathId
1541 * @param Srb
1542 *
1543 */
1544 VOID
1545 AhciProcessIO (
1546 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1547 __in UCHAR PathId,
1548 __in PSCSI_REQUEST_BLOCK Srb
1549 )
1550 {
1551 PSCSI_REQUEST_BLOCK tmpSrb;
1552 STOR_LOCK_HANDLE lockhandle = {0};
1553 PAHCI_PORT_EXTENSION PortExtension;
1554 ULONG commandSlotMask, occupiedSlots, slotIndex, NCS;
1555
1556 AhciDebugPrint("AhciProcessIO()\n");
1557 AhciDebugPrint("\tPathId: %d\n", PathId);
1558
1559 PortExtension = &AdapterExtension->PortExtension[PathId];
1560
1561 NT_ASSERT(PathId < AdapterExtension->PortCount);
1562
1563 // Acquire Lock
1564 StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
1565
1566 // add Srb to queue
1567 AddQueue(&PortExtension->SrbQueue, Srb);
1568
1569 if (PortExtension->DeviceParams.IsActive == FALSE)
1570 {
1571 // Release Lock
1572 StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
1573 return; // we should wait for device to get active
1574 }
1575
1576 occupiedSlots = (PortExtension->QueueSlots | PortExtension->CommandIssuedSlots); // Busy command slots for given port
1577 NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
1578 commandSlotMask = (1 << NCS) - 1; // available slots mask
1579
1580 commandSlotMask = (commandSlotMask & ~occupiedSlots);
1581 if(commandSlotMask != 0)
1582 {
1583 // iterate over HBA port slots
1584 for (slotIndex = 0; slotIndex < NCS; slotIndex++)
1585 {
1586 // find first free slot
1587 if ((commandSlotMask & (1 << slotIndex)) != 0)
1588 {
1589 tmpSrb = RemoveQueue(&PortExtension->SrbQueue);
1590 if (tmpSrb != NULL)
1591 {
1592 NT_ASSERT(tmpSrb->PathId == PathId);
1593 AhciProcessSrb(PortExtension, tmpSrb, slotIndex);
1594 }
1595 else
1596 {
1597 break;
1598 }
1599 }
1600 else
1601 {
1602 break;
1603 }
1604 }
1605 }
1606
1607 // program HBA port
1608 AhciActivatePort(PortExtension);
1609
1610 // Release Lock
1611 StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
1612
1613 return;
1614 }// -- AhciProcessIO();
1615
1616 /**
1617 * @name AtapiInquiryCompletion
1618 * @implemented
1619 *
1620 * AtapiInquiryCompletion routine should be called after device signals
1621 * for device inquiry request is completed (through interrupt) -- ATAPI Device only
1622 *
1623 * @param PortExtension
1624 * @param Srb
1625 *
1626 */
1627 VOID
1628 AtapiInquiryCompletion (
1629 __in PVOID _Extension,
1630 __in PVOID _Srb
1631 )
1632 {
1633 PAHCI_PORT_EXTENSION PortExtension;
1634 PAHCI_ADAPTER_EXTENSION AdapterExtension;
1635 PSCSI_REQUEST_BLOCK Srb;
1636 BOOLEAN status;
1637
1638 AhciDebugPrint("AtapiInquiryCompletion()\n");
1639
1640 PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
1641 Srb = (PSCSI_REQUEST_BLOCK)_Srb;
1642
1643 NT_ASSERT(Srb != NULL);
1644 NT_ASSERT(PortExtension != NULL);
1645
1646 AdapterExtension = PortExtension->AdapterExtension;
1647
1648 // send queue depth
1649 status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension,
1650 Srb->PathId,
1651 Srb->TargetId,
1652 Srb->Lun,
1653 AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
1654
1655 NT_ASSERT(status == TRUE);
1656 return;
1657 }// -- AtapiInquiryCompletion();
1658
1659 /**
1660 * @name InquiryCompletion
1661 * @implemented
1662 *
1663 * InquiryCompletion routine should be called after device signals
1664 * for device inquiry request is completed (through interrupt)
1665 *
1666 * @param PortExtension
1667 * @param Srb
1668 *
1669 */
1670 VOID
1671 InquiryCompletion (
1672 __in PVOID _Extension,
1673 __in PVOID _Srb
1674 )
1675 {
1676 PAHCI_PORT_EXTENSION PortExtension;
1677 PSCSI_REQUEST_BLOCK Srb;
1678
1679 // PCDB cdb;
1680 BOOLEAN status;
1681 PINQUIRYDATA InquiryData;
1682 PAHCI_SRB_EXTENSION SrbExtension;
1683 PAHCI_ADAPTER_EXTENSION AdapterExtension;
1684 PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
1685
1686 AhciDebugPrint("InquiryCompletion()\n");
1687
1688 PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
1689 Srb = (PSCSI_REQUEST_BLOCK)_Srb;
1690
1691 NT_ASSERT(Srb != NULL);
1692 NT_ASSERT(PortExtension != NULL);
1693
1694 // cdb = (PCDB)&Srb->Cdb;
1695 InquiryData = Srb->DataBuffer;
1696 SrbExtension = GetSrbExtension(Srb);
1697 AdapterExtension = PortExtension->AdapterExtension;
1698 IdentifyDeviceData = PortExtension->IdentifyDeviceData;
1699
1700 if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
1701 {
1702 if (Srb->SrbStatus == SRB_STATUS_NO_DEVICE)
1703 {
1704 PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
1705 }
1706 return;
1707 }
1708
1709 NT_ASSERT(InquiryData != NULL);
1710 NT_ASSERT(Srb->SrbStatus == SRB_STATUS_SUCCESS);
1711
1712 // Device specific data
1713 PortExtension->DeviceParams.MaxLba.QuadPart = 0;
1714
1715 if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY)
1716 {
1717 PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA;
1718 if (IdentifyDeviceData->GeneralConfiguration.RemovableMedia)
1719 {
1720 PortExtension->DeviceParams.RemovableDevice = 1;
1721 }
1722
1723 if ((IdentifyDeviceData->CommandSetSupport.BigLba) && (IdentifyDeviceData->CommandSetActive.BigLba))
1724 {
1725 PortExtension->DeviceParams.Lba48BitMode = 1;
1726 }
1727
1728 PortExtension->DeviceParams.AccessType = DIRECT_ACCESS_DEVICE;
1729
1730 /* Device max address lba */
1731 if (PortExtension->DeviceParams.Lba48BitMode)
1732 {
1733 PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->Max48BitLBA[0];
1734 PortExtension->DeviceParams.MaxLba.HighPart = IdentifyDeviceData->Max48BitLBA[1];
1735 }
1736 else
1737 {
1738 PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->UserAddressableSectors;
1739 }
1740
1741 /* Bytes Per Logical Sector */
1742 if (IdentifyDeviceData->PhysicalLogicalSectorSize.LogicalSectorLongerThan256Words)
1743 {
1744 AhciDebugPrint("\tBytesPerLogicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1745 NT_ASSERT(FALSE);
1746 }
1747
1748 PortExtension->DeviceParams.BytesPerLogicalSector = DEVICE_ATA_BLOCK_SIZE;
1749
1750 /* Bytes Per Physical Sector */
1751 if (IdentifyDeviceData->PhysicalLogicalSectorSize.MultipleLogicalSectorsPerPhysicalSector)
1752 {
1753 AhciDebugPrint("\tBytesPerPhysicalSector != DEVICE_ATA_BLOCK_SIZE\n");
1754 NT_ASSERT(FALSE);
1755 }
1756
1757 PortExtension->DeviceParams.BytesPerPhysicalSector = DEVICE_ATA_BLOCK_SIZE;
1758
1759 // last byte should be NULL
1760 StorPortCopyMemory(PortExtension->DeviceParams.VendorId, IdentifyDeviceData->ModelNumber, sizeof(PortExtension->DeviceParams.VendorId) - 1);
1761 StorPortCopyMemory(PortExtension->DeviceParams.RevisionID, IdentifyDeviceData->FirmwareRevision, sizeof(PortExtension->DeviceParams.RevisionID) - 1);
1762 StorPortCopyMemory(PortExtension->DeviceParams.SerialNumber, IdentifyDeviceData->SerialNumber, sizeof(PortExtension->DeviceParams.SerialNumber) - 1);
1763
1764 PortExtension->DeviceParams.VendorId[sizeof(PortExtension->DeviceParams.VendorId) - 1] = '\0';
1765 PortExtension->DeviceParams.RevisionID[sizeof(PortExtension->DeviceParams.RevisionID) - 1] = '\0';
1766 PortExtension->DeviceParams.SerialNumber[sizeof(PortExtension->DeviceParams.SerialNumber) - 1] = '\0';
1767
1768 // TODO: Add other device params
1769 AhciDebugPrint("\tATA Device\n");
1770 }
1771 else
1772 {
1773 AhciDebugPrint("\tATAPI Device\n");
1774 PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
1775 PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE;
1776 }
1777
1778 // INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h
1779 if (Srb->DataTransferLength < INQUIRYDATABUFFERSIZE)
1780 {
1781 AhciDebugPrint("\tDataBufferLength < sizeof(INQUIRYDATA), Could crash the driver.\n");
1782 NT_ASSERT(FALSE);
1783 }
1784
1785 // update data transfer length
1786 Srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
1787
1788 // prepare data to send
1789 InquiryData->Versions = 2;
1790 InquiryData->Wide32Bit = 1;
1791 InquiryData->CommandQueue = 0; // NCQ not supported
1792 InquiryData->ResponseDataFormat = 0x2;
1793 InquiryData->DeviceTypeModifier = 0;
1794 InquiryData->DeviceTypeQualifier = DEVICE_CONNECTED;
1795 InquiryData->AdditionalLength = INQUIRYDATABUFFERSIZE - 5;
1796 InquiryData->DeviceType = PortExtension->DeviceParams.AccessType;
1797 InquiryData->RemovableMedia = PortExtension->DeviceParams.RemovableDevice;
1798
1799 // Fill VendorID, Product Revision Level and other string fields
1800 StorPortCopyMemory(InquiryData->VendorId, PortExtension->DeviceParams.VendorId, sizeof(InquiryData->VendorId) - 1);
1801 StorPortCopyMemory(InquiryData->ProductId, PortExtension->DeviceParams.RevisionID, sizeof(PortExtension->DeviceParams.RevisionID));
1802 StorPortCopyMemory(InquiryData->ProductRevisionLevel, PortExtension->DeviceParams.SerialNumber, sizeof(InquiryData->ProductRevisionLevel) - 1);
1803
1804 InquiryData->VendorId[sizeof(InquiryData->VendorId) - 1] = '\0';
1805 InquiryData->ProductId[sizeof(InquiryData->ProductId) - 1] = '\0';
1806 InquiryData->ProductRevisionLevel[sizeof(InquiryData->ProductRevisionLevel) - 1] = '\0';
1807
1808 // send queue depth
1809 status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension,
1810 Srb->PathId,
1811 Srb->TargetId,
1812 Srb->Lun,
1813 AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
1814
1815 NT_ASSERT(status == TRUE);
1816 return;
1817 }// -- InquiryCompletion();
1818
1819 /**
1820 * @name AhciATAPICommand
1821 * @implemented
1822 *
1823 * Handles ATAPI Requests commands
1824 *
1825 * @param AdapterExtension
1826 * @param Srb
1827 * @param Cdb
1828 *
1829 * @return
1830 * return STOR status for AhciATAPICommand
1831 */
1832 UCHAR
1833 AhciATAPICommand (
1834 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1835 __in PSCSI_REQUEST_BLOCK Srb,
1836 __in PCDB Cdb
1837 )
1838 {
1839 ULONG SrbFlags, DataBufferLength;
1840 PAHCI_SRB_EXTENSION SrbExtension;
1841 PAHCI_PORT_EXTENSION PortExtension;
1842
1843 AhciDebugPrint("AhciATAPICommand()\n");
1844
1845 SrbFlags = Srb->SrbFlags;
1846 SrbExtension = GetSrbExtension(Srb);
1847 DataBufferLength = Srb->DataTransferLength;
1848 PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
1849
1850 NT_ASSERT(PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI);
1851
1852 NT_ASSERT(SrbExtension != NULL);
1853
1854 SrbExtension->AtaFunction = ATA_FUNCTION_ATAPI_COMMAND;
1855 SrbExtension->Flags = 0;
1856
1857 if (SrbFlags & SRB_FLAGS_DATA_IN)
1858 {
1859 SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
1860 }
1861
1862 if (SrbFlags & SRB_FLAGS_DATA_OUT)
1863 {
1864 SrbExtension->Flags |= ATA_FLAGS_DATA_OUT;
1865 }
1866
1867 SrbExtension->FeaturesLow = 0;
1868
1869 SrbExtension->CompletionRoutine = NULL;
1870
1871 NT_ASSERT(Cdb != NULL);
1872 switch(Cdb->CDB10.OperationCode)
1873 {
1874 case SCSIOP_INQUIRY:
1875 SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
1876 SrbExtension->CompletionRoutine = AtapiInquiryCompletion;
1877 break;
1878 case SCSIOP_READ:
1879 SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
1880 SrbExtension->FeaturesLow = 0x5;
1881 break;
1882 case SCSIOP_WRITE:
1883 SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
1884 SrbExtension->FeaturesLow = 0x1;
1885 break;
1886 }
1887
1888 SrbExtension->CommandReg = IDE_COMMAND_ATAPI_PACKET;
1889
1890 SrbExtension->LBA0 = 0;
1891 SrbExtension->LBA1 = (UCHAR)(DataBufferLength >> 0);
1892 SrbExtension->LBA2 = (UCHAR)(DataBufferLength >> 8);
1893 SrbExtension->Device = 0;
1894 SrbExtension->LBA3 = 0;
1895 SrbExtension->LBA4 = 0;
1896 SrbExtension->LBA5 = 0;
1897 SrbExtension->FeaturesHigh = 0;
1898 SrbExtension->SectorCountLow = 0;
1899 SrbExtension->SectorCountHigh = 0;
1900
1901 if ((SrbExtension->Flags & ATA_FLAGS_DATA_IN) || (SrbExtension->Flags & ATA_FLAGS_DATA_OUT))
1902 {
1903 SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb);
1904 }
1905
1906 return SRB_STATUS_PENDING;
1907 }// -- AhciATAPICommand();
1908
1909 /**
1910 * @name DeviceRequestSense
1911 * @implemented
1912 *
1913 * Handle SCSIOP_MODE_SENSE OperationCode
1914 *
1915 * @param AdapterExtension
1916 * @param Srb
1917 * @param Cdb
1918 *
1919 * @return
1920 * return STOR status for DeviceRequestSense
1921 */
1922 UCHAR
1923 DeviceRequestSense (
1924 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1925 __in PSCSI_REQUEST_BLOCK Srb,
1926 __in PCDB Cdb
1927 )
1928 {
1929 PMODE_PARAMETER_HEADER ModeHeader;
1930 PAHCI_PORT_EXTENSION PortExtension;
1931
1932 AhciDebugPrint("DeviceRequestSense()\n");
1933
1934 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
1935 NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_MODE_SENSE);
1936
1937 PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
1938
1939 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
1940 {
1941 return AhciATAPICommand(AdapterExtension, Srb, Cdb);
1942 }
1943
1944 ModeHeader = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;
1945
1946 NT_ASSERT(ModeHeader != NULL);
1947
1948 AhciZeroMemory((PCHAR)ModeHeader, Srb->DataTransferLength);
1949
1950 ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER);
1951 ModeHeader->MediumType = 0;
1952 ModeHeader->DeviceSpecificParameter = 0;
1953 ModeHeader->BlockDescriptorLength = 0;
1954
1955 if (Cdb->MODE_SENSE.PageCode == MODE_SENSE_CURRENT_VALUES)
1956 {
1957 ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1958 ModeHeader->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
1959 }
1960
1961 return SRB_STATUS_SUCCESS;
1962 }// -- DeviceRequestSense();
1963
1964 /**
1965 * @name DeviceRequestReadWrite
1966 * @implemented
1967 *
1968 * Handle SCSIOP_READ SCSIOP_WRITE OperationCode
1969 *
1970 * @param AdapterExtension
1971 * @param Srb
1972 * @param Cdb
1973 *
1974 * @return
1975 * return STOR status for DeviceRequestReadWrite
1976 */
1977 UCHAR
1978 DeviceRequestReadWrite (
1979 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
1980 __in PSCSI_REQUEST_BLOCK Srb,
1981 __in PCDB Cdb
1982 )
1983 {
1984 BOOLEAN IsReading;
1985 ULONG64 StartOffset;
1986 PAHCI_SRB_EXTENSION SrbExtension;
1987 PAHCI_PORT_EXTENSION PortExtension;
1988 ULONG DataTransferLength, BytesPerSector, SectorCount;
1989
1990 AhciDebugPrint("DeviceRequestReadWrite()\n");
1991
1992 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
1993 NT_ASSERT((Cdb->CDB10.OperationCode == SCSIOP_READ) || (Cdb->CDB10.OperationCode == SCSIOP_WRITE));
1994
1995 SrbExtension = GetSrbExtension(Srb);
1996 PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
1997
1998 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
1999 {
2000 return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2001 }
2002
2003 DataTransferLength = Srb->DataTransferLength;
2004 BytesPerSector = PortExtension->DeviceParams.BytesPerLogicalSector;
2005
2006 NT_ASSERT(BytesPerSector > 0);
2007
2008 //ROUND_UP(DataTransferLength, BytesPerSector);
2009
2010 SectorCount = DataTransferLength / BytesPerSector;
2011
2012 Srb->DataTransferLength = SectorCount * BytesPerSector;
2013
2014 StartOffset = AhciGetLba(Cdb, Srb->CdbLength);
2015 IsReading = (Cdb->CDB10.OperationCode == SCSIOP_READ);
2016
2017 NT_ASSERT(SectorCount > 0);
2018
2019 SrbExtension->AtaFunction = ATA_FUNCTION_ATA_READ;
2020 SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
2021 SrbExtension->CompletionRoutine = NULL;
2022
2023 if (IsReading)
2024 {
2025 SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
2026 SrbExtension->CommandReg = IDE_COMMAND_READ_DMA;
2027 }
2028 else
2029 {
2030 SrbExtension->Flags |= ATA_FLAGS_DATA_OUT;
2031 SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA;
2032 }
2033
2034 SrbExtension->FeaturesLow = 0;
2035 SrbExtension->LBA0 = (StartOffset >> 0) & 0xFF;
2036 SrbExtension->LBA1 = (StartOffset >> 8) & 0xFF;
2037 SrbExtension->LBA2 = (StartOffset >> 16) & 0xFF;
2038
2039 SrbExtension->Device = (0xA0 | IDE_LBA_MODE);
2040
2041 if (PortExtension->DeviceParams.Lba48BitMode)
2042 {
2043 SrbExtension->Flags |= ATA_FLAGS_48BIT_COMMAND;
2044
2045 if (IsReading)
2046 {
2047 SrbExtension->CommandReg = IDE_COMMAND_READ_DMA_EXT;
2048 }
2049 else
2050 {
2051 SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA_EXT;
2052 }
2053
2054 SrbExtension->LBA3 = (StartOffset >> 24) & 0xFF;
2055 SrbExtension->LBA4 = (StartOffset >> 32) & 0xFF;
2056 SrbExtension->LBA5 = (StartOffset >> 40) & 0xFF;
2057 }
2058 else
2059 {
2060 NT_ASSERT(FALSE);
2061 }
2062
2063 SrbExtension->FeaturesHigh = 0;
2064 SrbExtension->SectorCountLow = (SectorCount >> 0) & 0xFF;
2065 SrbExtension->SectorCountHigh = (SectorCount >> 8) & 0xFF;
2066
2067 NT_ASSERT(SectorCount < 0x100);
2068
2069 SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb);
2070
2071 return SRB_STATUS_PENDING;
2072 }// -- DeviceRequestReadWrite();
2073
2074 /**
2075 * @name DeviceRequestCapacity
2076 * @implemented
2077 *
2078 * Handle SCSIOP_READ_CAPACITY OperationCode
2079 *
2080 * @param AdapterExtension
2081 * @param Srb
2082 * @param Cdb
2083 *
2084 * @return
2085 * return STOR status for DeviceRequestCapacity
2086 */
2087 UCHAR
2088 DeviceRequestCapacity (
2089 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2090 __in PSCSI_REQUEST_BLOCK Srb,
2091 __in PCDB Cdb
2092 )
2093 {
2094 ULONG MaxLba, BytesPerLogicalSector;
2095 PREAD_CAPACITY_DATA ReadCapacity;
2096 PAHCI_PORT_EXTENSION PortExtension;
2097
2098 AhciDebugPrint("DeviceRequestCapacity()\n");
2099
2100 UNREFERENCED_PARAMETER(AdapterExtension);
2101 UNREFERENCED_PARAMETER(Cdb);
2102
2103 NT_ASSERT(Srb->DataBuffer != NULL);
2104 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
2105
2106
2107 PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
2108
2109 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
2110 {
2111 return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2112 }
2113
2114 if (Cdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY)
2115 {
2116 ReadCapacity = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
2117
2118 BytesPerLogicalSector = PortExtension->DeviceParams.BytesPerLogicalSector;
2119 MaxLba = (ULONG)PortExtension->DeviceParams.MaxLba.QuadPart - 1;
2120
2121 // I trust you windows :D
2122 NT_ASSERT(Srb->DataTransferLength >= sizeof(READ_CAPACITY_DATA));
2123
2124 // I trust you user :D
2125 NT_ASSERT(PortExtension->DeviceParams.MaxLba.QuadPart < (ULONG)-1);
2126
2127 // Actually I don't trust anyone :p
2128 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2129
2130 REVERSE_BYTES(&ReadCapacity->BytesPerBlock, &BytesPerLogicalSector);
2131 REVERSE_BYTES(&ReadCapacity->LogicalBlockAddress, &MaxLba);
2132 }
2133 else
2134 {
2135 AhciDebugPrint("\tSCSIOP_READ_CAPACITY16 not supported\n");
2136 NT_ASSERT(FALSE);
2137 }
2138
2139 return SRB_STATUS_SUCCESS;
2140 }// -- DeviceRequestCapacity();
2141
2142 /**
2143 * @name DeviceRequestComplete
2144 * @implemented
2145 *
2146 * Handle UnHandled Requests
2147 *
2148 * @param AdapterExtension
2149 * @param Srb
2150 * @param Cdb
2151 *
2152 * @return
2153 * return STOR status for DeviceRequestComplete
2154 */
2155 UCHAR
2156 DeviceRequestComplete (
2157 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2158 __in PSCSI_REQUEST_BLOCK Srb,
2159 __in PCDB Cdb
2160 )
2161 {
2162 AhciDebugPrint("DeviceRequestComplete()\n");
2163
2164 UNREFERENCED_PARAMETER(AdapterExtension);
2165 UNREFERENCED_PARAMETER(Cdb);
2166
2167 Srb->ScsiStatus = SCSISTAT_GOOD;
2168
2169 return SRB_STATUS_SUCCESS;
2170 }// -- DeviceRequestComplete();
2171
2172 /**
2173 * @name DeviceReportLuns
2174 * @implemented
2175 *
2176 * Handle SCSIOP_REPORT_LUNS OperationCode
2177 *
2178 * @param AdapterExtension
2179 * @param Srb
2180 * @param Cdb
2181 *
2182 * @return
2183 * return STOR status for DeviceReportLuns
2184 */
2185 UCHAR
2186 DeviceReportLuns (
2187 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2188 __in PSCSI_REQUEST_BLOCK Srb,
2189 __in PCDB Cdb
2190 )
2191 {
2192 PLUN_LIST LunList;
2193 PAHCI_PORT_EXTENSION PortExtension;
2194
2195 AhciDebugPrint("DeviceReportLuns()\n");
2196
2197 UNREFERENCED_PARAMETER(Cdb);
2198
2199 PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
2200
2201 NT_ASSERT(Srb->DataTransferLength >= sizeof(LUN_LIST));
2202 NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_REPORT_LUNS);
2203
2204 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
2205 {
2206 return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2207 }
2208
2209 LunList = (PLUN_LIST)Srb->DataBuffer;
2210
2211 NT_ASSERT(LunList != NULL);
2212
2213 AhciZeroMemory((PCHAR)LunList, sizeof(LUN_LIST));
2214
2215 LunList->LunListLength[3] = 8;
2216
2217 Srb->ScsiStatus = SCSISTAT_GOOD;
2218 Srb->DataTransferLength = sizeof(LUN_LIST);
2219
2220 return SRB_STATUS_SUCCESS;
2221 }// -- DeviceReportLuns();
2222
2223 /**
2224 * @name DeviceInquiryRequest
2225 * @implemented
2226 *
2227 * Tells wheather given port is implemented or not
2228 *
2229 * @param AdapterExtension
2230 * @param Srb
2231 * @param Cdb
2232 *
2233 * @return
2234 * return STOR status for DeviceInquiryRequest
2235 *
2236 * @remark
2237 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
2238 */
2239 UCHAR
2240 DeviceInquiryRequest (
2241 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2242 __in PSCSI_REQUEST_BLOCK Srb,
2243 __in PCDB Cdb
2244 )
2245 {
2246 PVOID DataBuffer;
2247 PAHCI_SRB_EXTENSION SrbExtension;
2248 PAHCI_PORT_EXTENSION PortExtension;
2249 PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer;
2250 ULONG DataBufferLength, RequiredDataBufferLength;
2251
2252 AhciDebugPrint("DeviceInquiryRequest()\n");
2253
2254 NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_INQUIRY);
2255 NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
2256
2257 SrbExtension = GetSrbExtension(Srb);
2258 PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
2259
2260 if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
2261 {
2262 return AhciATAPICommand(AdapterExtension, Srb, Cdb);
2263 }
2264
2265 if (Srb->Lun != 0)
2266 {
2267 return SRB_STATUS_SELECTION_TIMEOUT;
2268 }
2269 else if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
2270 {
2271 // 3.6.1
2272 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
2273 AhciDebugPrint("\tEVPD Inquired\n");
2274 NT_ASSERT(SrbExtension != NULL);
2275
2276 SrbExtension->AtaFunction = ATA_FUNCTION_ATA_IDENTIFY;
2277 SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
2278 SrbExtension->CompletionRoutine = InquiryCompletion;
2279 SrbExtension->CommandReg = IDE_COMMAND_NOT_VALID;
2280
2281 // TODO: Should use AhciZeroMemory
2282 SrbExtension->FeaturesLow = 0;
2283 SrbExtension->LBA0 = 0;
2284 SrbExtension->LBA1 = 0;
2285 SrbExtension->LBA2 = 0;
2286 SrbExtension->Device = 0xA0;
2287 SrbExtension->LBA3 = 0;
2288 SrbExtension->LBA4 = 0;
2289 SrbExtension->LBA5 = 0;
2290 SrbExtension->FeaturesHigh = 0;
2291 SrbExtension->SectorCountLow = 0;
2292 SrbExtension->SectorCountHigh = 0;
2293
2294 SrbExtension->Sgl.NumberOfElements = 1;
2295 SrbExtension->Sgl.List[0].PhysicalAddress.LowPart = PortExtension->IdentifyDeviceDataPhysicalAddress.LowPart;
2296 SrbExtension->Sgl.List[0].PhysicalAddress.HighPart = PortExtension->IdentifyDeviceDataPhysicalAddress.HighPart;
2297 SrbExtension->Sgl.List[0].Length = sizeof(IDENTIFY_DEVICE_DATA);
2298
2299 SrbExtension->pSgl = &SrbExtension->Sgl;
2300 return SRB_STATUS_PENDING;
2301 }
2302 else
2303 {
2304 AhciDebugPrint("\tVPD Inquired\n");
2305
2306 DataBuffer = Srb->DataBuffer;
2307 DataBufferLength = Srb->DataTransferLength;
2308 RequiredDataBufferLength = DataBufferLength; // make the compiler happy :p
2309
2310 if (DataBuffer == NULL)
2311 {
2312 return SRB_STATUS_INVALID_REQUEST;
2313 }
2314
2315 AhciZeroMemory(DataBuffer, DataBufferLength);
2316
2317 switch(Cdb->CDB6INQUIRY3.PageCode)
2318 {
2319 case VPD_SUPPORTED_PAGES:
2320 {
2321 AhciDebugPrint("\tVPD_SUPPORTED_PAGES\n");
2322 RequiredDataBufferLength = sizeof(VPD_SUPPORTED_PAGES_PAGE) + 1;
2323
2324 if (DataBufferLength < RequiredDataBufferLength)
2325 {
2326 AhciDebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength, RequiredDataBufferLength);
2327 return SRB_STATUS_INVALID_REQUEST;
2328 }
2329
2330 VpdOutputBuffer = (PVPD_SUPPORTED_PAGES_PAGE)DataBuffer;
2331
2332 VpdOutputBuffer->DeviceType = PortExtension->DeviceParams.AccessType;
2333 VpdOutputBuffer->DeviceTypeQualifier = 0;
2334 VpdOutputBuffer->PageCode = VPD_SUPPORTED_PAGES;
2335 VpdOutputBuffer->PageLength = 1;
2336 VpdOutputBuffer->SupportedPageList[0] = VPD_SUPPORTED_PAGES;
2337 //VpdOutputBuffer->SupportedPageList[1] = VPD_SERIAL_NUMBER;
2338 //VpdOutputBuffer->SupportedPageList[2] = VPD_DEVICE_IDENTIFIERS;
2339
2340 NT_ASSERT(VpdOutputBuffer->DeviceType == DIRECT_ACCESS_DEVICE);
2341 }
2342 break;
2343 case VPD_SERIAL_NUMBER:
2344 {
2345 AhciDebugPrint("\tVPD_SERIAL_NUMBER\n");
2346 }
2347 break;
2348 case VPD_DEVICE_IDENTIFIERS:
2349 {
2350 AhciDebugPrint("\tVPD_DEVICE_IDENTIFIERS\n");
2351 }
2352 break;
2353 default:
2354 AhciDebugPrint("\tPageCode: %x\n", Cdb->CDB6INQUIRY3.PageCode);
2355 return SRB_STATUS_INVALID_REQUEST;
2356 }
2357
2358 Srb->DataTransferLength = RequiredDataBufferLength;
2359 return SRB_STATUS_SUCCESS;
2360 }
2361 }// -- DeviceInquiryRequest();
2362
2363 /**
2364 * @name AhciAdapterReset
2365 * @implemented
2366 *
2367 * 10.4.3 HBA Reset
2368 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
2369 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
2370 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
2371 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
2372 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
2373 * the HBA reset has completed.
2374 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
2375 * a hung or locked state.
2376 *
2377 * @param AdapterExtension
2378 *
2379 * @return
2380 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
2381 */
2382 BOOLEAN
2383 AhciAdapterReset (
2384 __in PAHCI_ADAPTER_EXTENSION AdapterExtension
2385 )
2386 {
2387 ULONG ticks;
2388 AHCI_GHC ghc;
2389 PAHCI_MEMORY_REGISTERS abar = NULL;
2390
2391 AhciDebugPrint("AhciAdapterReset()\n");
2392
2393 abar = AdapterExtension->ABAR_Address;
2394 if (abar == NULL) // basic sanity
2395 {
2396 return FALSE;
2397 }
2398
2399 // HR -- Very first bit (lowest significant)
2400 ghc.HR = 1;
2401 StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc.Status);
2402
2403 for (ticks = 0; ticks < 50; ++ticks)
2404 {
2405 ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
2406 if (ghc.HR == 0)
2407 {
2408 break;
2409 }
2410 StorPortStallExecution(20000);
2411 }
2412
2413 if (ticks == 50)// 1 second
2414 {
2415 AhciDebugPrint("\tDevice Timeout\n");
2416 return FALSE;
2417 }
2418
2419 return TRUE;
2420 }// -- AhciAdapterReset();
2421
2422 /**
2423 * @name AhciZeroMemory
2424 * @implemented
2425 *
2426 * Clear buffer by filling zeros
2427 *
2428 * @param Buffer
2429 * @param BufferSize
2430 */
2431 __inline
2432 VOID
2433 AhciZeroMemory (
2434 __out PCHAR Buffer,
2435 __in ULONG BufferSize
2436 )
2437 {
2438 ULONG i;
2439 for (i = 0; i < BufferSize; i++)
2440 {
2441 Buffer[i] = 0;
2442 }
2443
2444 return;
2445 }// -- AhciZeroMemory();
2446
2447 /**
2448 * @name IsPortValid
2449 * @implemented
2450 *
2451 * Tells wheather given port is implemented or not
2452 *
2453 * @param AdapterExtension
2454 * @param PathId
2455 *
2456 * @return
2457 * return TRUE if provided port is valid (implemented) or not
2458 */
2459 __inline
2460 BOOLEAN
2461 IsPortValid (
2462 __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
2463 __in ULONG pathId
2464 )
2465 {
2466 NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT);
2467
2468 if (pathId >= AdapterExtension->PortCount)
2469 {
2470 return FALSE;
2471 }
2472
2473 return AdapterExtension->PortExtension[pathId].DeviceParams.IsActive;
2474 }// -- IsPortValid()
2475
2476 /**
2477 * @name AddQueue
2478 * @implemented
2479 *
2480 * Add Srb to Queue
2481 *
2482 * @param Queue
2483 * @param Srb
2484 *
2485 * @return
2486 * return TRUE if Srb is successfully added to Queue
2487 *
2488 */
2489 __inline
2490 BOOLEAN
2491 AddQueue (
2492 __inout PAHCI_QUEUE Queue,
2493 __in PVOID Srb
2494 )
2495 {
2496 NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
2497 NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
2498
2499 if (Queue->Tail == ((Queue->Head + 1) % MAXIMUM_QUEUE_BUFFER_SIZE))
2500 return FALSE;
2501
2502 Queue->Buffer[Queue->Head++] = Srb;
2503 Queue->Head %= MAXIMUM_QUEUE_BUFFER_SIZE;
2504
2505 return TRUE;
2506 }// -- AddQueue();
2507
2508 /**
2509 * @name RemoveQueue
2510 * @implemented
2511 *
2512 * Remove and return Srb from Queue
2513 *
2514 * @param Queue
2515 *
2516 * @return
2517 * return Srb
2518 *
2519 */
2520 __inline
2521 PVOID
2522 RemoveQueue (
2523 __inout PAHCI_QUEUE Queue
2524 )
2525 {
2526 PVOID Srb;
2527
2528 NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
2529 NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
2530
2531 if (Queue->Head == Queue->Tail)
2532 return NULL;
2533
2534 Srb = Queue->Buffer[Queue->Tail++];
2535 Queue->Tail %= MAXIMUM_QUEUE_BUFFER_SIZE;
2536
2537 return Srb;
2538 }// -- RemoveQueue();
2539
2540 /**
2541 * @name GetSrbExtension
2542 * @implemented
2543 *
2544 * GetSrbExtension from Srb make sure It is properly aligned
2545 *
2546 * @param Srb
2547 *
2548 * @return
2549 * return SrbExtension
2550 *
2551 */
2552 __inline
2553 PAHCI_SRB_EXTENSION
2554 GetSrbExtension (
2555 __in PSCSI_REQUEST_BLOCK Srb
2556 )
2557 {
2558 ULONG Offset;
2559 ULONG_PTR SrbExtension;
2560
2561 SrbExtension = (ULONG_PTR)Srb->SrbExtension;
2562 Offset = SrbExtension % 128;
2563
2564 // CommandTable should be 128 byte aligned
2565 if (Offset != 0)
2566 Offset = 128 - Offset;
2567
2568 return (PAHCI_SRB_EXTENSION)(SrbExtension + Offset);
2569 }// -- PAHCI_SRB_EXTENSION();
2570
2571 /**
2572 * @name AhciGetLba
2573 * @implemented
2574 *
2575 * Find the logical address of demand block from Cdb
2576 *
2577 * @param Srb
2578 *
2579 * @return
2580 * return Logical Address of the block
2581 *
2582 */
2583 __inline
2584 ULONG64
2585 AhciGetLba (
2586 __in PCDB Cdb,
2587 __in ULONG CdbLength
2588 )
2589 {
2590 ULONG64 lba = 0;
2591
2592 NT_ASSERT(Cdb != NULL);
2593 NT_ASSERT(CdbLength != 0);
2594
2595 if (CdbLength == 0x10)
2596 {
2597 REVERSE_BYTES_QUAD(&lba, Cdb->CDB16.LogicalBlock);
2598 }
2599 else
2600 {
2601 lba |= Cdb->CDB10.LogicalBlockByte3 << 0;
2602 lba |= Cdb->CDB10.LogicalBlockByte2 << 8;
2603 lba |= Cdb->CDB10.LogicalBlockByte1 << 16;
2604 lba |= Cdb->CDB10.LogicalBlockByte0 << 24;
2605 }
2606
2607 return lba;
2608 }// -- AhciGetLba();