changes after code review
[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 AhciPortInitialize (
23 __in PAHCI_PORT_EXTENSION portExtension
24 )
25 {
26 ULONG mappedLength;
27 PAHCI_MEMORY_REGISTERS abar;
28 PAHCI_ADAPTER_EXTENSION adapterExtension;
29 STOR_PHYSICAL_ADDRESS commandListPhysical, receivedFISPhysical;
30
31 DebugPrint("AhciPortInitialize()\n");
32
33 NT_ASSERT(portExtension != NULL);
34
35 adapterExtension = portExtension->AdapterExtension;
36 abar = adapterExtension->ABAR_Address;
37
38 NT_ASSERT(abar != NULL);
39
40 portExtension->Port = &abar->PortList[portExtension->PortNumber];
41
42 commandListPhysical = StorPortGetPhysicalAddress( adapterExtension,
43 NULL,
44 portExtension->CommandList,
45 &mappedLength);
46
47 if ((mappedLength) == 0 || ((commandListPhysical.LowPart % 1024) != 0))
48 {
49 DebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength);
50 return FALSE;
51 }
52
53 receivedFISPhysical = StorPortGetPhysicalAddress( adapterExtension,
54 NULL,
55 portExtension->ReceivedFIS,
56 &mappedLength);
57
58 if ((mappedLength) == 0 || ((receivedFISPhysical.LowPart % 1024) != 0))
59 {
60 DebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength);
61 return FALSE;
62 }
63
64 if ((adapterExtension->CAP & AHCI_Global_HBA_CAP_S64A) != 0)
65 {
66 DebugPrint("\tCAP.S64A not supported\n");
67 return FALSE;
68 }
69
70 // 10.1.2 For each implemented port, system software shall allocate memory for and program:
71 //  PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
72 //  PxFB and PxFBU (if CAP.S64A is set to ‘1’)
73 // Note: Assuming 32bit support only
74 StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->CLB, commandListPhysical.LowPart);
75 StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->FB, receivedFISPhysical.LowPart);
76
77 // set device power state flag to D0
78 portExtension->DevicePowerState = StorPowerDeviceD0;
79
80 // clear pending interrupts
81 StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->SERR, (ULONG)-1);
82 StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->IS, (ULONG)-1);
83 StorPortWriteRegisterUlong(adapterExtension, portExtension->AdapterExtension->IS, (1 << portExtension->PortNumber));
84
85 return TRUE;
86 }// -- AhciPortInitialize();
87
88 /**
89 * @name AhciAllocateResourceForAdapter
90 * @implemented
91 *
92 * Allocate memory from poll for required pointers
93 *
94 * @param adapterExtension
95 * @param ConfigInfo
96 *
97 * @return
98 * return TRUE if allocation was successful
99 */
100 BOOLEAN
101 AhciAllocateResourceForAdapter (
102 __in PAHCI_ADAPTER_EXTENSION adapterExtension,
103 __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
104 )
105 {
106 PVOID portsExtension = NULL;
107 PCHAR nonCachedExtension;
108 ULONG status, index, NCS, AlignedNCS;
109 ULONG portCount, portImplemented, nonCachedExtensionSize;
110
111 DebugPrint("AhciAllocateResourceForAdapter()\n");
112
113 NCS = AHCI_Global_Port_CAP_NCS(adapterExtension->CAP);
114 AlignedNCS = ROUND_UP(NCS, 8);
115
116 // get port count -- Number of set bits in `adapterExtension->PortImplemented`
117 portCount = 0;
118 portImplemented = adapterExtension->PortImplemented;
119 while (portImplemented > 0)
120 {
121 portCount++;
122 portImplemented &= (portImplemented - 1);
123 }
124
125 NT_ASSERT(portCount != 0);
126 DebugPrint("\tPort Count: %d\n", portCount);
127
128 nonCachedExtensionSize = sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned
129 sizeof(AHCI_RECEIVED_FIS);
130
131 // align nonCachedExtensionSize to 1024
132 nonCachedExtensionSize = ROUND_UP(nonCachedExtensionSize, 1024);
133
134 adapterExtension->NonCachedExtension = StorPortGetUncachedExtension( adapterExtension,
135 ConfigInfo,
136 nonCachedExtensionSize * portCount);
137
138 if (adapterExtension->NonCachedExtension == NULL)
139 {
140 DebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
141 return FALSE;
142 }
143
144 nonCachedExtension = adapterExtension->NonCachedExtension;
145 AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize * portCount);
146
147 for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
148 {
149 adapterExtension->PortExtension[index].IsActive = FALSE;
150 if ((adapterExtension->PortImplemented & (1 << index)) != 0)
151 {
152 adapterExtension->PortExtension[index].PortNumber = index;
153 adapterExtension->PortExtension[index].IsActive = TRUE;
154 adapterExtension->PortExtension[index].AdapterExtension = adapterExtension;
155 adapterExtension->PortExtension[index].CommandList = nonCachedExtension;
156 adapterExtension->PortExtension[index].ReceivedFIS = (PAHCI_RECEIVED_FIS)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
157 nonCachedExtension += nonCachedExtensionSize;
158 }
159 }
160
161 return TRUE;
162 }// -- AhciAllocateResourceForAdapter();
163
164 /**
165 * @name AhciHwInitialize
166 * @implemented
167 *
168 * initializes the HBA and finds all devices that are of interest to the miniport driver.
169 *
170 * @param adapterExtension
171 *
172 * @return
173 * return TRUE if intialization was successful
174 */
175 BOOLEAN
176 AhciHwInitialize (
177 __in PVOID AdapterExtension
178 )
179 {
180 ULONG ghc, messageCount, status;
181 PAHCI_ADAPTER_EXTENSION adapterExtension;
182
183 DebugPrint("AhciHwInitialize()\n");
184
185 adapterExtension = AdapterExtension;
186 adapterExtension->StateFlags.MessagePerPort = FALSE;
187
188 // First check what type of interrupt/synchronization device is using
189 ghc = StorPortReadRegisterUlong(adapterExtension, &adapterExtension->ABAR_Address->GHC);
190
191 // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector
192 // but has reverted to using the first vector only. When this bit is cleared to ‘0’,
193 // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
194 // software has allocated the number of messages requested
195 if ((ghc & AHCI_Global_HBA_CONTROL_MRSM) == 0)
196 {
197 adapterExtension->StateFlags.MessagePerPort = TRUE;
198 DebugPrint("\tMultiple MSI based message not supported\n");
199 }
200
201 return TRUE;
202 }// -- AhciHwInitialize();
203
204 /**
205 * @name AhciInterruptHandler
206 * @implemented
207 *
208 * Interrupt Handler for portExtension
209 *
210 * @param portExtension
211 *
212 */
213 VOID
214 AhciInterruptHandler (
215 __in PAHCI_PORT_EXTENSION portExtension
216 )
217 {
218 DebugPrint("AhciInterruptHandler()\n");
219 DebugPrint("\tPort Number: %d\n", portExtension->PortNumber);
220
221 }// -- AhciInterruptHandler();
222
223 /**
224 * @name AhciHwInterrupt
225 * @implemented
226 *
227 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
228 *
229 * @param adapterExtension
230 *
231 * @return
232 * return TRUE Indicates that an interrupt was pending on adapter.
233 * return FALSE Indicates the interrupt was not ours.
234 */
235 BOOLEAN
236 AhciHwInterrupt(
237 __in PVOID AdapterExtension
238 )
239 {
240 ULONG portPending, nextPort, i;
241 PAHCI_ADAPTER_EXTENSION adapterExtension;
242
243 DebugPrint("AhciHwInterrupt()\n");
244
245 adapterExtension = AdapterExtension;
246
247 if (adapterExtension->StateFlags.Removed)
248 {
249 return FALSE;
250 }
251
252 portPending = StorPortReadRegisterUlong(adapterExtension, adapterExtension->IS);
253 // we process interrupt for implemented ports only
254 portPending = portPending & adapterExtension->PortImplemented;
255
256 if (portPending == 0)
257 {
258 return FALSE;
259 }
260
261 for (i = 1; i <= MAXIMUM_AHCI_PORT_COUNT; i++)
262 {
263 nextPort = (adapterExtension->LastInterruptPort + i) % MAXIMUM_AHCI_PORT_COUNT;
264
265 if ((portPending & (0x1 << nextPort)) == 0)
266 continue;
267
268 if ((nextPort == adapterExtension->LastInterruptPort)
269 || (adapterExtension->PortExtension[nextPort].IsActive == FALSE))
270 {
271 return FALSE;
272 }
273
274 // we can assign this interrupt to this port
275 adapterExtension->LastInterruptPort = nextPort;
276 AhciInterruptHandler(&adapterExtension->PortExtension[nextPort]);
277 return TRUE;
278 }
279
280 DebugPrint("\tSomething wrong");
281 return FALSE;
282 }// -- AhciHwInterrupt();
283
284 /**
285 * @name AhciHwStartIo
286 * @implemented
287 *
288 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
289 *
290 * @param adapterExtension
291 * @param Srb
292 *
293 * @return
294 * return TRUE if the request was accepted
295 * return FALSE if the request must be submitted later
296 */
297 BOOLEAN
298 AhciHwStartIo (
299 __in PVOID AdapterExtension,
300 __in PSCSI_REQUEST_BLOCK Srb
301 )
302 {
303 UCHAR function, pathId;
304 PAHCI_ADAPTER_EXTENSION adapterExtension;
305
306 DebugPrint("AhciHwStartIo()\n");
307
308 pathId = Srb->PathId;
309 function = Srb->Function;
310 adapterExtension = AdapterExtension;
311
312 if (!IsPortValid(adapterExtension, pathId))
313 {
314 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
315 StorPortNotification(RequestComplete, adapterExtension, Srb);
316 return TRUE;
317 }
318
319 // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp
320 // If the function member of an SRB is set to SRB_FUNCTION_PNP,
321 // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK.
322 if (function == SRB_FUNCTION_PNP)
323 {
324 PSCSI_PNP_REQUEST_BLOCK pnpRequest;
325
326 pnpRequest = (PSCSI_PNP_REQUEST_BLOCK)Srb;
327 if ((pnpRequest->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST) != 0)
328 {
329 if ((pnpRequest->PnPAction == StorRemoveDevice) ||
330 (pnpRequest->PnPAction == StorSurpriseRemoval))
331 {
332 Srb->SrbStatus = SRB_STATUS_SUCCESS;
333 adapterExtension->StateFlags.Removed = 1;
334 DebugPrint("\tadapter removed\n");
335 }
336 else if (pnpRequest->PnPAction == StorStopDevice)
337 {
338 Srb->SrbStatus = SRB_STATUS_SUCCESS;
339 DebugPrint("\tRequested to Stop the adapter\n");
340 }
341 else
342 {
343 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
344 }
345
346 StorPortNotification(RequestComplete, adapterExtension, Srb);
347 return TRUE;
348 }
349 }
350
351 if (function == SRB_FUNCTION_EXECUTE_SCSI)
352 {
353 // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
354 // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
355 // routine does the following:
356 //
357 // - Gets and/or sets up whatever context the miniport driver maintains in its device,
358 // logical unit, and/or SRB extensions
359 // For example, a miniport driver might set up a logical unit extension with pointers
360 // to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value,
361 // and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be
362 // carried out on the HBA.
363 //
364 // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags,
365 // for the requested operation
366 // For a device I/O operation, such an internal routine generally selects the target device
367 // and sends the CDB over the bus to the target logical unit.
368 if (Srb->CdbLength > 0)
369 {
370 PCDB cdb = (PCDB)&Srb->Cdb;
371 if (cdb->CDB10.OperationCode == SCSIOP_INQUIRY)
372 {
373 Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb);
374 StorPortNotification(RequestComplete, adapterExtension, Srb);
375
376 return TRUE;
377 }
378 }
379 else
380 {
381 Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
382 StorPortNotification(RequestComplete, adapterExtension, Srb);
383 return TRUE;
384 }
385 }
386
387 DebugPrint("\tUnknow function code recieved: %x\n", function);
388 Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
389 StorPortNotification(RequestComplete, adapterExtension, Srb);
390 return TRUE;
391 }// -- AhciHwStartIo();
392
393 /**
394 * @name AhciHwResetBus
395 * @not_implemented
396 *
397 * The HwStorResetBus routine is called by the port driver to clear error conditions.
398 *
399 * @param adapterExtension
400 * @param PathId
401 *
402 * @return
403 * return TRUE if bus was successfully reset
404 */
405 BOOLEAN
406 AhciHwResetBus (
407 __in PVOID AdapterExtension,
408 __in ULONG PathId
409 )
410 {
411 PAHCI_ADAPTER_EXTENSION adapterExtension;
412
413 DebugPrint("AhciHwResetBus()\n");
414
415 adapterExtension = AdapterExtension;
416
417 return FALSE;
418 }// -- AhciHwResetBus();
419
420 /**
421 * @name AhciHwFindAdapter
422 * @implemented
423 *
424 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
425 * HBA is supported and, if it is, to return configuration information about that adapter.
426 *
427 * 10.1 Platform Communication
428 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
429
430 * @param DeviceExtension
431 * @param HwContext
432 * @param BusInformation
433 * @param ArgumentString
434 * @param ConfigInfo
435 * @param Reserved3
436 *
437 * @return
438 * SP_RETURN_FOUND
439 * 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.
440 *
441 * SP_RETURN_ERROR
442 * 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.
443 *
444 * SP_RETURN_BAD_CONFIG
445 * Indicates that the supplied configuration information was invalid for the adapter.
446 *
447 * SP_RETURN_NOT_FOUND
448 * Indicates that no supported HBA was found for the supplied configuration information.
449 *
450 * @remarks Called by Storport.
451 */
452 ULONG
453 AhciHwFindAdapter (
454 __in PVOID AdapterExtension,
455 __in PVOID HwContext,
456 __in PVOID BusInformation,
457 __in PVOID ArgumentString,
458 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
459 __in PBOOLEAN Reserved3
460 )
461 {
462 ULONG ghc;
463 ULONG index;
464 ULONG portCount, portImplemented;
465 ULONG pci_cfg_len;
466 UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
467 PACCESS_RANGE accessRange;
468
469 PAHCI_MEMORY_REGISTERS abar;
470 PPCI_COMMON_CONFIG pciConfigData;
471 PAHCI_ADAPTER_EXTENSION adapterExtension;
472
473 DebugPrint("AhciHwFindAdapter()\n");
474
475 adapterExtension = AdapterExtension;
476 adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
477 adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
478
479 // get PCI configuration header
480 pci_cfg_len = StorPortGetBusData(
481 adapterExtension,
482 PCIConfiguration,
483 adapterExtension->SystemIoBusNumber,
484 adapterExtension->SlotNumber,
485 pci_cfg_buf,
486 sizeof(PCI_COMMON_CONFIG));
487
488 if (pci_cfg_len != sizeof(PCI_COMMON_CONFIG))
489 {
490 DebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG), pci_cfg_len);
491 return SP_RETURN_ERROR;//Not a valid device at the given bus number
492 }
493
494 pciConfigData = pci_cfg_buf;
495 adapterExtension->VendorID = pciConfigData->VendorID;
496 adapterExtension->DeviceID = pciConfigData->DeviceID;
497 adapterExtension->RevisionID = pciConfigData->RevisionID;
498 // 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).
499 adapterExtension->AhciBaseAddress = pciConfigData->u.type0.BaseAddresses[5] & (0xFFFFFFF0);
500
501 DebugPrint("\tVendorID:%d DeviceID:%d RevisionID:%d\n", adapterExtension->VendorID, adapterExtension->DeviceID, adapterExtension->RevisionID);
502
503 // 2.1.11
504 abar = NULL;
505 if (ConfigInfo->NumberOfAccessRanges > 0)
506 {
507 for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++)
508 {
509 accessRange = *ConfigInfo->AccessRanges;
510 if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
511 {
512 abar = StorPortGetDeviceBase(
513 adapterExtension,
514 ConfigInfo->AdapterInterfaceType,
515 ConfigInfo->SystemIoBusNumber,
516 accessRange[index].RangeStart,
517 accessRange[index].RangeLength,
518 !accessRange[index].RangeInMemory);
519 break;
520 }
521 }
522 }
523
524 if (abar == NULL)
525 {
526 DebugPrint("\tabar == NULL\n");
527 return SP_RETURN_ERROR; // corrupted information supplied
528 }
529
530 adapterExtension->ABAR_Address = abar;
531 adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP);
532 adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2);
533 adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS);
534 adapterExtension->LastInterruptPort = -1;
535
536 // 10.1.2
537 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
538 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
539 ghc = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
540 // AE := Highest Significant bit of GHC
541 if ((ghc & AHCI_Global_HBA_CONTROL_AE) != 0)//Hmm, controller was already in power state
542 {
543 // reset controller to have it in known state
544 DebugPrint("\tAE Already set, Reset()\n");
545 if (!AhciAdapterReset(adapterExtension)){
546 DebugPrint("\tReset Failed!\n");
547 return SP_RETURN_ERROR;// reset failed
548 }
549 }
550
551 ghc = AHCI_Global_HBA_CONTROL_AE;// only AE=1
552 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
553
554 adapterExtension->IS = &abar->IS;
555 adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
556
557 if (adapterExtension->PortImplemented == 0)
558 {
559 DebugPrint("\tadapterExtension->PortImplemented == 0\n");
560 return SP_RETURN_ERROR;
561 }
562
563 ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;//128 KB
564 ConfigInfo->NumberOfPhysicalBreaks = 0x21;
565 ConfigInfo->MaximumNumberOfTargets = 1;
566 ConfigInfo->MaximumNumberOfLogicalUnits = 1;
567 ConfigInfo->ResetTargetSupported = TRUE;
568 ConfigInfo->NumberOfBuses = MAXIMUM_AHCI_PORT_COUNT;
569 ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
570 ConfigInfo->ScatterGather = TRUE;
571
572 // Turn IE -- Interrupt Enabled
573 ghc |= AHCI_Global_HBA_CONTROL_IE;
574 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
575
576 // allocate necessary resource for each port
577 if (!AhciAllocateResourceForAdapter(adapterExtension, ConfigInfo))
578 {
579 DebugPrint("\tAhciAllocateResourceForAdapter() == FALSE\n");
580 return SP_RETURN_ERROR;
581 }
582
583 for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
584 {
585 if ((adapterExtension->PortImplemented & (0x1<<index)) != 0)
586 AhciPortInitialize(&adapterExtension->PortExtension[index]);
587 }
588
589 return SP_RETURN_FOUND;
590 }// -- AhciHwFindAdapter();
591
592 /**
593 * @name DriverEntry
594 * @implemented
595 *
596 * Initial Entrypoint for storahci miniport driver
597 *
598 * @param DriverObject
599 * @param RegistryPath
600 *
601 * @return
602 * NT_STATUS in case of driver loaded successfully.
603 */
604 ULONG
605 DriverEntry (
606 __in PVOID DriverObject,
607 __in PVOID RegistryPath
608 )
609 {
610 HW_INITIALIZATION_DATA hwInitializationData;
611 ULONG i, status;
612
613 DebugPrint("Storahci Loaded\n");
614
615 // initialize the hardware data structure
616 AhciZeroMemory(&hwInitializationData, sizeof(HW_INITIALIZATION_DATA));
617
618 // set size of hardware initialization structure
619 hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
620
621 // identity required miniport entry point routines
622 hwInitializationData.HwStartIo = AhciHwStartIo;
623 hwInitializationData.HwResetBus = AhciHwResetBus;
624 hwInitializationData.HwInterrupt = AhciHwInterrupt;
625 hwInitializationData.HwInitialize = AhciHwInitialize;
626 hwInitializationData.HwFindAdapter = AhciHwFindAdapter;
627
628 // adapter specific information
629 hwInitializationData.NeedPhysicalAddresses = TRUE;
630 hwInitializationData.TaggedQueuing = TRUE;
631 hwInitializationData.AutoRequestSense = TRUE;
632 hwInitializationData.MultipleRequestPerLu = TRUE;
633
634 hwInitializationData.NumberOfAccessRanges = 6;
635 hwInitializationData.AdapterInterfaceType = PCIBus;
636 hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
637
638 // set required extension sizes
639 hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION);
640 hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION);
641
642 // register our hw init data
643 status = StorPortInitialize(
644 DriverObject,
645 RegistryPath,
646 &hwInitializationData,
647 NULL);
648
649 DebugPrint("\tstatus:%x\n", status);
650 return status;
651 }// -- DriverEntry();
652
653 /**
654 * @name AhciAdapterReset
655 * @implemented
656 *
657 * 10.4.3 HBA Reset
658 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
659 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
660 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
661 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
662 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
663 * the HBA reset has completed.
664 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
665 * a hung or locked state.
666 *
667 * @param adapterExtension
668 *
669 * @return
670 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
671 */
672 BOOLEAN
673 AhciAdapterReset (
674 __in PAHCI_ADAPTER_EXTENSION adapterExtension
675 )
676 {
677 ULONG ghc, ticks;
678 PAHCI_MEMORY_REGISTERS abar = NULL;
679
680 DebugPrint("AhciAdapterReset()\n");
681
682 abar = adapterExtension->ABAR_Address;
683 if (abar == NULL) // basic sanity
684 {
685 return FALSE;
686 }
687
688 // HR -- Very first bit (lowest significant)
689 ghc = AHCI_Global_HBA_CONTROL_HR;
690 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
691
692 for (ticks = 0; ticks < 50; ++ticks)
693 {
694 if ((StorPortReadRegisterUlong(adapterExtension, &abar->GHC) & AHCI_Global_HBA_CONTROL_HR) == 0)
695 {
696 break;
697 }
698 StorPortStallExecution(20000);
699 }
700
701 if (ticks == 50)// 1 second
702 {
703 DebugPrint("\tDevice Timeout\n");
704 return FALSE;
705 }
706
707 return TRUE;
708 }// -- AhciAdapterReset();
709
710 /**
711 * @name AhciZeroMemory
712 * @implemented
713 *
714 * Clear buffer by filling zeros
715 *
716 * @param buffer
717 */
718 __inline
719 VOID
720 AhciZeroMemory (
721 __out PCHAR buffer,
722 __in ULONG bufferSize
723 )
724 {
725 ULONG i;
726 for (i = 0; i < bufferSize; i++)
727 buffer[i] = 0;
728 }// -- AhciZeroMemory();
729
730 /**
731 * @name IsPortValid
732 * @implemented
733 *
734 * Tells wheather given port is implemented or not
735 *
736 * @param adapterExtension
737 * @param PathId
738 *
739 * @return
740 * return TRUE if provided port is valid (implemented) or not
741 */
742 __inline
743 BOOLEAN
744 IsPortValid (
745 __in PAHCI_ADAPTER_EXTENSION adapterExtension,
746 __in UCHAR pathId
747 )
748 {
749 NT_ASSERT(pathId >= 0);
750
751 if (pathId >= MAXIMUM_AHCI_PORT_COUNT)
752 {
753 return FALSE;
754 }
755
756 return adapterExtension->PortExtension[pathId].IsActive;
757 }// -- IsPortValid()
758
759 /**
760 * @name DeviceInquiryRequest
761 * @implemented
762 *
763 * Tells wheather given port is implemented or not
764 *
765 * @param adapterExtension
766 * @param Srb
767 * @param Cdb
768 *
769 * @return
770 * return STOR status for DeviceInquiryRequest
771 *
772 * @remark
773 * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
774 */
775 ULONG
776 DeviceInquiryRequest (
777 __in PAHCI_ADAPTER_EXTENSION adapterExtension,
778 __in PSCSI_REQUEST_BLOCK Srb,
779 __in PCDB Cdb
780 )
781 {
782 PVOID DataBuffer;
783 ULONG DataBufferLength;
784
785 DebugPrint("DeviceInquiryRequest()\n");
786
787 // 3.6.1
788 // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
789 if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
790 {
791 DebugPrint("\tEVPD Inquired\n");
792 }
793 else
794 {
795 DebugPrint("\tVPD Inquired\n");
796
797 DataBuffer = Srb->DataBuffer;
798 DataBufferLength = Srb->DataTransferLength;
799
800 if (DataBuffer == NULL)
801 return SRB_STATUS_INVALID_REQUEST;
802
803 AhciZeroMemory(DataBuffer, DataBufferLength);
804 }
805
806 return SRB_STATUS_BAD_FUNCTION;
807 }// -- DeviceInquiryRequest();