[USBSTOR]
[reactos.git] / reactos / drivers / usb / usbstor / scsi.c
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 }