4c7c3efb7d70596bb6004f0ca42c99290381dfc5
[reactos.git] / drivers / usb / usbstor / scsi.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: USB block storage device driver.
5 * COPYRIGHT: 2005-2006 James Tabor
6 * 2011-2012 Michael Martin (michael.martin@reactos.org)
7 * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbstor.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 NTSTATUS
17 USBSTOR_BuildCBW(
18 IN ULONG Tag,
19 IN ULONG DataTransferLength,
20 IN UCHAR LUN,
21 IN UCHAR CommandBlockLength,
22 IN PUCHAR CommandBlock,
23 IN OUT PCBW Control)
24 {
25 ASSERT(CommandBlockLength <= 16);
26
27 Control->Signature = CBW_SIGNATURE;
28 Control->Tag = Tag;
29 Control->DataTransferLength = DataTransferLength;
30 Control->Flags = (CommandBlock[0] != SCSIOP_WRITE) ? 0x80 : 0x00;
31 Control->LUN = (LUN & MAX_LUN);
32 Control->CommandBlockLength = CommandBlockLength;
33
34 RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength);
35
36 return STATUS_SUCCESS;
37 }
38
39 PIRP_CONTEXT
40 USBSTOR_AllocateIrpContext()
41 {
42 PIRP_CONTEXT Context;
43
44 Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT));
45 if (!Context)
46 {
47 return NULL;
48 }
49
50 Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512);
51 if (!Context->cbw)
52 {
53 FreeItem(Context);
54 return NULL;
55 }
56
57 return Context;
58 }
59
60 BOOLEAN
61 USBSTOR_IsCSWValid(
62 PIRP_CONTEXT Context)
63 {
64 if (Context->csw->Signature != CSW_SIGNATURE)
65 {
66 DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature);
67 return FALSE;
68 }
69
70 if (Context->csw->Tag != (ULONG_PTR)Context->csw)
71 {
72 DPRINT1("[USBSTOR] Expected Tag %Ix but got %x\n", (ULONG_PTR)Context->csw, Context->csw->Tag);
73 return FALSE;
74 }
75
76 if (Context->csw->Status != 0x00)
77 {
78 DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status);
79 return FALSE;
80 }
81
82 return TRUE;
83 }
84
85 NTSTATUS
86 USBSTOR_QueueWorkItem(
87 PIRP_CONTEXT Context,
88 PIRP Irp)
89 {
90 PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData;
91
92 ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG);
93 if (!ErrorHandlerWorkItemData)
94 {
95 return STATUS_INSUFFICIENT_RESOURCES;
96 }
97
98 // error handling started
99 Context->FDODeviceExtension->SrbErrorHandlingActive = TRUE;
100
101 // srb error handling finished
102 Context->FDODeviceExtension->TimerWorkQueueEnabled = FALSE;
103
104 // Initialize and queue the work item to handle the error
105 ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem,
106 ErrorHandlerWorkItemRoutine,
107 ErrorHandlerWorkItemData);
108
109 ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
110 ErrorHandlerWorkItemData->Context = Context;
111 ErrorHandlerWorkItemData->Irp = Irp;
112 ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
113
114 DPRINT1("Queuing WorkItemROutine\n");
115 ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue);
116 return STATUS_MORE_PROCESSING_REQUIRED;
117 }
118
119 IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine;
120
121 NTSTATUS
122 NTAPI
123 USBSTOR_CSWCompletionRoutine(
124 PDEVICE_OBJECT DeviceObject,
125 PIRP Irp,
126 PVOID Ctx)
127 {
128 PIRP_CONTEXT Context;
129 PIO_STACK_LOCATION IoStack;
130 PSCSI_REQUEST_BLOCK Request;
131 PCDB pCDB;
132 PREAD_CAPACITY_DATA_EX CapacityDataEx;
133 PREAD_CAPACITY_DATA CapacityData;
134 PUFI_CAPACITY_RESPONSE Response;
135 NTSTATUS Status;
136
137 Context = (PIRP_CONTEXT)Ctx;
138
139 if (Context->TransferBufferMDL)
140 {
141 // is there an irp associated
142 if (Context->Irp)
143 {
144 // did we allocate the mdl
145 if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
146 {
147 IoFreeMdl(Context->TransferBufferMDL);
148 }
149 }
150 else
151 {
152 IoFreeMdl(Context->TransferBufferMDL);
153 }
154 }
155
156 DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status);
157
158 if (!NT_SUCCESS(Irp->IoStatus.Information))
159 {
160 if (Context->ErrorIndex == 0)
161 {
162 Context->ErrorIndex = 1;
163
164 // clear stall and resend cbw
165 Status = USBSTOR_QueueWorkItem(Context, Irp);
166 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
167 return STATUS_MORE_PROCESSING_REQUIRED;
168 }
169
170 // perform reset recovery
171 Context->ErrorIndex = 2;
172 IoFreeIrp(Irp);
173 Status = USBSTOR_QueueWorkItem(Context, NULL);
174 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
175 return STATUS_MORE_PROCESSING_REQUIRED;
176 }
177
178 if (!USBSTOR_IsCSWValid(Context))
179 {
180 // perform reset recovery
181 Context->ErrorIndex = 2;
182 IoFreeIrp(Irp);
183 Status = USBSTOR_QueueWorkItem(Context, NULL);
184 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
185 return STATUS_MORE_PROCESSING_REQUIRED;
186 }
187
188
189 IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
190
191 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
192 ASSERT(Request);
193
194 Status = Irp->IoStatus.Status;
195
196 pCDB = (PCDB)Request->Cdb;
197 Request->SrbStatus = SRB_STATUS_SUCCESS;
198
199 // read capacity needs special work
200 if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
201 {
202 // get output buffer
203 Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;
204
205 // store in pdo
206 Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
207 Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
208
209 if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
210 {
211 // get input buffer
212 CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer;
213
214 // set result
215 CapacityDataEx->BytesPerBlock = Response->BlockLength;
216 CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
217 Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);
218 }
219 else
220 {
221 // get input buffer
222 CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer;
223
224 // set result
225 CapacityData->BytesPerBlock = Response->BlockLength;
226 CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
227 Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
228 }
229
230 FreeItem(Context->TransferData);
231 }
232
233 FreeItem(Context->cbw);
234
235 // FIXME: check status
236 Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
237 Context->Irp->IoStatus.Information = Context->TransferDataLength;
238
239 // terminate current request
240 USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
241
242 IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
243
244 USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
245
246 IoFreeIrp(Irp);
247 FreeItem(Context);
248 return STATUS_MORE_PROCESSING_REQUIRED;
249 }
250
251 VOID
252 USBSTOR_SendCSW(
253 PIRP_CONTEXT Context,
254 PIRP Irp)
255 {
256 PIO_STACK_LOCATION IoStack;
257
258 IoStack = IoGetNextIrpStackLocation(Irp);
259
260 // now initialize the urb for sending the csw
261 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
262 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
263 Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
264 Context->csw,
265 NULL,
266 512, //FIXME
267 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
268 NULL);
269
270 // initialize stack location
271 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
272 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
273 IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
274 IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
275 Irp->IoStatus.Status = STATUS_SUCCESS;
276
277 IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
278
279 IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
280 }
281
282 IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
283
284 NTSTATUS
285 NTAPI
286 USBSTOR_DataCompletionRoutine(
287 PDEVICE_OBJECT DeviceObject,
288 PIRP Irp,
289 PVOID Ctx)
290 {
291 PIRP_CONTEXT Context;
292 NTSTATUS Status;
293
294
295 DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
296
297 Context = (PIRP_CONTEXT)Ctx;
298
299 if (!NT_SUCCESS(Irp->IoStatus.Status))
300 {
301 // clear stall and resend cbw
302 Context->ErrorIndex = 1;
303 Status = USBSTOR_QueueWorkItem(Context, Irp);
304 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
305 return STATUS_MORE_PROCESSING_REQUIRED;
306 }
307
308 USBSTOR_SendCSW(Context, Irp);
309
310 return STATUS_MORE_PROCESSING_REQUIRED;
311 }
312
313 IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine;
314
315 NTSTATUS
316 NTAPI
317 USBSTOR_CBWCompletionRoutine(
318 PDEVICE_OBJECT DeviceObject,
319 PIRP Irp,
320 PVOID Ctx)
321 {
322 PIRP_CONTEXT Context;
323 PIO_STACK_LOCATION IoStack;
324 UCHAR Code;
325 USBD_PIPE_HANDLE PipeHandle;
326
327 DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
328
329 Context = (PIRP_CONTEXT)Ctx;
330 IoStack = IoGetNextIrpStackLocation(Irp);
331
332 // is there data to be submitted
333 if (Context->TransferDataLength)
334 {
335 // get command code
336 Code = Context->cbw->CommandBlock[0];
337
338 if (Code == SCSIOP_WRITE)
339 {
340 // write request - use bulk out pipe
341 PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
342 }
343 else
344 {
345 // default bulk in pipe
346 PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
347 }
348
349 // now initialize the urb for sending data
350 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
351 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
352 PipeHandle,
353 NULL,
354 Context->TransferBufferMDL,
355 Context->TransferDataLength,
356 ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)),
357 NULL);
358
359 IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
360 }
361 else
362 {
363 // now initialize the urb for sending the csw
364 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
365 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
366 Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
367 Context->csw,
368 NULL,
369 512, //FIXME
370 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
371 NULL);
372
373 IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
374 }
375
376 // initialize stack location
377 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
378 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
379 IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
380 IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
381 Irp->IoStatus.Status = STATUS_SUCCESS;
382
383 IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
384
385 return STATUS_MORE_PROCESSING_REQUIRED;
386 }
387
388 VOID
389 DumpCBW(
390 PUCHAR Block)
391 {
392 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",
393 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,
394 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,
395 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,
396 Block[30] & 0xFF);
397
398 }
399
400 NTSTATUS
401 USBSTOR_SendCBW(
402 PIRP_CONTEXT Context,
403 PIRP Irp)
404 {
405 PIO_STACK_LOCATION IoStack;
406
407 IoStack = IoGetNextIrpStackLocation(Irp);
408
409 // initialize stack location
410 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
411 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
412 IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
413 IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
414 Irp->IoStatus.Status = STATUS_SUCCESS;
415
416 IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
417
418 return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
419 }
420
421 NTSTATUS
422 USBSTOR_SendRequest(
423 IN PDEVICE_OBJECT DeviceObject,
424 IN PIRP OriginalRequest,
425 IN UCHAR CommandLength,
426 IN PUCHAR Command,
427 IN ULONG TransferDataLength,
428 IN PUCHAR TransferData,
429 IN ULONG RetryCount)
430 {
431 PIRP_CONTEXT Context;
432 PPDO_DEVICE_EXTENSION PDODeviceExtension;
433 PFDO_DEVICE_EXTENSION FDODeviceExtension;
434 PIRP Irp;
435 PUCHAR MdlVirtualAddress;
436
437 Context = USBSTOR_AllocateIrpContext();
438 if (!Context)
439 {
440 return STATUS_INSUFFICIENT_RESOURCES;
441 }
442
443 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
444 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
445
446 USBSTOR_BuildCBW(PtrToUlong(Context->cbw),
447 TransferDataLength,
448 PDODeviceExtension->LUN,
449 CommandLength,
450 Command,
451 Context->cbw);
452
453 DPRINT("CBW %p\n", Context->cbw);
454 DumpCBW((PUCHAR)Context->cbw);
455
456 // now initialize the urb
457 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
458 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
459 FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
460 Context->cbw,
461 NULL,
462 sizeof(CBW),
463 USBD_TRANSFER_DIRECTION_OUT,
464 NULL);
465
466 // initialize rest of context
467 Context->Irp = OriginalRequest;
468 Context->TransferData = TransferData;
469 Context->TransferDataLength = TransferDataLength;
470 Context->FDODeviceExtension = FDODeviceExtension;
471 Context->PDODeviceExtension = PDODeviceExtension;
472 Context->RetryCount = RetryCount;
473
474 // is there transfer data
475 if (Context->TransferDataLength)
476 {
477 // check if the original request already does have an mdl associated
478 if (OriginalRequest)
479 {
480 if ((OriginalRequest->MdlAddress != NULL) &&
481 (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
482 {
483 // Sanity check that the Mdl does describe the TransferData for read/write
484 if (CommandLength == UFI_READ_WRITE_CMD_LEN)
485 {
486 MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);
487
488 // is there an offset
489 if (MdlVirtualAddress != Context->TransferData)
490 {
491 // lets build an mdl
492 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
493 if (!Context->TransferBufferMDL)
494 {
495 FreeItem(Context->cbw);
496 FreeItem(Context);
497 return STATUS_INSUFFICIENT_RESOURCES;
498 }
499
500 IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
501 }
502 }
503
504 if (!Context->TransferBufferMDL)
505 {
506 // I/O paging request
507 Context->TransferBufferMDL = OriginalRequest->MdlAddress;
508 }
509 }
510 else
511 {
512 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
513 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
514 if (!Context->TransferBufferMDL)
515 {
516 FreeItem(Context->cbw);
517 FreeItem(Context);
518 return STATUS_INSUFFICIENT_RESOURCES;
519 }
520
521 MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
522 }
523 }
524 else
525 {
526 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
527 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
528 if (!Context->TransferBufferMDL)
529 {
530 FreeItem(Context->cbw);
531 FreeItem(Context);
532 return STATUS_INSUFFICIENT_RESOURCES;
533 }
534
535 MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
536 }
537 }
538
539 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
540 if (!Irp)
541 {
542 FreeItem(Context->cbw);
543 FreeItem(Context);
544 return STATUS_INSUFFICIENT_RESOURCES;
545 }
546
547 if (OriginalRequest)
548 {
549 IoMarkIrpPending(OriginalRequest);
550 }
551
552 USBSTOR_SendCBW(Context, Irp);
553
554 return STATUS_PENDING;
555 }
556
557 NTSTATUS
558 USBSTOR_SendFormatCapacity(
559 IN PDEVICE_OBJECT DeviceObject,
560 IN PIRP Irp,
561 IN ULONG RetryCount)
562 {
563 UFI_READ_FORMAT_CAPACITY Cmd;
564 PPDO_DEVICE_EXTENSION PDODeviceExtension;
565 PIO_STACK_LOCATION IoStack;
566 PSCSI_REQUEST_BLOCK Request;
567
568 IoStack = IoGetCurrentIrpStackLocation(Irp);
569 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
570 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
571
572 // initialize inquiry cmd
573 RtlZeroMemory(&Cmd, sizeof(UFI_READ_FORMAT_CAPACITY));
574 Cmd.Code = SCSIOP_READ_FORMATTED_CAPACITY;
575 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
576 Cmd.AllocationLengthMsb = HTONS(Request->DataTransferLength & 0xFFFF) >> 8;
577 Cmd.AllocationLengthLsb = HTONS(Request->DataTransferLength & 0xFFFF) & 0xFF;
578
579 return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_FORMAT_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
580 }
581
582 NTSTATUS
583 USBSTOR_SendInquiry(
584 IN PDEVICE_OBJECT DeviceObject,
585 IN PIRP Irp,
586 IN ULONG RetryCount)
587 {
588 UFI_INQUIRY_CMD Cmd;
589 PPDO_DEVICE_EXTENSION PDODeviceExtension;
590 PIO_STACK_LOCATION IoStack;
591 PSCSI_REQUEST_BLOCK Request;
592
593 IoStack = IoGetCurrentIrpStackLocation(Irp);
594 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
595 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
596
597 // initialize inquiry cmd
598 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
599 Cmd.Code = SCSIOP_INQUIRY;
600 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
601 Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
602
603 ASSERT(Request->DataTransferLength >= sizeof(UFI_INQUIRY_RESPONSE));
604
605 return USBSTOR_SendRequest(DeviceObject, Irp, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
606 }
607
608 NTSTATUS
609 USBSTOR_SendCapacity(
610 IN PDEVICE_OBJECT DeviceObject,
611 IN PIRP Irp,
612 IN ULONG RetryCount)
613 {
614 UFI_CAPACITY_CMD Cmd;
615 PUFI_CAPACITY_RESPONSE Response;
616 PPDO_DEVICE_EXTENSION PDODeviceExtension;
617
618 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
619
620 Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, PAGE_SIZE);
621 if (!Response)
622 {
623 return STATUS_INSUFFICIENT_RESOURCES;
624 }
625
626 // initialize capacity cmd
627 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
628 Cmd.Code = SCSIOP_READ_CAPACITY;
629 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
630
631 return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response, RetryCount);
632 }
633
634 NTSTATUS
635 USBSTOR_SendModeSense(
636 IN PDEVICE_OBJECT DeviceObject,
637 IN PIRP Irp,
638 IN ULONG RetryCount)
639 {
640 #if 0
641 UFI_SENSE_CMD Cmd;
642 NTSTATUS Status;
643 PVOID Response;
644 PCBW OutControl;
645 PCDB pCDB;
646 PUFI_MODE_PARAMETER_HEADER Header;
647 #endif
648 PPDO_DEVICE_EXTENSION PDODeviceExtension;
649 PIO_STACK_LOCATION IoStack;
650 PSCSI_REQUEST_BLOCK Request;
651
652 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
653 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
654
655 IoStack = IoGetCurrentIrpStackLocation(Irp);
656 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
657
658 RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength);
659 Request->SrbStatus = SRB_STATUS_SUCCESS;
660 Irp->IoStatus.Information = Request->DataTransferLength;
661 Irp->IoStatus.Status = STATUS_SUCCESS;
662 USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
663 IoCompleteRequest(Irp, IO_NO_INCREMENT);
664
665 USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
666
667 return STATUS_SUCCESS;
668
669 #if 0
670 //
671 // get SCSI command data block
672 //
673 pCDB = (PCDB)Request->Cdb;
674
675 //
676 // get PDO device extension
677 //
678 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
679
680 //
681 // allocate sense response from non paged pool
682 //
683 Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
684 if (!Response)
685 {
686 //
687 // no memory
688 //
689 return STATUS_INSUFFICIENT_RESOURCES;
690 }
691
692 //
693 // sanity check
694 //
695
696
697 // Supported pages
698 // MODE_PAGE_ERROR_RECOVERY
699 // MODE_PAGE_FLEXIBILE
700 // MODE_PAGE_LUN_MAPPING
701 // MODE_PAGE_FAULT_REPORTING
702 // MODE_SENSE_RETURN_ALL
703
704 //
705 // initialize mode sense cmd
706 //
707 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
708 Cmd.Code = SCSIOP_MODE_SENSE;
709 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
710 Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
711 Cmd.PC = pCDB->MODE_SENSE.Pc;
712 Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
713
714 DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
715 DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
716
717 //
718 // now send mode sense cmd
719 //
720 Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
721 if (!NT_SUCCESS(Status))
722 {
723 //
724 // failed to send CBW
725 //
726 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
727 FreeItem(Response);
728 ASSERT(FALSE);
729 return Status;
730 }
731
732 //
733 // now send data block response
734 //
735 Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
736 if (!NT_SUCCESS(Status))
737 {
738 //
739 // failed to send CBW
740 //
741 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
742 FreeItem(Response);
743 ASSERT(FALSE);
744 return Status;
745 }
746
747 Header = (PUFI_MODE_PARAMETER_HEADER)Response;
748
749 //
750 // TODO: build layout
751 //
752 // first struct is the header
753 // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
754 //
755 // followed by
756 // MODE_PARAMETER_BLOCK
757 //
758 //
759 UNIMPLEMENTED;
760
761 //
762 // send csw
763 //
764 Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
765
766 DPRINT1("------------------------\n");
767 DPRINT1("CSW %p\n", &CSW);
768 DPRINT1("Signature %x\n", CSW.Signature);
769 DPRINT1("Tag %x\n", CSW.Tag);
770 DPRINT1("DataResidue %x\n", CSW.DataResidue);
771 DPRINT1("Status %x\n", CSW.Status);
772
773 //
774 // FIXME: handle error
775 //
776 ASSERT(CSW.Status == 0);
777 ASSERT(CSW.DataResidue == 0);
778
779 //
780 // calculate transfer length
781 //
782 *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
783
784 //
785 // copy buffer
786 //
787 RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
788
789 //
790 // free item
791 //
792 FreeItem(OutControl);
793
794 //
795 // free response
796 //
797 FreeItem(Response);
798
799 //
800 // done
801 //
802 return Status;
803 #endif
804 }
805
806 NTSTATUS
807 USBSTOR_SendReadWrite(
808 IN PDEVICE_OBJECT DeviceObject,
809 IN PIRP Irp,
810 IN ULONG RetryCount)
811 {
812 UFI_READ_WRITE_CMD Cmd;
813 PPDO_DEVICE_EXTENSION PDODeviceExtension;
814 PCDB pCDB;
815 ULONG BlockCount, Temp;
816 PIO_STACK_LOCATION IoStack;
817 PSCSI_REQUEST_BLOCK Request;
818
819 IoStack = IoGetCurrentIrpStackLocation(Irp);
820 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
821
822 pCDB = (PCDB)Request->Cdb;
823
824 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
825
826 DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
827
828 ASSERT(PDODeviceExtension->BlockLength);
829
830 BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
831
832 // initialize read cmd
833 RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
834 Cmd.Code = pCDB->AsByte[0];
835 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
836 Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
837 Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
838 Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
839 Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
840 Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
841 Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;
842
843 Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1);
844 ASSERT(Temp == BlockCount);
845
846 DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
847
848 return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
849 }
850
851 NTSTATUS
852 USBSTOR_SendTestUnit(
853 IN PDEVICE_OBJECT DeviceObject,
854 IN OUT PIRP Irp,
855 IN ULONG RetryCount)
856 {
857 UFI_TEST_UNIT_CMD Cmd;
858 PPDO_DEVICE_EXTENSION PDODeviceExtension;
859 PIO_STACK_LOCATION IoStack;
860 PSCSI_REQUEST_BLOCK Request;
861
862 IoStack = IoGetCurrentIrpStackLocation(Irp);
863 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
864
865 ASSERT(Request->DataTransferLength == 0);
866
867 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
868
869 // initialize test unit cmd
870 RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
871 Cmd.Code = SCSIOP_TEST_UNIT_READY;
872 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
873
874 return USBSTOR_SendRequest(DeviceObject, Irp, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL, RetryCount);
875 }
876
877 NTSTATUS
878 USBSTOR_SendUnknownRequest(
879 IN PDEVICE_OBJECT DeviceObject,
880 IN OUT PIRP Irp,
881 IN ULONG RetryCount)
882 {
883 PPDO_DEVICE_EXTENSION PDODeviceExtension;
884 PIO_STACK_LOCATION IoStack;
885 PSCSI_REQUEST_BLOCK Request;
886 UFI_UNKNOWN_CMD Cmd;
887
888 IoStack = IoGetCurrentIrpStackLocation(Irp);
889 Request = IoStack->Parameters.Others.Argument1;
890 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
891
892 // check that we're sending to the right LUN
893 ASSERT(Request->Cdb[1] == (PDODeviceExtension->LUN & MAX_LUN));
894 ASSERT(Request->CdbLength <= sizeof(UFI_UNKNOWN_CMD));
895
896 RtlCopyMemory(&Cmd, Request->Cdb, Request->CdbLength);
897
898 return USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)&Cmd, Request->DataTransferLength, Request->DataBuffer, RetryCount);
899 }
900
901 NTSTATUS
902 USBSTOR_HandleExecuteSCSI(
903 IN PDEVICE_OBJECT DeviceObject,
904 IN PIRP Irp,
905 IN ULONG RetryCount)
906 {
907 PCDB pCDB;
908 NTSTATUS Status;
909 PIO_STACK_LOCATION IoStack;
910 PSCSI_REQUEST_BLOCK Request;
911 PPDO_DEVICE_EXTENSION PDODeviceExtension;
912
913 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
914 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
915
916 IoStack = IoGetCurrentIrpStackLocation(Irp);
917 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
918 pCDB = (PCDB)Request->Cdb;
919
920 DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
921
922 if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
923 {
924 ASSERT(Request->DataBuffer);
925
926 DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength);
927 Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount);
928 }
929 else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
930 {
931 DPRINT("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
932 ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
933 ASSERT(Request->DataBuffer);
934
935 Status = USBSTOR_SendModeSense(DeviceObject, Irp, RetryCount);
936 }
937 else if (pCDB->AsByte[0] == SCSIOP_READ_FORMATTED_CAPACITY)
938 {
939 DPRINT("SCSIOP_READ_FORMATTED_CAPACITY DataTransferLength %lu\n", Request->DataTransferLength);
940
941 Status = USBSTOR_SendFormatCapacity(DeviceObject, Irp, RetryCount);
942 }
943 else if (pCDB->AsByte[0] == SCSIOP_INQUIRY)
944 {
945 DPRINT("SCSIOP_INQUIRY DataTransferLength %lu\n", Request->DataTransferLength);
946
947 Status = USBSTOR_SendInquiry(DeviceObject, Irp, RetryCount);
948 }
949 else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ || pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
950 {
951 DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
952
953 Status = USBSTOR_SendReadWrite(DeviceObject, Irp, RetryCount);
954 }
955 else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
956 {
957 DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
958
959 // just complete the request
960 Request->SrbStatus = SRB_STATUS_SUCCESS;
961 Irp->IoStatus.Status = STATUS_SUCCESS;
962 Irp->IoStatus.Information = Request->DataTransferLength;
963 USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
964 IoCompleteRequest(Irp, IO_NO_INCREMENT);
965
966 USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
967
968 return STATUS_SUCCESS;
969 }
970 else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
971 {
972 DPRINT("SCSIOP_TEST_UNIT_READY\n");
973
974 Status = USBSTOR_SendTestUnit(DeviceObject, Irp, RetryCount);
975 }
976 else
977 {
978 // Unknown request. Simply forward
979 DPRINT1("Forwarding unknown Operation Code %x\n", pCDB->AsByte[0]);
980 Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount);
981 }
982
983 return Status;
984 }