[NTOS:KE/x64] Handle NMI vs swapgs race condition
[reactos.git] / drivers / storage / port / storport / miniport.c
1 /*
2 * PROJECT: ReactOS Storport Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Miniport interface code
5 * COPYRIGHT: Copyright 2017 Eric Kohl (eric.kohl@reactos.org)
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include "precomp.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 /* FUNCTIONS ******************************************************************/
17
18 static
19 NTSTATUS
20 InitializeConfiguration(
21 _In_ PPORT_CONFIGURATION_INFORMATION PortConfig,
22 _In_ PHW_INITIALIZATION_DATA InitData,
23 _In_ ULONG BusNumber,
24 _In_ ULONG SlotNumber)
25 {
26 PCONFIGURATION_INFORMATION ConfigInfo;
27 ULONG i;
28
29 DPRINT1("InitializeConfiguration(%p %p %lu %lu)\n",
30 PortConfig, InitData, BusNumber, SlotNumber);
31
32 /* Get the configurration information */
33 ConfigInfo = IoGetConfigurationInformation();
34
35 /* Initialize the port configuration */
36 RtlZeroMemory(PortConfig,
37 sizeof(PORT_CONFIGURATION_INFORMATION));
38
39 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
40 PortConfig->SystemIoBusNumber = BusNumber;
41 PortConfig->SlotNumber = SlotNumber;
42 PortConfig->AdapterInterfaceType = InitData->AdapterInterfaceType;
43
44 PortConfig->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
45 PortConfig->DmaChannel = SP_UNINITIALIZED_VALUE;
46 PortConfig->DmaPort = SP_UNINITIALIZED_VALUE;
47
48 PortConfig->InterruptMode = LevelSensitive;
49
50 PortConfig->Master = TRUE;
51 PortConfig->AtdiskPrimaryClaimed = ConfigInfo->AtDiskPrimaryAddressClaimed;
52 PortConfig->AtdiskSecondaryClaimed = ConfigInfo->AtDiskSecondaryAddressClaimed;
53 PortConfig->Dma32BitAddresses = TRUE;
54 PortConfig->DemandMode = FALSE;
55 PortConfig->MapBuffers = InitData->MapBuffers;
56
57 PortConfig->NeedPhysicalAddresses = TRUE;
58 PortConfig->TaggedQueuing = TRUE;
59 PortConfig->AutoRequestSense = TRUE;
60 PortConfig->MultipleRequestPerLu = TRUE;
61 PortConfig->ReceiveEvent = InitData->ReceiveEvent;
62 PortConfig->RealModeInitialized = FALSE;
63 PortConfig->BufferAccessScsiPortControlled = TRUE;
64 PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS_PER_BUS;
65
66 PortConfig->SpecificLuExtensionSize = InitData->SpecificLuExtensionSize;
67 PortConfig->SrbExtensionSize = InitData->SrbExtensionSize;
68 PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
69 PortConfig->WmiDataProvider = TRUE;
70
71 PortConfig->NumberOfAccessRanges = InitData->NumberOfAccessRanges;
72 DPRINT1("NumberOfAccessRanges: %lu\n", PortConfig->NumberOfAccessRanges);
73 if (PortConfig->NumberOfAccessRanges != 0)
74 {
75 PortConfig->AccessRanges = ExAllocatePoolWithTag(NonPagedPool,
76 PortConfig->NumberOfAccessRanges * sizeof(ACCESS_RANGE),
77 TAG_ACCRESS_RANGE);
78 if (PortConfig->AccessRanges == NULL)
79 return STATUS_NO_MEMORY;
80
81 RtlZeroMemory(PortConfig->AccessRanges,
82 PortConfig->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
83 }
84
85 for (i = 0; i < RTL_NUMBER_OF(PortConfig->InitiatorBusId); i++)
86 {
87 PortConfig->InitiatorBusId[i] = (CCHAR)SP_UNINITIALIZED_VALUE;
88 }
89
90 return STATUS_SUCCESS;
91 }
92
93
94 static
95 VOID
96 AssignResourcesToConfiguration(
97 _In_ PPORT_CONFIGURATION_INFORMATION PortConfiguration,
98 _In_ PCM_RESOURCE_LIST ResourceList,
99 _In_ ULONG NumberOfAccessRanges)
100 {
101 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
102 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
103 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
104 PACCESS_RANGE AccessRange;
105 INT i, j;
106 ULONG RangeNumber = 0, Interrupt = 0, Dma = 0;
107
108 DPRINT1("AssignResourceToConfiguration(%p %p %lu)\n",
109 PortConfiguration, ResourceList, NumberOfAccessRanges);
110
111 FullDescriptor = &ResourceList->List[0];
112 for (i = 0; i < ResourceList->Count; i++)
113 {
114 PartialResourceList = &FullDescriptor->PartialResourceList;
115
116 for (j = 0; j < PartialResourceList->Count; j++)
117 {
118 PartialDescriptor = &PartialResourceList->PartialDescriptors[j];
119
120 switch (PartialDescriptor->Type)
121 {
122 case CmResourceTypePort:
123 DPRINT1("Port: 0x%I64x (0x%lx)\n",
124 PartialDescriptor->u.Port.Start.QuadPart,
125 PartialDescriptor->u.Port.Length);
126 if (RangeNumber < NumberOfAccessRanges)
127 {
128 AccessRange = &((*(PortConfiguration->AccessRanges))[RangeNumber]);
129 AccessRange->RangeStart = PartialDescriptor->u.Port.Start;
130 AccessRange->RangeLength = PartialDescriptor->u.Port.Length;
131 AccessRange->RangeInMemory = FALSE;
132 RangeNumber++;
133 }
134 break;
135
136 case CmResourceTypeMemory:
137 DPRINT1("Memory: 0x%I64x (0x%lx)\n",
138 PartialDescriptor->u.Memory.Start.QuadPart,
139 PartialDescriptor->u.Memory.Length);
140 if (RangeNumber < NumberOfAccessRanges)
141 {
142 AccessRange = &((*(PortConfiguration->AccessRanges))[RangeNumber]);
143 AccessRange->RangeStart = PartialDescriptor->u.Memory.Start;
144 AccessRange->RangeLength = PartialDescriptor->u.Memory.Length;
145 AccessRange->RangeInMemory = TRUE;
146 RangeNumber++;
147 }
148 break;
149
150 case CmResourceTypeInterrupt:
151 DPRINT1("Interrupt: Level %lu Vector %lu\n",
152 PartialDescriptor->u.Interrupt.Level,
153 PartialDescriptor->u.Interrupt.Vector);
154 if (Interrupt == 0)
155 {
156 /* Copy interrupt data */
157 PortConfiguration->BusInterruptLevel = PartialDescriptor->u.Interrupt.Level;
158 PortConfiguration->BusInterruptVector = PartialDescriptor->u.Interrupt.Vector;
159
160 /* Set interrupt mode accordingly to the resource */
161 if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
162 {
163 PortConfiguration->InterruptMode = Latched;
164 }
165 else if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
166 {
167 PortConfiguration->InterruptMode = LevelSensitive;
168 }
169 }
170 else if (Interrupt == 1)
171 {
172 /* Copy interrupt data */
173 PortConfiguration->BusInterruptLevel2 = PartialDescriptor->u.Interrupt.Level;
174 PortConfiguration->BusInterruptVector2 = PartialDescriptor->u.Interrupt.Vector;
175
176 /* Set interrupt mode accordingly to the resource */
177 if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
178 {
179 PortConfiguration->InterruptMode2 = Latched;
180 }
181 else if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
182 {
183 PortConfiguration->InterruptMode2 = LevelSensitive;
184 }
185 }
186 Interrupt++;
187 break;
188
189 case CmResourceTypeDma:
190 DPRINT1("Dma: Channel: %lu Port: %lu\n",
191 PartialDescriptor->u.Dma.Channel,
192 PartialDescriptor->u.Dma.Port);
193 if (Dma == 0)
194 {
195 PortConfiguration->DmaChannel = PartialDescriptor->u.Dma.Channel;
196 PortConfiguration->DmaPort = PartialDescriptor->u.Dma.Port;
197
198 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
199 PortConfiguration->DmaWidth = Width8Bits;
200 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
201 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16))
202 PortConfiguration->DmaWidth = Width16Bits;
203 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
204 PortConfiguration->DmaWidth = Width32Bits;
205 }
206 else if (Dma == 1)
207 {
208 PortConfiguration->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
209 PortConfiguration->DmaPort2 = PartialDescriptor->u.Dma.Port;
210
211 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
212 PortConfiguration->DmaWidth2 = Width8Bits;
213 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
214 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16))
215 PortConfiguration->DmaWidth2 = Width16Bits;
216 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
217 PortConfiguration->DmaWidth2 = Width32Bits;
218 }
219 Dma++;
220 break;
221
222 default:
223 DPRINT1("Other: %u\n", PartialDescriptor->Type);
224 break;
225 }
226 }
227
228 /* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
229 FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptor->PartialResourceList.PartialDescriptors +
230 FullDescriptor->PartialResourceList.Count);
231 }
232 }
233
234
235 NTSTATUS
236 MiniportInitialize(
237 _In_ PMINIPORT Miniport,
238 _In_ PFDO_DEVICE_EXTENSION DeviceExtension,
239 _In_ PHW_INITIALIZATION_DATA InitData)
240 {
241 PMINIPORT_DEVICE_EXTENSION MiniportExtension;
242 ULONG Size;
243 NTSTATUS Status;
244
245 DPRINT1("MiniportInitialize(%p %p %p)\n",
246 Miniport, DeviceExtension, InitData);
247
248 Miniport->DeviceExtension = DeviceExtension;
249 Miniport->InitData = InitData;
250
251 /* Calculate the miniport device extension size */
252 Size = sizeof(MINIPORT_DEVICE_EXTENSION) +
253 Miniport->InitData->DeviceExtensionSize;
254
255 /* Allocate and initialize the miniport device extension */
256 MiniportExtension = ExAllocatePoolWithTag(NonPagedPool,
257 Size,
258 TAG_MINIPORT_DATA);
259 if (MiniportExtension == NULL)
260 return STATUS_NO_MEMORY;
261
262 RtlZeroMemory(MiniportExtension, Size);
263
264 MiniportExtension->Miniport = Miniport;
265 Miniport->MiniportExtension = MiniportExtension;
266
267 /* Initialize the port configuration */
268 Status = InitializeConfiguration(&Miniport->PortConfig,
269 InitData,
270 DeviceExtension->BusNumber,
271 DeviceExtension->SlotNumber);
272 if (!NT_SUCCESS(Status))
273 return Status;
274
275 /* Assign the resources to the port configuration */
276 AssignResourcesToConfiguration(&Miniport->PortConfig,
277 DeviceExtension->AllocatedResources,
278 InitData->NumberOfAccessRanges);
279
280 return STATUS_SUCCESS;
281 }
282
283
284 NTSTATUS
285 MiniportFindAdapter(
286 _In_ PMINIPORT Miniport)
287 {
288 BOOLEAN Reserved = FALSE;
289 ULONG Result;
290 NTSTATUS Status;
291
292 DPRINT1("MiniportFindAdapter(%p)\n", Miniport);
293
294 /* Call the miniport HwFindAdapter routine */
295 Result = Miniport->InitData->HwFindAdapter(&Miniport->MiniportExtension->HwDeviceExtension,
296 NULL,
297 NULL,
298 NULL,
299 &Miniport->PortConfig,
300 &Reserved);
301 DPRINT1("HwFindAdapter() returned %lu\n", Result);
302
303 /* Convert the result to a status code */
304 switch (Result)
305 {
306 case SP_RETURN_NOT_FOUND:
307 DPRINT1("SP_RETURN_NOT_FOUND\n");
308 Status = STATUS_NOT_FOUND;
309 break;
310
311 case SP_RETURN_FOUND:
312 DPRINT1("SP_RETURN_FOUND\n");
313 Status = STATUS_SUCCESS;
314 break;
315
316 case SP_RETURN_ERROR:
317 DPRINT1("SP_RETURN_ERROR\n");
318 Status = STATUS_ADAPTER_HARDWARE_ERROR;
319 break;
320
321 case SP_RETURN_BAD_CONFIG:
322 DPRINT1("SP_RETURN_BAD_CONFIG\n");
323 Status = STATUS_DEVICE_CONFIGURATION_ERROR;
324 break;
325
326 default:
327 DPRINT1("Unknown result: %lu\n", Result);
328 Status = STATUS_INTERNAL_ERROR;
329 break;
330 }
331
332 return Status;
333 }
334
335
336 NTSTATUS
337 MiniportHwInitialize(
338 _In_ PMINIPORT Miniport)
339 {
340 BOOLEAN Result;
341
342 DPRINT1("MiniportHwInitialize(%p)\n", Miniport);
343
344 /* Call the miniport HwInitialize routine */
345 Result = Miniport->InitData->HwInitialize(&Miniport->MiniportExtension->HwDeviceExtension);
346 DPRINT1("HwInitialize() returned %u\n", Result);
347
348 return Result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
349 }
350
351
352 BOOLEAN
353 MiniportHwInterrupt(
354 _In_ PMINIPORT Miniport)
355 {
356 BOOLEAN Result;
357
358 DPRINT1("MiniportHwInterrupt(%p)\n",
359 Miniport);
360
361 Result = Miniport->InitData->HwInterrupt(&Miniport->MiniportExtension->HwDeviceExtension);
362 DPRINT1("HwInterrupt() returned %u\n", Result);
363
364 return Result;
365 }
366
367
368 BOOLEAN
369 MiniportStartIo(
370 _In_ PMINIPORT Miniport,
371 _In_ PSCSI_REQUEST_BLOCK Srb)
372 {
373 BOOLEAN Result;
374
375 DPRINT1("MiniportHwStartIo(%p %p)\n",
376 Miniport, Srb);
377
378 Result = Miniport->InitData->HwStartIo(&Miniport->MiniportExtension->HwDeviceExtension, Srb);
379 DPRINT1("HwStartIo() returned %u\n", Result);
380
381 return Result;
382 }
383
384 /* EOF */