2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbstor/disk.c
5 * PURPOSE: USB block storage device driver.
8 * Michael Martin (michael.martin@reactos.org)
9 * Johannes Anderwald (johannes.anderwald@reactos.org)
18 USBSTOR_HandleInternalDeviceControl(
19 IN PDEVICE_OBJECT DeviceObject
,
22 PIO_STACK_LOCATION IoStack
;
23 PSCSI_REQUEST_BLOCK Request
;
24 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
28 // get current stack location
30 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
35 Request
= (PSCSI_REQUEST_BLOCK
)IoStack
->Parameters
.Others
.Argument1
;
43 // get device extension
45 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
50 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
52 switch(Request
->Function
)
54 case SRB_FUNCTION_EXECUTE_SCSI
:
56 DPRINT("SRB_FUNCTION_EXECUTE_SCSI\n");
59 // check if request is valid
61 if (Request
->SrbFlags
& (SRB_FLAGS_DATA_IN
| SRB_FLAGS_DATA_OUT
))
64 // data is transferred with this irp
66 if ((Request
->SrbFlags
& (SRB_FLAGS_DATA_IN
| SRB_FLAGS_DATA_OUT
)) == (SRB_FLAGS_DATA_IN
| SRB_FLAGS_DATA_OUT
) ||
67 Request
->DataTransferLength
== 0 ||
68 Irp
->MdlAddress
== NULL
)
73 Status
= STATUS_INVALID_PARAMETER
;
80 // sense buffer request
82 if (Request
->DataTransferLength
||
83 Request
->DataBuffer
||
89 Status
= STATUS_INVALID_PARAMETER
;
97 if (!USBSTOR_QueueAddIrp(PDODeviceExtension
->LowerDeviceObject
, Irp
))
100 // irp was not added to the queue
102 IoStartPacket(PDODeviceExtension
->LowerDeviceObject
, Irp
, &Request
->QueueSortKey
, USBSTOR_CancelIo
);
108 return STATUS_PENDING
;
110 case SRB_FUNCTION_RELEASE_DEVICE
:
112 DPRINT1("SRB_FUNCTION_RELEASE_DEVICE\n");
116 ASSERT(PDODeviceExtension
->Claimed
== TRUE
);
121 PDODeviceExtension
->Claimed
= FALSE
;
122 Status
= STATUS_SUCCESS
;
125 case SRB_FUNCTION_CLAIM_DEVICE
:
127 DPRINT1("SRB_FUNCTION_CLAIM_DEVICE\n");
129 // check if the device has been claimed
131 if (PDODeviceExtension
->Claimed
)
134 // device has already been claimed
136 Status
= STATUS_DEVICE_BUSY
;
137 Request
->SrbStatus
= SRB_STATUS_BUSY
;
144 PDODeviceExtension
->Claimed
= TRUE
;
147 // output device object
149 Request
->DataBuffer
= DeviceObject
;
152 // completed successfully
154 Status
= STATUS_SUCCESS
;
157 case SRB_FUNCTION_RELEASE_QUEUE
:
159 DPRINT1("SRB_FUNCTION_RELEASE_QUEUE\n");
164 USBSTOR_QueueRelease(PDODeviceExtension
->LowerDeviceObject
);
167 // set status success
169 Request
->SrbStatus
= SRB_STATUS_SUCCESS
;
170 Status
= STATUS_SUCCESS
;
174 case SRB_FUNCTION_SHUTDOWN
:
175 case SRB_FUNCTION_FLUSH
:
176 case SRB_FUNCTION_FLUSH_QUEUE
:
178 DPRINT1("SRB_FUNCTION_FLUSH / SRB_FUNCTION_FLUSH_QUEUE / SRB_FUNCTION_SHUTDOWN\n");
180 // HACK: don't flush pending requests
181 #if 0 // we really need a proper storage stack
183 // wait for pending requests to finish
185 USBSTOR_QueueWaitForPendingRequests(PDODeviceExtension
->LowerDeviceObject
);
188 // set status success
190 Request
->SrbStatus
= SRB_STATUS_SUCCESS
;
191 Status
= STATUS_SUCCESS
;
199 Status
= STATUS_NOT_SUPPORTED
;
200 Request
->SrbStatus
= SRB_STATUS_ERROR
;
207 Irp
->IoStatus
.Status
= Status
;
208 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
213 USBSTOR_GetFieldLength(
218 ULONG LastCharacterPosition
= 0;
221 // scan the field and return last positon which contains a valid character
223 for(Index
= 0; Index
< MaxLength
; Index
++)
225 if (Name
[Index
] != ' ')
228 // trim white spaces from field
230 LastCharacterPosition
= Index
;
235 // convert from zero based index to length
237 return LastCharacterPosition
+ 1;
241 USBSTOR_HandleQueryProperty(
242 IN PDEVICE_OBJECT DeviceObject
,
245 PIO_STACK_LOCATION IoStack
;
246 PSTORAGE_PROPERTY_QUERY PropertyQuery
;
247 PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader
;
248 PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor
;
249 ULONG FieldLengthVendor
, FieldLengthProduct
, FieldLengthRevision
, TotalLength
, FieldLengthSerialNumber
;
250 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
251 PUFI_INQUIRY_RESPONSE InquiryData
;
252 PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor
;
254 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
255 UNICODE_STRING SerialNumber
;
256 ANSI_STRING AnsiString
;
259 DPRINT("USBSTOR_HandleQueryProperty\n");
262 // get current stack location
264 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
269 ASSERT(IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
>= sizeof(STORAGE_PROPERTY_QUERY
));
270 ASSERT(Irp
->AssociatedIrp
.SystemBuffer
);
273 // get property query
275 PropertyQuery
= (PSTORAGE_PROPERTY_QUERY
)Irp
->AssociatedIrp
.SystemBuffer
;
278 // check property type
280 if (PropertyQuery
->PropertyId
!= StorageDeviceProperty
&&
281 PropertyQuery
->PropertyId
!= StorageAdapterProperty
)
284 // only device property / adapter property are supported
286 return STATUS_INVALID_PARAMETER_1
;
292 if (PropertyQuery
->QueryType
== PropertyExistsQuery
)
295 // device property / adapter property is supported
297 return STATUS_SUCCESS
;
300 if (PropertyQuery
->QueryType
!= PropertyStandardQuery
)
303 // only standard query and exists query are supported
305 return STATUS_INVALID_PARAMETER_2
;
309 // check if it is a device property
311 if (PropertyQuery
->PropertyId
== StorageDeviceProperty
)
313 DPRINT("USBSTOR_HandleQueryProperty StorageDeviceProperty OutputBufferLength %lu\n", IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
);
316 // get device extension
318 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
319 ASSERT(PDODeviceExtension
);
320 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
323 // get device extension
325 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
326 ASSERT(FDODeviceExtension
);
327 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
332 InquiryData
= (PUFI_INQUIRY_RESPONSE
)PDODeviceExtension
->InquiryData
;
336 // compute extra parameters length
338 FieldLengthVendor
= USBSTOR_GetFieldLength(InquiryData
->Vendor
, 8);
339 FieldLengthProduct
= USBSTOR_GetFieldLength(InquiryData
->Product
, 16);
340 FieldLengthRevision
= USBSTOR_GetFieldLength(InquiryData
->Revision
, 4);
343 // is there a serial number
345 if (FDODeviceExtension
->SerialNumber
)
350 FieldLengthSerialNumber
= wcslen(FDODeviceExtension
->SerialNumber
->bString
);
357 FieldLengthSerialNumber
= 0;
361 // total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1
362 // -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data
364 TotalLength
= sizeof(STORAGE_DEVICE_DESCRIPTOR
) + FieldLengthVendor
+ FieldLengthProduct
+ FieldLengthRevision
+ FieldLengthSerialNumber
+ 3;
367 // check if output buffer is long enough
369 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< TotalLength
)
374 DescriptorHeader
= (PSTORAGE_DESCRIPTOR_HEADER
)Irp
->AssociatedIrp
.SystemBuffer
;
375 ASSERT(IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= sizeof(STORAGE_DESCRIPTOR_HEADER
));
378 // return required size
380 DescriptorHeader
->Version
= TotalLength
;
381 DescriptorHeader
->Size
= TotalLength
;
383 Irp
->IoStatus
.Information
= sizeof(STORAGE_DESCRIPTOR_HEADER
);
384 return STATUS_SUCCESS
;
388 // get device descriptor
390 DeviceDescriptor
= (PSTORAGE_DEVICE_DESCRIPTOR
)Irp
->AssociatedIrp
.SystemBuffer
;
393 // initialize device descriptor
395 DeviceDescriptor
->Version
= TotalLength
;
396 DeviceDescriptor
->Size
= TotalLength
;
397 DeviceDescriptor
->DeviceType
= InquiryData
->DeviceType
;
398 DeviceDescriptor
->DeviceTypeModifier
= (InquiryData
->RMB
& 0x7F);
399 DeviceDescriptor
->RemovableMedia
= (InquiryData
->RMB
& 0x80) ? TRUE
: FALSE
;
400 DeviceDescriptor
->CommandQueueing
= FALSE
;
401 DeviceDescriptor
->BusType
= BusTypeUsb
;
402 DeviceDescriptor
->VendorIdOffset
= sizeof(STORAGE_DEVICE_DESCRIPTOR
) - sizeof(UCHAR
);
403 DeviceDescriptor
->ProductIdOffset
= DeviceDescriptor
->VendorIdOffset
+ FieldLengthVendor
+ 1;
404 DeviceDescriptor
->ProductRevisionOffset
= DeviceDescriptor
->ProductIdOffset
+ FieldLengthProduct
+ 1;
405 DeviceDescriptor
->SerialNumberOffset
= (FieldLengthSerialNumber
> 0 ? DeviceDescriptor
->ProductRevisionOffset
+ FieldLengthRevision
+ 1 : 0);
406 DeviceDescriptor
->RawPropertiesLength
= FieldLengthVendor
+ FieldLengthProduct
+ FieldLengthRevision
+ FieldLengthSerialNumber
+ 3 + (FieldLengthSerialNumber
> 0 ? + 1 : 0);
411 Buffer
= (PUCHAR
)((ULONG_PTR
)DeviceDescriptor
+ sizeof(STORAGE_DEVICE_DESCRIPTOR
) - sizeof(UCHAR
));
416 RtlCopyMemory(Buffer
, InquiryData
->Vendor
, FieldLengthVendor
);
417 Buffer
[FieldLengthVendor
] = '\0';
418 Buffer
+= FieldLengthVendor
+ 1;
423 RtlCopyMemory(Buffer
, InquiryData
->Product
, FieldLengthProduct
);
424 Buffer
[FieldLengthProduct
] = '\0';
425 Buffer
+= FieldLengthProduct
+ 1;
430 RtlCopyMemory(Buffer
, InquiryData
->Revision
, FieldLengthRevision
);
431 Buffer
[FieldLengthRevision
] = '\0';
432 Buffer
+= FieldLengthRevision
+ 1;
435 // copy serial number
437 if (FieldLengthSerialNumber
)
440 // init unicode string
442 RtlInitUnicodeString(&SerialNumber
, FDODeviceExtension
->SerialNumber
->bString
);
447 AnsiString
.Buffer
= (PCHAR
)Buffer
;
448 AnsiString
.Length
= 0;
449 AnsiString
.MaximumLength
= FieldLengthSerialNumber
* sizeof(WCHAR
);
452 // convert to ansi code
454 Status
= RtlUnicodeStringToAnsiString(&AnsiString
, &SerialNumber
, FALSE
);
455 ASSERT(Status
== STATUS_SUCCESS
);
459 DPRINT("Vendor %s\n", (LPCSTR
)((ULONG_PTR
)DeviceDescriptor
+ DeviceDescriptor
->VendorIdOffset
));
460 DPRINT("Product %s\n", (LPCSTR
)((ULONG_PTR
)DeviceDescriptor
+ DeviceDescriptor
->ProductIdOffset
));
461 DPRINT("Revision %s\n", (LPCSTR
)((ULONG_PTR
)DeviceDescriptor
+ DeviceDescriptor
->ProductRevisionOffset
));
462 DPRINT("Serial %s\n", (LPCSTR
)((ULONG_PTR
)DeviceDescriptor
+ DeviceDescriptor
->SerialNumberOffset
));
467 Irp
->IoStatus
.Information
= TotalLength
;
468 return STATUS_SUCCESS
;
473 // adapter property query request
475 DPRINT("USBSTOR_HandleQueryProperty StorageAdapterProperty OutputBufferLength %lu\n", IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
);
477 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(STORAGE_ADAPTER_DESCRIPTOR
))
482 DescriptorHeader
= (PSTORAGE_DESCRIPTOR_HEADER
)Irp
->AssociatedIrp
.SystemBuffer
;
483 ASSERT(IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= sizeof(STORAGE_DESCRIPTOR_HEADER
));
486 // return required size
488 DescriptorHeader
->Version
= sizeof(STORAGE_ADAPTER_DESCRIPTOR
);
489 DescriptorHeader
->Size
= sizeof(STORAGE_ADAPTER_DESCRIPTOR
);
491 Irp
->IoStatus
.Information
= sizeof(STORAGE_DESCRIPTOR_HEADER
);
492 return STATUS_SUCCESS
;
496 // get adapter descriptor, information is returned in the same buffer
498 AdapterDescriptor
= (PSTORAGE_ADAPTER_DESCRIPTOR
)Irp
->AssociatedIrp
.SystemBuffer
;
501 // fill out descriptor
503 AdapterDescriptor
->Version
= sizeof(STORAGE_ADAPTER_DESCRIPTOR
);
504 AdapterDescriptor
->Size
= sizeof(STORAGE_ADAPTER_DESCRIPTOR
);
505 AdapterDescriptor
->MaximumTransferLength
= MAXULONG
; //FIXME compute some sane value
506 AdapterDescriptor
->MaximumPhysicalPages
= 25; //FIXME compute some sane value
507 AdapterDescriptor
->AlignmentMask
= 0;
508 AdapterDescriptor
->AdapterUsesPio
= FALSE
;
509 AdapterDescriptor
->AdapterScansDown
= FALSE
;
510 AdapterDescriptor
->CommandQueueing
= FALSE
;
511 AdapterDescriptor
->AcceleratedTransfer
= FALSE
;
512 AdapterDescriptor
->BusType
= BusTypeUsb
;
513 AdapterDescriptor
->BusMajorVersion
= 0x2; //FIXME verify
514 AdapterDescriptor
->BusMinorVersion
= 0x00; //FIXME
517 // store returned length
519 Irp
->IoStatus
.Information
= sizeof(STORAGE_ADAPTER_DESCRIPTOR
);
524 return STATUS_SUCCESS
;
529 USBSTOR_HandleDeviceControl(
530 IN PDEVICE_OBJECT DeviceObject
,
533 PIO_STACK_LOCATION IoStack
;
535 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
536 PSCSI_ADAPTER_BUS_INFO BusInfo
;
537 PSCSI_INQUIRY_DATA InquiryData
;
538 PINQUIRYDATA ScsiInquiryData
;
539 PUFI_INQUIRY_RESPONSE UFIInquiryResponse
;
542 // get current stack location
544 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
546 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_STORAGE_QUERY_PROPERTY
)
551 Status
= USBSTOR_HandleQueryProperty(DeviceObject
, Irp
);
553 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH
)
556 // query scsi pass through
558 DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH NOT implemented\n");
559 Status
= STATUS_NOT_SUPPORTED
;
561 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
)
564 // query scsi pass through direct
566 DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH_DIRECT NOT implemented\n");
567 Status
= STATUS_NOT_SUPPORTED
;
569 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER
)
572 // query serial number
574 DPRINT1("USBSTOR_HandleDeviceControl IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER NOT implemented\n");
575 Status
= STATUS_NOT_SUPPORTED
;
577 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_CAPABILITIES
)
579 PIO_SCSI_CAPABILITIES Capabilities
;
581 /* Legacy port capability query */
582 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
== sizeof(PVOID
))
584 Capabilities
= *((PVOID
*)Irp
->AssociatedIrp
.SystemBuffer
) = ExAllocatePool(NonPagedPool
, sizeof(IO_SCSI_CAPABILITIES
));
585 Irp
->IoStatus
.Information
= sizeof(PVOID
);
589 Capabilities
= Irp
->AssociatedIrp
.SystemBuffer
;
590 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
595 Capabilities
->MaximumTransferLength
= MAXULONG
;
596 Capabilities
->MaximumPhysicalPages
= 25;
597 Capabilities
->SupportedAsynchronousEvents
= 0;
598 Capabilities
->AlignmentMask
= 0;
599 Capabilities
->TaggedQueuing
= FALSE
;
600 Capabilities
->AdapterScansDown
= FALSE
;
601 Capabilities
->AdapterUsesPio
= FALSE
;
602 Status
= STATUS_SUCCESS
;
606 Status
= STATUS_INSUFFICIENT_RESOURCES
;
609 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_INQUIRY_DATA
)
612 // get device extension
614 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
615 ASSERT(PDODeviceExtension
);
616 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
621 BusInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
622 InquiryData
= (PSCSI_INQUIRY_DATA
)(BusInfo
+ 1);
623 ScsiInquiryData
= (PINQUIRYDATA
)InquiryData
->InquiryData
;
629 UFIInquiryResponse
= (PUFI_INQUIRY_RESPONSE
)PDODeviceExtension
->InquiryData
;
630 ASSERT(UFIInquiryResponse
);
633 BusInfo
->NumberOfBuses
= 1;
634 BusInfo
->BusData
[0].NumberOfLogicalUnits
= 1; //FIXME
635 BusInfo
->BusData
[0].InitiatorBusId
= 0;
636 BusInfo
->BusData
[0].InquiryDataOffset
= sizeof(SCSI_ADAPTER_BUS_INFO
);
638 InquiryData
->PathId
= 0;
639 InquiryData
->TargetId
= 0;
640 InquiryData
->Lun
= PDODeviceExtension
->LUN
& MAX_LUN
;
641 InquiryData
->DeviceClaimed
= PDODeviceExtension
->Claimed
;
642 InquiryData
->InquiryDataLength
= sizeof(INQUIRYDATA
);
643 InquiryData
->NextInquiryDataOffset
= 0;
645 RtlZeroMemory(ScsiInquiryData
, sizeof(INQUIRYDATA
));
646 ScsiInquiryData
->DeviceType
= UFIInquiryResponse
->DeviceType
;
647 ScsiInquiryData
->DeviceTypeQualifier
= (UFIInquiryResponse
->RMB
& 0x7F);
649 /* Hack for IoReadPartitionTable call in disk.sys */
650 ScsiInquiryData
->RemovableMedia
= ((ScsiInquiryData
->DeviceType
!= DIRECT_ACCESS_DEVICE
) ? ((UFIInquiryResponse
->RMB
& 0x80) ? 1 : 0) : 0);
652 ScsiInquiryData
->Versions
= 0x04;
653 ScsiInquiryData
->ResponseDataFormat
= 0x02;
654 ScsiInquiryData
->AdditionalLength
= 31;
655 ScsiInquiryData
->SoftReset
= 0;
656 ScsiInquiryData
->CommandQueue
= 0;
657 ScsiInquiryData
->LinkedCommands
= 0;
658 ScsiInquiryData
->RelativeAddressing
= 0;
660 RtlCopyMemory(&ScsiInquiryData
->VendorId
, UFIInquiryResponse
->Vendor
, USBSTOR_GetFieldLength(UFIInquiryResponse
->Vendor
, 8));
661 RtlCopyMemory(&ScsiInquiryData
->ProductId
, UFIInquiryResponse
->Product
, USBSTOR_GetFieldLength(UFIInquiryResponse
->Product
, 16));
663 Irp
->IoStatus
.Information
= sizeof(SCSI_ADAPTER_BUS_INFO
) + sizeof(SCSI_INQUIRY_DATA
) + sizeof(INQUIRYDATA
) - 1;
664 Status
= STATUS_SUCCESS
;
666 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_SCSI_GET_ADDRESS
)
668 PSCSI_ADDRESS Address
= Irp
->AssociatedIrp
.SystemBuffer
;
670 Address
->Length
= sizeof(SCSI_ADDRESS
);
671 Address
->PortNumber
= 0;
673 Address
->TargetId
= 0;
674 Address
->Lun
= (((PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->LUN
& MAX_LUN
);
675 Irp
->IoStatus
.Information
= sizeof(SCSI_ADDRESS
);
677 Status
= STATUS_SUCCESS
;
684 DPRINT("USBSTOR_HandleDeviceControl IoControl %x not supported\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
685 Status
= STATUS_NOT_SUPPORTED
;