Added INF File for driver installation with minimal configuration.
[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 VOID AhciZeroMemory(
15 __in PCHAR buffer,
16 __in ULONG bufferSize
17 );
18
19 /**
20 * @name AhciPortInitialize
21 * @implemented
22 *
23 * Initialize port by setting up PxCLB & PxFB Registers
24 *
25 * @param portExtension
26 *
27 * @return
28 * Return true if intialization was successful
29 */
30 BOOLEAN AhciPortInitialize(
31 __in PAHCI_PORT_EXTENSION portExtension
32 )
33 {
34 ULONG mappedLength;
35 PAHCI_MEMORY_REGISTERS abar;
36 PAHCI_ADAPTER_EXTENSION adapterExtension;
37 STOR_PHYSICAL_ADDRESS commandListPhysical, receivedFISPhysical;
38
39 StorPortDebugPrint(0, "AhciPortInitialize()\n");
40
41 adapterExtension = portExtension->AdapterExtension;
42 abar = adapterExtension->ABAR_Address;
43 portExtension->Port = &abar->PortList[portExtension->PortNumber];
44
45 commandListPhysical = StorPortGetPhysicalAddress(adapterExtension, NULL, portExtension->CommandList, &mappedLength);
46 if (mappedLength == 0 || (commandListPhysical.LowPart % 1024) != 0){
47 StorPortDebugPrint(0, "\tcommandListPhysical mappedLength:%d\n", mappedLength);
48 return FALSE;
49 }
50
51 receivedFISPhysical = StorPortGetPhysicalAddress(adapterExtension, NULL, portExtension->ReceivedFIS, &mappedLength);
52 if (mappedLength == 0 || (receivedFISPhysical.LowPart % 256) != 0){
53 StorPortDebugPrint(0, "\treceivedFISPhysical mappedLength:%d\n", mappedLength);
54 return FALSE;
55 }
56
57 // 10.1.2 For each implemented port, system software shall allocate memory for and program:
58 //  PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
59 //  PxFB and PxFBU (if CAP.S64A is set to ‘1’)
60 //Note: Assuming 32bit support only
61 StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->CLB, commandListPhysical.LowPart);
62 StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->FB, receivedFISPhysical.LowPart);
63
64 return TRUE;
65 }// -- AhciPortInitialize();
66
67 /**
68 * @name AhciAllocateResourceForAdapter
69 * @implemented
70 *
71 * Allocate memory from poll for required pointers
72 *
73 * @param adapterExtension
74 * @param ConfigInfo
75 *
76 * @return
77 * return TRUE if allocation was successful
78 */
79 BOOLEAN AhciAllocateResourceForAdapter(
80 __in PAHCI_ADAPTER_EXTENSION adapterExtension,
81 __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
82 )
83 {
84 PVOID portsExtension = NULL;
85 PCHAR nonCachedExtension;
86 ULONG portCount, portImplemented, status, index, NCS, AlignedNCS, nonCachedExtensionSize, currentCount;
87
88 StorPortDebugPrint(0, "AhciAllocateResourceForAdapter()\n");
89
90 // 3.1.1 NCS = CAP[12:08] -> Align
91 NCS = (adapterExtension->CAP & 0xF00) >> 8;
92 AlignedNCS = ((NCS/8) + 1) * 8;
93
94 // get port count -- Number of set bits in `adapterExtension->PortImplemented`
95 portCount = 0;
96 portImplemented = adapterExtension->PortImplemented;
97 while(portImplemented > 0)
98 {
99 portCount++;
100 portImplemented &= (portImplemented-1);
101 }
102 StorPortDebugPrint(0, "\tPort Count: %d\n", portCount);
103
104 nonCachedExtensionSize = sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned
105 sizeof(AHCI_RECEIVED_FIS);
106 //align nonCachedExtensionSize to 1K
107 nonCachedExtensionSize = (((nonCachedExtensionSize - 1) / 0x400) + 1) * 0x400;
108 nonCachedExtensionSize *= portCount;
109
110 adapterExtension->NonCachedExtension = StorPortGetUncachedExtension(adapterExtension, ConfigInfo, nonCachedExtensionSize);
111 if (adapterExtension->NonCachedExtension == NULL) {
112 StorPortDebugPrint(0, "\tadapterExtension->NonCachedExtension == NULL\n");
113 return FALSE;
114 }
115
116 nonCachedExtension = (PCHAR)adapterExtension->NonCachedExtension;
117
118 AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize);
119
120
121 // allocate memory for port extension
122 /* --> Allocate memory for port extension, but right now it is returning STOR_STATUS_NOT_IMPLEMENTED
123 so, for testing purpose, I allocated during driver entry itself.
124 status = StorPortAllocatePool(
125 adapterExtension,
126 portCount * sizeof(AHCI_PORT_EXTENSION),
127 AHCI_POOL_TAG,
128 (PVOID*)&portsExtension);
129
130 if (status != STOR_STATUS_SUCCESS){
131 StorPortDebugPrint(0, "\tstatus : %x\n", status);
132 return FALSE;
133 }
134
135 AhciZeroMemory((PCHAR)portsExtension, portCount * sizeof(AHCI_PORT_EXTENSION));
136 */
137 nonCachedExtensionSize /= portCount;
138 currentCount = 0;
139 for (index = 0; index < 32; index++)
140 {
141 if ((adapterExtension->PortImplemented & (1<<index)) != 0)
142 {
143 //adapterExtension->PortExtension[index] = (PAHCI_PORT_EXTENSION)((PCHAR)portsExtension + sizeof(AHCI_PORT_EXTENSION) * currentCount);
144
145 adapterExtension->PortExtension[index].PortNumber = index;
146 adapterExtension->PortExtension[index].AdapterExtension = adapterExtension;
147 adapterExtension->PortExtension[index].CommandList = (PAHCI_COMMAND_HEADER)(nonCachedExtension + (currentCount*nonCachedExtensionSize));
148 adapterExtension->PortExtension[index].ReceivedFIS = (PAHCI_RECEIVED_FIS)((PCHAR)adapterExtension->PortExtension[index].CommandList + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
149 currentCount++;
150 }
151 }
152
153 return TRUE;
154 }// -- AhciAllocateResourceForAdapter();
155
156 /**
157 * @name AhciHwInitialize
158 * @implemented
159 *
160 * initializes the HBA and finds all devices that are of interest to the miniport driver.
161 *
162 * @param adapterExtension
163 *
164 * @return
165 * return TRUE if intialization was successful
166 */
167 BOOLEAN AhciHwInitialize(
168 __in PVOID AdapterExtension
169 )
170 {
171 PAHCI_ADAPTER_EXTENSION adapterExtension;
172
173 StorPortDebugPrint(0, "AhciHwInitialize()\n");
174
175 adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension;
176
177 return TRUE;
178 }// -- AhciHwInitialize();
179
180 /**
181 * @name AhciHwInterrupt
182 * @implemented
183 *
184 * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
185 *
186 * @param adapterExtension
187 *
188 * @return
189 * return TRUE Indicates that an interrupt was pending on adapter.
190 * return FALSE Indicates the interrupt was not ours.
191 */
192 BOOLEAN AhciHwInterrupt(
193 __in PVOID AdapterExtension
194 )
195 {
196 PAHCI_ADAPTER_EXTENSION adapterExtension;
197
198 StorPortDebugPrint(0, "AhciHwInterrupt()\n");
199
200 adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension;
201
202 return TRUE;
203 }// -- AhciHwInterrupt();
204
205 /**
206 * @name AhciHwStartIo
207 * @implemented
208 *
209 * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
210 *
211 * @param adapterExtension
212 * @param Srb
213 *
214 * @return
215 * return TRUE if the request was accepted
216 * return FALSE if the request must be submitted later
217 */
218 BOOLEAN AhciHwStartIo(
219 __in PVOID AdapterExtension,
220 __in PSCSI_REQUEST_BLOCK Srb
221
222 )
223 {
224 UCHAR function;
225 PAHCI_ADAPTER_EXTENSION adapterExtension;
226
227 StorPortDebugPrint(0, "AhciHwStartIo()\n");
228
229 adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension;
230 function = Srb->Function;
231
232 return TRUE;
233 }// -- AhciHwStartIo();
234
235 /**
236 * @name AhciHwResetBus
237 * @implemented
238 *
239 * The HwStorResetBus routine is called by the port driver to clear error conditions.
240 *
241 * @param adapterExtension
242 * @param PathId
243 *
244 * @return
245 * return TRUE if bus was successfully reset
246 */
247 BOOLEAN AhciHwResetBus(
248 __in PVOID AdapterExtension,
249 __in ULONG PathId
250
251 )
252 {
253 PAHCI_ADAPTER_EXTENSION adapterExtension;
254
255 StorPortDebugPrint(0, "AhciHwResetBus()\n");
256
257 adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension;
258
259 return TRUE;
260 }// -- AhciHwResetBus();
261
262 /**
263 * @name AhciHwFindAdapter
264 * @implemented
265 *
266 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
267 * HBA is supported and, if it is, to return configuration information about that adapter.
268 *
269 * 10.1 Platform Communication
270 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
271
272 * @param DeviceExtension
273 * @param HwContext
274 * @param BusInformation
275 * @param ArgumentString
276 * @param ConfigInfo
277 * @param Reserved3
278 *
279 * @return
280 * SP_RETURN_FOUND
281 * 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.
282 *
283 * SP_RETURN_ERROR
284 * 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.
285 *
286 * SP_RETURN_BAD_CONFIG
287 * Indicates that the supplied configuration information was invalid for the adapter.
288 *
289 * SP_RETURN_NOT_FOUND
290 * Indicates that no supported HBA was found for the supplied configuration information.
291 *
292 * @remarks Called by Storport.
293 */
294 ULONG AhciHwFindAdapter(
295 __in PVOID AdapterExtension,
296 __in PVOID HwContext,
297 __in PVOID BusInformation,
298 __in PVOID ArgumentString,
299 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
300 __in PBOOLEAN Reserved3
301 )
302 {
303 ULONG ghc;
304 ULONG index;
305 ULONG portCount, portImplemented;
306 ULONG pci_cfg_len;
307 UCHAR pci_cfg_buf[0x30];
308
309 PAHCI_MEMORY_REGISTERS abar;
310 PPCI_COMMON_CONFIG pciConfigData;
311 PAHCI_ADAPTER_EXTENSION adapterExtension;
312
313 StorPortDebugPrint(0, "AhciHwFindAdapter()\n");
314
315 adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension;
316 adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
317 adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
318
319 // get PCI configuration header
320 pci_cfg_len = StorPortGetBusData(
321 adapterExtension,
322 PCIConfiguration,
323 adapterExtension->SystemIoBusNumber,
324 adapterExtension->SlotNumber,
325 (PVOID)pci_cfg_buf,
326 (ULONG)0x30);
327
328 if (pci_cfg_len != 0x30){
329 StorPortDebugPrint(0, "\tpci_cfg_len != 0x30 :: %d", pci_cfg_len);
330 return SP_RETURN_ERROR;//Not a valid device at the given bus number
331 }
332
333 pciConfigData = (PPCI_COMMON_CONFIG)pci_cfg_buf;
334 adapterExtension->VendorID = pciConfigData->VendorID;
335 adapterExtension->DeviceID = pciConfigData->DeviceID;
336 adapterExtension->RevisionID = pciConfigData->RevisionID;
337 // 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).
338 adapterExtension->AhciBaseAddress = pciConfigData->u.type0.BaseAddresses[5] & (0xFFFFFFF0);
339
340 StorPortDebugPrint(0, "\tVendorID:%d DeviceID:%d RevisionID:%d\n", adapterExtension->VendorID, adapterExtension->DeviceID, adapterExtension->RevisionID);
341
342 // 2.1.11
343 abar = NULL;
344 if (ConfigInfo->NumberOfAccessRanges > 0)
345 {
346 for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++)
347 {
348 if ((*(ConfigInfo->AccessRanges))[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
349 {
350 abar = (PAHCI_MEMORY_REGISTERS)StorPortGetDeviceBase(
351 adapterExtension,
352 ConfigInfo->AdapterInterfaceType,
353 ConfigInfo->SystemIoBusNumber,
354 (*(ConfigInfo->AccessRanges))[index].RangeStart,
355 (*(ConfigInfo->AccessRanges))[index].RangeLength,
356 (BOOLEAN)!(*(ConfigInfo->AccessRanges))[index].RangeInMemory);
357 break;
358 }
359 }
360 }
361
362 if (abar == NULL){
363 StorPortDebugPrint(0, "\tabar == NULL\n");
364 return SP_RETURN_ERROR; // corrupted information supplied
365 }
366
367 adapterExtension->ABAR_Address = abar;
368 adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP);
369 adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2);
370 adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS);
371
372 // 10.1.2
373 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
374 // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
375 ghc = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
376 // AE := Highest Significant bit of GHC
377 if ((ghc & (0x1<<31)) == 1)//Hmm, controller was already in power state
378 {
379 // reset controller to have it in know state
380 StorPortDebugPrint(0, "\tAE Already set, Reset()\n");
381 if (!AhciAdapterReset(adapterExtension)){
382 StorPortDebugPrint(0, "\tReset Failed!\n");
383 return SP_RETURN_ERROR;// reset failed
384 }
385 }
386
387 ghc = 0x1<<31;// only AE=1
388 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
389
390 adapterExtension->IS = abar->IS;
391 adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
392
393 if (adapterExtension->PortImplemented == 0){
394 StorPortDebugPrint(0, "\tadapterExtension->PortImplemented == 0\n");
395 return SP_RETURN_ERROR;
396 }
397
398 ConfigInfo->MaximumTransferLength = 128 * 1024;//128 KB
399 ConfigInfo->NumberOfPhysicalBreaks = 0x21;
400 ConfigInfo->MaximumNumberOfTargets = 1;
401 ConfigInfo->MaximumNumberOfLogicalUnits = 1;
402 ConfigInfo->ResetTargetSupported = TRUE;
403 ConfigInfo->NumberOfBuses = 32;
404 ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
405 ConfigInfo->ScatterGather = TRUE;
406
407 // Turn IE -- Interrupt Enabled
408 ghc |= 0x2;
409 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
410
411 // allocate necessary resource for each port
412 if (!AhciAllocateResourceForAdapter(adapterExtension, ConfigInfo)){
413 StorPortDebugPrint(0, "\tAhciAllocateResourceForAdapter() == FALSE\n");
414 return SP_RETURN_ERROR;
415 }
416
417 for (index = 0; index < 32; index++)
418 {
419 if ((adapterExtension->PortImplemented & (1<<index)) != 0)
420 AhciPortInitialize(&adapterExtension->PortExtension[index]);
421 }
422
423 return SP_RETURN_FOUND;
424 }// -- AhciHwFindAdapter();
425
426 /**
427 * @name DriverEntry
428 * @implemented
429 *
430 * Initial Entrypoint for storahci miniport driver
431 *
432 * @param DriverObject
433 * @param RegistryPath
434 *
435 * @return
436 * NT_STATUS in case of driver loaded successfully.
437 */
438 ULONG DriverEntry(
439 __in PVOID DriverObject,
440 __in PVOID RegistryPath
441 )
442 {
443 HW_INITIALIZATION_DATA hwInitializationData;
444 ULONG i, status;
445
446 StorPortDebugPrint(0, "Storahci Loaded 10023\n");
447
448 // initialize the hardware data structure
449 AhciZeroMemory((PCHAR)&hwInitializationData, sizeof(HW_INITIALIZATION_DATA));
450
451 // set size of hardware initialization structure
452 hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
453
454 // identity required miniport entry point routines
455 hwInitializationData.HwStartIo = AhciHwStartIo;
456 hwInitializationData.HwResetBus = AhciHwResetBus;
457 hwInitializationData.HwInterrupt = AhciHwInterrupt;
458 hwInitializationData.HwInitialize = AhciHwInitialize;
459 hwInitializationData.HwFindAdapter = AhciHwFindAdapter;
460
461 // adapter specific information
462 hwInitializationData.NeedPhysicalAddresses = TRUE;
463 hwInitializationData.TaggedQueuing = TRUE;
464 hwInitializationData.AutoRequestSense = TRUE;
465 hwInitializationData.MultipleRequestPerLu = TRUE;
466
467 hwInitializationData.NumberOfAccessRanges = 6;
468 hwInitializationData.AdapterInterfaceType = PCIBus;
469 hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
470
471 // set required extension sizes
472 hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION);
473 hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION);
474
475 // register our hw init data
476 status = StorPortInitialize(
477 DriverObject,
478 RegistryPath,
479 &hwInitializationData,
480 NULL);
481 StorPortDebugPrint(0, "\tstatus:%x\n", status);
482 return status;
483 }// -- DriverEntry();
484
485 /**
486 * @name AhciAdapterReset
487 * @implemented
488 *
489 * 10.4.3 HBA Reset
490 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
491 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
492 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
493 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
494 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
495 * the HBA reset has completed.
496 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
497 * a hung or locked state.
498 *
499 * @param adapterExtension
500 *
501 * @return
502 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
503 */
504 BOOLEAN AhciAdapterReset(
505 __in PAHCI_ADAPTER_EXTENSION adapterExtension
506 )
507 {
508 ULONG ghc, ticks;
509 PAHCI_MEMORY_REGISTERS abar = NULL;
510
511 StorPortDebugPrint(0, "AhciAdapterReset()\n");
512
513 abar = adapterExtension->ABAR_Address;
514 if (abar == NULL) // basic sanity
515 return FALSE;
516
517 // HR -- Very first bit (lowest significant)
518 ghc = 1;
519 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
520
521 for (ticks = 0; (ticks < 50) &&
522 (StorPortReadRegisterUlong(adapterExtension, &abar->GHC) == 1);
523 StorPortStallExecution(20000), ticks++);
524
525 if (ticks == 50) { //1 second
526 StorPortDebugPrint(0, "\tDevice Timeout\n");
527 return FALSE;
528 }
529
530 return TRUE;
531 }// -- AhciAdapterReset();
532
533 /**
534 * @name AhciZeroMemory
535 * @implemented
536 *
537 * Clear buffer by filling zeros
538 *
539 * @param buffer
540 */
541 VOID AhciZeroMemory(
542 __in PCHAR buffer,
543 __in ULONG bufferSize
544 )
545 {
546 ULONG i;
547 for (i = 0; i < bufferSize; i++)
548 buffer[i] = 0;
549 }// -- AhciZeroMemory();