[USBSTOR] Do not attempt additional processing of SCSI requests.
[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 PUFI_CAPACITY_RESPONSE Response;
133 NTSTATUS Status;
134
135 Context = (PIRP_CONTEXT)Ctx;
136
137 if (Context->TransferBufferMDL)
138 {
139 // is there an irp associated
140 if (Context->Irp)
141 {
142 // did we allocate the mdl
143 if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
144 {
145 IoFreeMdl(Context->TransferBufferMDL);
146 }
147 }
148 else
149 {
150 IoFreeMdl(Context->TransferBufferMDL);
151 }
152 }
153
154 DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status);
155
156 if (!NT_SUCCESS(Irp->IoStatus.Information))
157 {
158 if (Context->ErrorIndex == 0)
159 {
160 Context->ErrorIndex = 1;
161
162 // clear stall and resend cbw
163 Status = USBSTOR_QueueWorkItem(Context, Irp);
164 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
165 return STATUS_MORE_PROCESSING_REQUIRED;
166 }
167
168 // perform reset recovery
169 Context->ErrorIndex = 2;
170 IoFreeIrp(Irp);
171 Status = USBSTOR_QueueWorkItem(Context, NULL);
172 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
173 return STATUS_MORE_PROCESSING_REQUIRED;
174 }
175
176 if (!USBSTOR_IsCSWValid(Context))
177 {
178 // perform reset recovery
179 Context->ErrorIndex = 2;
180 IoFreeIrp(Irp);
181 Status = USBSTOR_QueueWorkItem(Context, NULL);
182 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
183 return STATUS_MORE_PROCESSING_REQUIRED;
184 }
185
186
187 IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
188
189 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
190 ASSERT(Request);
191
192 Status = Irp->IoStatus.Status;
193
194 pCDB = (PCDB)Request->Cdb;
195 Request->SrbStatus = SRB_STATUS_SUCCESS;
196
197 // read capacity needs special work
198 if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
199 {
200 // get output buffer
201 Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;
202
203 // store in pdo
204 Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
205 Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
206 }
207
208 FreeItem(Context->cbw);
209
210 // FIXME: check status
211 Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
212 Context->Irp->IoStatus.Information = Context->TransferDataLength;
213
214 // terminate current request
215 USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
216
217 IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
218
219 USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
220
221 IoFreeIrp(Irp);
222 FreeItem(Context);
223 return STATUS_MORE_PROCESSING_REQUIRED;
224 }
225
226 VOID
227 USBSTOR_SendCSW(
228 PIRP_CONTEXT Context,
229 PIRP Irp)
230 {
231 PIO_STACK_LOCATION IoStack;
232
233 IoStack = IoGetNextIrpStackLocation(Irp);
234
235 // now initialize the urb for sending the csw
236 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
237 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
238 Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
239 Context->csw,
240 NULL,
241 512, //FIXME
242 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
243 NULL);
244
245 // initialize stack location
246 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
247 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
248 IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
249 IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
250 Irp->IoStatus.Status = STATUS_SUCCESS;
251
252 IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
253
254 IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
255 }
256
257 IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
258
259 NTSTATUS
260 NTAPI
261 USBSTOR_DataCompletionRoutine(
262 PDEVICE_OBJECT DeviceObject,
263 PIRP Irp,
264 PVOID Ctx)
265 {
266 PIRP_CONTEXT Context;
267 NTSTATUS Status;
268
269
270 DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
271
272 Context = (PIRP_CONTEXT)Ctx;
273
274 if (!NT_SUCCESS(Irp->IoStatus.Status))
275 {
276 // clear stall and resend cbw
277 Context->ErrorIndex = 1;
278 Status = USBSTOR_QueueWorkItem(Context, Irp);
279 ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
280 return STATUS_MORE_PROCESSING_REQUIRED;
281 }
282
283 USBSTOR_SendCSW(Context, Irp);
284
285 return STATUS_MORE_PROCESSING_REQUIRED;
286 }
287
288 IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine;
289
290 NTSTATUS
291 NTAPI
292 USBSTOR_CBWCompletionRoutine(
293 PDEVICE_OBJECT DeviceObject,
294 PIRP Irp,
295 PVOID Ctx)
296 {
297 PIRP_CONTEXT Context;
298 PIO_STACK_LOCATION IoStack;
299 UCHAR Code;
300 USBD_PIPE_HANDLE PipeHandle;
301
302 DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
303
304 Context = (PIRP_CONTEXT)Ctx;
305 IoStack = IoGetNextIrpStackLocation(Irp);
306
307 // is there data to be submitted
308 if (Context->TransferDataLength)
309 {
310 // get command code
311 Code = Context->cbw->CommandBlock[0];
312
313 if (Code == SCSIOP_WRITE)
314 {
315 // write request - use bulk out pipe
316 PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
317 }
318 else
319 {
320 // default bulk in pipe
321 PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
322 }
323
324 // now initialize the urb for sending data
325 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
326 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
327 PipeHandle,
328 NULL,
329 Context->TransferBufferMDL,
330 Context->TransferDataLength,
331 ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)),
332 NULL);
333
334 IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
335 }
336 else
337 {
338 // now initialize the urb for sending the csw
339 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
340 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
341 Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
342 Context->csw,
343 NULL,
344 512, //FIXME
345 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
346 NULL);
347
348 IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
349 }
350
351 // initialize stack location
352 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
353 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
354 IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
355 IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
356 Irp->IoStatus.Status = STATUS_SUCCESS;
357
358 IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
359
360 return STATUS_MORE_PROCESSING_REQUIRED;
361 }
362
363 VOID
364 DumpCBW(
365 PUCHAR Block)
366 {
367 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",
368 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,
369 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,
370 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,
371 Block[30] & 0xFF);
372
373 }
374
375 NTSTATUS
376 USBSTOR_SendCBW(
377 PIRP_CONTEXT Context,
378 PIRP Irp)
379 {
380 PIO_STACK_LOCATION IoStack;
381
382 IoStack = IoGetNextIrpStackLocation(Irp);
383
384 // initialize stack location
385 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
386 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
387 IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
388 IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
389 Irp->IoStatus.Status = STATUS_SUCCESS;
390
391 IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
392
393 return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
394 }
395
396 NTSTATUS
397 USBSTOR_SendRequest(
398 IN PDEVICE_OBJECT DeviceObject,
399 IN PIRP OriginalRequest,
400 IN UCHAR CommandLength,
401 IN PUCHAR Command,
402 IN ULONG TransferDataLength,
403 IN PUCHAR TransferData,
404 IN ULONG RetryCount)
405 {
406 PIRP_CONTEXT Context;
407 PPDO_DEVICE_EXTENSION PDODeviceExtension;
408 PFDO_DEVICE_EXTENSION FDODeviceExtension;
409 PIRP Irp;
410 PUCHAR MdlVirtualAddress;
411
412 Context = USBSTOR_AllocateIrpContext();
413 if (!Context)
414 {
415 return STATUS_INSUFFICIENT_RESOURCES;
416 }
417
418 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
419 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
420
421 USBSTOR_BuildCBW(PtrToUlong(Context->cbw),
422 TransferDataLength,
423 PDODeviceExtension->LUN,
424 CommandLength,
425 Command,
426 Context->cbw);
427
428 DPRINT("CBW %p\n", Context->cbw);
429 DumpCBW((PUCHAR)Context->cbw);
430
431 // now initialize the urb
432 UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
433 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
434 FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
435 Context->cbw,
436 NULL,
437 sizeof(CBW),
438 USBD_TRANSFER_DIRECTION_OUT,
439 NULL);
440
441 // initialize rest of context
442 Context->Irp = OriginalRequest;
443 Context->TransferData = TransferData;
444 Context->TransferDataLength = TransferDataLength;
445 Context->FDODeviceExtension = FDODeviceExtension;
446 Context->PDODeviceExtension = PDODeviceExtension;
447 Context->RetryCount = RetryCount;
448
449 // is there transfer data
450 if (Context->TransferDataLength)
451 {
452 // check if the original request already does have an mdl associated
453 if (OriginalRequest)
454 {
455 if ((OriginalRequest->MdlAddress != NULL) &&
456 (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
457 {
458 // Sanity check that the Mdl does describe the TransferData for read/write
459 if (CommandLength == UFI_READ_WRITE_CMD_LEN)
460 {
461 MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);
462
463 // is there an offset
464 if (MdlVirtualAddress != Context->TransferData)
465 {
466 // lets build an mdl
467 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
468 if (!Context->TransferBufferMDL)
469 {
470 FreeItem(Context->cbw);
471 FreeItem(Context);
472 return STATUS_INSUFFICIENT_RESOURCES;
473 }
474
475 IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
476 }
477 }
478
479 if (!Context->TransferBufferMDL)
480 {
481 // I/O paging request
482 Context->TransferBufferMDL = OriginalRequest->MdlAddress;
483 }
484 }
485 else
486 {
487 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
488 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
489 if (!Context->TransferBufferMDL)
490 {
491 FreeItem(Context->cbw);
492 FreeItem(Context);
493 return STATUS_INSUFFICIENT_RESOURCES;
494 }
495
496 MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
497 }
498 }
499 else
500 {
501 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
502 Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
503 if (!Context->TransferBufferMDL)
504 {
505 FreeItem(Context->cbw);
506 FreeItem(Context);
507 return STATUS_INSUFFICIENT_RESOURCES;
508 }
509
510 MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
511 }
512 }
513
514 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
515 if (!Irp)
516 {
517 FreeItem(Context->cbw);
518 FreeItem(Context);
519 return STATUS_INSUFFICIENT_RESOURCES;
520 }
521
522 if (OriginalRequest)
523 {
524 IoMarkIrpPending(OriginalRequest);
525 }
526
527 USBSTOR_SendCBW(Context, Irp);
528
529 return STATUS_PENDING;
530 }
531
532 NTSTATUS
533 USBSTOR_HandleExecuteSCSI(
534 IN PDEVICE_OBJECT DeviceObject,
535 IN PIRP Irp,
536 IN ULONG RetryCount)
537 {
538 PCDB pCDB;
539 NTSTATUS Status;
540 PIO_STACK_LOCATION IoStack;
541 PSCSI_REQUEST_BLOCK Request;
542 PPDO_DEVICE_EXTENSION PDODeviceExtension;
543
544 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
545 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
546
547 IoStack = IoGetCurrentIrpStackLocation(Irp);
548 Request = IoStack->Parameters.Scsi.Srb;
549 pCDB = (PCDB)Request->Cdb;
550
551 DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x, Length %lu\n", pCDB->CDB10.OperationCode, Request->DataTransferLength);
552
553 // check that we're sending to the right LUN
554 ASSERT(pCDB->CDB10.LogicalUnitNumber == (PDODeviceExtension->LUN & MAX_LUN));
555 Status = USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)pCDB, Request->DataTransferLength, Request->DataBuffer, RetryCount);
556
557 return Status;
558 }