Required changes to meet community coding style.
[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 /**
15 * @name AhciFindAdapter
16 * @implemented
17 *
18 * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
19 * HBA is supported and, if it is, to return configuration information about that adapter.
20 *
21 * 10.1 Platform Communication
22 * http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
23
24 * @param DeviceExtension
25 * @param HwContext
26 * @param BusInformation
27 * @param ArgumentString
28 * @param ConfigInfo
29 * @param Reserved3
30 *
31 * @return
32 * SP_RETURN_FOUND
33 * 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.
34 *
35 * SP_RETURN_ERROR
36 * 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.
37 *
38 * SP_RETURN_BAD_CONFIG
39 * Indicates that the supplied configuration information was invalid for the adapter.
40 *
41 * SP_RETURN_NOT_FOUND
42 * Indicates that no supported HBA was found for the supplied configuration information.
43 *
44 * @remarks Called by Storport.
45 */
46 ULONG AhciFindAdapter(
47 IN PVOID DeviceExtension,
48 __in PVOID HwContext,
49 __in PVOID BusInformation,
50 __in IN PVOID ArgumentString,
51 __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
52 __in PBOOLEAN Reserved3
53 )
54 {
55 ULONG ghc;
56 ULONG portCount, portImplemented;
57 ULONG pci_cfg_len;
58 UCHAR pci_cfg_buf[0x30];
59
60 PAHCI_MEMORY_REGISTERS abar;
61 PPCI_COMMON_CONFIG pciConfigData;
62 PAHCI_ADAPTER_EXTENSION adapterExtension;
63
64 adapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
65 adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
66 adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
67
68 // get PCI configuration header
69 pci_cfg_len = StorPortGetBusData(
70 adapterExtension,
71 PCIConfiguration,
72 adapterExtension->SystemIoBusNumber,
73 adapterExtension->SlotNumber,
74 (PVOID)pci_cfg_buf,
75 (ULONG)0x30);
76
77 if (pci_cfg_len != 0x30)
78 return SP_RETURN_ERROR;//Not a valid device at the given bus number
79
80 pciConfigData = (PPCI_COMMON_CONFIG)pci_cfg_buf;
81 adapterExtension->VendorID = pciConfigData->VendorID;
82 adapterExtension->DeviceID = pciConfigData->DeviceID;
83 adapterExtension->RevisionID = pciConfigData->RevisionID;
84 // 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).
85 adapterExtension->AhciBaseAddress = pciConfigData->u.type0.BaseAddresses[5] & (0xFFFFFFF0);
86
87 // 2.1.11
88 abar = NULL;
89 if (ConfigInfo->NumberOfAccessRanges > 0)
90 {
91 ULONG accessIndex;
92 for (accessIndex = 0; accessIndex < ConfigInfo->NumberOfAccessRanges; accessIndex++)
93 {
94 if ((*(ConfigInfo->AccessRanges))[accessIndex].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
95 {
96 abar = (PAHCI_MEMORY_REGISTERS)StorPortGetDeviceBase(
97 adapterExtension,
98 ConfigInfo->AdapterInterfaceType,
99 ConfigInfo->SystemIoBusNumber,
100 (*(ConfigInfo->AccessRanges))[accessIndex].RangeStart,
101 (*(ConfigInfo->AccessRanges))[accessIndex].RangeLength,
102 (BOOLEAN)!(*(ConfigInfo->AccessRanges))[accessIndex].RangeInMemory);
103 break;
104 }
105 }
106 }
107
108 if (abar == NULL)
109 return SP_RETURN_ERROR; // corrupted information supplied
110
111 adapterExtension->ABAR_Address = abar;
112 adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP);
113 adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2);
114 adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS);
115
116 // 10.1.2
117 // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
118 ghc = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
119 // AE := Highest Significant bit of GHC
120 if ((ghc & (0x1<<31)) == 1)//Hmm, controller was already in power state
121 {
122 // reset controller to have it in know state
123 DebugPrint("AhciFindAdapter -> AE Already set, Reset()\n");
124 if (!AhciAdapterReset(adapterExtension))
125 return SP_RETURN_ERROR;// reset failed
126 }
127
128 ghc = 0x1<<31;// only AE=1
129 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
130
131 adapterExtension->IS = abar->IS;
132 adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
133
134 if (adapterExtension->PortImplemented == 0)
135 return SP_RETURN_ERROR;
136
137 // get port count -- Number of set bits in `adapterExtension->PortImplemented`
138 portCount = 0;
139 portImplemented = adapterExtension->PortImplemented;
140 while(portImplemented > 0)
141 {
142 portCount++;
143 portImplemented &= (portImplemented - 1);// i love playing with bits :D
144 }
145
146 ConfigInfo->MaximumTransferLength = 128 * 1024;//128 KB
147 ConfigInfo->NumberOfPhysicalBreaks = 0x21;
148 ConfigInfo->MaximumNumberOfTargets = 1;
149 ConfigInfo->MaximumNumberOfLogicalUnits = 1;
150 ConfigInfo->ResetTargetSupported = TRUE;
151 ConfigInfo->NumberOfBuses = 32;
152 ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
153 ConfigInfo->ScatterGather = TRUE;
154
155 // Turn IE -- Interrupt Enabled
156 ghc |= 0x2;
157 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
158
159
160
161 return SP_RETURN_FOUND;
162 }// -- AhciFindAdapter();
163
164 /**
165 * @name DriverEntry
166 * @implemented
167 *
168 * Initial Entrypoint for storahci miniport driver
169 *
170 * @param DriverObject
171 * @param RegistryPath
172 *
173 * @return
174 * NT_STATUS in case of driver loaded successfully.
175 */
176 ULONG DriverEntry(
177 IN PVOID DriverObject,
178 IN PVOID RegistryPath
179 )
180 {
181 HW_INITIALIZATION_DATA hwInitializationData;
182 ULONG i, status;
183
184 DebugPrint("Storahci -> DriverEntry()\n");
185
186 // initialize the hardware data structure
187 for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++)
188 ((PUCHAR)&hwInitializationData)[i] = 0;
189
190 // set size of hardware initialization structure
191 hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
192
193 // identity required miniport entry point routines
194 hwInitializationData.HwFindAdapter = AhciFindAdapter;
195
196 // adapter specific information
197 hwInitializationData.NeedPhysicalAddresses = TRUE;
198 hwInitializationData.TaggedQueuing = TRUE;
199 hwInitializationData.AutoRequestSense = TRUE;
200 hwInitializationData.MultipleRequestPerLu = TRUE;
201
202 hwInitializationData.NumberOfAccessRanges = 6;
203 hwInitializationData.AdapterInterfaceType = PCIBus;
204 hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
205
206 // set required extension sizes
207 hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION);
208 hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION);
209
210 // register our hw init data
211 status = StorPortInitialize(
212 DriverObject,
213 RegistryPath,
214 &hwInitializationData,
215 NULL);
216
217 return status;
218 }// -- DriverEntry();
219
220 /**
221 * @name AhciAdapterReset
222 * @implemented
223 *
224 * 10.4.3 HBA Reset
225 * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
226 * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
227 * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
228 * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
229 * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
230 * the HBA reset has completed.
231 * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
232 * a hung or locked state.
233 *
234 * @param adapterExtension
235 *
236 * @return
237 * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
238 */
239 BOOLEAN AhciAdapterReset(
240 PAHCI_ADAPTER_EXTENSION adapterExtension
241 )
242 {
243 ULONG ghc, ticks;
244 PAHCI_MEMORY_REGISTERS abar = NULL;
245
246 abar = adapterExtension->ABAR_Address;
247
248 if (abar == NULL) // basic sanity
249 return FALSE;
250
251 // HR -- Very first bit (lowest significant)
252 ghc = 1;
253 StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
254
255 for (ticks = 0; (ticks < 50) &&
256 (StorPortReadRegisterUlong(adapterExtension, &abar->GHC) == 1);
257 StorPortStallExecution(20000), ticks++);
258
259 if (ticks == 50)//1 second
260 return FALSE;
261
262 return TRUE;
263 }// -- AhciAdapterReset();