23d7f88c6714c9e6ecb4a4aebf6f813d523cfe45
[reactos.git] / reactos / drivers / usb / usbstor / error.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/error.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_GetEndpointStatus(
16 IN PDEVICE_OBJECT DeviceObject,
17 IN UCHAR bEndpointAddress,
18 OUT PUSHORT Value)
19 {
20 PURB Urb;
21 NTSTATUS Status;
22
23 //
24 // allocate urb
25 //
26 DPRINT("Allocating URB\n");
27 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
28 if (!Urb)
29 {
30 //
31 // out of memory
32 //
33 DPRINT1("OutofMemory!\n");
34 return STATUS_INSUFFICIENT_RESOURCES;
35 }
36
37 //
38 // build status
39 //
40 UsbBuildGetStatusRequest(Urb, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT, bEndpointAddress & 0x0F, Value, NULL, NULL);
41
42 //
43 // send the request
44 //
45 DPRINT1("Sending Request DeviceObject %x, Urb %x\n", DeviceObject, Urb);
46 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
47
48 //
49 // free urb
50 //
51 FreeItem(Urb);
52
53 //
54 // done
55 //
56 return Status;
57 }
58
59
60
61 NTSTATUS
62 USBSTOR_ResetPipeWithHandle(
63 IN PDEVICE_OBJECT DeviceObject,
64 IN USBD_PIPE_HANDLE PipeHandle)
65 {
66 PURB Urb;
67 NTSTATUS Status;
68
69 //
70 // allocate urb
71 //
72 DPRINT("Allocating URB\n");
73 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
74 if (!Urb)
75 {
76 //
77 // out of memory
78 //
79 DPRINT1("OutofMemory!\n");
80 return STATUS_INSUFFICIENT_RESOURCES;
81 }
82
83 //
84 // initialize the urb
85 //
86 Urb->UrbPipeRequest.Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
87 Urb->UrbPipeRequest.Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
88 Urb->UrbPipeRequest.PipeHandle = PipeHandle;
89
90 //
91 // send the request
92 //
93 DPRINT1("Sending Request DeviceObject %x, Urb %x\n", DeviceObject, Urb);
94 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
95
96 //
97 // free urb
98 //
99 FreeItem(Urb);
100
101 //
102 // done
103 //
104 return Status;
105 }
106
107
108 NTSTATUS
109 USBSTOR_HandleTransferError(
110 PDEVICE_OBJECT DeviceObject,
111 PIRP_CONTEXT Context)
112 {
113 NTSTATUS Status;
114 PIO_STACK_LOCATION Stack;
115 USBD_PIPE_HANDLE PipeHandle;
116 PSCSI_REQUEST_BLOCK Request;
117 PCDB pCDB;
118
119 DPRINT1("Entered Handle Transfer Error\n");
120 //
121 // Determine pipehandle
122 //
123 if (Context->cbw->CommandBlock[0] == SCSIOP_WRITE)
124 {
125 //
126 // write request used bulk out pipe
127 //
128 PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
129 }
130 else
131 {
132 //
133 // default bulk in pipe
134 //
135 PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
136 }
137
138 switch (Context->Urb.UrbHeader.Status)
139 {
140 case USBD_STATUS_STALL_PID:
141 {
142 //
143 // First attempt to reset the pipe
144 //
145 DPRINT1("Resetting Pipe\n");
146 Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, PipeHandle);
147 if (NT_SUCCESS(Status))
148 {
149 Status = STATUS_SUCCESS;
150 break;
151 }
152
153 DPRINT1("Failed to reset pipe %x\n", Status);
154
155 //
156 // FIXME: Reset of pipe failed, attempt to reset port
157 //
158
159 Status = STATUS_UNSUCCESSFUL;
160 break;
161 }
162 //
163 // FIXME: Handle more errors
164 //
165 default:
166 {
167 DPRINT1("Error not handled\n");
168 Status = STATUS_UNSUCCESSFUL;
169 }
170 }
171
172 Stack = IoGetCurrentIrpStackLocation(Context->Irp);
173 Request = (PSCSI_REQUEST_BLOCK)Stack->Parameters.Others.Argument1;
174 pCDB = (PCDB)Request->Cdb;
175 if (Status != STATUS_SUCCESS)
176 {
177 /* Complete the master IRP */
178 Context->Irp->IoStatus.Status = Status;
179 Context->Irp->IoStatus.Information = 0;
180 USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
181 IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
182
183 /* Start the next request */
184 USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
185
186 /* Signal the context event */
187 if (Context->Event)
188 KeSetEvent(Context->Event, 0, FALSE);
189
190 /* Cleanup the IRP context */
191 if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
192 FreeItem(Context->TransferData);
193 FreeItem(Context->cbw);
194 FreeItem(Context);
195 }
196 else
197 {
198
199 DPRINT1("Retrying\n");
200 Status = USBSTOR_HandleExecuteSCSI(*Context->PDODeviceExtension->PDODeviceObject, Context->Irp);
201
202 /* Cleanup the old IRP context */
203 if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
204 FreeItem(Context->TransferData);
205 FreeItem(Context->cbw);
206 FreeItem(Context);
207 }
208
209 DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status);
210 return Status;
211 }
212
213 VOID
214 NTAPI
215 ErrorHandlerWorkItemRoutine(
216 PVOID Context)
217 {
218 NTSTATUS Status;
219 PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context;
220
221 Status = USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context);
222
223 //
224 // Free Work Item Data
225 //
226 ExFreePool(WorkItemData);
227 }