reactos/drivers/usb/usbstor/fdo.c
Justin Miller a65b6ae946
[USBSTOR] Don't assert on clean up if initization didnt finish (#7412)
During investigation into some of the USB stack issues we've been running into I've found that when a USB storage device is already plugged in during boot and removed before it finishes initialization we run into this assert.

The logic in this function removes the pools made for the following entries in DeviceExtension indiscriminately this makes debugging a bit more difficult. Instead of depending on this behavior of ALWAYS being filled with valid data, let's free the following pools ONLY if they're initialized. This change prevents us from bugchecking when USB flash drives are removed early during boot. This makes the debugging experience a little more sane.
2024-10-02 23:21:50 +02:00

365 lines
12 KiB
C

/*
* PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: USB block storage device driver.
* COPYRIGHT: 2005-2006 James Tabor
* 2011-2012 Michael Martin (michael.martin@reactos.org)
* 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
* 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
#include "usbstor.h"
#define NDEBUG
#include <debug.h>
#if DBG
static
VOID
USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
{
DPRINT("Dumping Device Descriptor %p\n", DeviceDescriptor);
DPRINT("bLength %x\n", DeviceDescriptor->bLength);
DPRINT("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
DPRINT("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
DPRINT("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
DPRINT("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
DPRINT("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
DPRINT("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
DPRINT("idVendor %x\n", DeviceDescriptor->idVendor);
DPRINT("idProduct %x\n", DeviceDescriptor->idProduct);
DPRINT("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
DPRINT("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
DPRINT("iProduct %x\n", DeviceDescriptor->iProduct);
DPRINT("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
DPRINT("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
}
#endif
NTSTATUS
USBSTOR_FdoHandleDeviceRelations(
IN PFDO_DEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp)
{
INT32 DeviceCount = 0;
LONG Index;
PDEVICE_RELATIONS DeviceRelations;
PIO_STACK_LOCATION IoStack;
IoStack = IoGetCurrentIrpStackLocation(Irp);
// FDO always only handles bus relations
if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
{
// go through array and count device objects
for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
{
if (DeviceExtension->ChildPDO[Index])
{
DeviceCount++;
}
}
DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount - 1) * sizeof(PDEVICE_OBJECT), USB_STOR_TAG);
if (!DeviceRelations)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
DeviceRelations->Count = 0;
// add device objects
for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
{
if (DeviceExtension->ChildPDO[Index])
{
// store child pdo
DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
// add reference
ObReferenceObject(DeviceExtension->ChildPDO[Index]);
DeviceRelations->Count++;
}
}
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
IoCopyCurrentIrpStackLocationToNext(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
NTSTATUS
USBSTOR_FdoHandleRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PFDO_DEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp)
{
NTSTATUS Status;
ULONG Index;
DPRINT("Handling FDO removal %p\n", DeviceObject);
// FIXME: wait for devices finished processing
for (Index = 0; Index < USB_MAXCHILDREN; Index++)
{
if (DeviceExtension->ChildPDO[Index] != NULL)
{
DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
}
}
// Freeing everything in DeviceExtension
if (DeviceExtension->DeviceDescriptor)
ExFreePoolWithTag(DeviceExtension->DeviceDescriptor, USB_STOR_TAG);
if (DeviceExtension->ConfigurationDescriptor)
ExFreePoolWithTag(DeviceExtension->ConfigurationDescriptor, USB_STOR_TAG);
if (DeviceExtension->InterfaceInformation)
ExFreePoolWithTag(DeviceExtension->InterfaceInformation, USB_STOR_TAG);
if (DeviceExtension->ResetDeviceWorkItem)
IoFreeWorkItem(DeviceExtension->ResetDeviceWorkItem);
if (DeviceExtension->SerialNumber)
ExFreePoolWithTag(DeviceExtension->SerialNumber, USB_STOR_TAG);
// Send the IRP down the stack
IoSkipCurrentIrpStackLocation(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
// Detach from the device stack
IoDetachDevice(DeviceExtension->LowerDeviceObject);
IoDeleteDevice(DeviceObject);
return Status;
}
NTSTATUS
USBSTOR_FdoHandleStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PFDO_DEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp)
{
PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
NTSTATUS Status;
UCHAR Index = 0;
PIO_WORKITEM WorkItem;
// forward irp to lower device
if (!IoForwardIrpSynchronously(DeviceExtension->LowerDeviceObject, Irp))
{
return STATUS_UNSUCCESSFUL;
}
Status = Irp->IoStatus.Status;
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
return Status;
}
if (!DeviceExtension->ResetDeviceWorkItem)
{
WorkItem = IoAllocateWorkItem(DeviceObject);
DeviceExtension->ResetDeviceWorkItem = WorkItem;
if (!WorkItem)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
}
// initialize irp queue
USBSTOR_QueueInitialize(DeviceExtension);
// first get device & configuration & string descriptor
Status = USBSTOR_GetDescriptors(DeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
return Status;
}
#if DBG
USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
#endif
// Check that this device uses bulk transfers and is SCSI
InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
if (InterfaceDesc->bInterfaceProtocol != USB_PROTOCOL_BULK)
{
DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
return STATUS_NOT_SUPPORTED;
}
if (InterfaceDesc->bInterfaceSubClass == USB_SUBCLASS_UFI)
{
DPRINT1("USB Floppy devices are not supported\n");
return STATUS_NOT_SUPPORTED;
}
// now select an interface
Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
if (!NT_SUCCESS(Status))
{
// failed to get device descriptor
DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
return Status;
}
// check if we got a bulk in + bulk out endpoint
Status = USBSTOR_GetPipeHandles(DeviceExtension);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
return Status;
}
Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
return Status;
}
// now create for each LUN a device object, 1 minimum
do
{
Status = USBSTOR_CreatePDO(DeviceObject, Index);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
return Status;
}
Index++;
DeviceExtension->InstanceCount++;
} while(Index < DeviceExtension->MaxLUN);
#if 0
//
// finally get usb device interface
//
Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
if (!NT_SUCCESS(Status))
{
//
// failed to device interface
//
DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
return Status;
}
#endif
//IoStartTimer(DeviceObject);
DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_FdoHandlePnp(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PFDO_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
IoStack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->Common.IsFDO);
switch(IoStack->MinorFunction)
{
case IRP_MN_SURPRISE_REMOVAL:
{
DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
// forward irp to next device object
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p Type: %u\n", DeviceObject, IoStack->Parameters.QueryDeviceRelations.Type);
return USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
}
case IRP_MN_STOP_DEVICE:
{
DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
IoStopTimer(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
// forward irp to next device object
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
case IRP_MN_REMOVE_DEVICE:
{
DPRINT("IRP_MN_REMOVE_DEVICE\n");
return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
}
case IRP_MN_QUERY_CAPABILITIES:
{
// FIXME: set custom capabilities
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
{
if (DeviceExtension->IrpPendingCount != 0 || DeviceExtension->ActiveSrb != NULL)
{
/* We have pending requests */
DPRINT1("Failing removal/stop request due to pending requests present\n");
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* We're all clear */
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
break;
}
case IRP_MN_START_DEVICE:
{
Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
break;
}
default:
{
// forward irp to next device object
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
}
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}