984296214cf6b783f229a93ac1cba9524658dc51
[reactos.git] / drivers / usb / usbstor / disk.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: USB block storage device driver.
5 * COPYRIGHT: 2005-2006 James Tabor
6 * 2011-2012 Michael Martin (michael.martin@reactos.org)
7 * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbstor.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 NTSTATUS
17 USBSTOR_HandleInternalDeviceControl(
18 IN PDEVICE_OBJECT DeviceObject,
19 IN PIRP Irp)
20 {
21 PIO_STACK_LOCATION IoStack;
22 PSCSI_REQUEST_BLOCK Request;
23 PPDO_DEVICE_EXTENSION PDODeviceExtension;
24 NTSTATUS Status;
25
26 IoStack = IoGetCurrentIrpStackLocation(Irp);
27 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
28 ASSERT(Request);
29 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
30 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
31
32 switch(Request->Function)
33 {
34 case SRB_FUNCTION_EXECUTE_SCSI:
35 {
36 DPRINT("SRB_FUNCTION_EXECUTE_SCSI\n");
37
38 // check if request is valid
39 if (Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT))
40 {
41 // data is transferred with this irp
42 if ((Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) == (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) ||
43 Request->DataTransferLength == 0 ||
44 Irp->MdlAddress == NULL)
45 {
46 Status = STATUS_INVALID_PARAMETER;
47 break;
48 }
49 }
50 else
51 {
52 // sense buffer request
53 if (Request->DataTransferLength || Request->DataBuffer || Irp->MdlAddress)
54 {
55 Status = STATUS_INVALID_PARAMETER;
56 break;
57 }
58 }
59
60 // add the request
61 if (!USBSTOR_QueueAddIrp(PDODeviceExtension->LowerDeviceObject, Irp))
62 {
63 IoStartPacket(PDODeviceExtension->LowerDeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);
64 }
65
66 return STATUS_PENDING;
67 }
68 case SRB_FUNCTION_RELEASE_DEVICE:
69 {
70 DPRINT1("SRB_FUNCTION_RELEASE_DEVICE\n");
71 ASSERT(PDODeviceExtension->Claimed == TRUE);
72
73 // release claim
74 PDODeviceExtension->Claimed = FALSE;
75 Status = STATUS_SUCCESS;
76 break;
77 }
78 case SRB_FUNCTION_CLAIM_DEVICE:
79 {
80 DPRINT1("SRB_FUNCTION_CLAIM_DEVICE\n");
81
82 // check if the device has been claimed
83 if (PDODeviceExtension->Claimed)
84 {
85 // device has already been claimed
86 Status = STATUS_DEVICE_BUSY;
87 Request->SrbStatus = SRB_STATUS_BUSY;
88 break;
89 }
90
91 // claim device
92 PDODeviceExtension->Claimed = TRUE;
93
94 // output device object
95 Request->DataBuffer = DeviceObject;
96
97 Status = STATUS_SUCCESS;
98 break;
99 }
100 case SRB_FUNCTION_RELEASE_QUEUE:
101 {
102 DPRINT1("SRB_FUNCTION_RELEASE_QUEUE\n");
103
104 USBSTOR_QueueRelease(PDODeviceExtension->LowerDeviceObject);
105
106 Request->SrbStatus = SRB_STATUS_SUCCESS;
107 Status = STATUS_SUCCESS;
108 break;
109 }
110
111 case SRB_FUNCTION_SHUTDOWN:
112 case SRB_FUNCTION_FLUSH:
113 case SRB_FUNCTION_FLUSH_QUEUE:
114 {
115 DPRINT1("SRB_FUNCTION_FLUSH / SRB_FUNCTION_FLUSH_QUEUE / SRB_FUNCTION_SHUTDOWN\n");
116
117 // HACK: don't flush pending requests
118 #if 0 // we really need a proper storage stack
119 //
120 // wait for pending requests to finish
121 //
122 USBSTOR_QueueWaitForPendingRequests(PDODeviceExtension->LowerDeviceObject);
123 #endif
124
125 Request->SrbStatus = SRB_STATUS_SUCCESS;
126 Status = STATUS_SUCCESS;
127 break;
128 }
129 default:
130 {
131 //
132 // not supported
133 //
134 Status = STATUS_NOT_SUPPORTED;
135 Request->SrbStatus = SRB_STATUS_ERROR;
136 }
137 }
138
139 Irp->IoStatus.Status = Status;
140 IoCompleteRequest(Irp, IO_NO_INCREMENT);
141 return Status;
142 }
143
144 ULONG
145 USBSTOR_GetFieldLength(
146 IN PUCHAR Name,
147 IN ULONG MaxLength)
148 {
149 ULONG Index;
150 ULONG LastCharacterPosition = 0;
151
152 // scan the field and return last position which contains a valid character
153 for(Index = 0; Index < MaxLength; Index++)
154 {
155 if (Name[Index] != ' ')
156 {
157 // trim white spaces from field
158 LastCharacterPosition = Index;
159 }
160 }
161
162 // convert from zero based index to length
163 return LastCharacterPosition + 1;
164 }
165
166 NTSTATUS
167 USBSTOR_HandleQueryProperty(
168 IN PDEVICE_OBJECT DeviceObject,
169 IN PIRP Irp)
170 {
171 PIO_STACK_LOCATION IoStack;
172 PSTORAGE_PROPERTY_QUERY PropertyQuery;
173 PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader;
174 PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor;
175 ULONG FieldLengthVendor, FieldLengthProduct, FieldLengthRevision, TotalLength, FieldLengthSerialNumber;
176 PPDO_DEVICE_EXTENSION PDODeviceExtension;
177 PINQUIRYDATA InquiryData;
178 PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor;
179 PUCHAR Buffer;
180 PFDO_DEVICE_EXTENSION FDODeviceExtension;
181 UNICODE_STRING SerialNumber;
182 ANSI_STRING AnsiString;
183 NTSTATUS Status;
184
185 DPRINT("USBSTOR_HandleQueryProperty\n");
186
187 IoStack = IoGetCurrentIrpStackLocation(Irp);
188 ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY));
189 ASSERT(Irp->AssociatedIrp.SystemBuffer);
190
191 PropertyQuery = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
192
193 // check property type
194 if (PropertyQuery->PropertyId != StorageDeviceProperty &&
195 PropertyQuery->PropertyId != StorageAdapterProperty)
196 {
197 // only device property / adapter property are supported
198 return STATUS_INVALID_PARAMETER_1;
199 }
200
201 // check query type
202 if (PropertyQuery->QueryType == PropertyExistsQuery)
203 {
204 // device property / adapter property is supported
205 return STATUS_SUCCESS;
206 }
207
208 if (PropertyQuery->QueryType != PropertyStandardQuery)
209 {
210 // only standard query and exists query are supported
211 return STATUS_INVALID_PARAMETER_2;
212 }
213
214 // check if it is a device property
215 if (PropertyQuery->PropertyId == StorageDeviceProperty)
216 {
217 DPRINT("USBSTOR_HandleQueryProperty StorageDeviceProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
218
219 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
220 ASSERT(PDODeviceExtension);
221 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
222
223 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
224 ASSERT(FDODeviceExtension);
225 ASSERT(FDODeviceExtension->Common.IsFDO);
226
227 InquiryData = PDODeviceExtension->InquiryData;
228 ASSERT(InquiryData);
229
230 // compute extra parameters length
231 FieldLengthVendor = USBSTOR_GetFieldLength(InquiryData->VendorId, 8);
232 FieldLengthProduct = USBSTOR_GetFieldLength(InquiryData->ProductId, 16);
233 FieldLengthRevision = USBSTOR_GetFieldLength(InquiryData->ProductRevisionLevel, 4);
234
235 if (FDODeviceExtension->SerialNumber)
236 {
237 FieldLengthSerialNumber = wcslen(FDODeviceExtension->SerialNumber->bString);
238 }
239 else
240 {
241 FieldLengthSerialNumber = 0;
242 }
243
244 // total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1
245 // -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data
246 TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3;
247
248 // check if output buffer is long enough
249 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < TotalLength)
250 {
251 // buffer too small
252 DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
253 ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER));
254
255 // return required size
256 DescriptorHeader->Version = TotalLength;
257 DescriptorHeader->Size = TotalLength;
258
259 Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
260 return STATUS_SUCCESS;
261 }
262
263 // initialize the device descriptor
264 DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
265
266 DeviceDescriptor->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
267 DeviceDescriptor->Size = TotalLength;
268 DeviceDescriptor->DeviceType = InquiryData->DeviceType;
269 DeviceDescriptor->DeviceTypeModifier = InquiryData->DeviceTypeModifier;
270 DeviceDescriptor->RemovableMedia = InquiryData->RemovableMedia;
271 DeviceDescriptor->CommandQueueing = FALSE;
272 DeviceDescriptor->BusType = BusTypeUsb;
273 DeviceDescriptor->VendorIdOffset = sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR);
274 DeviceDescriptor->ProductIdOffset = DeviceDescriptor->VendorIdOffset + FieldLengthVendor + 1;
275 DeviceDescriptor->ProductRevisionOffset = DeviceDescriptor->ProductIdOffset + FieldLengthProduct + 1;
276 DeviceDescriptor->SerialNumberOffset = (FieldLengthSerialNumber > 0 ? DeviceDescriptor->ProductRevisionOffset + FieldLengthRevision + 1 : 0);
277 DeviceDescriptor->RawPropertiesLength = FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3 + (FieldLengthSerialNumber > 0 ? + 1 : 0);
278
279 // copy descriptors
280 Buffer = (PUCHAR)((ULONG_PTR)DeviceDescriptor + sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR));
281
282 RtlCopyMemory(Buffer, InquiryData->VendorId, FieldLengthVendor);
283 Buffer[FieldLengthVendor] = '\0';
284 Buffer += FieldLengthVendor + 1;
285
286 RtlCopyMemory(Buffer, InquiryData->ProductId, FieldLengthProduct);
287 Buffer[FieldLengthProduct] = '\0';
288 Buffer += FieldLengthProduct + 1;
289
290 RtlCopyMemory(Buffer, InquiryData->ProductRevisionLevel, FieldLengthRevision);
291 Buffer[FieldLengthRevision] = '\0';
292 Buffer += FieldLengthRevision + 1;
293
294 if (FieldLengthSerialNumber)
295 {
296 RtlInitUnicodeString(&SerialNumber, FDODeviceExtension->SerialNumber->bString);
297
298 AnsiString.Buffer = (PCHAR)Buffer;
299 AnsiString.Length = 0;
300 AnsiString.MaximumLength = FieldLengthSerialNumber * sizeof(WCHAR);
301
302 Status = RtlUnicodeStringToAnsiString(&AnsiString, &SerialNumber, FALSE);
303 ASSERT(Status == STATUS_SUCCESS);
304 }
305
306 DPRINT("Vendor %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->VendorIdOffset));
307 DPRINT("Product %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductIdOffset));
308 DPRINT("Revision %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductRevisionOffset));
309 DPRINT("Serial %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->SerialNumberOffset));
310
311 Irp->IoStatus.Information = TotalLength;
312 return STATUS_SUCCESS;
313 }
314 else
315 {
316 // adapter property query request
317
318 DPRINT("USBSTOR_HandleQueryProperty StorageAdapterProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
319
320 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_ADAPTER_DESCRIPTOR))
321 {
322 // buffer too small
323 DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
324 ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER));
325
326 // return required size
327 DescriptorHeader->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
328 DescriptorHeader->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
329
330 Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
331 return STATUS_SUCCESS;
332 }
333
334 // get adapter descriptor, information is returned in the same buffer
335 AdapterDescriptor = (PSTORAGE_ADAPTER_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
336
337 // fill out descriptor
338 AdapterDescriptor->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
339 AdapterDescriptor->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
340 AdapterDescriptor->MaximumTransferLength = MAXULONG; //FIXME compute some sane value
341 AdapterDescriptor->MaximumPhysicalPages = 25; //FIXME compute some sane value
342 AdapterDescriptor->AlignmentMask = 0;
343 AdapterDescriptor->AdapterUsesPio = FALSE;
344 AdapterDescriptor->AdapterScansDown = FALSE;
345 AdapterDescriptor->CommandQueueing = FALSE;
346 AdapterDescriptor->AcceleratedTransfer = FALSE;
347 AdapterDescriptor->BusType = BusTypeUsb;
348 AdapterDescriptor->BusMajorVersion = 0x2; //FIXME verify
349 AdapterDescriptor->BusMinorVersion = 0x00; //FIXME
350
351 // store returned length
352 Irp->IoStatus.Information = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
353
354 return STATUS_SUCCESS;
355 }
356 }
357
358 NTSTATUS
359 USBSTOR_HandleDeviceControl(
360 IN PDEVICE_OBJECT DeviceObject,
361 IN PIRP Irp)
362 {
363 PIO_STACK_LOCATION IoStack;
364 NTSTATUS Status;
365 PPDO_DEVICE_EXTENSION PDODeviceExtension;
366 PSCSI_ADAPTER_BUS_INFO BusInfo;
367 PSCSI_INQUIRY_DATA ScsiInquiryData;
368 PINQUIRYDATA InquiryData;
369
370 IoStack = IoGetCurrentIrpStackLocation(Irp);
371
372 switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
373 {
374 case IOCTL_STORAGE_QUERY_PROPERTY:
375 Status = USBSTOR_HandleQueryProperty(DeviceObject, Irp);
376 break;
377 case IOCTL_SCSI_PASS_THROUGH:
378 DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH NOT implemented\n");
379 Status = STATUS_NOT_SUPPORTED;
380 break;
381 case IOCTL_SCSI_PASS_THROUGH_DIRECT:
382 DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH_DIRECT NOT implemented\n");
383 Status = STATUS_NOT_SUPPORTED;
384 break;
385 case IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER:
386 DPRINT1("USBSTOR_HandleDeviceControl IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER NOT implemented\n");
387 Status = STATUS_NOT_SUPPORTED;
388 break;
389 case IOCTL_SCSI_GET_CAPABILITIES:
390 {
391 PIO_SCSI_CAPABILITIES Capabilities;
392
393 // Legacy port capability query
394 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
395 {
396 Capabilities = *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = ExAllocatePoolWithTag(NonPagedPool,
397 sizeof(IO_SCSI_CAPABILITIES),
398 USB_STOR_TAG);
399 Irp->IoStatus.Information = sizeof(PVOID);
400 }
401 else
402 {
403 Capabilities = Irp->AssociatedIrp.SystemBuffer;
404 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
405 }
406
407 if (Capabilities)
408 {
409 Capabilities->MaximumTransferLength = MAXULONG;
410 Capabilities->MaximumPhysicalPages = 25;
411 Capabilities->SupportedAsynchronousEvents = 0;
412 Capabilities->AlignmentMask = 0;
413 Capabilities->TaggedQueuing = FALSE;
414 Capabilities->AdapterScansDown = FALSE;
415 Capabilities->AdapterUsesPio = FALSE;
416 Status = STATUS_SUCCESS;
417 }
418 else
419 {
420 Status = STATUS_INSUFFICIENT_RESOURCES;
421 }
422
423 break;
424 }
425 case IOCTL_SCSI_GET_INQUIRY_DATA:
426 {
427 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
428 ASSERT(PDODeviceExtension);
429 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
430
431 // get parameters
432 BusInfo = Irp->AssociatedIrp.SystemBuffer;
433 ScsiInquiryData = (PSCSI_INQUIRY_DATA)(BusInfo + 1);
434 InquiryData = (PINQUIRYDATA)ScsiInquiryData->InquiryData;
435
436
437 BusInfo->NumberOfBuses = 1;
438 BusInfo->BusData[0].NumberOfLogicalUnits = 1; //FIXME
439 BusInfo->BusData[0].InitiatorBusId = 0;
440 BusInfo->BusData[0].InquiryDataOffset = sizeof(SCSI_ADAPTER_BUS_INFO);
441
442 ScsiInquiryData->PathId = 0;
443 ScsiInquiryData->TargetId = 0;
444 ScsiInquiryData->Lun = PDODeviceExtension->LUN & MAX_LUN;
445 ScsiInquiryData->DeviceClaimed = PDODeviceExtension->Claimed;
446 ScsiInquiryData->InquiryDataLength = sizeof(INQUIRYDATA);
447 ScsiInquiryData->NextInquiryDataOffset = 0;
448
449 // Note: INQUIRYDATA structure is larger than INQUIRYDATABUFFERSIZE
450 RtlZeroMemory(InquiryData, sizeof(INQUIRYDATA));
451 RtlCopyMemory(InquiryData, PDODeviceExtension->InquiryData, INQUIRYDATABUFFERSIZE);
452
453 InquiryData->Versions = 0x04;
454 InquiryData->ResponseDataFormat = 0x02; // some devices set this to 1
455
456 Irp->IoStatus.Information = sizeof(SCSI_ADAPTER_BUS_INFO) + sizeof(SCSI_INQUIRY_DATA) + sizeof(INQUIRYDATA) - 1;
457 Status = STATUS_SUCCESS;
458
459 break;
460 }
461 case IOCTL_SCSI_GET_ADDRESS:
462 {
463 PSCSI_ADDRESS Address = Irp->AssociatedIrp.SystemBuffer;
464
465 Address->Length = sizeof(SCSI_ADDRESS);
466 Address->PortNumber = 0;
467 Address->PathId = 0;
468 Address->TargetId = 0;
469 Address->Lun = (((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LUN & MAX_LUN);
470 Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
471
472 Status = STATUS_SUCCESS;
473
474 break;
475 }
476 default:
477 DPRINT("USBSTOR_HandleDeviceControl IoControl %x not supported\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
478 Status = STATUS_NOT_SUPPORTED;
479 break;
480 }
481
482 return Status;
483 }