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