xref: /reactos/drivers/storage/port/scsiport/ioctl.c (revision fc3ccb39)
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:     IOCTL handlers
5  * COPYRIGHT:   Eric Kohl (eric.kohl@reactos.org)
6  *              Aleksey Bragin (aleksey@reactos.org)
7  */
8 
9 #include "scsiport.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 
15 static
16 NTSTATUS
17 SpiGetInquiryData(
18     _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
19     _In_ PIRP Irp)
20 {
21     ULONG InquiryDataSize;
22     PSCSI_LUN_INFO LunInfo;
23     ULONG BusCount, LunCount, Length;
24     PIO_STACK_LOCATION IrpStack;
25     PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
26     PSCSI_INQUIRY_DATA InquiryData;
27     PSCSI_BUS_DATA BusData;
28     ULONG Bus;
29     PUCHAR Buffer;
30 
31     DPRINT("SpiGetInquiryData() called\n");
32 
33     /* Get pointer to the buffer */
34     IrpStack = IoGetCurrentIrpStackLocation(Irp);
35     Buffer = Irp->AssociatedIrp.SystemBuffer;
36 
37     /* Initialize bus and LUN counters */
38     BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
39     LunCount = 0;
40 
41     /* Calculate total number of LUNs */
42     for (Bus = 0; Bus < BusCount; Bus++)
43         LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
44 
45     /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
46     InquiryDataSize =
47         ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
48         sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
49 
50     /* Calculate data size */
51     Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * sizeof(SCSI_BUS_DATA);
52 
53     Length += InquiryDataSize * LunCount;
54 
55     /* Check, if all data is going to fit into provided buffer */
56     if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
57     {
58         Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
59         return STATUS_BUFFER_TOO_SMALL;
60     }
61 
62     /* Store data size in the IRP */
63     Irp->IoStatus.Information = Length;
64 
65     DPRINT("Data size: %lu\n", Length);
66 
67     AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
68 
69     AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
70 
71     /* Point InquiryData to the corresponding place inside Buffer */
72     InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
73                     (BusCount - 1) * sizeof(SCSI_BUS_DATA));
74 
75     /* Loop each bus */
76     for (Bus = 0; Bus < BusCount; Bus++)
77     {
78         BusData = &AdapterBusInfo->BusData[Bus];
79 
80         /* Calculate and save an offset of the inquiry data */
81         BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer);
82 
83         /* Get a pointer to the LUN information structure */
84         LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
85 
86         /* Store Initiator Bus Id */
87         BusData->InitiatorBusId =
88             DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
89 
90         /* Store LUN count */
91         BusData->NumberOfLogicalUnits =
92             DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
93 
94         /* Loop all LUNs */
95         while (LunInfo != NULL)
96         {
97             DPRINT("(Bus %lu Target %lu Lun %lu)\n",
98                    Bus, LunInfo->TargetId, LunInfo->Lun);
99 
100             /* Fill InquiryData with values */
101             InquiryData->PathId = LunInfo->PathId;
102             InquiryData->TargetId = LunInfo->TargetId;
103             InquiryData->Lun = LunInfo->Lun;
104             InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
105             InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
106             InquiryData->NextInquiryDataOffset =
107                 (ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
108 
109             /* Copy data in it */
110             RtlCopyMemory(InquiryData->InquiryData,
111                           LunInfo->InquiryData,
112                           INQUIRYDATABUFFERSIZE);
113 
114             /* Move to the next LUN */
115             LunInfo = LunInfo->Next;
116             InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
117         }
118 
119         /* Either mark the end, or set offset to 0 */
120         if (BusData->NumberOfLogicalUnits != 0)
121             ((PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
122         else
123             BusData->InquiryDataOffset = 0;
124     }
125 
126     /* Finish with success */
127     Irp->IoStatus.Status = STATUS_SUCCESS;
128     return STATUS_SUCCESS;
129 }
130 
131 /**********************************************************************
132  * NAME                         INTERNAL
133  *  ScsiPortDeviceControl
134  *
135  * DESCRIPTION
136  *  Answer requests for device control calls
137  *
138  * RUN LEVEL
139  *  PASSIVE_LEVEL
140  *
141  * ARGUMENTS
142  *  Standard dispatch arguments
143  *
144  * RETURNS
145  *  NTSTATUS
146  */
147 
148 NTSTATUS
149 NTAPI
150 ScsiPortDeviceControl(
151     _In_ PDEVICE_OBJECT DeviceObject,
152     _In_ PIRP Irp)
153 {
154     PIO_STACK_LOCATION Stack;
155     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
156     PDUMP_POINTERS DumpPointers;
157     NTSTATUS Status;
158 
159     DPRINT("ScsiPortDeviceControl()\n");
160 
161     Irp->IoStatus.Information = 0;
162 
163     Stack = IoGetCurrentIrpStackLocation(Irp);
164     DeviceExtension = DeviceObject->DeviceExtension;
165 
166     switch (Stack->Parameters.DeviceIoControl.IoControlCode)
167     {
168       case IOCTL_SCSI_GET_DUMP_POINTERS:
169         DPRINT("  IOCTL_SCSI_GET_DUMP_POINTERS\n");
170 
171         if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS))
172         {
173           Status = STATUS_BUFFER_OVERFLOW;
174           Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
175           break;
176         }
177 
178         DumpPointers = Irp->AssociatedIrp.SystemBuffer;
179         DumpPointers->DeviceObject = DeviceObject;
180         /* More data.. ? */
181 
182         Status = STATUS_SUCCESS;
183         Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
184         break;
185 
186       case IOCTL_SCSI_GET_CAPABILITIES:
187         DPRINT("  IOCTL_SCSI_GET_CAPABILITIES\n");
188         if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
189         {
190             *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
191 
192             Irp->IoStatus.Information = sizeof(PVOID);
193             Status = STATUS_SUCCESS;
194             break;
195         }
196 
197         if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
198         {
199             Status = STATUS_BUFFER_TOO_SMALL;
200             break;
201         }
202 
203         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
204                       &DeviceExtension->PortCapabilities,
205                       sizeof(IO_SCSI_CAPABILITIES));
206 
207         Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
208         Status = STATUS_SUCCESS;
209         break;
210 
211       case IOCTL_SCSI_GET_INQUIRY_DATA:
212           DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
213 
214           /* Copy inquiry data to the port device extension */
215           Status = SpiGetInquiryData(DeviceExtension, Irp);
216           break;
217 
218       case IOCTL_SCSI_MINIPORT:
219           DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
220           Status = STATUS_NOT_IMPLEMENTED;
221           break;
222 
223       case IOCTL_SCSI_PASS_THROUGH:
224           DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
225           Status = STATUS_NOT_IMPLEMENTED;
226           break;
227 
228       default:
229           if (DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode) == MOUNTDEVCONTROLTYPE)
230           {
231             switch (Stack->Parameters.DeviceIoControl.IoControlCode)
232             {
233             case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
234                 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
235                 break;
236             case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
237                 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n");
238                 break;
239             default:
240                 DPRINT("  got ioctl intended for the mount manager: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
241                 break;
242             }
243           } else {
244             DPRINT1("  unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
245           }
246           Status = STATUS_NOT_IMPLEMENTED;
247           break;
248     }
249 
250     /* Complete the request with the given status */
251     Irp->IoStatus.Status = Status;
252     IoCompleteRequest(Irp, IO_NO_INCREMENT);
253 
254     return Status;
255 }
256