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