[USBEHCI_NEW]
[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 NTSTATUS
50 USBSTOR_SendCBW(
51 IN PDEVICE_OBJECT DeviceObject,
52 IN UCHAR CommandBlockLength,
53 IN PUCHAR CommandBlock,
54 IN ULONG DataTransferLength,
55 OUT PCBW *OutControl)
56 {
57 PCBW Control;
58 NTSTATUS Status;
59 PURB Urb;
60 PPDO_DEVICE_EXTENSION PDODeviceExtension;
61 PFDO_DEVICE_EXTENSION FDODeviceExtension;
62
63 //
64 // get PDO device extension
65 //
66 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
67
68 //
69 // get FDO device extension
70 //
71 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
72
73 //
74 // first allocate CBW
75 //
76 Control = (PCBW)AllocateItem(NonPagedPool, 512);
77 if (!Control)
78 {
79 //
80 // no memory
81 //
82 return STATUS_INSUFFICIENT_RESOURCES;
83 }
84
85 //
86 // first allocate CBW
87 //
88 Status = USBSTOR_BuildCBW(0xDEADDEAD, DataTransferLength, PDODeviceExtension->LUN, CommandBlockLength, CommandBlock, Control);
89 if (!NT_SUCCESS(Status))
90 {
91 //
92 // failed to build CBW
93 //
94 return Status;
95 }
96
97 //
98 // now build the urb
99 //
100 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
101 if (!Urb)
102 {
103 //
104 // failed to allocate urb
105 //
106 FreeItem(Control);
107 return STATUS_INSUFFICIENT_RESOURCES;
108 }
109
110 //
111 // now initialize the urb
112 //
113 Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
114 Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
115 Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
116 Urb->UrbBulkOrInterruptTransfer.TransferBuffer = (PVOID)Control;
117 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = sizeof(CBW);
118 Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK;
119
120 //
121 // now send urb
122 //
123 Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
124
125 //
126 // free urb
127 //
128 FreeItem(Urb);
129
130 //
131 // store cbw
132 //
133 *OutControl = Control;
134
135 //
136 // return operation status
137 //
138 return Status;
139 }
140
141 NTSTATUS
142 USBSTOR_SendData(
143 IN PDEVICE_OBJECT DeviceObject,
144 IN ULONG DataTransferLength,
145 IN PVOID DataTransfer)
146 {
147 PMDL TransferBufferMDL;
148 PURB Urb;
149 NTSTATUS Status;
150 PPDO_DEVICE_EXTENSION PDODeviceExtension;
151 PFDO_DEVICE_EXTENSION FDODeviceExtension;
152
153 //
154 // get PDO device extension
155 //
156 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
157
158 //
159 // get FDO device extension
160 //
161 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
162
163 //
164 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
165 //
166 TransferBufferMDL = IoAllocateMdl(DataTransfer, DataTransferLength, FALSE, FALSE, NULL);
167 if (!TransferBufferMDL)
168 {
169 //
170 // failed to allocate MDL
171 //
172 return STATUS_INSUFFICIENT_RESOURCES;
173 }
174
175 //
176 // build mdl for nonpaged pool
177 //
178 MmBuildMdlForNonPagedPool(TransferBufferMDL);
179
180 //
181 // now build the urb
182 //
183 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
184 if (!Urb)
185 {
186 //
187 // failed to allocate urb
188 //
189 IoFreeMdl(TransferBufferMDL);
190 return STATUS_INSUFFICIENT_RESOURCES;
191 }
192
193 //
194 // now initialize the urb
195 //
196 Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
197 Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
198 Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
199 Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = TransferBufferMDL;
200 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataTransferLength;
201 Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
202
203 //
204 // now send urb
205 //
206 Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
207
208 //
209 // free urb
210 //
211 FreeItem(Urb);
212
213 //
214 // free mdl
215 //
216 IoFreeMdl(TransferBufferMDL);
217
218 //
219 // done
220 //
221 return Status;
222 }
223
224 NTSTATUS
225 USBSTOR_SendCSW(
226 IN PDEVICE_OBJECT DeviceObject,
227 IN PVOID Data,
228 IN ULONG DataLength,
229 OUT PCSW OutCSW)
230 {
231 NTSTATUS Status;
232 PPDO_DEVICE_EXTENSION PDODeviceExtension;
233 PFDO_DEVICE_EXTENSION FDODeviceExtension;
234 PURB Urb;
235
236 //
237 // get PDO device extension
238 //
239 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
240
241 //
242 // get FDO device extension
243 //
244 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
245
246 //
247 // now build the urb
248 //
249 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
250 if (!Urb)
251 {
252 //
253 // failed to allocate urb
254 //
255 return STATUS_INSUFFICIENT_RESOURCES;
256 }
257
258 //
259 // now initialize the urb
260 //
261 Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
262 Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
263 Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
264 Urb->UrbBulkOrInterruptTransfer.TransferBuffer = Data;
265 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataLength;
266 Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
267
268 //
269 // now send urb
270 //
271 Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
272
273 if (NT_SUCCESS(Status))
274 {
275 //
276 // copy csw status
277 //
278 RtlCopyMemory(OutCSW, Data, sizeof(CSW));
279 }
280
281 //
282 // free urb
283 //
284 FreeItem(Urb);
285
286 //
287 // done
288 //
289 return Status;
290 }
291
292 NTSTATUS
293 USBSTOR_SendInquiryCmd(
294 IN PDEVICE_OBJECT DeviceObject)
295 {
296 UFI_INQUIRY_CMD Cmd;
297 CSW CSW;
298 NTSTATUS Status;
299 PUFI_INQUIRY_RESPONSE Response;
300 PPDO_DEVICE_EXTENSION PDODeviceExtension;
301 PCBW OutControl;
302
303 //
304 // get PDO device extension
305 //
306 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
307
308 //
309 // allocate inquiry response
310 //
311 Response = (PUFI_INQUIRY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_INQUIRY_RESPONSE));
312 if (!Response)
313 {
314 //
315 // no memory
316 //
317 return STATUS_INSUFFICIENT_RESOURCES;
318 }
319
320 //
321 // initialize inquiry cmd
322 //
323 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
324 Cmd.Code = SCSIOP_INQUIRY;
325 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
326 Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
327
328 //
329 // now send inquiry cmd
330 //
331 Status = USBSTOR_SendCBW(DeviceObject, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_INQUIRY_RESPONSE), &OutControl);
332 if (!NT_SUCCESS(Status))
333 {
334 //
335 // failed to send CBW
336 //
337 DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendCBW failed with %x\n", Status);
338 FreeItem(Response);
339 ASSERT(FALSE);
340 return Status;
341 }
342
343 //
344 // now send inquiry response
345 //
346 Status = USBSTOR_SendData(DeviceObject, sizeof(UFI_INQUIRY_RESPONSE), Response);
347 if (!NT_SUCCESS(Status))
348 {
349 //
350 // failed to send CBW
351 //
352 DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendData failed with %x\n", Status);
353 FreeItem(Response);
354 ASSERT(FALSE);
355 return Status;
356 }
357
358 DPRINT1("Response %p\n", Response);
359 DPRINT1("DeviceType %x\n", Response->DeviceType);
360 DPRINT1("RMB %x\n", Response->RMB);
361 DPRINT1("Version %x\n", Response->Version);
362 DPRINT1("Format %x\n", Response->Format);
363 DPRINT1("Length %x\n", Response->Length);
364 DPRINT1("Reserved %x\n", Response->Reserved);
365 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]);
366 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],
367 Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
368 Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
369 Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
370
371 DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
372
373 //
374 // send csw
375 //
376 Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
377
378 DPRINT1("------------------------\n");
379 DPRINT1("CSW %p\n", &CSW);
380 DPRINT1("Signature %x\n", CSW.Signature);
381 DPRINT1("Tag %x\n", CSW.Tag);
382 DPRINT1("DataResidue %x\n", CSW.DataResidue);
383 DPRINT1("Status %x\n", CSW.Status);
384
385 //
386 // free item
387 //
388 FreeItem(OutControl);
389
390 //
391 // store inquiry data
392 //
393 PDODeviceExtension->InquiryData = (PVOID)Response;
394
395 //
396 // FIXME: handle error
397 //
398 ASSERT(CSW.Status == 0);
399
400
401 //
402 // done
403 //
404 return Status;
405 }
406
407 NTSTATUS
408 USBSTOR_SendCapacityCmd(
409 IN PDEVICE_OBJECT DeviceObject,
410 OUT PREAD_CAPACITY_DATA_EX CapacityDataEx,
411 OUT PREAD_CAPACITY_DATA CapacityData)
412 {
413 UFI_CAPACITY_CMD Cmd;
414 CSW CSW;
415 NTSTATUS Status;
416 PUFI_CAPACITY_RESPONSE Response;
417 PPDO_DEVICE_EXTENSION PDODeviceExtension;
418 PCBW OutControl;
419
420 //
421 // get PDO device extension
422 //
423 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
424
425 //
426 // allocate capacity response
427 //
428 Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_CAPACITY_RESPONSE));
429 if (!Response)
430 {
431 //
432 // no memory
433 //
434 return STATUS_INSUFFICIENT_RESOURCES;
435 }
436
437 //
438 // initialize capacity cmd
439 //
440 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
441 Cmd.Code = SCSIOP_READ_CAPACITY;
442 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
443
444 //
445 // now send capacity cmd
446 //
447 Status = USBSTOR_SendCBW(DeviceObject, UFI_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), &OutControl);
448 if (!NT_SUCCESS(Status))
449 {
450 //
451 // failed to send CBW
452 //
453 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
454 FreeItem(Response);
455 ASSERT(FALSE);
456 return Status;
457 }
458
459 //
460 // now send inquiry response
461 //
462 Status = USBSTOR_SendData(DeviceObject, sizeof(UFI_CAPACITY_RESPONSE), Response);
463 if (!NT_SUCCESS(Status))
464 {
465 //
466 // failed to send CBW
467 //
468 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
469 FreeItem(Response);
470 ASSERT(FALSE);
471 return Status;
472 }
473
474 DPRINT1("LastLogicalBlockAddress %lu\n", NTOHL(Response->LastLogicalBlockAddress));
475 DPRINT1("BlockLength %lu\n", NTOHL(Response->BlockLength));
476 DPRINT1("Medium Length %lu\n", NTOHL(Response->BlockLength) * NTOHL(Response->LastLogicalBlockAddress));
477
478 //
479 // store response
480 //
481 if (CapacityDataEx)
482 {
483 CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
484 CapacityDataEx->BytesPerBlock = Response->BlockLength;
485 }
486 else
487 {
488 CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
489 CapacityData->BytesPerBlock = Response->BlockLength;
490 }
491
492 //
493 // send csw
494 //
495 Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
496
497 DPRINT1("------------------------\n");
498 DPRINT1("CSW %p\n", &CSW);
499 DPRINT1("Signature %x\n", CSW.Signature);
500 DPRINT1("Tag %x\n", CSW.Tag);
501 DPRINT1("DataResidue %x\n", CSW.DataResidue);
502 DPRINT1("Status %x\n", CSW.Status);
503
504 //
505 // FIXME: handle error
506 //
507 ASSERT(CSW.Status == 0);
508
509 //
510 // free item
511 //
512 FreeItem(OutControl);
513
514 //
515 // free response
516 //
517 FreeItem(Response);
518
519 //
520 // done
521 //
522 return Status;
523 }
524
525 NTSTATUS
526 USBSTOR_SendModeSenseCmd(
527 IN PDEVICE_OBJECT DeviceObject,
528 IN OUT PSCSI_REQUEST_BLOCK Request,
529 OUT PULONG TransferBufferLength)
530 {
531 UFI_SENSE_CMD Cmd;
532 CSW CSW;
533 NTSTATUS Status;
534 PVOID Response;
535 PPDO_DEVICE_EXTENSION PDODeviceExtension;
536 PCBW OutControl;
537 PCDB pCDB;
538 PUFI_MODE_PARAMETER_HEADER Header;
539
540 //
541 // get SCSI command data block
542 //
543 pCDB = (PCDB)Request->Cdb;
544
545 //
546 // get PDO device extension
547 //
548 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
549
550 //
551 // allocate sense response from non paged pool
552 //
553 Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
554 if (!Response)
555 {
556 //
557 // no memory
558 //
559 return STATUS_INSUFFICIENT_RESOURCES;
560 }
561
562 //
563 // sanity check
564 //
565
566
567 // Supported pages
568 // MODE_PAGE_ERROR_RECOVERY
569 // MODE_PAGE_FLEXIBILE
570 // MODE_PAGE_LUN_MAPPING
571 // MODE_PAGE_FAULT_REPORTING
572 // MODE_SENSE_RETURN_ALL
573
574 //
575 // initialize mode sense cmd
576 //
577 RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
578 Cmd.Code = SCSIOP_MODE_SENSE;
579 Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
580 Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
581 Cmd.PC = pCDB->MODE_SENSE.Pc;
582 Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
583
584 DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
585 DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
586
587 //
588 // now send mode sense cmd
589 //
590 Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
591 if (!NT_SUCCESS(Status))
592 {
593 //
594 // failed to send CBW
595 //
596 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
597 FreeItem(Response);
598 ASSERT(FALSE);
599 return Status;
600 }
601
602 //
603 // now send data block response
604 //
605 Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
606 if (!NT_SUCCESS(Status))
607 {
608 //
609 // failed to send CBW
610 //
611 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
612 FreeItem(Response);
613 ASSERT(FALSE);
614 return Status;
615 }
616
617 Header = (PUFI_MODE_PARAMETER_HEADER)Response;
618
619 //
620 // TODO: build layout
621 //
622 // first struct is the header
623 // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
624 //
625 // followed by
626 // MODE_PARAMETER_BLOCK
627 //
628 //
629 DbgBreakPoint();
630
631 //
632 // send csw
633 //
634 Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
635
636 DPRINT1("------------------------\n");
637 DPRINT1("CSW %p\n", &CSW);
638 DPRINT1("Signature %x\n", CSW.Signature);
639 DPRINT1("Tag %x\n", CSW.Tag);
640 DPRINT1("DataResidue %x\n", CSW.DataResidue);
641 DPRINT1("Status %x\n", CSW.Status);
642
643 //
644 // FIXME: handle error
645 //
646 ASSERT(CSW.Status == 0);
647 ASSERT(CSW.DataResidue == 0);
648
649 //
650 // calculate transfer length
651 //
652 *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
653
654 //
655 // copy buffer
656 //
657 RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
658
659 //
660 // free item
661 //
662 FreeItem(OutControl);
663
664 //
665 // free response
666 //
667 FreeItem(Response);
668
669 //
670 // done
671 //
672 return Status;
673 }
674