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