xref: /reactos/drivers/storage/port/scsiport/pdo.c (revision f095ff41)
1 /*
2  * PROJECT:     ReactOS Storage Stack / SCSIPORT storage port library
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Logical Unit (PDO) functions
5  * COPYRIGHT:   Eric Kohl (eric.kohl@reactos.org)
6  *              Aleksey Bragin (aleksey@reactos.org)
7  *              2020 Victor Perevertkin (victor.perevertkin@reactos.org)
8  */
9 
10 #include "scsiport.h"
11 #include "scsitypes.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 
17 PDEVICE_OBJECT
PdoCreateLunDevice(_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)18 PdoCreateLunDevice(
19     _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
20 {
21     PSCSI_PORT_LUN_EXTENSION LunExtension;
22     PDEVICE_OBJECT LunPDO;
23 
24     ULONG LunExtensionSize = DeviceExtension->LunExtensionSize + sizeof(SCSI_PORT_LUN_EXTENSION);
25 
26     NTSTATUS Status = IoCreateDevice(DeviceExtension->Common.DeviceObject->DriverObject,
27                                      LunExtensionSize,
28                                      NULL,
29                                      FILE_DEVICE_DISK,
30                                      FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
31                                      FALSE,
32                                      &LunPDO);
33 
34     if (!NT_SUCCESS(Status))
35     {
36         DPRINT1("Failed to create a Lun PDO, status: %x\n", Status);
37         return NULL;
38     }
39 
40     LunExtension = LunPDO->DeviceExtension;
41 
42     /* Zero everything */
43     RtlZeroMemory(LunExtension, LunExtensionSize);
44 
45     LunExtension->Common.IsFDO = FALSE;
46     LunExtension->Common.DeviceObject = LunPDO;
47     LunExtension->Common.LowerDevice = DeviceExtension->Common.DeviceObject;
48 
49     /* Initialize a list of requests */
50     InitializeListHead(&LunExtension->SrbInfo.Requests);
51 
52     /* Initialize timeout counter */
53     LunExtension->RequestTimeout = -1;
54 
55     /* Set maximum queue size */
56     LunExtension->MaxQueueCount = 256;
57 
58     /* Initialize request queue */
59     KeInitializeDeviceQueue(&LunExtension->DeviceQueue);
60 
61     LunPDO->Flags |= DO_DIRECT_IO;
62     LunPDO->Flags &= ~DO_DEVICE_INITIALIZING;
63 
64     return LunPDO;
65 }
66 
67 PSCSI_PORT_LUN_EXTENSION
GetLunByPath(_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,_In_ UCHAR PathId,_In_ UCHAR TargetId,_In_ UCHAR Lun)68 GetLunByPath(
69     _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
70     _In_ UCHAR PathId,
71     _In_ UCHAR TargetId,
72     _In_ UCHAR Lun)
73 {
74     if (PathId >= DeviceExtension->NumberOfBuses)
75     {
76         DPRINT1("Invalid PathId: %u\n", PathId);
77         return NULL;
78     }
79 
80     PSCSI_BUS_INFO bus = &DeviceExtension->Buses[PathId];
81 
82     for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
83          lunEntry != &bus->LunsListHead;
84          lunEntry = lunEntry->Flink)
85     {
86         PSCSI_PORT_LUN_EXTENSION lunExt =
87             CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
88 
89         if (lunExt->PathId == PathId &&
90             lunExt->TargetId == TargetId &&
91             lunExt->Lun == Lun)
92         {
93             return lunExt;
94         }
95     }
96 
97     DPRINT("SCSI LUN (%u, %u, %u) was not found\n", PathId, TargetId, Lun);
98     return NULL;
99 }
100 
101 PSCSI_REQUEST_BLOCK_INFO
SpiGetSrbData(_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,_In_ PSCSI_PORT_LUN_EXTENSION LunExtension,_In_ UCHAR QueueTag)102 SpiGetSrbData(
103     _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
104     _In_ PSCSI_PORT_LUN_EXTENSION LunExtension,
105     _In_ UCHAR QueueTag)
106 {
107     if (QueueTag == SP_UNTAGGED)
108     {
109         /* Return the pointer to SrbInfo */
110         return &LunExtension->SrbInfo;
111     }
112     else
113     {
114         /* Make sure the tag is valid, if it is - return the data */
115         if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
116             return NULL;
117         else
118             return &DeviceExtension->SrbInfo[QueueTag -1];
119     }
120 }
121 
122 static
123 ULONG
CopyField(IN PUCHAR Name,IN PCHAR Buffer,IN ULONG MaxLength,IN CHAR DefaultCharacter,IN BOOLEAN Trim)124 CopyField(
125     IN PUCHAR Name,
126     IN PCHAR Buffer,
127     IN ULONG MaxLength,
128     IN CHAR DefaultCharacter,
129     IN BOOLEAN Trim)
130 {
131     ULONG Index;
132 
133     for (Index = 0; Index < MaxLength; Index++)
134     {
135         if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ ||  Name[Index] == ',')
136         {
137             // convert to underscore
138             Buffer[Index] = DefaultCharacter;
139         }
140         else
141         {
142             // just copy character
143             Buffer[Index] = Name[Index];
144         }
145     }
146 
147     /* Trim trailing default characters */
148     if (Trim)
149     {
150         Index = MaxLength - 1;
151         for (;;)
152         {
153             if (Buffer[Index] != DefaultCharacter)
154             {
155                 Index++;
156                 break;
157             }
158 
159             Index--;
160         }
161     }
162 
163     return Index;
164 }
165 
166 static
167 NTSTATUS
PdoHandleQueryDeviceText(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)168 PdoHandleQueryDeviceText(
169     _In_ PDEVICE_OBJECT DeviceObject,
170     _Inout_ PIRP Irp)
171 {
172     PSCSI_PORT_LUN_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
173     PIO_STACK_LOCATION IoStack;
174     UINT32 Offset = 0;
175     PINQUIRYDATA InquiryData;
176     CHAR LocalBuffer[64];
177     ANSI_STRING AnsiString;
178     UNICODE_STRING DeviceDescription;
179 
180     DPRINT("PdoHandleQueryDeviceText\n");
181 
182     IoStack = IoGetCurrentIrpStackLocation(Irp);
183 
184     InquiryData = &DeviceExtension->InquiryData;
185 
186     switch (IoStack->Parameters.QueryDeviceText.DeviceTextType)
187     {
188         case DeviceTextDescription:
189         {
190             DPRINT("DeviceTextDescription\n");
191 
192             Offset += CopyField(InquiryData->VendorId,
193                                 &LocalBuffer[Offset],
194                                 sizeof(InquiryData->VendorId),
195                                 ' ',
196                                 TRUE);
197             LocalBuffer[Offset++] = ' ';
198             Offset += CopyField(InquiryData->ProductId,
199                                 &LocalBuffer[Offset],
200                                 sizeof(InquiryData->ProductId),
201                                 ' ',
202                                 TRUE);
203             Offset += sprintf(&LocalBuffer[Offset],
204                               " SCSI %s Device",
205                               GetDeviceType(InquiryData));
206             LocalBuffer[Offset++] = '\0';
207 
208             RtlInitAnsiString(&AnsiString, (PCSZ)&LocalBuffer);
209 
210             DeviceDescription.Length = 0;
211             DeviceDescription.MaximumLength = (USHORT)(Offset * sizeof(WCHAR));
212             DeviceDescription.Buffer = ExAllocatePoolWithTag(PagedPool,
213                                                              DeviceDescription.MaximumLength,
214                                                              TAG_SCSIPORT);
215             if (!DeviceDescription.Buffer)
216             {
217                 Irp->IoStatus.Information = 0;
218                 return STATUS_INSUFFICIENT_RESOURCES;
219             }
220 
221             RtlAnsiStringToUnicodeString(&DeviceDescription, &AnsiString, FALSE);
222 
223             Irp->IoStatus.Information = (ULONG_PTR)DeviceDescription.Buffer;
224             return STATUS_SUCCESS;
225         }
226 
227         case DeviceTextLocationInformation:
228         {
229             DPRINT("DeviceTextLocationInformation\n");
230 
231             sprintf(LocalBuffer, "Bus Number %d, Target ID %d, LUN %d",
232                     DeviceExtension->PathId, DeviceExtension->TargetId, DeviceExtension->Lun);
233 
234             RtlInitAnsiString(&AnsiString, (PCSZ)&LocalBuffer);
235 
236             DeviceDescription.Length = 0;
237             DeviceDescription.MaximumLength = (USHORT)((strlen(LocalBuffer) + 1) * sizeof(WCHAR));
238             DeviceDescription.Buffer = ExAllocatePoolWithTag(PagedPool,
239                                                              DeviceDescription.MaximumLength,
240                                                              TAG_SCSIPORT);
241             if (!DeviceDescription.Buffer)
242             {
243                 Irp->IoStatus.Information = 0;
244                 return STATUS_INSUFFICIENT_RESOURCES;
245             }
246 
247             RtlAnsiStringToUnicodeString(&DeviceDescription, &AnsiString, FALSE);
248 
249             Irp->IoStatus.Information = (ULONG_PTR)DeviceDescription.Buffer;
250             return STATUS_SUCCESS;
251         }
252 
253         default:
254         {
255             Irp->IoStatus.Information = 0;
256             return Irp->IoStatus.Status;
257         }
258     }
259 }
260 
261 static
262 NTSTATUS
PdoHandleQueryDeviceId(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)263 PdoHandleQueryDeviceId(
264     _In_ PDEVICE_OBJECT DeviceObject,
265     _Inout_ PIRP Irp)
266 {
267     PSCSI_PORT_LUN_EXTENSION DeviceExtension;
268     NTSTATUS Status;
269     CHAR Buffer[100] = {0};
270     LPCSTR DeviceType;
271     ULONG Offset = 0;
272     PINQUIRYDATA InquiryData;
273     ANSI_STRING AnsiString;
274     UNICODE_STRING DeviceId;
275 
276     DeviceExtension = DeviceObject->DeviceExtension;
277     InquiryData = &DeviceExtension->InquiryData;
278 
279     DeviceType = GetDeviceType(InquiryData);
280 
281     // lets create device string
282     Offset = sprintf(&Buffer[Offset], "SCSI\\");
283     Offset += sprintf(&Buffer[Offset], DeviceType);
284     Offset += sprintf(&Buffer[Offset], "&Ven_");
285     Offset += CopyField(InquiryData->VendorId, &Buffer[Offset], 8, '_', TRUE);
286     Offset += sprintf(&Buffer[Offset], "&Prod_");
287     Offset += CopyField(InquiryData->ProductId, &Buffer[Offset], 16, '_', TRUE);
288     Offset += sprintf(&Buffer[Offset], "&Rev_");
289     Offset += CopyField(InquiryData->ProductRevisionLevel, &Buffer[Offset], 4, '_', TRUE);
290     Buffer[Offset] = '\0';
291 
292     RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
293 
294     // allocate DeviceId string
295     Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, TRUE);
296 
297     if (NT_SUCCESS(Status))
298     {
299         Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
300     }
301 
302     DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status);
303 
304     return Status;
305 }
306 
307 static
308 VOID
ConvertToUnicodeString(IN CHAR * Buffer,IN ULONG ResultBufferLength,IN ULONG ResultBufferOffset,OUT LPWSTR ResultBuffer,OUT PULONG NewResultBufferOffset)309 ConvertToUnicodeString(
310     IN CHAR * Buffer,
311     IN ULONG ResultBufferLength,
312     IN ULONG ResultBufferOffset,
313     OUT LPWSTR ResultBuffer,
314     OUT PULONG NewResultBufferOffset)
315 {
316     UNICODE_STRING DeviceString;
317     ANSI_STRING AnsiString;
318     NTSTATUS Status;
319 
320     ASSERT(ResultBufferLength);
321     ASSERT(ResultBufferLength > ResultBufferOffset);
322 
323     DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n",
324         ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer));
325 
326     // construct destination string
327     DeviceString.Buffer = &ResultBuffer[ResultBufferOffset];
328     DeviceString.Length = 0;
329     DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR);
330 
331     // initialize source string
332     RtlInitAnsiString(&AnsiString, Buffer);
333 
334     Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE);
335     ASSERT(Status == STATUS_SUCCESS);
336 
337     // subtract consumed bytes
338     ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
339     ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
340 
341     *NewResultBufferOffset = ResultBufferOffset;
342 }
343 
344 static
345 NTSTATUS
PdoHandleQueryHardwareId(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)346 PdoHandleQueryHardwareId(
347     _In_ PDEVICE_OBJECT DeviceObject,
348     _Inout_ PIRP Irp)
349 {
350     PSCSI_PORT_LUN_EXTENSION PDODeviceExtension = DeviceObject->DeviceExtension;
351     LPCSTR GenericType, DeviceType;
352     LPWSTR Buffer;
353     CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50];
354     ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length, Id6Length;
355     ULONG Offset, TotalLength, Length;
356     PINQUIRYDATA InquiryData;
357 
358     InquiryData = &PDODeviceExtension->InquiryData;
359 
360     DeviceType = GetDeviceType(InquiryData);
361     GenericType = GetGenericType(InquiryData);
362 
363     ASSERT(GenericType);
364 
365     // generate id 1
366     // SCSI\SCSIType_VendorId(8)_ProductId(16)_Revision(4)
367     RtlZeroMemory(Id1, sizeof(Id1));
368     Offset = 0;
369     Offset = sprintf(&Id1[Offset], "SCSI\\");
370     Offset += sprintf(&Id1[Offset], DeviceType);
371     Offset += CopyField(InquiryData->VendorId, &Id1[Offset], 8, '_', FALSE);
372     Offset += CopyField(InquiryData->ProductId, &Id1[Offset], 16, '_', FALSE);
373     Offset += CopyField(InquiryData->ProductRevisionLevel, &Id1[Offset], 4, '_', FALSE);
374     Id1Length = strlen(Id1) + 1;
375     DPRINT("PdoHandleQueryHardwareId HardwareId1 %s\n", Id1);
376 
377     // generate id 2
378     // SCSI\SCSIType_VendorId(8)_ProductId(16)
379     RtlZeroMemory(Id2, sizeof(Id2));
380     Offset = 0;
381     Offset = sprintf(&Id2[Offset], "SCSI\\");
382     Offset += sprintf(&Id2[Offset], DeviceType);
383     Offset += CopyField(InquiryData->VendorId, &Id2[Offset], 8, '_', FALSE);
384     Offset += CopyField(InquiryData->ProductId, &Id2[Offset], 16, '_', FALSE);
385     Id2Length = strlen(Id2) + 1;
386     DPRINT("PdoHandleQueryHardwareId HardwareId2 %s\n", Id2);
387 
388     // generate id 3
389     // SCSI\SCSIType_VendorId(8)
390     RtlZeroMemory(Id3, sizeof(Id3));
391     Offset = 0;
392     Offset = sprintf(&Id3[Offset], "SCSI\\");
393     Offset += sprintf(&Id3[Offset], DeviceType);
394     Offset += CopyField(InquiryData->VendorId, &Id3[Offset], 8, '_', FALSE);
395     Id3Length = strlen(Id3) + 1;
396     DPRINT("PdoHandleQueryHardwareId HardwareId3 %s\n", Id3);
397 
398     // generate id 4
399     // SCSI\VendorId(8)_ProductId(16)_Revision(1)
400     RtlZeroMemory(Id4, sizeof(Id4));
401     Offset = 0;
402     Offset = sprintf(&Id4[Offset], "SCSI\\");
403     Offset += CopyField(InquiryData->VendorId, &Id4[Offset], 8, '_', FALSE);
404     Offset += CopyField(InquiryData->ProductId, &Id4[Offset], 16, '_', FALSE);
405     Offset += CopyField(InquiryData->ProductRevisionLevel, &Id4[Offset], 1, '_', FALSE);
406     Id4Length = strlen(Id4) + 1;
407     DPRINT("PdoHandleQueryHardwareId HardwareId4 %s\n", Id4);
408 
409     // generate id 5
410     // VendorId(8)_ProductId(16)_Revision(1)
411     RtlZeroMemory(Id5, sizeof(Id5));
412     Offset = 0;
413     Offset = CopyField(InquiryData->VendorId, &Id5[Offset], 8, '_', FALSE);
414     Offset += CopyField(InquiryData->ProductId, &Id5[Offset], 16, '_', FALSE);
415     Offset += CopyField(InquiryData->ProductRevisionLevel, &Id5[Offset], 1, '_', FALSE);
416     Id5Length = strlen(Id5) + 1;
417     DPRINT("PdoHandleQueryHardwareId HardwareId5 %s\n", Id5);
418 
419     // generate id 6
420     // SCSIType
421     RtlZeroMemory(Id6, sizeof(Id6));
422     Offset = 0;
423     Offset = sprintf(&Id6[Offset], GenericType);
424     Id6Length = strlen(Id6) + 1;
425     DPRINT("PdoHandleQueryHardwareId HardwareId6 %s\n", Id6);
426 
427     TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + 1;
428 
429     Buffer = ExAllocatePoolWithTag(PagedPool, TotalLength * sizeof(WCHAR), TAG_SCSIPORT);
430     if (!Buffer)
431     {
432         Irp->IoStatus.Information = 0;
433         return STATUS_INSUFFICIENT_RESOURCES;
434     }
435 
436     // reset offset
437     Offset = 0;
438     Length = TotalLength;
439 
440     ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset);
441     ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset);
442     ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset);
443     ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset);
444     ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset);
445     ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset);
446 
447     Buffer[Offset] = UNICODE_NULL;
448 
449     ASSERT(Offset + 1 == Length);
450 
451     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
452     return STATUS_SUCCESS;
453 }
454 
455 static
456 NTSTATUS
PdoHandleQueryCompatibleId(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)457 PdoHandleQueryCompatibleId(
458     _In_ PDEVICE_OBJECT DeviceObject,
459     _Inout_ PIRP Irp)
460 {
461     PSCSI_PORT_LUN_EXTENSION PDODeviceExtension = DeviceObject->DeviceExtension;
462     CHAR Buffer[100] = {0};
463     ULONG Length, Offset;
464     LPWSTR InstanceId;
465     LPCSTR DeviceType;
466 
467     DeviceType = GetDeviceType(&PDODeviceExtension->InquiryData);
468 
469     // format instance id
470     Length = sprintf(Buffer, "SCSI\\%s", DeviceType) + 1;
471     Length += sprintf(&Buffer[Length], "SCSI\\%s", "RAW") + 2;
472 
473     InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_SCSIPORT);
474     if (!InstanceId)
475     {
476         Irp->IoStatus.Information = 0;
477         return STATUS_INSUFFICIENT_RESOURCES;
478     }
479 
480     ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset);
481     ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset);
482 
483     InstanceId[Offset] = UNICODE_NULL;
484 
485     DPRINT("PdoHandleQueryCompatibleId %S\n", InstanceId);
486 
487     Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
488     return STATUS_SUCCESS;
489 }
490 
491 static
492 NTSTATUS
PdoHandleQueryInstanceId(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)493 PdoHandleQueryInstanceId(
494     _In_ PDEVICE_OBJECT DeviceObject,
495     _Inout_ PIRP Irp)
496 {
497     PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension;
498     WCHAR Buffer[26];
499     ULONG Length;
500     LPWSTR InstanceId;
501 
502     // use instance count and LUN
503     swprintf(Buffer, L"%x%x%x", lunExt->PathId, lunExt->TargetId, lunExt->Lun);
504 
505     Length = wcslen(Buffer) + 1;
506 
507     InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_SCSIPORT);
508     if (!InstanceId)
509     {
510         Irp->IoStatus.Information = 0;
511         return STATUS_INSUFFICIENT_RESOURCES;
512     }
513 
514     wcscpy(InstanceId, Buffer);
515 
516     DPRINT("PdoHandleQueryInstanceId %S\n", InstanceId);
517 
518     Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
519     return STATUS_SUCCESS;
520 }
521 
522 static
523 NTSTATUS
PdoHandleDeviceRelations(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)524 PdoHandleDeviceRelations(
525     _In_ PDEVICE_OBJECT DeviceObject,
526     _Inout_ PIRP Irp)
527 {
528     PDEVICE_RELATIONS deviceRelations;
529     PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
530 
531     // check if relation type is BusRelations
532     if (ioStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
533     {
534         // PDO handles only target device relation
535         return Irp->IoStatus.Status;
536     }
537 
538     deviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), TAG_SCSIPORT);
539     if (!deviceRelations)
540     {
541         return STATUS_INSUFFICIENT_RESOURCES;
542     }
543 
544     // initialize device relations
545     deviceRelations->Count = 1;
546     deviceRelations->Objects[0] = DeviceObject;
547     ObReferenceObject(DeviceObject);
548 
549     Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
550     return STATUS_SUCCESS;
551 }
552 
553 NTSTATUS
PdoDispatchPnp(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)554 PdoDispatchPnp(
555     _In_ PDEVICE_OBJECT DeviceObject,
556     _Inout_ PIRP Irp)
557 {
558     PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
559     PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension;
560     NTSTATUS status;
561 
562     DPRINT("PDO PnP request %s\n", GetIRPMinorFunctionString(ioStack->MinorFunction));
563 
564     ASSERT(!lunExt->Common.IsFDO);
565 
566     switch (ioStack->MinorFunction)
567     {
568         case IRP_MN_START_DEVICE:
569         {
570             RegistryInitLunKey(lunExt);
571             status = STATUS_SUCCESS;
572             break;
573         }
574         case IRP_MN_REMOVE_DEVICE:
575         case IRP_MN_QUERY_CAPABILITIES:
576         case IRP_MN_QUERY_REMOVE_DEVICE:
577         case IRP_MN_QUERY_STOP_DEVICE:
578         case IRP_MN_SURPRISE_REMOVAL:
579         {
580             status = STATUS_SUCCESS;
581             break;
582         }
583         case IRP_MN_QUERY_DEVICE_RELATIONS:
584         {
585             status = PdoHandleDeviceRelations(DeviceObject, Irp);
586             break;
587         }
588         case IRP_MN_QUERY_DEVICE_TEXT:
589         {
590             status = PdoHandleQueryDeviceText(DeviceObject, Irp);
591             break;
592         }
593         case IRP_MN_QUERY_ID:
594         {
595             DPRINT("IRP_MN_QUERY_ID IdType %s\n",
596                 DbgGetDeviceIDString(ioStack->Parameters.QueryId.IdType));
597 
598            if (ioStack->Parameters.QueryId.IdType == BusQueryDeviceID)
599            {
600                status = PdoHandleQueryDeviceId(DeviceObject, Irp);
601                break;
602            }
603            else if (ioStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
604            {
605                status = PdoHandleQueryHardwareId(DeviceObject, Irp);
606                break;
607            }
608            else if (ioStack->Parameters.QueryId.IdType == BusQueryInstanceID)
609            {
610                status = PdoHandleQueryInstanceId(DeviceObject, Irp);
611                break;
612            }
613            else if (ioStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
614            {
615                status = PdoHandleQueryCompatibleId(DeviceObject, Irp);
616                break;
617            }
618 
619            // fallthrough
620         }
621         default:
622         {
623             // do nothing
624             status = Irp->IoStatus.Status;
625         }
626     }
627 
628     if (status != STATUS_PENDING)
629     {
630         Irp->IoStatus.Status = status;
631         IoCompleteRequest(Irp, IO_NO_INCREMENT);
632     }
633 
634     return status;
635 }
636