return STATUS_SUCCESS;
}
+PIRP_CONTEXT
+USBSTOR_AllocateIrpContext()
+{
+ PIRP_CONTEXT Context;
+
+ //
+ // allocate irp context
+ //
+ Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT));
+ if (!Context)
+ {
+ //
+ // no memory
+ //
+ return NULL;
+ }
+
+ //
+ // allocate cbw block
+ //
+ Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512);
+ if (!Context->cbw)
+ {
+ //
+ // no memory
+ //
+ FreeItem(Context);
+ return NULL;
+ }
+
+ //
+ // done
+ //
+ return Context;
+
+}
+
+//
+// driver verifier
+//
+IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine;
+
NTSTATUS
-USBSTOR_SendCBW(
- IN PDEVICE_OBJECT DeviceObject,
- IN UCHAR CommandBlockLength,
- IN PUCHAR CommandBlock,
- IN ULONG DataTransferLength,
- OUT PCBW *OutControl)
+NTAPI
+USBSTOR_CSWCompletionRoutine(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Ctx)
{
- PCBW Control;
+ PIRP_CONTEXT Context;
+ PIO_STACK_LOCATION IoStack;
+ PSCSI_REQUEST_BLOCK Request;
+ PCDB pCDB;
+ PREAD_CAPACITY_DATA_EX CapacityDataEx;
+ PREAD_CAPACITY_DATA CapacityData;
+ PUFI_CAPACITY_RESPONSE Response;
+ PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData;
NTSTATUS Status;
PURB Urb;
- PPDO_DEVICE_EXTENSION PDODeviceExtension;
- PFDO_DEVICE_EXTENSION FDODeviceExtension;
- //
- // get PDO device extension
- //
- PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ DPRINT("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
//
- // get FDO device extension
+ // access context
//
- FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
+ Context = (PIRP_CONTEXT)Ctx;
//
- // first allocate CBW
+ // is there a mdl
//
- Control = (PCBW)AllocateItem(NonPagedPool, 512);
- if (!Control)
+ if (Context->TransferBufferMDL)
{
//
- // no memory
+ // is there an irp associated
//
- return STATUS_INSUFFICIENT_RESOURCES;
+ if (Context->Irp)
+ {
+ //
+ // did we allocate the mdl
+ //
+ if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
+ {
+ //
+ // free mdl
+ //
+ IoFreeMdl(Context->TransferBufferMDL);
+ }
+ }
+ else
+ {
+ //
+ // free mdl
+ //
+ IoFreeMdl(Context->TransferBufferMDL);
+ }
}
- //
- // first allocate CBW
- //
- Status = USBSTOR_BuildCBW(0xDEADDEAD, DataTransferLength, PDODeviceExtension->LUN, CommandBlockLength, CommandBlock, Control);
- if (!NT_SUCCESS(Status))
+ if (Context->Irp)
{
//
- // failed to build CBW
+ // get current stack location
//
- return Status;
+ IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
+
+ //
+ // get request block
+ //
+ Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+ ASSERT(Request);
+
+ Status = Irp->IoStatus.Status;
+
+ Urb = &Context->Urb;
+
+ //
+ // get SCSI command data block
+ //
+ pCDB = (PCDB)Request->Cdb;
+
+ //
+ // check status
+ //
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Status %x\n", Status);
+ DPRINT1("UrbStatus %x\n", Urb->UrbHeader.Status);
+
+ //
+ // Check for errors that can be handled
+ // FIXME: Verify all usb errors that can be recovered via pipe reset/port reset/controller reset
+ //
+ if ((Urb->UrbHeader.Status & USB_RECOVERABLE_ERRORS) == Urb->UrbHeader.Status)
+ {
+ DPRINT1("Attempting Error Recovery\n");
+ //
+ // If a Read Capacity Request free TransferBuffer
+ //
+ if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
+ {
+ FreeItem(Context->TransferData);
+ }
+
+ //
+ // Clean up the rest
+ //
+ FreeItem(Context->cbw);
+ FreeItem(Context);
+
+ //
+ // Allocate Work Item Data
+ //
+ ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG);
+ if (!ErrorHandlerWorkItemData)
+ {
+ DPRINT1("Failed to allocate memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ //
+ // Initialize and queue the work item to handle the error
+ //
+ ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem,
+ ErrorHandlerWorkItemRoutine,
+ ErrorHandlerWorkItemData);
+
+ ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
+ ErrorHandlerWorkItemData->Irp = Irp;
+ ErrorHandlerWorkItemData->Context = Context;
+ DPRINT1("Queuing WorkItemROutine\n");
+ ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ }
+ }
+
+ Request->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // read capacity needs special work
+ //
+ if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
+ {
+ //
+ // get output buffer
+ //
+ Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;
+
+ //
+ // store in pdo
+ //
+ Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
+ Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
+
+ if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
+ {
+ //
+ // get input buffer
+ //
+ CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer;
+
+ //
+ // set result
+ //
+ CapacityDataEx->BytesPerBlock = Response->BlockLength;
+ CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
+ Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);
+ }
+ else
+ {
+ //
+ // get input buffer
+ //
+ CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer;
+
+ //
+ // set result
+ //
+ CapacityData->BytesPerBlock = Response->BlockLength;
+ CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
+ Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
+ }
+
+ //
+ // free response
+ //
+ FreeItem(Context->TransferData);
+ }
}
//
- // now build the urb
+ // free cbw
//
- Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
- if (!Urb)
+ FreeItem(Context->cbw);
+
+
+ if (Context->Irp)
{
//
- // failed to allocate urb
+ // FIXME: check status
//
- FreeItem(Control);
- return STATUS_INSUFFICIENT_RESOURCES;
+ Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
+ Context->Irp->IoStatus.Information = Context->TransferDataLength;
+
+ //
+ // complete request
+ //
+ IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
+
+ //
+ // terminate current request
+ //
+ USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, TRUE);
+
+ //
+ // start next request
+ //
+ USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
+ }
+
+ if (Context->Event)
+ {
+ //
+ // signal event
+ //
+ KeSetEvent(Context->Event, 0, FALSE);
}
+
//
- // now initialize the urb
+ // free context
+ //
+ FreeItem(Context);
+
+ //
+ // done
//
- Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
- Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
- Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
- Urb->UrbBulkOrInterruptTransfer.TransferBuffer = (PVOID)Control;
- Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = sizeof(CBW);
- Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK;
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+//
+// driver verifier
+//
+IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
+
+NTSTATUS
+NTAPI
+USBSTOR_DataCompletionRoutine(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Ctx)
+{
+ PIRP_CONTEXT Context;
+ PIO_STACK_LOCATION IoStack;
+
+ DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
//
- // now send urb
+ // access context
//
- Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
+ Context = (PIRP_CONTEXT)Ctx;
//
- // free urb
+ // get next stack location
//
- FreeItem(Urb);
+
+ IoStack = IoGetNextIrpStackLocation(Irp);
//
- // store cbw
+ // now initialize the urb for sending the csw
//
- *OutControl = Control;
+ UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
+ Context->csw,
+ NULL,
+ 512, //FIXME
+ USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+ NULL);
//
- // return operation status
+ // initialize stack location
//
- return Status;
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+ IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
+ IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+
+ //
+ // setup completion routine
+ //
+ IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
+
+ //
+ // call driver
+ //
+ IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
}
+//
+// driver verifier
+//
+IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine;
+
NTSTATUS
-USBSTOR_SendData(
+NTAPI
+USBSTOR_CBWCompletionRoutine(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Ctx)
+{
+ PIRP_CONTEXT Context;
+ PIO_STACK_LOCATION IoStack;
+ UCHAR Code;
+ USBD_PIPE_HANDLE PipeHandle;
+
+ DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
+
+ //
+ // access context
+ //
+ Context = (PIRP_CONTEXT)Ctx;
+
+ //
+ // get next stack location
+ //
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ //
+ // is there data to be submitted
+ //
+ if (Context->TransferDataLength)
+ {
+ //
+ // get command code
+ //
+ Code = Context->cbw->CommandBlock[0];
+
+ if (Code == SCSIOP_WRITE)
+ {
+ //
+ // write request use bulk out pipe
+ //
+ PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
+ }
+ else
+ {
+ //
+ // default bulk in pipe
+ //
+ PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
+ }
+
+ //
+ // now initialize the urb for sending data
+ //
+ UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ PipeHandle,
+ NULL,
+ Context->TransferBufferMDL,
+ Context->TransferDataLength,
+ USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+ NULL);
+
+ //
+ // setup completion routine
+ //
+ IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
+ }
+ else
+ {
+ //
+ // now initialize the urb for sending the csw
+ //
+
+ UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
+ Context->csw,
+ NULL,
+ 512, //FIXME
+ USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+ NULL);
+
+ //
+ // setup completion routine
+ //
+ IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
+ }
+
+ //
+ // initialize stack location
+ //
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+ IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
+ IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ //
+ // call driver
+ //
+ IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+USBSTOR_SendRequest(
IN PDEVICE_OBJECT DeviceObject,
- IN ULONG DataTransferLength,
- IN PVOID DataTransfer)
+ IN PIRP OriginalRequest,
+ IN OPTIONAL PKEVENT Event,
+ IN UCHAR CommandLength,
+ IN PUCHAR Command,
+ IN ULONG TransferDataLength,
+ IN PUCHAR TransferData)
{
- PMDL TransferBufferMDL;
- PURB Urb;
- NTSTATUS Status;
+ PIRP_CONTEXT Context;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ PUCHAR MdlVirtualAddress;
+
+ //
+ // first allocate irp context
+ //
+ Context = USBSTOR_AllocateIrpContext();
+ if (!Context)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
//
// get PDO device extension
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
- // allocate mdl for buffer, buffer must be allocated from NonPagedPool
+ // now build the cbw
//
- TransferBufferMDL = IoAllocateMdl(DataTransfer, DataTransferLength, FALSE, FALSE, NULL);
- if (!TransferBufferMDL)
- {
- //
- // failed to allocate MDL
- //
- return STATUS_INSUFFICIENT_RESOURCES;
- }
+ USBSTOR_BuildCBW(0xDEADDEAD, // FIXME tag
+ TransferDataLength,
+ PDODeviceExtension->LUN,
+ CommandLength,
+ Command,
+ Context->cbw);
+
+ //
+ // now initialize the urb
+ //
+ UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
+ Context->cbw,
+ NULL,
+ sizeof(CBW),
+ USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK,
+ NULL);
//
- // build mdl for nonpaged pool
+ // initialize rest of context
//
- MmBuildMdlForNonPagedPool(TransferBufferMDL);
+ Context->Irp = OriginalRequest;
+ Context->TransferData = TransferData;
+ Context->TransferDataLength = TransferDataLength;
+ Context->FDODeviceExtension = FDODeviceExtension;
+ Context->PDODeviceExtension = PDODeviceExtension;
+ Context->Event = Event;
//
- // now build the urb
+ // is there transfer data
//
- Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
- if (!Urb)
+ if (Context->TransferDataLength)
{
//
- // failed to allocate urb
+ // check if the original request already does have an mdl associated
//
- IoFreeMdl(TransferBufferMDL);
+ if (OriginalRequest)
+ {
+ if ((OriginalRequest->MdlAddress != NULL) &&
+ (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
+ {
+ //
+ // Sanity check that the Mdl does describe the TransferData for read/write
+ //
+ if (CommandLength == UFI_READ_WRITE_CMD_LEN)
+ {
+ MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);
+ if (MdlVirtualAddress != Context->TransferData)
+ {
+ //
+ // lets build an mdl
+ //
+ Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
+ if (!Context->TransferBufferMDL)
+ {
+ //
+ // failed to allocate MDL
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // now build the partial mdl
+ //
+ IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
+ }
+ }
+
+ //
+ // I/O paging request
+ //
+ Context->TransferBufferMDL = OriginalRequest->MdlAddress;
+ }
+ else
+ {
+ //
+ // allocate mdl for buffer, buffer must be allocated from NonPagedPool
+ //
+ Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
+ if (!Context->TransferBufferMDL)
+ {
+ //
+ // failed to allocate MDL
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // build mdl for nonpaged pool
+ //
+ MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
+ }
+ }
+ else
+ {
+ //
+ // allocate mdl for buffer, buffer must be allocated from NonPagedPool
+ //
+ Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
+ if (!Context->TransferBufferMDL)
+ {
+ //
+ // failed to allocate MDL
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // build mdl for nonpaged pool
+ //
+ MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
+ }
+ }
+
+ //
+ // now allocate the request
+ //
+ Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+ if (!Irp)
+ {
+ FreeItem(Context->cbw);
+ FreeItem(Context);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
- // now initialize the urb
+ // get next stack location
//
- Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
- Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
- Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
- Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = TransferBufferMDL;
- Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataTransferLength;
- Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
+ IoStack = IoGetNextIrpStackLocation(Irp);
//
- // now send urb
+ // initialize stack location
//
- Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+ IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
+ IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
//
- // free urb
+ // setup completion routine
//
- FreeItem(Urb);
+ IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
+
+ if (OriginalRequest)
+ {
+ //
+ // mark orignal irp as pending
+ //
+ IoMarkIrpPending(OriginalRequest);
+ }
//
- // free mdl
+ // call driver
//
- IoFreeMdl(TransferBufferMDL);
+ IoCallDriver(FDODeviceExtension->LowerDeviceObject, Irp);
//
// done
//
- return Status;
+ return STATUS_PENDING;
}
NTSTATUS
-USBSTOR_SendCSW(
- IN PDEVICE_OBJECT DeviceObject,
- IN PVOID Data,
- IN ULONG DataLength,
- OUT PCSW OutCSW)
+USBSTOR_SendInquiryCmd(
+ IN PDEVICE_OBJECT DeviceObject)
{
+ UFI_INQUIRY_CMD Cmd;
NTSTATUS Status;
+ KEVENT Event;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
- PFDO_DEVICE_EXTENSION FDODeviceExtension;
- PURB Urb;
+ PUFI_INQUIRY_RESPONSE Response;
+
+
+ //
+ // allocate inquiry response
+ //
+ Response = AllocateItem(NonPagedPool, PAGE_SIZE);
+ if (!Response)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
//
// get PDO device extension
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
- // get FDO device extension
+ // initialize inquiry cmd
//
- FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
+ RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
+ Cmd.Code = SCSIOP_INQUIRY;
+ Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+ Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
//
- // now build the urb
+ // initialize event
//
- Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
- if (!Urb)
- {
- //
- // failed to allocate urb
- //
- return STATUS_INSUFFICIENT_RESOURCES;
- }
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
//
- // now initialize the urb
+ // now send the request
+ //
+ Status = USBSTOR_SendRequest(DeviceObject, NULL, &Event, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_INQUIRY_RESPONSE), (PUCHAR)Response);
+
+ //
+ // wait for the action to complete
+ //
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+ DPRINT1("Response %p\n", Response);
+ DPRINT1("DeviceType %x\n", Response->DeviceType);
+ DPRINT1("RMB %x\n", Response->RMB);
+ DPRINT1("Version %x\n", Response->Version);
+ DPRINT1("Format %x\n", Response->Format);
+ DPRINT1("Length %x\n", Response->Length);
+ DPRINT1("Reserved %x\n", Response->Reserved);
+ DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response->Vendor[0], Response->Vendor[1], Response->Vendor[2], Response->Vendor[3], Response->Vendor[4], Response->Vendor[5], Response->Vendor[6], Response->Vendor[7]);
+ DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response->Product[0], Response->Product[1], Response->Product[2], Response->Product[3],
+ Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
+ Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
+ Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
+
+ DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
+
//
- Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
- Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
- Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
- Urb->UrbBulkOrInterruptTransfer.TransferBuffer = Data;
- Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataLength;
- Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
+ // store inquiry data
+ //
+ PDODeviceExtension->InquiryData = (PVOID)Response;
//
- // now send urb
+ // done
//
- Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
+ return Status;
+}
+
+NTSTATUS
+USBSTOR_SendCapacityCmd(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ UFI_CAPACITY_CMD Cmd;
+ PUFI_CAPACITY_RESPONSE Response;
+ PPDO_DEVICE_EXTENSION PDODeviceExtension;
- if (NT_SUCCESS(Status))
+ //
+ // get PDO device extension
+ //
+ PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // allocate capacity response
+ //
+ Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_CAPACITY_RESPONSE));
+ if (!Response)
{
//
- // copy csw status
+ // no memory
//
- RtlCopyMemory(OutCSW, Data, sizeof(CSW));
+ return STATUS_INSUFFICIENT_RESOURCES;
}
//
- // free urb
+ // initialize capacity cmd
//
- FreeItem(Urb);
+ RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
+ Cmd.Code = SCSIOP_READ_CAPACITY;
+ Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
//
- // done
+ // send request, response will be freed in completion routine
//
- return Status;
+ return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response);
}
NTSTATUS
-USBSTOR_SendInquiryCmd(
- IN PDEVICE_OBJECT DeviceObject)
+USBSTOR_SendModeSenseCmd(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
{
- UFI_INQUIRY_CMD Cmd;
- CSW CSW;
+#if 0
+ UFI_SENSE_CMD Cmd;
NTSTATUS Status;
- PUFI_INQUIRY_RESPONSE Response;
- PPDO_DEVICE_EXTENSION PDODeviceExtension;
+ PVOID Response;
PCBW OutControl;
+ PCDB pCDB;
+ PUFI_MODE_PARAMETER_HEADER Header;
+#endif
+ PPDO_DEVICE_EXTENSION PDODeviceExtension;
+ PIO_STACK_LOCATION IoStack;
+ PSCSI_REQUEST_BLOCK Request;
+ //
+ // get current stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ //
+ // get request block
+ //
+ Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+ RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength);
+ Request->SrbStatus = SRB_STATUS_SUCCESS;
+ Irp->IoStatus.Information = Request->DataTransferLength;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// get PDO device extension
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
- // allocate inquiry response
+ // sanity check
+ //
+ ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+ //
+ // terminate current request
+ //
+ USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, TRUE);
+
+ //
+ // start next request
+ //
+ USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+
+ return STATUS_SUCCESS;
+
+#if 0
+ //
+ // get SCSI command data block
+ //
+ pCDB = (PCDB)Request->Cdb;
+
+ //
+ // get PDO device extension
+ //
+ PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
//
- Response = (PUFI_INQUIRY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_INQUIRY_RESPONSE));
+ // allocate sense response from non paged pool
+ //
+ Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
if (!Response)
{
//
}
//
- // initialize inquiry cmd
+ // sanity check
+ //
+
+
+ // Supported pages
+ // MODE_PAGE_ERROR_RECOVERY
+ // MODE_PAGE_FLEXIBILE
+ // MODE_PAGE_LUN_MAPPING
+ // MODE_PAGE_FAULT_REPORTING
+ // MODE_SENSE_RETURN_ALL
+
+ //
+ // initialize mode sense cmd
//
RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
- Cmd.Code = UFI_INQURIY_CODE;
+ Cmd.Code = SCSIOP_MODE_SENSE;
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
- Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
+ Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
+ Cmd.PC = pCDB->MODE_SENSE.Pc;
+ Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
+
+ DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
+ DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
//
- // now send inquiry cmd
+ // now send mode sense cmd
//
- Status = USBSTOR_SendCBW(DeviceObject, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_INQUIRY_RESPONSE), &OutControl);
+ Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
- DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendCBW failed with %x\n", Status);
+ DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
//
- // now send inquiry response
+ // now send data block response
//
- Status = USBSTOR_SendData(DeviceObject, sizeof(UFI_INQUIRY_RESPONSE), Response);
+ Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
- DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendData failed with %x\n", Status);
+ DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
- DPRINT1("Response %p\n", Response);
- DPRINT1("DeviceType %x\n", Response->DeviceType);
- DPRINT1("RMB %x\n", Response->RMB);
- DPRINT1("Version %x\n", Response->Version);
- DPRINT1("Format %x\n", Response->Format);
- DPRINT1("Length %x\n", Response->Length);
- DPRINT1("Reserved %x\n", Response->Reserved);
- DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response->Vendor[0], Response->Vendor[1], Response->Vendor[2], Response->Vendor[3], Response->Vendor[4], Response->Vendor[5], Response->Vendor[6], Response->Vendor[7]);
- DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response->Product[0], Response->Product[1], Response->Product[2], Response->Product[3],
- Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
- Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
- Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
+ Header = (PUFI_MODE_PARAMETER_HEADER)Response;
- DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
+ //
+ // TODO: build layout
+ //
+ // first struct is the header
+ // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
+ //
+ // followed by
+ // MODE_PARAMETER_BLOCK
+ //
+ //
+ UNIMPLEMENTED
//
// send csw
DPRINT1("DataResidue %x\n", CSW.DataResidue);
DPRINT1("Status %x\n", CSW.Status);
+ //
+ // FIXME: handle error
+ //
+ ASSERT(CSW.Status == 0);
+ ASSERT(CSW.DataResidue == 0);
+
+ //
+ // calculate transfer length
+ //
+ *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
+
+ //
+ // copy buffer
+ //
+ RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
+
//
// free item
//
FreeItem(OutControl);
//
- // store inquiry data
+ // free response
//
- PDODeviceExtension->InquiryData = (PVOID)Response;
+ FreeItem(Response);
//
- // FIXME: handle error
+ // done
//
- ASSERT(CSW.Status == 0);
+ return Status;
+#endif
+}
+
+NTSTATUS
+USBSTOR_SendReadWriteCmd(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ UFI_READ_WRITE_CMD Cmd;
+ PPDO_DEVICE_EXTENSION PDODeviceExtension;
+ PCDB pCDB;
+ ULONG BlockCount;
+ PIO_STACK_LOCATION IoStack;
+ PSCSI_REQUEST_BLOCK Request;
+ //
+ // get current stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
//
- // done
+ // get request block
//
+ Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+ //
+ // get SCSI command data block
+ //
+ pCDB = (PCDB)Request->Cdb;
+
+ //
+ // get PDO device extension
+ //
+ PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // informal debug print
+ //
+ DPRINT("USBSTOR_SendReadWriteCmd DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
+
+ //
+ // sanity check
+ //
+ ASSERT(PDODeviceExtension->BlockLength);
+
+ //
+ // block count
+ //
+ BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
+
+ //
+ // initialize read cmd
+ //
+ RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
+ Cmd.Code = pCDB->AsByte[0];
+ Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+ Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
+ Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
+ Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
+ Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
+ Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
+ Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;
+
+ DPRINT("USBSTOR_SendReadWriteCmd BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
+
+ //
+ // send request
+ //
+ return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer);
+}
+
+NTSTATUS
+USBSTOR_SendTestUnitCmd(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN OUT PIRP Irp)
+{
+ UFI_TEST_UNIT_CMD Cmd;
+ PPDO_DEVICE_EXTENSION PDODeviceExtension;
+ PIO_STACK_LOCATION IoStack;
+ PSCSI_REQUEST_BLOCK Request;
+
+ //
+ // get current stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ //
+ // get request block
+ //
+ Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+ //
+ // no transfer length
+ //
+ ASSERT(Request->DataTransferLength == 0);
+
+ //
+ // get PDO device extension
+ //
+ PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // initialize test unit cmd
+ //
+ RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
+ Cmd.Code = SCSIOP_TEST_UNIT_READY;
+ Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+
+ //
+ // send the request
+ //
+ return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL);
+}
+
+
+NTSTATUS
+USBSTOR_HandleExecuteSCSI(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PCDB pCDB;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IoStack;
+ PSCSI_REQUEST_BLOCK Request;
+ PPDO_DEVICE_EXTENSION PDODeviceExtension;
+
+ //
+ // get PDO device extension
+ //
+ PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // sanity check
+ //
+ ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+ //
+ // get current stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ //
+ // get request block
+ //
+ Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+ //
+ // get SCSI command data block
+ //
+ pCDB = (PCDB)Request->Cdb;
+
+ DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
+
+ if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
+ {
+ //
+ // sanity checks
+ //
+ ASSERT(Request->DataBuffer);
+
+ DPRINT("SCSIOP_READ_CAPACITY Length %\n", Request->DataTransferLength);
+ Status = USBSTOR_SendCapacityCmd(DeviceObject, Irp);
+ }
+ else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
+ {
+ DPRINT1("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
+ ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
+ ASSERT(Request->DataBuffer);
+
+ //
+ // send mode sense command
+ //
+ Status = USBSTOR_SendModeSenseCmd(DeviceObject, Irp);
+ }
+ else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ || pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
+ {
+ DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
+
+ //
+ // send read / write command
+ //
+ Status = USBSTOR_SendReadWriteCmd(DeviceObject, Irp);
+ }
+ else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
+ {
+ DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
+
+ //
+ // just complete the request
+ //
+ Request->SrbStatus = SRB_STATUS_SUCCESS;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = Request->DataTransferLength;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ //
+ // terminate current request
+ //
+ USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, TRUE);
+
+ //
+ // start next request
+ //
+ USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+
+ return STATUS_SUCCESS;
+ }
+ else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
+ {
+ DPRINT("SCSIOP_TEST_UNIT_READY\n");
+
+ //
+ // send test unit command
+ //
+ Status = USBSTOR_SendTestUnitCmd(DeviceObject, Irp);
+ }
+ else
+ {
+ UNIMPLEMENTED;
+ Request->SrbStatus = SRB_STATUS_ERROR;
+ Status = STATUS_NOT_SUPPORTED;
+ DbgBreakPoint();
+ }
+
return Status;
}