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 */
385