[USB-BRINGUP-TRUNK]
[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 not 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 ASSERT(MdlVirtualAddress == Context->TransferData);
593 }
594
595 //
596 // I/O paging request
597 //
598 Context->TransferBufferMDL = OriginalRequest->MdlAddress;
599 }
600 else
601 {
602 //
603 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
604 //
605 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
606 if (!Context->TransferBufferMDL)
607 {
608 //
609 // failed to allocate MDL
610 //
611 return STATUS_INSUFFICIENT_RESOURCES;
612 }
613
614 //
615 // build mdl for nonpaged pool
616 //
617 MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
618 }
619 }
620 else
621 {
622 //
623 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
624 //
625 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
626 if (!Context->TransferBufferMDL)
627 {
628 //
629 // failed to allocate MDL
630 //
631 return STATUS_INSUFFICIENT_RESOURCES;
632 }
633
634 //
635 // build mdl for nonpaged pool
636 //
637 MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
638 }
639 }
640
641 //
642 // now allocate the request
643 //
644 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
645 if (!Irp)
646 {
647 FreeItem(Context->cbw);
648 FreeItem(Context);
649 return STATUS_INSUFFICIENT_RESOURCES;
650 }
651
652 //
653 // get next stack location
654 //
655 IoStack = IoGetNextIrpStackLocation(Irp);
656
657 //
658 // initialize stack location
659 //
660 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
661 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
662 IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
663 IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
664 Irp->IoStatus.Status = STATUS_SUCCESS;
665
666 //
667 // setup completion routine
668 //
669 IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
670
671 if (OriginalRequest)
672 {
673 //
674 // mark orignal irp as pending
675 //
676 IoMarkIrpPending(OriginalRequest);
677 }
678
679 //
680 // call driver
681 //
682 IoCallDriver(FDODeviceExtension->LowerDeviceObject, Irp);
683
684 //
685 // done
686 //
687 return STATUS_PENDING;
688 }
689
690 NTSTATUS
691 USBSTOR_SendInquiryCmd(
692 IN PDEVICE_OBJECT DeviceObject)
693 {
694 UFI_INQUIRY_CMD Cmd;
695 NTSTATUS Status;
696 KEVENT Event;
697 PPDO_DEVICE_EXTENSION PDODeviceExtension;
698 PUFI_INQUIRY_RESPONSE Response;
699
700
701 //
702 // allocate inquiry response
703 //
704 Response = AllocateItem(NonPagedPool, PAGE_SIZE);
705 if (!Response)
706 {
707 //
708 // no memory
709 //
710 return STATUS_INSUFFICIENT_RESOURCES;
711 }
712
713 //
714 // get PDO device extension
715 //
716 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
717
718 //
719 // initialize inquiry cmd
720 //
721 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
722 Cmd.Code = SCSIOP_INQUIRY;
723 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
724 Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
725
726 //
727 // initialize event
728 //
729 KeInitializeEvent(&Event, NotificationEvent, FALSE);
730
731 //
732 // now send the request
733 //
734 Status = USBSTOR_SendRequest(DeviceObject, NULL, &Event, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_INQUIRY_RESPONSE), (PUCHAR)Response);
735
736 //
737 // wait for the action to complete
738 //
739 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
740
741 DPRINT1("Response %p\n", Response);
742 DPRINT1("DeviceType %x\n", Response->DeviceType);
743 DPRINT1("RMB %x\n", Response->RMB);
744 DPRINT1("Version %x\n", Response->Version);
745 DPRINT1("Format %x\n", Response->Format);
746 DPRINT1("Length %x\n", Response->Length);
747 DPRINT1("Reserved %x\n", Response->Reserved);
748 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]);
749 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],
750 Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
751 Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
752 Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
753
754 DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
755
756 //
757 // store inquiry data
758 //
759 PDODeviceExtension->InquiryData = (PVOID)Response;
760
761 //
762 // done
763 //
764 return Status;
765 }
766
767 NTSTATUS
768 USBSTOR_SendCapacityCmd(
769 IN PDEVICE_OBJECT DeviceObject,
770 IN PIRP Irp)
771 {
772 UFI_CAPACITY_CMD Cmd;
773 PUFI_CAPACITY_RESPONSE Response;
774 PPDO_DEVICE_EXTENSION PDODeviceExtension;
775
776 //
777 // get PDO device extension
778 //
779 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
780
781 //
782 // allocate capacity response
783 //
784 Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_CAPACITY_RESPONSE));
785 if (!Response)
786 {
787 //
788 // no memory
789 //
790 return STATUS_INSUFFICIENT_RESOURCES;
791 }
792
793 //
794 // initialize capacity cmd
795 //
796 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
797 Cmd.Code = SCSIOP_READ_CAPACITY;
798 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
799
800 //
801 // send request, response will be freed in completion routine
802 //
803 return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response);
804 }
805
806 NTSTATUS
807 USBSTOR_SendModeSenseCmd(
808 IN PDEVICE_OBJECT DeviceObject,
809 IN PIRP Irp)
810 {
811 #if 0
812 UFI_SENSE_CMD Cmd;
813 NTSTATUS Status;
814 PVOID Response;
815 PCBW OutControl;
816 PCDB pCDB;
817 PUFI_MODE_PARAMETER_HEADER Header;
818 #endif
819 PPDO_DEVICE_EXTENSION PDODeviceExtension;
820 PIO_STACK_LOCATION IoStack;
821 PSCSI_REQUEST_BLOCK Request;
822
823 //
824 // get current stack location
825 //
826 IoStack = IoGetCurrentIrpStackLocation(Irp);
827
828 //
829 // get request block
830 //
831 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
832
833 RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength);
834 Request->SrbStatus = SRB_STATUS_SUCCESS;
835 Irp->IoStatus.Information = Request->DataTransferLength;
836 Irp->IoStatus.Status = STATUS_SUCCESS;
837 IoCompleteRequest(Irp, IO_NO_INCREMENT);
838
839 //
840 // get PDO device extension
841 //
842 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
843
844 //
845 // sanity check
846 //
847 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
848
849 //
850 // terminate current request
851 //
852 USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, TRUE);
853
854 //
855 // start next request
856 //
857 USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
858
859 return STATUS_SUCCESS;
860
861 #if 0
862 //
863 // get SCSI command data block
864 //
865 pCDB = (PCDB)Request->Cdb;
866
867 //
868 // get PDO device extension
869 //
870 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
871
872 //
873 // allocate sense response from non paged pool
874 //
875 Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
876 if (!Response)
877 {
878 //
879 // no memory
880 //
881 return STATUS_INSUFFICIENT_RESOURCES;
882 }
883
884 //
885 // sanity check
886 //
887
888
889 // Supported pages
890 // MODE_PAGE_ERROR_RECOVERY
891 // MODE_PAGE_FLEXIBILE
892 // MODE_PAGE_LUN_MAPPING
893 // MODE_PAGE_FAULT_REPORTING
894 // MODE_SENSE_RETURN_ALL
895
896 //
897 // initialize mode sense cmd
898 //
899 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
900 Cmd.Code = SCSIOP_MODE_SENSE;
901 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
902 Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
903 Cmd.PC = pCDB->MODE_SENSE.Pc;
904 Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
905
906 DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
907 DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
908
909 //
910 // now send mode sense cmd
911 //
912 Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
913 if (!NT_SUCCESS(Status))
914 {
915 //
916 // failed to send CBW
917 //
918 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
919 FreeItem(Response);
920 ASSERT(FALSE);
921 return Status;
922 }
923
924 //
925 // now send data block response
926 //
927 Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
928 if (!NT_SUCCESS(Status))
929 {
930 //
931 // failed to send CBW
932 //
933 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
934 FreeItem(Response);
935 ASSERT(FALSE);
936 return Status;
937 }
938
939 Header = (PUFI_MODE_PARAMETER_HEADER)Response;
940
941 //
942 // TODO: build layout
943 //
944 // first struct is the header
945 // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
946 //
947 // followed by
948 // MODE_PARAMETER_BLOCK
949 //
950 //
951 UNIMPLEMENTED
952
953 //
954 // send csw
955 //
956 Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
957
958 DPRINT1("------------------------\n");
959 DPRINT1("CSW %p\n", &CSW);
960 DPRINT1("Signature %x\n", CSW.Signature);
961 DPRINT1("Tag %x\n", CSW.Tag);
962 DPRINT1("DataResidue %x\n", CSW.DataResidue);
963 DPRINT1("Status %x\n", CSW.Status);
964
965 //
966 // FIXME: handle error
967 //
968 ASSERT(CSW.Status == 0);
969 ASSERT(CSW.DataResidue == 0);
970
971 //
972 // calculate transfer length
973 //
974 *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
975
976 //
977 // copy buffer
978 //
979 RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
980
981 //
982 // free item
983 //
984 FreeItem(OutControl);
985
986 //
987 // free response
988 //
989 FreeItem(Response);
990
991 //
992 // done
993 //
994 return Status;
995 #endif
996 }
997
998 NTSTATUS
999 USBSTOR_SendReadWriteCmd(
1000 IN PDEVICE_OBJECT DeviceObject,
1001 IN PIRP Irp)
1002 {
1003 UFI_READ_WRITE_CMD Cmd;
1004 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1005 PCDB pCDB;
1006 ULONG BlockCount;
1007 PIO_STACK_LOCATION IoStack;
1008 PSCSI_REQUEST_BLOCK Request;
1009
1010 //
1011 // get current stack location
1012 //
1013 IoStack = IoGetCurrentIrpStackLocation(Irp);
1014
1015 //
1016 // get request block
1017 //
1018 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
1019
1020 //
1021 // get SCSI command data block
1022 //
1023 pCDB = (PCDB)Request->Cdb;
1024
1025 //
1026 // get PDO device extension
1027 //
1028 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1029
1030 //
1031 // informal debug print
1032 //
1033 DPRINT("USBSTOR_SendReadWriteCmd DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
1034
1035 //
1036 // sanity check
1037 //
1038 ASSERT(PDODeviceExtension->BlockLength);
1039
1040 //
1041 // block count
1042 //
1043 BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
1044
1045 //
1046 // initialize read cmd
1047 //
1048 RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
1049 Cmd.Code = pCDB->AsByte[0];
1050 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
1051 Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
1052 Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
1053 Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
1054 Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
1055 Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
1056 Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;
1057
1058 DPRINT("USBSTOR_SendReadWriteCmd BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
1059
1060 //
1061 // send request
1062 //
1063 return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer);
1064 }
1065
1066 NTSTATUS
1067 USBSTOR_SendTestUnitCmd(
1068 IN PDEVICE_OBJECT DeviceObject,
1069 IN OUT PIRP Irp)
1070 {
1071 UFI_TEST_UNIT_CMD Cmd;
1072 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1073 PIO_STACK_LOCATION IoStack;
1074 PSCSI_REQUEST_BLOCK Request;
1075
1076 //
1077 // get current stack location
1078 //
1079 IoStack = IoGetCurrentIrpStackLocation(Irp);
1080
1081 //
1082 // get request block
1083 //
1084 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
1085
1086 //
1087 // no transfer length
1088 //
1089 ASSERT(Request->DataTransferLength == 0);
1090
1091 //
1092 // get PDO device extension
1093 //
1094 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1095
1096 //
1097 // initialize test unit cmd
1098 //
1099 RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
1100 Cmd.Code = SCSIOP_TEST_UNIT_READY;
1101 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
1102
1103 //
1104 // send the request
1105 //
1106 return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL);
1107 }
1108
1109
1110 NTSTATUS
1111 USBSTOR_HandleExecuteSCSI(
1112 IN PDEVICE_OBJECT DeviceObject,
1113 IN PIRP Irp)
1114 {
1115 PCDB pCDB;
1116 NTSTATUS Status;
1117 PIO_STACK_LOCATION IoStack;
1118 PSCSI_REQUEST_BLOCK Request;
1119 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1120
1121 //
1122 // get PDO device extension
1123 //
1124 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1125
1126 //
1127 // sanity check
1128 //
1129 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
1130
1131 //
1132 // get current stack location
1133 //
1134 IoStack = IoGetCurrentIrpStackLocation(Irp);
1135
1136 //
1137 // get request block
1138 //
1139 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
1140
1141 //
1142 // get SCSI command data block
1143 //
1144 pCDB = (PCDB)Request->Cdb;
1145
1146 DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
1147
1148 if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
1149 {
1150 //
1151 // sanity checks
1152 //
1153 ASSERT(Request->DataBuffer);
1154
1155 DPRINT("SCSIOP_READ_CAPACITY Length %\n", Request->DataTransferLength);
1156 Status = USBSTOR_SendCapacityCmd(DeviceObject, Irp);
1157 }
1158 else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
1159 {
1160 DPRINT1("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
1161 ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
1162 ASSERT(Request->DataBuffer);
1163
1164 //
1165 // send mode sense command
1166 //
1167 Status = USBSTOR_SendModeSenseCmd(DeviceObject, Irp);
1168 }
1169 else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ || pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
1170 {
1171 DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
1172
1173 //
1174 // send read / write command
1175 //
1176 Status = USBSTOR_SendReadWriteCmd(DeviceObject, Irp);
1177 }
1178 else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
1179 {
1180 DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
1181
1182 //
1183 // just complete the request
1184 //
1185 Request->SrbStatus = SRB_STATUS_SUCCESS;
1186 Irp->IoStatus.Status = STATUS_SUCCESS;
1187 Irp->IoStatus.Information = Request->DataTransferLength;
1188 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1189
1190 //
1191 // terminate current request
1192 //
1193 USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, TRUE);
1194
1195 //
1196 // start next request
1197 //
1198 USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
1199
1200 return STATUS_SUCCESS;
1201 }
1202 else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
1203 {
1204 DPRINT("SCSIOP_TEST_UNIT_READY\n");
1205
1206 //
1207 // send test unit command
1208 //
1209 Status = USBSTOR_SendTestUnitCmd(DeviceObject, Irp);
1210 }
1211 else
1212 {
1213 UNIMPLEMENTED;
1214 Request->SrbStatus = SRB_STATUS_ERROR;
1215 Status = STATUS_NOT_SUPPORTED;
1216 DbgBreakPoint();
1217 }
1218
1219 return Status;
1220 }