[STORAHCI] Merge Storport Miniport driver by Aman Priyadarshi in GSoC.
[reactos.git] / reactos / drivers / storage / ide / pciidex / fdo.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: PCI IDE bus driver extension
4 * FILE: drivers/storage/pciidex/fdo.c
5 * PURPOSE: IRP_MJ_PNP operations for FDOs
6 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #include "pciidex.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #include <initguid.h>
15 #include <wdmguid.h>
16
17 static NTSTATUS
18 GetBusInterface(
19 IN PFDO_DEVICE_EXTENSION DeviceExtension)
20 {
21 PBUS_INTERFACE_STANDARD BusInterface = NULL;
22 KEVENT Event;
23 IO_STATUS_BLOCK IoStatus;
24 PIRP Irp;
25 PIO_STACK_LOCATION Stack;
26 NTSTATUS Status = STATUS_UNSUCCESSFUL;
27
28 if (DeviceExtension->BusInterface)
29 {
30 DPRINT("We already have the bus interface\n");
31 goto cleanup;
32 }
33
34 BusInterface = ExAllocatePool(PagedPool, sizeof(BUS_INTERFACE_STANDARD));
35 if (!BusInterface)
36 {
37 DPRINT("ExAllocatePool() failed\n");
38 Status = STATUS_INSUFFICIENT_RESOURCES;
39 goto cleanup;
40 }
41
42 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
43 Irp = IoBuildSynchronousFsdRequest(
44 IRP_MJ_PNP,
45 DeviceExtension->LowerDevice,
46 NULL,
47 0,
48 NULL,
49 &Event,
50 &IoStatus);
51 if (!Irp)
52 {
53 DPRINT("IoBuildSynchronousFsdRequest() failed\n");
54 Status = STATUS_INSUFFICIENT_RESOURCES;
55 goto cleanup;
56 }
57
58 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
59 Irp->IoStatus.Information = 0;
60
61 Stack = IoGetNextIrpStackLocation(Irp);
62 Stack->MajorFunction = IRP_MJ_PNP;
63 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
64 Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
65 Stack->Parameters.QueryInterface.Version = 1;
66 Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
67 Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
68 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
69
70 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
71 if (Status == STATUS_PENDING)
72 {
73 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
74 Status = IoStatus.Status;
75 }
76 if (!NT_SUCCESS(Status))
77 goto cleanup;
78
79 DeviceExtension->BusInterface = BusInterface;
80 BusInterface = NULL;
81 Status = STATUS_SUCCESS;
82
83 cleanup:
84 if (BusInterface) ExFreePool(BusInterface);
85 return Status;
86 }
87
88 static NTSTATUS
89 ReleaseBusInterface(
90 IN PFDO_DEVICE_EXTENSION DeviceExtension)
91 {
92 NTSTATUS Status = STATUS_UNSUCCESSFUL;
93
94 if (DeviceExtension->BusInterface)
95 {
96 (*DeviceExtension->BusInterface->InterfaceDereference)(
97 DeviceExtension->BusInterface->Context);
98 DeviceExtension->BusInterface = NULL;
99 Status = STATUS_SUCCESS;
100 }
101
102 return Status;
103 }
104
105 NTSTATUS NTAPI
106 PciIdeXAddDevice(
107 IN PDRIVER_OBJECT DriverObject,
108 IN PDEVICE_OBJECT Pdo)
109 {
110 PPCIIDEX_DRIVER_EXTENSION DriverExtension;
111 PFDO_DEVICE_EXTENSION DeviceExtension;
112 PDEVICE_OBJECT Fdo;
113 ULONG BytesRead;
114 PCI_COMMON_CONFIG PciConfig;
115 NTSTATUS Status;
116
117 DPRINT("PciIdeXAddDevice(%p %p)\n", DriverObject, Pdo);
118
119 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
120 ASSERT(DriverExtension);
121
122 Status = IoCreateDevice(
123 DriverObject,
124 sizeof(FDO_DEVICE_EXTENSION) + DriverExtension->MiniControllerExtensionSize,
125 NULL,
126 FILE_DEVICE_BUS_EXTENDER,
127 FILE_DEVICE_SECURE_OPEN,
128 TRUE,
129 &Fdo);
130 if (!NT_SUCCESS(Status))
131 {
132 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
133 return Status;
134 }
135
136 DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
137 RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
138
139 DeviceExtension->Common.IsFDO = TRUE;
140
141 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
142 if (!NT_SUCCESS(Status))
143 {
144 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
145 return Status;
146 }
147
148 Status = GetBusInterface(DeviceExtension);
149 if (!NT_SUCCESS(Status))
150 {
151 DPRINT("GetBusInterface() failed with status 0x%08lx\n", Status);
152 IoDetachDevice(DeviceExtension->LowerDevice);
153 return Status;
154 }
155
156 BytesRead = (*DeviceExtension->BusInterface->GetBusData)(
157 DeviceExtension->BusInterface->Context,
158 PCI_WHICHSPACE_CONFIG,
159 &PciConfig,
160 0,
161 PCI_COMMON_HDR_LENGTH);
162 if (BytesRead != PCI_COMMON_HDR_LENGTH)
163 {
164 DPRINT("BusInterface->GetBusData() failed()\n");
165 ReleaseBusInterface(DeviceExtension);
166 IoDetachDevice(DeviceExtension->LowerDevice);
167 return STATUS_IO_DEVICE_ERROR;
168 }
169
170 DeviceExtension->VendorId = PciConfig.VendorID;
171 DeviceExtension->DeviceId = PciConfig.DeviceID;
172
173 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
174
175 return STATUS_SUCCESS;
176 }
177
178 static NTSTATUS NTAPI
179 PciIdeXUdmaModesSupported(
180 IN IDENTIFY_DATA IdentifyData,
181 OUT PULONG BestXferMode,
182 OUT PULONG CurrentXferMode)
183 {
184 ULONG Best = PIO_MODE0;
185 ULONG Current = PIO_MODE0;
186
187 DPRINT("PciIdeXUdmaModesSupported(%lu, %p %p)\n",
188 IdentifyData, BestXferMode, CurrentXferMode);
189
190 /* FIXME: if current mode is a PIO mode, how to get it?
191 * At the moment, PIO_MODE0 is always returned...
192 */
193
194 if (IdentifyData.TranslationFieldsValid & 0x2)
195 {
196 /* PIO modes and some DMA modes are supported */
197 if (IdentifyData.AdvancedPIOModes & 0x10)
198 Best = PIO_MODE4;
199 else if (IdentifyData.AdvancedPIOModes & 0x8)
200 Best = PIO_MODE3;
201 else if (IdentifyData.AdvancedPIOModes & 0x4)
202 Best = PIO_MODE2;
203 else if (IdentifyData.AdvancedPIOModes & 0x2)
204 Best = PIO_MODE1;
205 else if (IdentifyData.AdvancedPIOModes & 0x1)
206 Best = PIO_MODE0;
207
208 if (IdentifyData.SingleWordDMASupport & 0x4)
209 Best = SWDMA_MODE2;
210 else if (IdentifyData.SingleWordDMASupport & 0x2)
211 Best = SWDMA_MODE1;
212 else if (IdentifyData.SingleWordDMASupport & 0x1)
213 Best = SWDMA_MODE0;
214
215 if (IdentifyData.SingleWordDMAActive & 0x4)
216 Current = SWDMA_MODE2;
217 else if (IdentifyData.SingleWordDMAActive & 0x2)
218 Current = SWDMA_MODE1;
219 else if (IdentifyData.SingleWordDMAActive & 0x1)
220 Current = SWDMA_MODE0;
221
222 if (IdentifyData.MultiWordDMASupport & 0x4)
223 Best = MWDMA_MODE2;
224 else if (IdentifyData.MultiWordDMASupport & 0x2)
225 Best = MWDMA_MODE1;
226 else if (IdentifyData.MultiWordDMASupport & 0x1)
227 Best = MWDMA_MODE0;
228
229 if (IdentifyData.MultiWordDMAActive & 0x4)
230 Current = MWDMA_MODE2;
231 else if (IdentifyData.MultiWordDMAActive & 0x2)
232 Current = MWDMA_MODE1;
233 else if (IdentifyData.MultiWordDMAActive & 0x1)
234 Current = MWDMA_MODE0;
235 }
236
237 if (IdentifyData.TranslationFieldsValid & 0x4)
238 {
239 /* UDMA modes are supported */
240 if (IdentifyData.UltraDMAActive & 0x10)
241 Current = UDMA_MODE4;
242 else if (IdentifyData.UltraDMAActive & 0x8)
243 Current = UDMA_MODE3;
244 else if (IdentifyData.UltraDMAActive & 0x4)
245 Current = UDMA_MODE2;
246 else if (IdentifyData.UltraDMAActive & 0x2)
247 Current = UDMA_MODE1;
248 else if (IdentifyData.UltraDMAActive & 0x1)
249 Current = UDMA_MODE0;
250
251 if (IdentifyData.UltraDMASupport & 0x10)
252 Best = UDMA_MODE4;
253 else if (IdentifyData.UltraDMASupport & 0x8)
254 Best = UDMA_MODE3;
255 else if (IdentifyData.UltraDMASupport & 0x4)
256 Best = UDMA_MODE2;
257 else if (IdentifyData.UltraDMASupport & 0x2)
258 Best = UDMA_MODE1;
259 else if (IdentifyData.UltraDMASupport & 0x1)
260 Best = UDMA_MODE0;
261 }
262
263 *BestXferMode = Best;
264 *CurrentXferMode = Current;
265 return TRUE;
266 }
267
268 static NTSTATUS
269 PciIdeXFdoStartDevice(
270 IN PDEVICE_OBJECT DeviceObject,
271 IN PIRP Irp)
272 {
273 PPCIIDEX_DRIVER_EXTENSION DriverExtension;
274 PFDO_DEVICE_EXTENSION DeviceExtension;
275 PCM_RESOURCE_LIST ResourceList;
276 NTSTATUS Status;
277
278 DPRINT("PciIdeXStartDevice(%p %p)\n", DeviceObject, Irp);
279
280 DriverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, DeviceObject->DriverObject);
281 ASSERT(DriverExtension);
282 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
283 ASSERT(DeviceExtension);
284 ASSERT(DeviceExtension->Common.IsFDO);
285
286 DeviceExtension->Properties.Size = sizeof(IDE_CONTROLLER_PROPERTIES);
287 DeviceExtension->Properties.ExtensionSize = DriverExtension->MiniControllerExtensionSize;
288 Status = DriverExtension->HwGetControllerProperties(
289 DeviceExtension->MiniControllerExtension,
290 &DeviceExtension->Properties);
291 if (!NT_SUCCESS(Status))
292 return Status;
293
294 DriverExtension->HwUdmaModesSupported = DeviceExtension->Properties.PciIdeUdmaModesSupported;
295 if (!DriverExtension->HwUdmaModesSupported)
296 /* This method is optional, so provide our own one */
297 DriverExtension->HwUdmaModesSupported = PciIdeXUdmaModesSupported;
298
299 /* Get bus master port base, if any */
300 ResourceList = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources;
301 if (ResourceList
302 && ResourceList->Count == 1
303 && ResourceList->List[0].PartialResourceList.Count == 1
304 && ResourceList->List[0].PartialResourceList.Version == 1
305 && ResourceList->List[0].PartialResourceList.Revision == 1
306 && ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type == CmResourceTypePort
307 && ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length == 16)
308 {
309 DeviceExtension->BusMasterPortBase = ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start;
310 }
311 return STATUS_SUCCESS;
312 }
313
314 static NTSTATUS
315 PciIdeXFdoQueryBusRelations(
316 IN PDEVICE_OBJECT DeviceObject,
317 OUT PDEVICE_RELATIONS* pDeviceRelations)
318 {
319 PFDO_DEVICE_EXTENSION DeviceExtension;
320 PDEVICE_RELATIONS DeviceRelations = NULL;
321 PDEVICE_OBJECT Pdo;
322 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
323 ULONG i, j;
324 ULONG PDOs = 0;
325 IDE_CHANNEL_STATE ChannelState;
326 NTSTATUS Status;
327
328 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
329 ASSERT(DeviceExtension);
330 ASSERT(DeviceExtension->Common.IsFDO);
331
332 for (i = 0; i < MAX_IDE_CHANNEL; i++)
333 {
334 if (DeviceExtension->Pdo[i])
335 {
336 PDOs++;
337 continue;
338 }
339 ChannelState = DeviceExtension->Properties.PciIdeChannelEnabled(
340 DeviceExtension->MiniControllerExtension, i);
341 if (ChannelState == ChannelDisabled)
342 {
343 DPRINT("Channel %lu is disabled\n", i);
344 continue;
345 }
346
347 /* Need to create a PDO */
348 Status = IoCreateDevice(
349 DeviceObject->DriverObject,
350 sizeof(PDO_DEVICE_EXTENSION),
351 NULL,
352 FILE_DEVICE_CONTROLLER,
353 FILE_AUTOGENERATED_DEVICE_NAME,
354 FALSE,
355 &Pdo);
356 if (!NT_SUCCESS(Status))
357 /* FIXME: handle error */
358 continue;
359
360 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
361 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
362 PdoDeviceExtension->Common.IsFDO = FALSE;
363 PdoDeviceExtension->Channel = i;
364 PdoDeviceExtension->ControllerFdo = DeviceObject;
365 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
366 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
367
368 DeviceExtension->Pdo[i] = Pdo;
369 PDOs++;
370 }
371
372 if (PDOs == 0)
373 {
374 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
375 PagedPool,
376 sizeof(DEVICE_RELATIONS));
377 }
378 else
379 {
380 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
381 PagedPool,
382 sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (PDOs - 1));
383 }
384 if (!DeviceRelations)
385 return STATUS_INSUFFICIENT_RESOURCES;
386
387 DeviceRelations->Count = PDOs;
388 for (i = 0, j = 0; i < MAX_IDE_CHANNEL; i++)
389 {
390 if (DeviceExtension->Pdo[i])
391 {
392 ObReferenceObject(DeviceExtension->Pdo[i]);
393 DeviceRelations->Objects[j++] = DeviceExtension->Pdo[i];
394 }
395 }
396
397 *pDeviceRelations = DeviceRelations;
398 return STATUS_SUCCESS;
399 }
400
401 NTSTATUS NTAPI
402 PciIdeXFdoPnpDispatch(
403 IN PDEVICE_OBJECT DeviceObject,
404 IN PIRP Irp)
405 {
406 ULONG MinorFunction;
407 PIO_STACK_LOCATION Stack;
408 ULONG_PTR Information = Irp->IoStatus.Information;
409 NTSTATUS Status;
410
411 Stack = IoGetCurrentIrpStackLocation(Irp);
412 MinorFunction = Stack->MinorFunction;
413
414 switch (MinorFunction)
415 {
416 case IRP_MN_START_DEVICE: /* 0x00 */
417 {
418 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
419 /* Call lower driver */
420 Status = ForwardIrpAndWait(DeviceObject, Irp);
421 if (NT_SUCCESS(Status))
422 Status = PciIdeXFdoStartDevice(DeviceObject, Irp);
423 break;
424 }
425 case IRP_MN_QUERY_REMOVE_DEVICE: /* 0x01 */
426 {
427 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
428 Status = STATUS_UNSUCCESSFUL;
429 break;
430 }
431 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
432 {
433 switch (Stack->Parameters.QueryDeviceRelations.Type)
434 {
435 case BusRelations:
436 {
437 PDEVICE_RELATIONS DeviceRelations = NULL;
438 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
439 Status = PciIdeXFdoQueryBusRelations(DeviceObject, &DeviceRelations);
440 Information = (ULONG_PTR)DeviceRelations;
441 break;
442 }
443 default:
444 {
445 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
446 Stack->Parameters.QueryDeviceRelations.Type);
447 Status = STATUS_NOT_IMPLEMENTED;
448 break;
449 }
450 }
451 break;
452 }
453 case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
454 {
455 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
456 Information |= PNP_DEVICE_NOT_DISABLEABLE;
457 Status = STATUS_SUCCESS;
458 break;
459 }
460 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
461 {
462 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
463 return ForwardIrpAndForget(DeviceObject, Irp);
464 }
465 default:
466 {
467 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", MinorFunction);
468 return ForwardIrpAndForget(DeviceObject, Irp);
469 }
470 }
471
472 Irp->IoStatus.Information = Information;
473 Irp->IoStatus.Status = Status;
474 IoCompleteRequest(Irp, IO_NO_INCREMENT);
475 return Status;
476 }