xref: /reactos/drivers/usb/usbstor/scsi.c (revision c2c66aff)
1 /*
2  * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        drivers/usb/usbstor/pdo.c
5  * PURPOSE:     USB block storage device driver.
6  * PROGRAMMERS:
7  *              James Tabor
8  *              Michael Martin (michael.martin@reactos.org)
9  *              Johannes Anderwald (johannes.anderwald@reactos.org)
10  */
11 
12 #include "usbstor.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 NTSTATUS
18 USBSTOR_BuildCBW(
19     IN ULONG Tag,
20     IN ULONG DataTransferLength,
21     IN UCHAR LUN,
22     IN UCHAR CommandBlockLength,
23     IN PUCHAR CommandBlock,
24     IN OUT PCBW Control)
25 {
26     //
27     // sanity check
28     //
29     ASSERT(CommandBlockLength <= 16);
30 
31     //
32     // now initialize CBW
33     //
34     Control->Signature = CBW_SIGNATURE;
35     Control->Tag = Tag;
36     Control->DataTransferLength = DataTransferLength;
37     Control->Flags = (CommandBlock[0] != SCSIOP_WRITE) ? 0x80 : 0x00;
38     Control->LUN = (LUN & MAX_LUN);
39     Control->CommandBlockLength = CommandBlockLength;
40 
41     //
42     // copy command block
43     //
44     RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength);
45 
46     //
47     // done
48     //
49     return STATUS_SUCCESS;
50 }
51 
52 PIRP_CONTEXT
53 USBSTOR_AllocateIrpContext()
54 {
55     PIRP_CONTEXT Context;
56 
57     //
58     // allocate irp context
59     //
60     Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT));
61     if (!Context)
62     {
63         //
64         // no memory
65         //
66         return NULL;
67     }
68 
69     //
70     // allocate cbw block
71     //
72     Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512);
73     if (!Context->cbw)
74     {
75         //
76         // no memory
77         //
78         FreeItem(Context);
79         return NULL;
80     }
81 
82     //
83     // done
84     //
85     return Context;
86 
87 }
88 
89 BOOLEAN
90 USBSTOR_IsCSWValid(
91     PIRP_CONTEXT Context)
92 {
93     //
94     // sanity checks
95     //
96     if (Context->csw->Signature != CSW_SIGNATURE)
97     {
98         DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature);
99         return FALSE;
100     }
101 
102     if (Context->csw->Tag != (ULONG)Context->csw)
103     {
104         DPRINT1("[USBSTOR] Expected Tag %x but got %x\n", (ULONG)Context->csw, Context->csw->Tag);
105         return FALSE;
106     }
107 
108     if (Context->csw->Status != 0x00)
109     {
110         DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status);
111         return FALSE;
112     }
113 
114     //
115     // CSW is valid
116     //
117     return TRUE;
118 
119 }
120 
121 NTSTATUS
122 USBSTOR_QueueWorkItem(
123     PIRP_CONTEXT Context,
124     PIRP Irp)
125 {
126     PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData;
127 
128     //
129     // Allocate Work Item Data
130     //
131     ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG);
132     if (!ErrorHandlerWorkItemData)
133     {
134         //
135         // no memory
136         //
137         return STATUS_INSUFFICIENT_RESOURCES;
138     }
139 
140     //
141     // error handling started
142     //
143     Context->FDODeviceExtension->SrbErrorHandlingActive = TRUE;
144 
145     //
146     // srb error handling finished
147     //
148     Context->FDODeviceExtension->TimerWorkQueueEnabled = FALSE;
149 
150     //
151     // Initialize and queue the work item to handle the error
152     //
153     ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem,
154                          ErrorHandlerWorkItemRoutine,
155                          ErrorHandlerWorkItemData);
156 
157     ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
158     ErrorHandlerWorkItemData->Context = Context;
159     ErrorHandlerWorkItemData->Irp = Irp;
160     ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
161 
162     DPRINT1("Queuing WorkItemROutine\n");
163     ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue);
164     return STATUS_MORE_PROCESSING_REQUIRED;
165 }
166 
167 
168 //
169 // driver verifier
170 //
171 IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine;
172 
173 NTSTATUS
174 NTAPI
175 USBSTOR_CSWCompletionRoutine(
176     PDEVICE_OBJECT DeviceObject,
177     PIRP Irp,
178     PVOID Ctx)
179 {
180     PIRP_CONTEXT Context;
181     PIO_STACK_LOCATION IoStack;
182     PSCSI_REQUEST_BLOCK Request;
183     PCDB pCDB;
184     PREAD_CAPACITY_DATA_EX CapacityDataEx;
185     PREAD_CAPACITY_DATA CapacityData;
186     PUFI_CAPACITY_RESPONSE Response;
187     NTSTATUS Status;
188 
189     //
190     // access context
191     //
192     Context = (PIRP_CONTEXT)Ctx;
193 
194     //
195     // is there a mdl
196     //
197     if (Context->TransferBufferMDL)
198     {
199         //
200         // is there an irp associated
201         //
202         if (Context->Irp)
203         {
204             //
205             // did we allocate the mdl
206             //
207             if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
208             {
209                 //
210                 // free mdl
211                 //
212                 IoFreeMdl(Context->TransferBufferMDL);
213             }
214         }
215         else
216         {
217             //
218             // free mdl
219             //
220             IoFreeMdl(Context->TransferBufferMDL);
221         }
222     }
223 
224     DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status);
225 
226     if (!NT_SUCCESS(Irp->IoStatus.Information))
227     {
228         if (Context->ErrorIndex == 0)
229         {
230             //
231             // increment error index
232             //
233             Context->ErrorIndex = 1;
234 
235             //
236             // clear stall and resend cbw
237             //
238             Status = USBSTOR_QueueWorkItem(Context, Irp);
239             ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
240             return STATUS_MORE_PROCESSING_REQUIRED;
241         }
242 
243         //
244         // perform reset recovery
245         //
246         Context->ErrorIndex = 2;
247         IoFreeIrp(Irp);
248         Status = USBSTOR_QueueWorkItem(Context, NULL);
249         ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
250         return STATUS_MORE_PROCESSING_REQUIRED;
251     }
252 
253     if (!USBSTOR_IsCSWValid(Context))
254     {
255         //
256         // perform reset recovery
257         //
258         Context->ErrorIndex = 2;
259         IoFreeIrp(Irp);
260         Status = USBSTOR_QueueWorkItem(Context, NULL);
261         ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
262         return STATUS_MORE_PROCESSING_REQUIRED;
263     }
264 
265 
266     //
267     // get current stack location
268     //
269     IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
270 
271     //
272     // get request block
273     //
274     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
275     ASSERT(Request);
276 
277     Status = Irp->IoStatus.Status;
278 
279     //
280     // get SCSI command data block
281     //
282     pCDB = (PCDB)Request->Cdb;
283     Request->SrbStatus = SRB_STATUS_SUCCESS;
284 
285     //
286     // read capacity needs special work
287     //
288     if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
289     {
290         //
291         // get output buffer
292         //
293         Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;
294 
295         //
296         // store in pdo
297         //
298         Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
299         Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
300 
301         if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
302         {
303             //
304             // get input buffer
305             //
306             CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer;
307 
308             //
309             // set result
310             //
311             CapacityDataEx->BytesPerBlock = Response->BlockLength;
312             CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
313             Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);
314        }
315        else
316        {
317             //
318             // get input buffer
319             //
320             CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer;
321 
322             //
323             // set result
324             //
325             CapacityData->BytesPerBlock = Response->BlockLength;
326             CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
327             Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
328        }
329 
330        //
331        // free response
332        //
333        FreeItem(Context->TransferData);
334     }
335 
336     //
337     // free cbw
338     //
339     FreeItem(Context->cbw);
340 
341     //
342     // FIXME: check status
343     //
344     Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
345     Context->Irp->IoStatus.Information = Context->TransferDataLength;
346 
347     //
348     // terminate current request
349     //
350     USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
351 
352     //
353     // complete request
354     //
355     IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
356 
357     //
358     // start next request
359     //
360     USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
361 
362     //
363     // free our allocated irp
364     //
365     IoFreeIrp(Irp);
366 
367     //
368     // free context
369     //
370     FreeItem(Context);
371 
372     //
373     // done
374     //
375     return STATUS_MORE_PROCESSING_REQUIRED;
376 }
377 
378 VOID
379 USBSTOR_SendCSW(
380     PIRP_CONTEXT Context,
381     PIRP Irp)
382 {
383     PIO_STACK_LOCATION IoStack;
384 
385     //
386     // get next irp stack location
387     //
388     IoStack = IoGetNextIrpStackLocation(Irp);
389 
390     //
391     // now initialize the urb for sending the csw
392     //
393     UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
394                                            sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
395                                            Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
396                                            Context->csw,
397                                            NULL,
398                                            512, //FIXME
399                                            USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
400                                            NULL);
401 
402     //
403     // initialize stack location
404     //
405     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
406     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
407     IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
408     IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
409     Irp->IoStatus.Status = STATUS_SUCCESS;
410 
411 
412     //
413     // setup completion routine
414     //
415     IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
416 
417     //
418     // call driver
419     //
420     IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
421 }
422 
423 
424 //
425 // driver verifier
426 //
427 IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
428 
429 NTSTATUS
430 NTAPI
431 USBSTOR_DataCompletionRoutine(
432     PDEVICE_OBJECT DeviceObject,
433     PIRP Irp,
434     PVOID Ctx)
435 {
436     PIRP_CONTEXT Context;
437     NTSTATUS Status;
438 
439 
440     DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
441 
442     //
443     // access context
444     //
445     Context = (PIRP_CONTEXT)Ctx;
446 
447     if (!NT_SUCCESS(Irp->IoStatus.Status))
448     {
449         //
450         // clear stall and resend cbw
451         //
452         Context->ErrorIndex = 1;
453         Status = USBSTOR_QueueWorkItem(Context, Irp);
454         ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
455         return STATUS_MORE_PROCESSING_REQUIRED;
456     }
457 
458     //
459     // send csw
460     //
461     USBSTOR_SendCSW(Context, Irp);
462 
463     //
464     // cancel completion
465     //
466     return STATUS_MORE_PROCESSING_REQUIRED;
467 }
468 
469 //
470 // driver verifier
471 //
472 IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine;
473 
474 NTSTATUS
475 NTAPI
476 USBSTOR_CBWCompletionRoutine(
477     PDEVICE_OBJECT DeviceObject,
478     PIRP Irp,
479     PVOID Ctx)
480 {
481     PIRP_CONTEXT Context;
482     PIO_STACK_LOCATION IoStack;
483     UCHAR Code;
484     USBD_PIPE_HANDLE PipeHandle;
485 
486     DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
487 
488     //
489     // access context
490     //
491     Context = (PIRP_CONTEXT)Ctx;
492 
493     //
494     // get next stack location
495     //
496     IoStack = IoGetNextIrpStackLocation(Irp);
497 
498     //
499     // is there data to be submitted
500     //
501     if (Context->TransferDataLength)
502     {
503         //
504         // get command code
505         //
506         Code = Context->cbw->CommandBlock[0];
507 
508         if (Code == SCSIOP_WRITE)
509         {
510             //
511             // write request use bulk out pipe
512             //
513             PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
514         }
515         else
516         {
517             //
518             // default bulk in pipe
519             //
520             PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
521         }
522 
523         //
524         // now initialize the urb for sending data
525         //
526         UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
527                                                sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
528                                                PipeHandle,
529                                                NULL,
530                                                Context->TransferBufferMDL,
531                                                Context->TransferDataLength,
532                                                ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)),
533                                                NULL);
534 
535         //
536         // setup completion routine
537         //
538         IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
539     }
540     else
541     {
542         //
543         // now initialize the urb for sending the csw
544         //
545 
546         UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
547                                                sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
548                                                Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
549                                                Context->csw,
550                                                NULL,
551                                                512, //FIXME
552                                                USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
553                                                NULL);
554 
555         //
556         // setup completion routine
557         //
558         IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
559     }
560 
561     //
562     // initialize stack location
563     //
564     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
565     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
566     IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
567     IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
568     Irp->IoStatus.Status = STATUS_SUCCESS;
569 
570     //
571     // call driver
572     //
573     IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
574 
575     return STATUS_MORE_PROCESSING_REQUIRED;
576 }
577 
578 VOID
579 DumpCBW(
580     PUCHAR Block)
581 {
582     DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
583         Block[0] & 0xFF, Block[1] & 0xFF, Block[2] & 0xFF, Block[3] & 0xFF, Block[4] & 0xFF, Block[5] & 0xFF, Block[6] & 0xFF, Block[7] & 0xFF, Block[8] & 0xFF, Block[9] & 0xFF,
584         Block[10] & 0xFF, Block[11] & 0xFF, Block[12] & 0xFF, Block[13] & 0xFF, Block[14] & 0xFF, Block[15] & 0xFF, Block[16] & 0xFF, Block[17] & 0xFF, Block[18] & 0xFF, Block[19] & 0xFF,
585         Block[20] & 0xFF, Block[21] & 0xFF, Block[22] & 0xFF, Block[23] & 0xFF, Block[24] & 0xFF, Block[25] & 0xFF, Block[26] & 0xFF, Block[27] & 0xFF, Block[28] & 0xFF, Block[29] & 0xFF,
586         Block[30] & 0xFF);
587 
588 }
589 
590 NTSTATUS
591 USBSTOR_SendCBW(
592     PIRP_CONTEXT Context,
593     PIRP Irp)
594 {
595     PIO_STACK_LOCATION IoStack;
596 
597     //
598     // get next stack location
599     //
600     IoStack = IoGetNextIrpStackLocation(Irp);
601 
602     //
603     // initialize stack location
604     //
605     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
606     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
607     IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
608     IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
609     Irp->IoStatus.Status = STATUS_SUCCESS;
610 
611     //
612     // setup completion routine
613     //
614     IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
615 
616     //
617     // call driver
618     //
619     return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
620 }
621 
622 NTSTATUS
623 USBSTOR_SendRequest(
624     IN PDEVICE_OBJECT DeviceObject,
625     IN PIRP OriginalRequest,
626     IN UCHAR CommandLength,
627     IN PUCHAR Command,
628     IN ULONG TransferDataLength,
629     IN PUCHAR TransferData,
630     IN ULONG RetryCount)
631 {
632     PIRP_CONTEXT Context;
633     PPDO_DEVICE_EXTENSION PDODeviceExtension;
634     PFDO_DEVICE_EXTENSION FDODeviceExtension;
635     PIRP Irp;
636     PUCHAR MdlVirtualAddress;
637 
638     //
639     // first allocate irp context
640     //
641     Context = USBSTOR_AllocateIrpContext();
642     if (!Context)
643     {
644         //
645         // no memory
646         //
647         return STATUS_INSUFFICIENT_RESOURCES;
648     }
649 
650     //
651     // get PDO device extension
652     //
653     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
654 
655     //
656     // get FDO device extension
657     //
658     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
659 
660     //
661     // now build the cbw
662     //
663     USBSTOR_BuildCBW((ULONG)Context->cbw,
664                      TransferDataLength,
665                      PDODeviceExtension->LUN,
666                      CommandLength,
667                      Command,
668                      Context->cbw);
669 
670     DPRINT("CBW %p\n", Context->cbw);
671     DumpCBW((PUCHAR)Context->cbw);
672 
673     //
674     // now initialize the urb
675     //
676     UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
677                                            sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
678                                            FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
679                                            Context->cbw,
680                                            NULL,
681                                            sizeof(CBW),
682                                            USBD_TRANSFER_DIRECTION_OUT,
683                                            NULL);
684 
685     //
686     // initialize rest of context
687     //
688     Context->Irp = OriginalRequest;
689     Context->TransferData = TransferData;
690     Context->TransferDataLength = TransferDataLength;
691     Context->FDODeviceExtension = FDODeviceExtension;
692     Context->PDODeviceExtension = PDODeviceExtension;
693     Context->RetryCount = RetryCount;
694 
695     //
696     // is there transfer data
697     //
698     if (Context->TransferDataLength)
699     {
700         //
701         // check if the original request already does have an mdl associated
702         //
703         if (OriginalRequest)
704         {
705             if ((OriginalRequest->MdlAddress != NULL) &&
706                 (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
707             {
708                 //
709                 // Sanity check that the Mdl does describe the TransferData for read/write
710                 //
711                 if (CommandLength == UFI_READ_WRITE_CMD_LEN)
712                 {
713                     MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);
714 
715                     //
716                     // is there an offset
717                     //
718                     if (MdlVirtualAddress != Context->TransferData)
719                     {
720                         //
721                         // lets build an mdl
722                         //
723                         Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
724                         if (!Context->TransferBufferMDL)
725                         {
726                             //
727                             // failed to allocate MDL
728                             //
729                             FreeItem(Context->cbw);
730                             FreeItem(Context);
731                             return STATUS_INSUFFICIENT_RESOURCES;
732                         }
733 
734                         //
735                         // now build the partial mdl
736                         //
737                         IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
738                     }
739                 }
740 
741                 if (!Context->TransferBufferMDL)
742                 {
743                     //
744                     // I/O paging request
745                     //
746                     Context->TransferBufferMDL = OriginalRequest->MdlAddress;
747                 }
748             }
749             else
750             {
751                 //
752                 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
753                 //
754                 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
755                 if (!Context->TransferBufferMDL)
756                 {
757                     //
758                     // failed to allocate MDL
759                     //
760                     FreeItem(Context->cbw);
761                     FreeItem(Context);
762                     return STATUS_INSUFFICIENT_RESOURCES;
763                 }
764 
765                 //
766                 // build mdl for nonpaged pool
767                 //
768                 MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
769             }
770         }
771         else
772         {
773             //
774             // allocate mdl for buffer, buffer must be allocated from NonPagedPool
775             //
776             Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
777             if (!Context->TransferBufferMDL)
778             {
779                 //
780                 // failed to allocate MDL
781                 //
782                 FreeItem(Context->cbw);
783                 FreeItem(Context);
784                 return STATUS_INSUFFICIENT_RESOURCES;
785             }
786 
787             //
788             // build mdl for nonpaged pool
789             //
790             MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
791         }
792     }
793 
794     //
795     // now allocate the request
796     //
797     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
798     if (!Irp)
799     {
800         FreeItem(Context->cbw);
801         FreeItem(Context);
802         return STATUS_INSUFFICIENT_RESOURCES;
803     }
804 
805     if (OriginalRequest)
806     {
807         //
808         // mark orignal irp as pending
809         //
810         IoMarkIrpPending(OriginalRequest);
811     }
812 
813     //
814     // send request
815     //
816     USBSTOR_SendCBW(Context, Irp);
817 
818     //
819     // done
820     //
821     return STATUS_PENDING;
822 }
823 
824 NTSTATUS
825 USBSTOR_SendFormatCapacity(
826     IN PDEVICE_OBJECT DeviceObject,
827     IN PIRP Irp,
828     IN ULONG RetryCount)
829 {
830     UFI_READ_FORMAT_CAPACITY Cmd;
831     PPDO_DEVICE_EXTENSION PDODeviceExtension;
832     PIO_STACK_LOCATION IoStack;
833     PSCSI_REQUEST_BLOCK Request;
834 
835     //
836     // get current stack location
837     //
838     IoStack = IoGetCurrentIrpStackLocation(Irp);
839 
840     //
841     // get PDO device extension
842     //
843     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
844 
845     //
846     // get request block
847     //
848     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
849 
850     //
851     // initialize inquiry cmd
852     //
853     RtlZeroMemory(&Cmd, sizeof(UFI_READ_FORMAT_CAPACITY));
854     Cmd.Code = SCSIOP_READ_FORMATTED_CAPACITY;
855     Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
856     Cmd.AllocationLengthMsb = HTONS(Request->DataTransferLength & 0xFFFF) >> 8;
857     Cmd.AllocationLengthLsb = HTONS(Request->DataTransferLength & 0xFFFF) & 0xFF;
858 
859     //
860     // now send the request
861     //
862     return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_FORMAT_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
863 }
864 
865 NTSTATUS
866 USBSTOR_SendInquiry(
867     IN PDEVICE_OBJECT DeviceObject,
868     IN PIRP Irp,
869     IN ULONG RetryCount)
870 {
871     UFI_INQUIRY_CMD Cmd;
872     PPDO_DEVICE_EXTENSION PDODeviceExtension;
873     PIO_STACK_LOCATION IoStack;
874     PSCSI_REQUEST_BLOCK Request;
875 
876     //
877     // get current stack location
878     //
879     IoStack = IoGetCurrentIrpStackLocation(Irp);
880 
881     //
882     // get request block
883     //
884     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
885 
886     //
887     // get PDO device extension
888     //
889     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
890 
891     //
892     // initialize inquiry cmd
893     //
894     RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
895     Cmd.Code = SCSIOP_INQUIRY;
896     Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
897     Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
898 
899     //
900     // sanity check
901     //
902     ASSERT(Request->DataTransferLength >= sizeof(UFI_INQUIRY_RESPONSE));
903 
904     //
905     // now send the request
906     //
907     return USBSTOR_SendRequest(DeviceObject, Irp, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
908 }
909 
910 NTSTATUS
911 USBSTOR_SendCapacity(
912     IN PDEVICE_OBJECT DeviceObject,
913     IN PIRP Irp,
914     IN ULONG RetryCount)
915 {
916     UFI_CAPACITY_CMD Cmd;
917     PUFI_CAPACITY_RESPONSE Response;
918     PPDO_DEVICE_EXTENSION PDODeviceExtension;
919 
920     //
921     // get PDO device extension
922     //
923     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
924 
925     //
926     // allocate capacity response
927     //
928     Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, PAGE_SIZE);
929     if (!Response)
930     {
931         //
932         // no memory
933         //
934         return STATUS_INSUFFICIENT_RESOURCES;
935     }
936 
937     //
938     // initialize capacity cmd
939     //
940     RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
941     Cmd.Code = SCSIOP_READ_CAPACITY;
942     Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
943 
944     //
945     // send request, response will be freed in completion routine
946     //
947     return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response, RetryCount);
948 }
949 
950 NTSTATUS
951 USBSTOR_SendModeSense(
952     IN PDEVICE_OBJECT DeviceObject,
953     IN PIRP Irp,
954     IN ULONG RetryCount)
955 {
956 #if 0
957     UFI_SENSE_CMD Cmd;
958     NTSTATUS Status;
959     PVOID Response;
960     PCBW OutControl;
961     PCDB pCDB;
962     PUFI_MODE_PARAMETER_HEADER Header;
963 #endif
964     PPDO_DEVICE_EXTENSION PDODeviceExtension;
965     PIO_STACK_LOCATION IoStack;
966     PSCSI_REQUEST_BLOCK Request;
967 
968     //
969     // get PDO device extension
970     //
971     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
972 
973     //
974     // sanity check
975     //
976     ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
977 
978     //
979     // get current stack location
980     //
981     IoStack = IoGetCurrentIrpStackLocation(Irp);
982 
983     //
984     // get request block
985     //
986     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
987 
988     RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength);
989     Request->SrbStatus = SRB_STATUS_SUCCESS;
990     Irp->IoStatus.Information = Request->DataTransferLength;
991     Irp->IoStatus.Status = STATUS_SUCCESS;
992     USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
993     IoCompleteRequest(Irp, IO_NO_INCREMENT);
994 
995     //
996     // start next request
997     //
998     USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
999 
1000     return STATUS_SUCCESS;
1001 
1002 #if 0
1003     //
1004     // get SCSI command data block
1005     //
1006     pCDB = (PCDB)Request->Cdb;
1007 
1008     //
1009     // get PDO device extension
1010     //
1011     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1012 
1013     //
1014     // allocate sense response from non paged pool
1015     //
1016     Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
1017     if (!Response)
1018     {
1019         //
1020         // no memory
1021         //
1022         return STATUS_INSUFFICIENT_RESOURCES;
1023     }
1024 
1025     //
1026     // sanity check
1027     //
1028 
1029 
1030     // Supported pages
1031     // MODE_PAGE_ERROR_RECOVERY
1032     // MODE_PAGE_FLEXIBILE
1033     // MODE_PAGE_LUN_MAPPING
1034     // MODE_PAGE_FAULT_REPORTING
1035     // MODE_SENSE_RETURN_ALL
1036 
1037     //
1038     // initialize mode sense cmd
1039     //
1040     RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
1041     Cmd.Code = SCSIOP_MODE_SENSE;
1042     Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
1043     Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
1044     Cmd.PC = pCDB->MODE_SENSE.Pc;
1045     Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
1046 
1047     DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
1048     DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
1049 
1050     //
1051     // now send mode sense cmd
1052     //
1053     Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
1054     if (!NT_SUCCESS(Status))
1055     {
1056         //
1057         // failed to send CBW
1058         //
1059         DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
1060         FreeItem(Response);
1061         ASSERT(FALSE);
1062         return Status;
1063     }
1064 
1065     //
1066     // now send data block response
1067     //
1068     Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
1069     if (!NT_SUCCESS(Status))
1070     {
1071         //
1072         // failed to send CBW
1073         //
1074         DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
1075         FreeItem(Response);
1076         ASSERT(FALSE);
1077         return Status;
1078     }
1079 
1080     Header = (PUFI_MODE_PARAMETER_HEADER)Response;
1081 
1082     //
1083     // TODO: build layout
1084     //
1085     // first struct is the header
1086     // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
1087     //
1088     // followed by
1089     // MODE_PARAMETER_BLOCK
1090     //
1091     //
1092     UNIMPLEMENTED;
1093 
1094     //
1095     // send csw
1096     //
1097     Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
1098 
1099     DPRINT1("------------------------\n");
1100     DPRINT1("CSW %p\n", &CSW);
1101     DPRINT1("Signature %x\n", CSW.Signature);
1102     DPRINT1("Tag %x\n", CSW.Tag);
1103     DPRINT1("DataResidue %x\n", CSW.DataResidue);
1104     DPRINT1("Status %x\n", CSW.Status);
1105 
1106     //
1107     // FIXME: handle error
1108     //
1109     ASSERT(CSW.Status == 0);
1110     ASSERT(CSW.DataResidue == 0);
1111 
1112     //
1113     // calculate transfer length
1114     //
1115     *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
1116 
1117     //
1118     // copy buffer
1119     //
1120     RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
1121 
1122     //
1123     // free item
1124     //
1125     FreeItem(OutControl);
1126 
1127     //
1128     // free response
1129     //
1130     FreeItem(Response);
1131 
1132     //
1133     // done
1134     //
1135     return Status;
1136 #endif
1137 }
1138 
1139 NTSTATUS
1140 USBSTOR_SendReadWrite(
1141     IN PDEVICE_OBJECT DeviceObject,
1142     IN PIRP Irp,
1143     IN ULONG RetryCount)
1144 {
1145     UFI_READ_WRITE_CMD Cmd;
1146     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1147     PCDB pCDB;
1148     ULONG BlockCount, Temp;
1149     PIO_STACK_LOCATION IoStack;
1150     PSCSI_REQUEST_BLOCK Request;
1151 
1152     //
1153     // get current stack location
1154     //
1155     IoStack = IoGetCurrentIrpStackLocation(Irp);
1156 
1157     //
1158     // get request block
1159     //
1160     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
1161 
1162     //
1163     // get SCSI command data block
1164     //
1165     pCDB = (PCDB)Request->Cdb;
1166 
1167     //
1168     // get PDO device extension
1169     //
1170     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1171 
1172     //
1173     // informal debug print
1174     //
1175     DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
1176 
1177     //
1178     // sanity check
1179     //
1180     ASSERT(PDODeviceExtension->BlockLength);
1181 
1182     //
1183     // block count
1184     //
1185     BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
1186 
1187     //
1188     // initialize read cmd
1189     //
1190     RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
1191     Cmd.Code = pCDB->AsByte[0];
1192     Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
1193     Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
1194     Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
1195     Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
1196     Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
1197     Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
1198     Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;
1199 
1200     //
1201     // sanity check
1202     //
1203     Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1);
1204     ASSERT(Temp == BlockCount);
1205 
1206     DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
1207 
1208     //
1209     // send request
1210     //
1211     return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
1212 }
1213 
1214 NTSTATUS
1215 USBSTOR_SendTestUnit(
1216     IN PDEVICE_OBJECT DeviceObject,
1217     IN OUT PIRP Irp,
1218     IN ULONG RetryCount)
1219 {
1220     UFI_TEST_UNIT_CMD Cmd;
1221     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1222     PIO_STACK_LOCATION IoStack;
1223     PSCSI_REQUEST_BLOCK Request;
1224 
1225     //
1226     // get current stack location
1227     //
1228     IoStack = IoGetCurrentIrpStackLocation(Irp);
1229 
1230     //
1231     // get request block
1232     //
1233     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
1234 
1235     //
1236     // no transfer length
1237     //
1238     ASSERT(Request->DataTransferLength == 0);
1239 
1240     //
1241     // get PDO device extension
1242     //
1243     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1244 
1245     //
1246     // initialize test unit cmd
1247     //
1248     RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
1249     Cmd.Code = SCSIOP_TEST_UNIT_READY;
1250     Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
1251 
1252     //
1253     // send the request
1254     //
1255     return USBSTOR_SendRequest(DeviceObject, Irp, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL, RetryCount);
1256 }
1257 
1258 NTSTATUS
1259 USBSTOR_SendUnknownRequest(
1260     IN PDEVICE_OBJECT DeviceObject,
1261     IN OUT PIRP Irp,
1262     IN ULONG RetryCount)
1263 {
1264     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1265     PIO_STACK_LOCATION IoStack;
1266     PSCSI_REQUEST_BLOCK Request;
1267     UFI_UNKNOWN_CMD Cmd;
1268 
1269     //
1270     // get current stack location
1271     //
1272     IoStack = IoGetCurrentIrpStackLocation(Irp);
1273 
1274     //
1275     // get request block
1276     //
1277     Request = IoStack->Parameters.Others.Argument1;
1278 
1279     //
1280     // get PDO device extension
1281     //
1282     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1283 
1284     //
1285     // check that we're sending to the right LUN
1286     //
1287     ASSERT(Request->Cdb[1] == (PDODeviceExtension->LUN & MAX_LUN));
1288 
1289     //
1290     // sanity check
1291     //
1292     ASSERT(Request->CdbLength <= sizeof(UFI_UNKNOWN_CMD));
1293 
1294     //
1295     // initialize test unit cmd
1296     //
1297     RtlCopyMemory(&Cmd, Request->Cdb, Request->CdbLength);
1298 
1299     //
1300     // send the request
1301     //
1302     return USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)&Cmd, Request->DataTransferLength, Request->DataBuffer, RetryCount);
1303 }
1304 
1305 NTSTATUS
1306 USBSTOR_HandleExecuteSCSI(
1307     IN PDEVICE_OBJECT DeviceObject,
1308     IN PIRP Irp,
1309     IN ULONG RetryCount)
1310 {
1311     PCDB pCDB;
1312     NTSTATUS Status;
1313     PIO_STACK_LOCATION IoStack;
1314     PSCSI_REQUEST_BLOCK Request;
1315     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1316 
1317     //
1318     // get PDO device extension
1319     //
1320     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1321 
1322     //
1323     // sanity check
1324     //
1325     ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
1326 
1327     //
1328     // get current stack location
1329     //
1330     IoStack = IoGetCurrentIrpStackLocation(Irp);
1331 
1332     //
1333     // get request block
1334     //
1335     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
1336 
1337     //
1338     // get SCSI command data block
1339     //
1340     pCDB = (PCDB)Request->Cdb;
1341 
1342     DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
1343 
1344     if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
1345     {
1346         //
1347         // sanity checks
1348         //
1349         ASSERT(Request->DataBuffer);
1350 
1351         DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength);
1352         Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount);
1353     }
1354     else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
1355     {
1356         DPRINT("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
1357         ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
1358         ASSERT(Request->DataBuffer);
1359 
1360         //
1361         // send mode sense command
1362         //
1363         Status = USBSTOR_SendModeSense(DeviceObject, Irp, RetryCount);
1364     }
1365     else if (pCDB->AsByte[0] == SCSIOP_READ_FORMATTED_CAPACITY)
1366     {
1367         DPRINT("SCSIOP_READ_FORMATTED_CAPACITY DataTransferLength %lu\n", Request->DataTransferLength);
1368 
1369         //
1370         // send read format capacity
1371         //
1372         Status = USBSTOR_SendFormatCapacity(DeviceObject, Irp, RetryCount);
1373     }
1374     else if (pCDB->AsByte[0] == SCSIOP_INQUIRY)
1375     {
1376         DPRINT("SCSIOP_INQUIRY DataTransferLength %lu\n", Request->DataTransferLength);
1377 
1378         //
1379         // send read format capacity
1380         //
1381         Status = USBSTOR_SendInquiry(DeviceObject, Irp, RetryCount);
1382     }
1383     else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ ||  pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
1384     {
1385         DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
1386 
1387         //
1388         // send read / write command
1389         //
1390         Status = USBSTOR_SendReadWrite(DeviceObject, Irp, RetryCount);
1391     }
1392     else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
1393     {
1394         DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
1395 
1396         //
1397         // just complete the request
1398         //
1399         Request->SrbStatus = SRB_STATUS_SUCCESS;
1400         Irp->IoStatus.Status = STATUS_SUCCESS;
1401         Irp->IoStatus.Information = Request->DataTransferLength;
1402         USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
1403         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1404 
1405         //
1406         // start next request
1407         //
1408         USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
1409 
1410         return STATUS_SUCCESS;
1411     }
1412     else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
1413     {
1414         DPRINT("SCSIOP_TEST_UNIT_READY\n");
1415 
1416         //
1417         // send test unit command
1418         //
1419         Status = USBSTOR_SendTestUnit(DeviceObject, Irp, RetryCount);
1420     }
1421     else
1422     {
1423         // Unknown request. Simply forward
1424         DPRINT1("Forwarding unknown Operation Code %x\n", pCDB->AsByte[0]);
1425         Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount);
1426     }
1427 
1428     return Status;
1429 }
1430