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 * 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
19 _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
22 ULONG InquiryDataSize
;
23 ULONG BusCount
, Length
;
24 PIO_STACK_LOCATION IrpStack
;
25 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
26 PSCSI_INQUIRY_DATA InquiryData
;
29 DPRINT("SpiGetInquiryData() called\n");
31 /* Get pointer to the buffer */
32 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
33 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
35 /* Initialize bus and LUN counters */
36 BusCount
= DeviceExtension
->NumberOfBuses
;
38 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
39 InquiryDataSize
= ALIGN_UP(sizeof(SCSI_INQUIRY_DATA
) - 1 + INQUIRYDATABUFFERSIZE
, ULONG
);
41 /* Calculate data size */
42 Length
= sizeof(SCSI_ADAPTER_BUS_INFO
) + (BusCount
- 1) * sizeof(SCSI_BUS_DATA
);
44 Length
+= InquiryDataSize
* DeviceExtension
->TotalLUCount
;
46 /* Check, if all data is going to fit into provided buffer */
47 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< Length
)
49 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
50 return STATUS_BUFFER_TOO_SMALL
;
53 /* Store data size in the IRP */
54 Irp
->IoStatus
.Information
= Length
;
56 DPRINT("Data size: %lu\n", Length
);
58 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
60 AdapterBusInfo
->NumberOfBuses
= (UCHAR
)BusCount
;
62 /* Point InquiryData to the corresponding place inside Buffer */
63 InquiryData
= (PSCSI_INQUIRY_DATA
)(Buffer
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
64 (BusCount
- 1) * sizeof(SCSI_BUS_DATA
));
67 for (UINT8 pathId
= 0; pathId
< DeviceExtension
->NumberOfBuses
; pathId
++)
69 PSCSI_BUS_DATA BusData
= &AdapterBusInfo
->BusData
[pathId
];
71 /* Calculate and save an offset of the inquiry data */
72 BusData
->InquiryDataOffset
= (ULONG
)((PUCHAR
)InquiryData
- Buffer
);
74 /* Store Initiator Bus Id */
75 BusData
->InitiatorBusId
= DeviceExtension
->Buses
[pathId
].BusIdentifier
;
78 BusData
->NumberOfLogicalUnits
= DeviceExtension
->Buses
[pathId
].LogicalUnitsCount
;
81 PSCSI_BUS_INFO bus
= &DeviceExtension
->Buses
[pathId
];
83 for (PLIST_ENTRY lunEntry
= bus
->LunsListHead
.Flink
;
84 lunEntry
!= &bus
->LunsListHead
;
85 lunEntry
= lunEntry
->Flink
)
87 PSCSI_PORT_LUN_EXTENSION lunExt
=
88 CONTAINING_RECORD(lunEntry
, SCSI_PORT_LUN_EXTENSION
, LunEntry
);
90 DPRINT("(Bus %lu Target %lu Lun %lu)\n", pathId
, lunExt
->TargetId
, lunExt
->Lun
);
92 /* Fill InquiryData with values */
93 InquiryData
->PathId
= lunExt
->PathId
;
94 InquiryData
->TargetId
= lunExt
->TargetId
;
95 InquiryData
->Lun
= lunExt
->Lun
;
96 InquiryData
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
97 InquiryData
->DeviceClaimed
= lunExt
->DeviceClaimed
;
98 InquiryData
->NextInquiryDataOffset
=
99 (ULONG
)((PUCHAR
)InquiryData
+ InquiryDataSize
- Buffer
);
101 /* Copy data in it */
102 RtlCopyMemory(InquiryData
->InquiryData
,
103 &lunExt
->InquiryData
,
104 INQUIRYDATABUFFERSIZE
);
106 /* Move to the next LUN */
107 InquiryData
= (PSCSI_INQUIRY_DATA
) ((ULONG_PTR
)InquiryData
+ InquiryDataSize
);
110 /* Either mark the end, or set offset to 0 */
111 if (BusData
->NumberOfLogicalUnits
!= 0)
112 ((PSCSI_INQUIRY_DATA
) ((PCHAR
)InquiryData
- InquiryDataSize
))->NextInquiryDataOffset
= 0;
114 BusData
->InquiryDataOffset
= 0;
117 /* Finish with success */
118 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
119 return STATUS_SUCCESS
;
126 _In_ UINT32 MaxLength
)
129 UINT32 LastCharacterPosition
= 0;
131 // scan the field and return last position which contains a valid character
132 for (Index
= 0; Index
< MaxLength
; Index
++)
134 if (Name
[Index
] != ' ')
136 // trim white spaces from field
137 LastCharacterPosition
= Index
;
141 // convert from zero based index to length
142 return LastCharacterPosition
+ 1;
147 PdoHandleQueryProperty(
148 _In_ PDEVICE_OBJECT DeviceObject
,
151 PIO_STACK_LOCATION ioStack
= IoGetCurrentIrpStackLocation(Irp
);
152 PSCSI_PORT_LUN_EXTENSION lunExt
= DeviceObject
->DeviceExtension
;
155 ASSERT(ioStack
->Parameters
.DeviceIoControl
.InputBufferLength
>= sizeof(STORAGE_PROPERTY_QUERY
));
156 ASSERT(Irp
->AssociatedIrp
.SystemBuffer
);
157 ASSERT(!lunExt
->Common
.IsFDO
);
159 PSTORAGE_PROPERTY_QUERY PropertyQuery
= Irp
->AssociatedIrp
.SystemBuffer
;
161 // check property type
162 if (PropertyQuery
->PropertyId
!= StorageDeviceProperty
&&
163 PropertyQuery
->PropertyId
!= StorageAdapterProperty
)
165 // only device property / adapter property are supported
166 status
= STATUS_INVALID_PARAMETER_1
;
171 if (PropertyQuery
->QueryType
== PropertyExistsQuery
)
173 // device property / adapter property is supported
174 status
= STATUS_SUCCESS
;
178 if (PropertyQuery
->QueryType
!= PropertyStandardQuery
)
180 // only standard query and exists query are supported
181 status
= STATUS_INVALID_PARAMETER_2
;
185 switch (PropertyQuery
->PropertyId
)
187 case StorageDeviceProperty
:
189 PINQUIRYDATA inquiryData
= &lunExt
->InquiryData
;
191 // compute extra parameters length
192 UINT32 FieldLengthVendor
= GetFieldLength(inquiryData
->VendorId
, 8),
193 FieldLengthProduct
= GetFieldLength(inquiryData
->ProductId
, 16),
194 FieldLengthRevision
= GetFieldLength(inquiryData
->ProductRevisionLevel
, 4);
196 // total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1
197 // -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data
198 UINT32 TotalLength
= sizeof(STORAGE_DEVICE_DESCRIPTOR
)
201 + FieldLengthRevision
204 // check if output buffer is long enough
205 if (ioStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< TotalLength
)
208 PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader
= Irp
->AssociatedIrp
.SystemBuffer
;
209 ASSERT(ioStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>=
210 sizeof(STORAGE_DESCRIPTOR_HEADER
));
212 // return required size
213 DescriptorHeader
->Version
= TotalLength
;
214 DescriptorHeader
->Size
= TotalLength
;
216 Irp
->IoStatus
.Information
= sizeof(STORAGE_DESCRIPTOR_HEADER
);
217 status
= STATUS_SUCCESS
;
221 // initialize the device descriptor
222 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor
= Irp
->AssociatedIrp
.SystemBuffer
;
224 deviceDescriptor
->Version
= sizeof(STORAGE_DEVICE_DESCRIPTOR
);
225 deviceDescriptor
->Size
= TotalLength
;
226 deviceDescriptor
->DeviceType
= inquiryData
->DeviceType
;
227 deviceDescriptor
->DeviceTypeModifier
= inquiryData
->DeviceTypeModifier
;
228 deviceDescriptor
->RemovableMedia
= inquiryData
->RemovableMedia
;
229 deviceDescriptor
->CommandQueueing
= inquiryData
->CommandQueue
;
230 deviceDescriptor
->BusType
= BusTypeScsi
;
231 deviceDescriptor
->VendorIdOffset
=
232 FIELD_OFFSET(STORAGE_DEVICE_DESCRIPTOR
, RawDeviceProperties
);
233 deviceDescriptor
->ProductIdOffset
=
234 deviceDescriptor
->VendorIdOffset
+ FieldLengthVendor
+ 1;
235 deviceDescriptor
->ProductRevisionOffset
=
236 deviceDescriptor
->ProductIdOffset
+ FieldLengthProduct
+ 1;
237 deviceDescriptor
->SerialNumberOffset
= 0;
238 deviceDescriptor
->RawPropertiesLength
=
239 FieldLengthVendor
+ FieldLengthProduct
+ FieldLengthRevision
+ 3;
242 PUCHAR Buffer
= deviceDescriptor
->RawDeviceProperties
;
244 RtlCopyMemory(Buffer
, inquiryData
->VendorId
, FieldLengthVendor
);
245 Buffer
[FieldLengthVendor
] = '\0';
246 Buffer
+= FieldLengthVendor
+ 1;
248 RtlCopyMemory(Buffer
, inquiryData
->ProductId
, FieldLengthProduct
);
249 Buffer
[FieldLengthProduct
] = '\0';
250 Buffer
+= FieldLengthProduct
+ 1;
252 RtlCopyMemory(Buffer
, inquiryData
->ProductRevisionLevel
, FieldLengthRevision
);
253 Buffer
[FieldLengthRevision
] = '\0';
254 Buffer
+= FieldLengthRevision
+ 1;
256 DPRINT("Vendor %s\n",
257 (LPCSTR
)((ULONG_PTR
)deviceDescriptor
+ deviceDescriptor
->VendorIdOffset
));
258 DPRINT("Product %s\n",
259 (LPCSTR
)((ULONG_PTR
)deviceDescriptor
+ deviceDescriptor
->ProductIdOffset
));
260 DPRINT("Revision %s\n",
261 (LPCSTR
)((ULONG_PTR
)deviceDescriptor
+ deviceDescriptor
->ProductRevisionOffset
));
263 Irp
->IoStatus
.Information
= TotalLength
;
264 status
= STATUS_SUCCESS
;
267 case StorageAdapterProperty
:
269 // forward to the lower device
270 IoSkipCurrentIrpStackLocation(Irp
);
271 return IoCallDriver(lunExt
->Common
.LowerDevice
, Irp
);
273 case StorageDeviceIdProperty
:
280 status
= STATUS_NOT_IMPLEMENTED
;
286 Irp
->IoStatus
.Status
= status
;
287 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
293 FdoHandleQueryProperty(
294 _In_ PDEVICE_OBJECT DeviceObject
,
297 PIO_STACK_LOCATION ioStack
= IoGetCurrentIrpStackLocation(Irp
);
298 PSCSI_PORT_DEVICE_EXTENSION portExt
= DeviceObject
->DeviceExtension
;
301 ASSERT(ioStack
->Parameters
.DeviceIoControl
.InputBufferLength
>= sizeof(STORAGE_PROPERTY_QUERY
));
302 ASSERT(Irp
->AssociatedIrp
.SystemBuffer
);
303 ASSERT(portExt
->Common
.IsFDO
);
305 PSTORAGE_PROPERTY_QUERY PropertyQuery
= Irp
->AssociatedIrp
.SystemBuffer
;
307 // check property type (handle only StorageAdapterProperty)
308 if (PropertyQuery
->PropertyId
!= StorageAdapterProperty
)
310 if (PropertyQuery
->PropertyId
== StorageDeviceProperty
||
311 PropertyQuery
->PropertyId
== StorageDeviceIdProperty
)
313 status
= STATUS_INVALID_DEVICE_REQUEST
;
317 status
= STATUS_INVALID_PARAMETER_1
;
324 if (PropertyQuery
->QueryType
== PropertyExistsQuery
)
326 // device property / adapter property is supported
327 status
= STATUS_SUCCESS
;
331 if (PropertyQuery
->QueryType
!= PropertyStandardQuery
)
333 // only standard query and exists query are supported
334 status
= STATUS_INVALID_PARAMETER_2
;
338 if (ioStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8
))
341 PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader
= Irp
->AssociatedIrp
.SystemBuffer
;
342 ASSERT(ioStack
->Parameters
.DeviceIoControl
.OutputBufferLength
343 >= sizeof(STORAGE_DESCRIPTOR_HEADER
));
345 // return required size
346 DescriptorHeader
->Version
= sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8
);
347 DescriptorHeader
->Size
= sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8
);
349 Irp
->IoStatus
.Information
= sizeof(STORAGE_DESCRIPTOR_HEADER
);
350 status
= STATUS_SUCCESS
;
354 // get adapter descriptor, information is returned in the same buffer
355 PSTORAGE_ADAPTER_DESCRIPTOR_WIN8 adapterDescriptor
= Irp
->AssociatedIrp
.SystemBuffer
;
357 // fill out descriptor
358 // NOTE: STORAGE_ADAPTER_DESCRIPTOR_WIN8 may vary in size, so it's important to zero out
360 *adapterDescriptor
= (STORAGE_ADAPTER_DESCRIPTOR_WIN8
) {
361 .Version
= sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8
),
362 .Size
= sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8
),
363 .MaximumTransferLength
= portExt
->PortCapabilities
.MaximumTransferLength
,
364 .MaximumPhysicalPages
= portExt
->PortCapabilities
.MaximumPhysicalPages
,
365 .AlignmentMask
= portExt
->PortCapabilities
.AlignmentMask
,
366 .AdapterUsesPio
= portExt
->PortCapabilities
.AdapterUsesPio
,
367 .AdapterScansDown
= portExt
->PortCapabilities
.AdapterScansDown
,
368 .CommandQueueing
= portExt
->PortCapabilities
.TaggedQueuing
,
369 .AcceleratedTransfer
= TRUE
,
370 .BusType
= BusTypeScsi
, // FIXME
371 .BusMajorVersion
= 2,
375 // store returned length
376 Irp
->IoStatus
.Information
= sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8
);
377 status
= STATUS_SUCCESS
;
380 Irp
->IoStatus
.Status
= status
;
381 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
385 /**********************************************************************
387 * ScsiPortDeviceControl
390 * Answer requests for device control calls
396 * Standard dispatch arguments
404 ScsiPortDeviceControl(
405 _In_ PDEVICE_OBJECT DeviceObject
,
408 PIO_STACK_LOCATION Stack
;
409 PSCSI_PORT_COMMON_EXTENSION comExt
= DeviceObject
->DeviceExtension
;
410 PSCSI_PORT_DEVICE_EXTENSION portExt
;
411 PSCSI_PORT_LUN_EXTENSION lunExt
;
414 DPRINT("ScsiPortDeviceControl()\n");
416 Irp
->IoStatus
.Information
= 0;
418 Stack
= IoGetCurrentIrpStackLocation(Irp
);
420 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
422 case IOCTL_STORAGE_QUERY_PROPERTY
:
424 DPRINT(" IOCTL_STORAGE_QUERY_PROPERTY\n");
426 if (!VerifyIrpInBufferSize(Irp
, sizeof(STORAGE_PROPERTY_QUERY
)))
428 status
= STATUS_BUFFER_TOO_SMALL
;
433 return FdoHandleQueryProperty(DeviceObject
, Irp
);
435 return PdoHandleQueryProperty(DeviceObject
, Irp
);
437 case IOCTL_SCSI_GET_ADDRESS
:
439 DPRINT(" IOCTL_SCSI_GET_ADDRESS\n");
443 status
= STATUS_INVALID_DEVICE_REQUEST
;
447 PSCSI_ADDRESS address
= Irp
->AssociatedIrp
.SystemBuffer
;
448 if (!VerifyIrpOutBufferSize(Irp
, sizeof(*address
)))
450 status
= STATUS_BUFFER_TOO_SMALL
;
454 lunExt
= DeviceObject
->DeviceExtension
;
455 portExt
= comExt
->LowerDevice
->DeviceExtension
;
457 address
->Length
= sizeof(SCSI_ADDRESS
);
458 address
->PortNumber
= portExt
->PortNumber
;
459 address
->PathId
= lunExt
->PathId
;
460 address
->TargetId
= lunExt
->TargetId
;
461 address
->Lun
= lunExt
->Lun
;
463 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
464 status
= STATUS_SUCCESS
;
467 case IOCTL_SCSI_GET_DUMP_POINTERS
:
469 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
473 IoSkipCurrentIrpStackLocation(Irp
);
474 return IoCallDriver(comExt
->LowerDevice
, Irp
);
477 PDUMP_POINTERS dumpPointers
= Irp
->AssociatedIrp
.SystemBuffer
;
478 if (!VerifyIrpOutBufferSize(Irp
, sizeof(*dumpPointers
)))
480 status
= STATUS_BUFFER_TOO_SMALL
;
484 dumpPointers
->DeviceObject
= DeviceObject
;
487 status
= STATUS_SUCCESS
;
488 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
491 case IOCTL_SCSI_GET_CAPABILITIES
:
493 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
497 status
= STATUS_INVALID_DEVICE_REQUEST
;
501 if (!VerifyIrpOutBufferSize(Irp
, sizeof(IO_SCSI_CAPABILITIES
)))
503 status
= STATUS_BUFFER_TOO_SMALL
;
507 portExt
= DeviceObject
->DeviceExtension
;
509 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
,
510 &portExt
->PortCapabilities
,
511 sizeof(IO_SCSI_CAPABILITIES
));
513 status
= STATUS_SUCCESS
;
514 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
517 case IOCTL_SCSI_GET_INQUIRY_DATA
:
519 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
523 status
= STATUS_INVALID_DEVICE_REQUEST
;
527 /* Copy inquiry data to the port device extension */
528 status
= SpiGetInquiryData(DeviceObject
->DeviceExtension
, Irp
);
531 case IOCTL_SCSI_MINIPORT
:
532 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
533 status
= STATUS_NOT_IMPLEMENTED
;
536 case IOCTL_SCSI_PASS_THROUGH
:
537 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
538 status
= STATUS_NOT_IMPLEMENTED
;
542 DPRINT1("unknown ioctl code: 0x%lX\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
543 status
= STATUS_NOT_SUPPORTED
;
547 /* Complete the request with the given status */
548 Irp
->IoStatus
.Status
= status
;
549 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);