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