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