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 = -1; //SP_UNINITIALIZED_VALUE;
45     PortConfig->DmaChannel = -1; //SP_UNINITIALIZED_VALUE;
46     PortConfig->DmaPort = -1; //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 = 128;
65 
66     PortConfig->SpecificLuExtensionSize = InitData->SpecificLuExtensionSize;
67     PortConfig->SrbExtensionSize = InitData->SrbExtensionSize;
68     PortConfig->MaximumNumberOfLogicalUnits = 1;
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 < 7; i++)
86         PortConfig->InitiatorBusId[i] = 0xff;
87 
88     return STATUS_SUCCESS;
89 }
90 
91 
92 static
93 VOID
94 AssignResourcesToConfiguration(
95     _In_ PPORT_CONFIGURATION_INFORMATION PortConfiguration,
96     _In_ PCM_RESOURCE_LIST ResourceList,
97     _In_ ULONG NumberOfAccessRanges)
98 {
99     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
100     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
101     PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
102     PACCESS_RANGE AccessRange;
103     INT i, j;
104     ULONG RangeNumber = 0, Interrupt = 0, Dma = 0;
105 
106     DPRINT1("AssignResourceToConfiguration(%p %p %lu)\n",
107             PortConfiguration, ResourceList, NumberOfAccessRanges);
108 
109     FullDescriptor = &ResourceList->List[0];
110     for (i = 0; i < ResourceList->Count; i++)
111     {
112         PartialResourceList = &FullDescriptor->PartialResourceList;
113 
114         for (j = 0; j < PartialResourceList->Count; j++)
115         {
116             PartialDescriptor = &PartialResourceList->PartialDescriptors[j];
117 
118             switch (PartialDescriptor->Type)
119             {
120                 case CmResourceTypePort:
121                     DPRINT1("Port: 0x%I64x (0x%lx)\n",
122                             PartialDescriptor->u.Port.Start.QuadPart,
123                             PartialDescriptor->u.Port.Length);
124                     if (RangeNumber < NumberOfAccessRanges)
125                     {
126                         AccessRange = &((*(PortConfiguration->AccessRanges))[RangeNumber]);
127                         AccessRange->RangeStart = PartialDescriptor->u.Port.Start;
128                         AccessRange->RangeLength = PartialDescriptor->u.Port.Length;
129                         AccessRange->RangeInMemory = FALSE;
130                         RangeNumber++;
131                     }
132                     break;
133 
134                 case CmResourceTypeMemory:
135                     DPRINT1("Memory: 0x%I64x (0x%lx)\n",
136                             PartialDescriptor->u.Memory.Start.QuadPart,
137                             PartialDescriptor->u.Memory.Length);
138                     if (RangeNumber < NumberOfAccessRanges)
139                     {
140                         AccessRange = &((*(PortConfiguration->AccessRanges))[RangeNumber]);
141                         AccessRange->RangeStart = PartialDescriptor->u.Memory.Start;
142                         AccessRange->RangeLength = PartialDescriptor->u.Memory.Length;
143                         AccessRange->RangeInMemory = TRUE;
144                         RangeNumber++;
145                     }
146                     break;
147 
148                 case CmResourceTypeInterrupt:
149                     DPRINT1("Interrupt: Level %lu  Vector %lu\n",
150                             PartialDescriptor->u.Interrupt.Level,
151                             PartialDescriptor->u.Interrupt.Vector);
152                     if (Interrupt == 0)
153                     {
154                         /* Copy interrupt data */
155                         PortConfiguration->BusInterruptLevel = PartialDescriptor->u.Interrupt.Level;
156                         PortConfiguration->BusInterruptVector = PartialDescriptor->u.Interrupt.Vector;
157 
158                         /* Set interrupt mode accordingly to the resource */
159                         if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
160                         {
161                             PortConfiguration->InterruptMode = Latched;
162                         }
163                         else if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
164                         {
165                             PortConfiguration->InterruptMode = LevelSensitive;
166                         }
167                     }
168                     else if (Interrupt == 1)
169                     {
170                         /* Copy interrupt data */
171                         PortConfiguration->BusInterruptLevel2 = PartialDescriptor->u.Interrupt.Level;
172                         PortConfiguration->BusInterruptVector2 = PartialDescriptor->u.Interrupt.Vector;
173 
174                         /* Set interrupt mode accordingly to the resource */
175                         if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
176                         {
177                             PortConfiguration->InterruptMode2 = Latched;
178                         }
179                         else if (PartialDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
180                         {
181                             PortConfiguration->InterruptMode2 = LevelSensitive;
182                         }
183                     }
184                     Interrupt++;
185                     break;
186 
187                 case CmResourceTypeDma:
188                     DPRINT1("Dma: Channel: %lu  Port: %lu\n",
189                             PartialDescriptor->u.Dma.Channel,
190                             PartialDescriptor->u.Dma.Port);
191                     if (Dma == 0)
192                     {
193                         PortConfiguration->DmaChannel = PartialDescriptor->u.Dma.Channel;
194                         PortConfiguration->DmaPort = PartialDescriptor->u.Dma.Port;
195 
196                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
197                             PortConfiguration->DmaWidth = Width8Bits;
198                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
199                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16))
200                             PortConfiguration->DmaWidth = Width16Bits;
201                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
202                             PortConfiguration->DmaWidth = Width32Bits;
203                     }
204                     else if (Dma == 1)
205                     {
206                         PortConfiguration->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
207                         PortConfiguration->DmaPort2 = PartialDescriptor->u.Dma.Port;
208 
209                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
210                             PortConfiguration->DmaWidth2 = Width8Bits;
211                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
212                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16))
213                             PortConfiguration->DmaWidth2 = Width16Bits;
214                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
215                             PortConfiguration->DmaWidth2 = Width32Bits;
216                     }
217                     Dma++;
218                     break;
219 
220                 default:
221                     DPRINT1("Other: %u\n", PartialDescriptor->Type);
222                     break;
223             }
224         }
225 
226         /* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
227         FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptor->PartialResourceList.PartialDescriptors +
228                                                         FullDescriptor->PartialResourceList.Count);
229     }
230 }
231 
232 
233 NTSTATUS
234 MiniportInitialize(
235     _In_ PMINIPORT Miniport,
236     _In_ PFDO_DEVICE_EXTENSION DeviceExtension,
237     _In_ PHW_INITIALIZATION_DATA InitData)
238 {
239     PMINIPORT_DEVICE_EXTENSION MiniportExtension;
240     ULONG Size;
241     NTSTATUS Status;
242 
243     DPRINT1("MiniportInitialize(%p %p %p)\n",
244             Miniport, DeviceExtension, InitData);
245 
246     Miniport->DeviceExtension = DeviceExtension;
247     Miniport->InitData = InitData;
248 
249     /* Calculate the miniport device extension size */
250     Size = sizeof(MINIPORT_DEVICE_EXTENSION) +
251            Miniport->InitData->DeviceExtensionSize;
252 
253     /* Allocate and initialize the miniport device extension */
254     MiniportExtension = ExAllocatePoolWithTag(NonPagedPool,
255                                               Size,
256                                               TAG_MINIPORT_DATA);
257     if (MiniportExtension == NULL)
258         return STATUS_NO_MEMORY;
259 
260     RtlZeroMemory(MiniportExtension, Size);
261 
262     MiniportExtension->Miniport = Miniport;
263     Miniport->MiniportExtension = MiniportExtension;
264 
265     /* Initialize the port configuration */
266     Status = InitializeConfiguration(&Miniport->PortConfig,
267                                      InitData,
268                                      DeviceExtension->BusNumber,
269                                      DeviceExtension->SlotNumber);
270     if (!NT_SUCCESS(Status))
271         return Status;
272 
273     /* Assign the resources to the port configuration */
274     AssignResourcesToConfiguration(&Miniport->PortConfig,
275                                    DeviceExtension->AllocatedResources,
276                                    InitData->NumberOfAccessRanges);
277 
278     return STATUS_SUCCESS;
279 }
280 
281 
282 NTSTATUS
283 MiniportFindAdapter(
284     _In_ PMINIPORT Miniport)
285 {
286     BOOLEAN Reserved = FALSE;
287     ULONG Result;
288     NTSTATUS Status;
289 
290     DPRINT1("MiniportFindAdapter(%p)\n", Miniport);
291 
292     /* Call the miniport HwFindAdapter routine */
293     Result = Miniport->InitData->HwFindAdapter(&Miniport->MiniportExtension->HwDeviceExtension,
294                                                NULL,
295                                                NULL,
296                                                NULL,
297                                                &Miniport->PortConfig,
298                                                &Reserved);
299     DPRINT1("HwFindAdapter() returned %lu\n", Result);
300 
301     /* Convert the result to a status code */
302     switch (Result)
303     {
304         case SP_RETURN_NOT_FOUND:
305             DPRINT1("SP_RETURN_NOT_FOUND\n");
306             Status = STATUS_NOT_FOUND;
307             break;
308 
309         case SP_RETURN_FOUND:
310             DPRINT1("SP_RETURN_FOUND\n");
311             Status = STATUS_SUCCESS;
312             break;
313 
314         case SP_RETURN_ERROR:
315             DPRINT1("SP_RETURN_ERROR\n");
316             Status = STATUS_ADAPTER_HARDWARE_ERROR;
317             break;
318 
319         case SP_RETURN_BAD_CONFIG:
320             DPRINT1("SP_RETURN_BAD_CONFIG\n");
321             Status = STATUS_DEVICE_CONFIGURATION_ERROR;
322             break;
323 
324         default:
325             DPRINT1("Unknown result: %lu\n", Result);
326             Status = STATUS_INTERNAL_ERROR;
327             break;
328     }
329 
330     return Status;
331 }
332 
333 
334 NTSTATUS
335 MiniportHwInitialize(
336     _In_ PMINIPORT Miniport)
337 {
338     BOOLEAN Result;
339 
340     DPRINT1("MiniportHwInitialize(%p)\n", Miniport);
341 
342     /* Call the miniport HwInitialize routine */
343     Result = Miniport->InitData->HwInitialize(&Miniport->MiniportExtension->HwDeviceExtension);
344     DPRINT1("HwInitialize() returned %u\n", Result);
345 
346     return Result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
347 }
348 
349 
350 BOOLEAN
351 MiniportHwInterrupt(
352     _In_ PMINIPORT Miniport)
353 {
354     BOOLEAN Result;
355 
356     DPRINT1("MiniportHwInterrupt(%p)\n",
357             Miniport);
358 
359     Result = Miniport->InitData->HwInterrupt(&Miniport->MiniportExtension->HwDeviceExtension);
360     DPRINT1("HwInterrupt() returned %u\n", Result);
361 
362     return Result;
363 }
364 
365 /* EOF */
366