]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
MdeModulePkg/UsbMassStorage: Add 16 byte SCSI cmds support if the last LBA can not...
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassImpl.c
1 /** @file
2 USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
3
4 Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "UsbMass.h"
16
17 #define USB_MASS_TRANSPORT_COUNT 3
18 //
19 // Array of USB transport interfaces.
20 //
21 USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = {
22 &mUsbCbi0Transport,
23 &mUsbCbi1Transport,
24 &mUsbBotTransport,
25 };
26
27 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
28 USBMassDriverBindingSupported,
29 USBMassDriverBindingStart,
30 USBMassDriverBindingStop,
31 0x11,
32 NULL,
33 NULL
34 };
35
36 /**
37 Reset the block device.
38
39 This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
40 It resets the block device hardware.
41 ExtendedVerification is ignored in this implementation.
42
43 @param This Indicates a pointer to the calling context.
44 @param ExtendedVerification Indicates that the driver may perform a more exhaustive
45 verification operation of the device during reset.
46
47 @retval EFI_SUCCESS The block device was reset.
48 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
49
50 **/
51 EFI_STATUS
52 EFIAPI
53 UsbMassReset (
54 IN EFI_BLOCK_IO_PROTOCOL *This,
55 IN BOOLEAN ExtendedVerification
56 )
57 {
58 USB_MASS_DEVICE *UsbMass;
59 EFI_TPL OldTpl;
60 EFI_STATUS Status;
61
62 //
63 // Raise TPL to TPL_NOTIFY to serialize all its operations
64 // to protect shared data structures.
65 //
66 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
67
68 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
69 Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
70
71 gBS->RestoreTPL (OldTpl);
72
73 return Status;
74 }
75
76 /**
77 Reads the requested number of blocks from the device.
78
79 This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
80 It reads the requested number of blocks from the device.
81 All the blocks are read, or an error is returned.
82
83 @param This Indicates a pointer to the calling context.
84 @param MediaId The media ID that the read request is for.
85 @param Lba The starting logical block address to read from on the device.
86 @param BufferSize The size of the Buffer in bytes.
87 This must be a multiple of the intrinsic block size of the device.
88 @param Buffer A pointer to the destination buffer for the data. The caller is
89 responsible for either having implicit or explicit ownership of the buffer.
90
91 @retval EFI_SUCCESS The data was read correctly from the device.
92 @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
93 @retval EFI_NO_MEDIA There is no media in the device.
94 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
95 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
96 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
97 or the buffer is not on proper alignment.
98
99 **/
100 EFI_STATUS
101 EFIAPI
102 UsbMassReadBlocks (
103 IN EFI_BLOCK_IO_PROTOCOL *This,
104 IN UINT32 MediaId,
105 IN EFI_LBA Lba,
106 IN UINTN BufferSize,
107 OUT VOID *Buffer
108 )
109 {
110 USB_MASS_DEVICE *UsbMass;
111 EFI_BLOCK_IO_MEDIA *Media;
112 EFI_STATUS Status;
113 EFI_TPL OldTpl;
114 UINTN TotalBlock;
115
116 //
117 // Raise TPL to TPL_NOTIFY to serialize all its operations
118 // to protect shared data structures.
119 //
120 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
121 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
122 Media = &UsbMass->BlockIoMedia;
123
124 //
125 // If it is a removable media, such as CD-Rom or Usb-Floppy,
126 // need to detect the media before each read/write. While some of
127 // Usb-Flash is marked as removable media.
128 //
129 if (Media->RemovableMedia) {
130 Status = UsbBootDetectMedia (UsbMass);
131 if (EFI_ERROR (Status)) {
132 goto ON_EXIT;
133 }
134 }
135
136 if (!(Media->MediaPresent)) {
137 Status = EFI_NO_MEDIA;
138 goto ON_EXIT;
139 }
140
141 if (MediaId != Media->MediaId) {
142 Status = EFI_MEDIA_CHANGED;
143 goto ON_EXIT;
144 }
145
146 if (BufferSize == 0) {
147 Status = EFI_SUCCESS;
148 goto ON_EXIT;
149 }
150
151 if (Buffer == NULL) {
152 Status = EFI_INVALID_PARAMETER;
153 goto ON_EXIT;
154 }
155
156 //
157 // BufferSize must be a multiple of the intrinsic block size of the device.
158 //
159 if ((BufferSize % Media->BlockSize) != 0) {
160 Status = EFI_BAD_BUFFER_SIZE;
161 goto ON_EXIT;
162 }
163
164 TotalBlock = BufferSize / Media->BlockSize;
165
166 //
167 // Make sure the range to read is valid.
168 //
169 if (Lba + TotalBlock - 1 > Media->LastBlock) {
170 Status = EFI_INVALID_PARAMETER;
171 goto ON_EXIT;
172 }
173
174 if (UsbMass->Cdb16Byte) {
175 Status = UsbBootReadBlocks16 (UsbMass, Lba, TotalBlock, Buffer);
176 } else {
177 Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
178 }
179
180 if (EFI_ERROR (Status)) {
181 DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
182 UsbMassReset (This, TRUE);
183 }
184
185 ON_EXIT:
186 gBS->RestoreTPL (OldTpl);
187 return Status;
188 }
189
190
191 /**
192 Writes a specified number of blocks to the device.
193
194 This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
195 It writes a specified number of blocks to the device.
196 All blocks are written, or an error is returned.
197
198 @param This Indicates a pointer to the calling context.
199 @param MediaId The media ID that the write request is for.
200 @param Lba The starting logical block address to be written.
201 @param BufferSize The size of the Buffer in bytes.
202 This must be a multiple of the intrinsic block size of the device.
203 @param Buffer Pointer to the source buffer for the data.
204
205 @retval EFI_SUCCESS The data were written correctly to the device.
206 @retval EFI_WRITE_PROTECTED The device cannot be written to.
207 @retval EFI_NO_MEDIA There is no media in the device.
208 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
209 @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
210 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
211 block size of the device.
212 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
213 or the buffer is not on proper alignment.
214
215 **/
216 EFI_STATUS
217 EFIAPI
218 UsbMassWriteBlocks (
219 IN EFI_BLOCK_IO_PROTOCOL *This,
220 IN UINT32 MediaId,
221 IN EFI_LBA Lba,
222 IN UINTN BufferSize,
223 IN VOID *Buffer
224 )
225 {
226 USB_MASS_DEVICE *UsbMass;
227 EFI_BLOCK_IO_MEDIA *Media;
228 EFI_STATUS Status;
229 EFI_TPL OldTpl;
230 UINTN TotalBlock;
231
232 //
233 // Raise TPL to TPL_NOTIFY to serialize all its operations
234 // to protect shared data structures.
235 //
236 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
237 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
238 Media = &UsbMass->BlockIoMedia;
239
240 //
241 // If it is a removable media, such as CD-Rom or Usb-Floppy,
242 // need to detect the media before each read/write. Some of
243 // USB Flash is marked as removable media.
244 //
245 if (Media->RemovableMedia) {
246 Status = UsbBootDetectMedia (UsbMass);
247 if (EFI_ERROR (Status)) {
248 goto ON_EXIT;
249 }
250 }
251
252 if (!(Media->MediaPresent)) {
253 Status = EFI_NO_MEDIA;
254 goto ON_EXIT;
255 }
256
257 if (MediaId != Media->MediaId) {
258 Status = EFI_MEDIA_CHANGED;
259 goto ON_EXIT;
260 }
261
262 if (BufferSize == 0) {
263 Status = EFI_SUCCESS;
264 goto ON_EXIT;
265 }
266
267 if (Buffer == NULL) {
268 Status = EFI_INVALID_PARAMETER;
269 goto ON_EXIT;
270 }
271
272 //
273 // BufferSize must be a multiple of the intrinsic block size of the device.
274 //
275 if ((BufferSize % Media->BlockSize) != 0) {
276 Status = EFI_BAD_BUFFER_SIZE;
277 goto ON_EXIT;
278 }
279
280 TotalBlock = BufferSize / Media->BlockSize;
281
282 //
283 // Make sure the range to write is valid.
284 //
285 if (Lba + TotalBlock - 1 > Media->LastBlock) {
286 Status = EFI_INVALID_PARAMETER;
287 goto ON_EXIT;
288 }
289
290 //
291 // Try to write the data even the device is marked as ReadOnly,
292 // and clear the status should the write succeed.
293 //
294 if (UsbMass->Cdb16Byte) {
295 Status = UsbBootWriteBlocks16 (UsbMass, Lba, TotalBlock, Buffer);
296 } else {
297 Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
298 }
299
300 if (EFI_ERROR (Status)) {
301 DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
302 UsbMassReset (This, TRUE);
303 }
304
305 ON_EXIT:
306 gBS->RestoreTPL (OldTpl);
307 return Status;
308 }
309
310 /**
311 Flushes all modified data to a physical block device.
312
313 This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
314 USB mass storage device doesn't support write cache,
315 so return EFI_SUCCESS directly.
316
317 @param This Indicates a pointer to the calling context.
318
319 @retval EFI_SUCCESS All outstanding data were written correctly to the device.
320 @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
321 @retval EFI_NO_MEDIA There is no media in the device.
322
323 **/
324 EFI_STATUS
325 EFIAPI
326 UsbMassFlushBlocks (
327 IN EFI_BLOCK_IO_PROTOCOL *This
328 )
329 {
330 return EFI_SUCCESS;
331 }
332
333 /**
334 Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
335
336 @param UsbMass The USB mass storage device
337
338 @retval EFI_SUCCESS The media parameters are updated successfully.
339 @retval Others Failed to get the media parameters.
340
341 **/
342 EFI_STATUS
343 UsbMassInitMedia (
344 IN USB_MASS_DEVICE *UsbMass
345 )
346 {
347 EFI_BLOCK_IO_MEDIA *Media;
348 EFI_STATUS Status;
349
350 Media = &UsbMass->BlockIoMedia;
351
352 //
353 // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,
354 // section for Block I/O Protocol.
355 //
356 Media->MediaPresent = FALSE;
357 Media->LogicalPartition = FALSE;
358 Media->ReadOnly = FALSE;
359 Media->WriteCaching = FALSE;
360 Media->IoAlign = 0;
361 Media->MediaId = 1;
362
363 Status = UsbBootGetParams (UsbMass);
364 return Status;
365 }
366
367 /**
368 Initilize the USB Mass Storage transport.
369
370 This function tries to find the matching USB Mass Storage transport
371 protocol for USB device. If found, initializes the matching transport.
372
373 @param This The USB mass driver's driver binding.
374 @param Controller The device to test.
375 @param Transport The pointer to pointer to USB_MASS_TRANSPORT.
376 @param Context The parameter for USB_MASS_DEVICE.Context.
377 @param MaxLun Get the MaxLun if is BOT dev.
378
379 @retval EFI_SUCCESS The initialization is successful.
380 @retval EFI_UNSUPPORTED No matching transport protocol is found.
381 @retval Others Failed to initialize dev.
382
383 **/
384 EFI_STATUS
385 UsbMassInitTransport (
386 IN EFI_DRIVER_BINDING_PROTOCOL *This,
387 IN EFI_HANDLE Controller,
388 OUT USB_MASS_TRANSPORT **Transport,
389 OUT VOID **Context,
390 OUT UINT8 *MaxLun
391 )
392 {
393 EFI_USB_IO_PROTOCOL *UsbIo;
394 EFI_USB_INTERFACE_DESCRIPTOR Interface;
395 UINT8 Index;
396 EFI_STATUS Status;
397
398 Status = gBS->OpenProtocol (
399 Controller,
400 &gEfiUsbIoProtocolGuid,
401 (VOID **) &UsbIo,
402 This->DriverBindingHandle,
403 Controller,
404 EFI_OPEN_PROTOCOL_BY_DRIVER
405 );
406
407 if (EFI_ERROR (Status)) {
408 return Status;
409 }
410
411 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
412 if (EFI_ERROR (Status)) {
413 goto ON_EXIT;
414 }
415
416 Status = EFI_UNSUPPORTED;
417
418 //
419 // Traverse the USB_MASS_TRANSPORT arrary and try to find the
420 // matching transport protocol.
421 // If not found, return EFI_UNSUPPORTED.
422 // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
423 //
424 for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
425 *Transport = mUsbMassTransport[Index];
426
427 if (Interface.InterfaceProtocol == (*Transport)->Protocol) {
428 Status = (*Transport)->Init (UsbIo, Context);
429 break;
430 }
431 }
432
433 if (EFI_ERROR (Status)) {
434 goto ON_EXIT;
435 }
436
437 //
438 // For BOT device, try to get its max LUN.
439 // If max LUN is 0, then it is a non-lun device.
440 // Otherwise, it is a multi-lun device.
441 //
442 if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
443 (*Transport)->GetMaxLun (*Context, MaxLun);
444 }
445
446 ON_EXIT:
447 gBS->CloseProtocol (
448 Controller,
449 &gEfiUsbIoProtocolGuid,
450 This->DriverBindingHandle,
451 Controller
452 );
453 return Status;
454 }
455
456 /**
457 Initialize data for device that supports multiple LUNSs.
458
459 @param This The Driver Binding Protocol instance.
460 @param Controller The device to initialize.
461 @param Transport Pointer to USB_MASS_TRANSPORT.
462 @param Context Parameter for USB_MASS_DEVICE.Context.
463 @param DevicePath The remaining device path.
464 @param MaxLun The max LUN number.
465
466 @retval EFI_SUCCESS At least one LUN is initialized successfully.
467 @retval EFI_OUT_OF_RESOURCES Out of resource while creating device path node.
468 @retval Other Initialization fails.
469
470 **/
471 EFI_STATUS
472 UsbMassInitMultiLun (
473 IN EFI_DRIVER_BINDING_PROTOCOL *This,
474 IN EFI_HANDLE Controller,
475 IN USB_MASS_TRANSPORT *Transport,
476 IN VOID *Context,
477 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
478 IN UINT8 MaxLun
479 )
480 {
481 USB_MASS_DEVICE *UsbMass;
482 EFI_USB_IO_PROTOCOL *UsbIo;
483 DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode;
484 UINT8 Index;
485 EFI_STATUS Status;
486
487 ASSERT (MaxLun > 0);
488
489 for (Index = 0; Index <= MaxLun; Index++) {
490
491 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
492
493 UsbIo = NULL;
494 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
495 ASSERT (UsbMass != NULL);
496
497 UsbMass->Signature = USB_MASS_SIGNATURE;
498 UsbMass->UsbIo = UsbIo;
499 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
500 UsbMass->BlockIo.Reset = UsbMassReset;
501 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
502 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
503 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
504 UsbMass->OpticalStorage = FALSE;
505 UsbMass->Transport = Transport;
506 UsbMass->Context = Context;
507 UsbMass->Lun = Index;
508
509 //
510 // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
511 //
512 Status = UsbMassInitMedia (UsbMass);
513 if (!EFI_ERROR (Status)) {
514 //
515 // According to USB Mass Storage Specification for Bootability, only following
516 // 4 Peripheral Device Types are in spec.
517 //
518 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
519 (UsbMass->Pdt != USB_PDT_CDROM) &&
520 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
521 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
522 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
523 goto ON_ERROR;
524 }
525 } else if (Status != EFI_NO_MEDIA){
526 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
527 goto ON_ERROR;
528 }
529
530 //
531 // Create a device path node for device logic unit, and append it.
532 //
533 LunNode.Header.Type = MESSAGING_DEVICE_PATH;
534 LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
535 LunNode.Lun = UsbMass->Lun;
536
537 SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
538
539 UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
540
541 if (UsbMass->DevicePath == NULL) {
542 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
543
544 Status = EFI_OUT_OF_RESOURCES;
545 goto ON_ERROR;
546 }
547
548 InitializeDiskInfo (UsbMass);
549
550 //
551 // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.
552 //
553 Status = gBS->InstallMultipleProtocolInterfaces (
554 &UsbMass->Controller,
555 &gEfiDevicePathProtocolGuid,
556 UsbMass->DevicePath,
557 &gEfiBlockIoProtocolGuid,
558 &UsbMass->BlockIo,
559 &gEfiDiskInfoProtocolGuid,
560 &UsbMass->DiskInfo,
561 NULL
562 );
563
564 if (EFI_ERROR (Status)) {
565 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
566 goto ON_ERROR;
567 }
568
569 //
570 // Open USB I/O Protocol by child to setup a parent-child relationship.
571 //
572 Status = gBS->OpenProtocol (
573 Controller,
574 &gEfiUsbIoProtocolGuid,
575 (VOID **) &UsbIo,
576 This->DriverBindingHandle,
577 UsbMass->Controller,
578 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
579 );
580
581 if (EFI_ERROR (Status)) {
582 DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
583 gBS->UninstallMultipleProtocolInterfaces (
584 &UsbMass->Controller,
585 &gEfiDevicePathProtocolGuid,
586 UsbMass->DevicePath,
587 &gEfiBlockIoProtocolGuid,
588 &UsbMass->BlockIo,
589 &gEfiDiskInfoProtocolGuid,
590 &UsbMass->DiskInfo,
591 NULL
592 );
593 goto ON_ERROR;
594 }
595
596 DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
597 }
598
599 return EFI_SUCCESS;
600
601 ON_ERROR:
602 if (UsbMass != NULL) {
603 if (UsbMass->DevicePath != NULL) {
604 FreePool (UsbMass->DevicePath);
605 }
606 FreePool (UsbMass);
607 }
608 if (UsbIo != NULL) {
609 gBS->CloseProtocol (
610 Controller,
611 &gEfiUsbIoProtocolGuid,
612 This->DriverBindingHandle,
613 UsbMass->Controller
614 );
615 }
616
617 //
618 // Return EFI_SUCCESS if at least one LUN is initialized successfully.
619 //
620 if (Index > 0) {
621 return EFI_SUCCESS;
622 } else {
623 return Status;
624 }
625 }
626
627 /**
628 Initialize data for device that does not support multiple LUNSs.
629
630 @param This The Driver Binding Protocol instance.
631 @param Controller The device to initialize.
632 @param Transport Pointer to USB_MASS_TRANSPORT.
633 @param Context Parameter for USB_MASS_DEVICE.Context.
634
635 @retval EFI_SUCCESS Initialization succeeds.
636 @retval Other Initialization fails.
637
638 **/
639 EFI_STATUS
640 UsbMassInitNonLun (
641 IN EFI_DRIVER_BINDING_PROTOCOL *This,
642 IN EFI_HANDLE Controller,
643 IN USB_MASS_TRANSPORT *Transport,
644 IN VOID *Context
645 )
646 {
647 USB_MASS_DEVICE *UsbMass;
648 EFI_USB_IO_PROTOCOL *UsbIo;
649 EFI_STATUS Status;
650
651 UsbIo = NULL;
652 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
653 ASSERT (UsbMass != NULL);
654
655 Status = gBS->OpenProtocol (
656 Controller,
657 &gEfiUsbIoProtocolGuid,
658 (VOID **) &UsbIo,
659 This->DriverBindingHandle,
660 Controller,
661 EFI_OPEN_PROTOCOL_BY_DRIVER
662 );
663
664 if (EFI_ERROR (Status)) {
665 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));
666 goto ON_ERROR;
667 }
668
669 UsbMass->Signature = USB_MASS_SIGNATURE;
670 UsbMass->Controller = Controller;
671 UsbMass->UsbIo = UsbIo;
672 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
673 UsbMass->BlockIo.Reset = UsbMassReset;
674 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
675 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
676 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
677 UsbMass->OpticalStorage = FALSE;
678 UsbMass->Transport = Transport;
679 UsbMass->Context = Context;
680
681 //
682 // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
683 //
684 Status = UsbMassInitMedia (UsbMass);
685 if (!EFI_ERROR (Status)) {
686 //
687 // According to USB Mass Storage Specification for Bootability, only following
688 // 4 Peripheral Device Types are in spec.
689 //
690 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
691 (UsbMass->Pdt != USB_PDT_CDROM) &&
692 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
693 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
694 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
695 goto ON_ERROR;
696 }
697 } else if (Status != EFI_NO_MEDIA){
698 DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
699 goto ON_ERROR;
700 }
701
702 InitializeDiskInfo (UsbMass);
703
704 Status = gBS->InstallMultipleProtocolInterfaces (
705 &Controller,
706 &gEfiBlockIoProtocolGuid,
707 &UsbMass->BlockIo,
708 &gEfiDiskInfoProtocolGuid,
709 &UsbMass->DiskInfo,
710 NULL
711 );
712 if (EFI_ERROR (Status)) {
713 goto ON_ERROR;
714 }
715
716 return EFI_SUCCESS;
717
718 ON_ERROR:
719 if (UsbMass != NULL) {
720 FreePool (UsbMass);
721 }
722 if (UsbIo != NULL) {
723 gBS->CloseProtocol (
724 Controller,
725 &gEfiUsbIoProtocolGuid,
726 This->DriverBindingHandle,
727 Controller
728 );
729 }
730 return Status;
731 }
732
733
734 /**
735 Check whether the controller is a supported USB mass storage.
736
737 @param This The USB mass storage driver binding protocol.
738 @param Controller The controller handle to check.
739 @param RemainingDevicePath The remaining device path.
740
741 @retval EFI_SUCCESS The driver supports this controller.
742 @retval other This device isn't supported.
743
744 **/
745 EFI_STATUS
746 EFIAPI
747 USBMassDriverBindingSupported (
748 IN EFI_DRIVER_BINDING_PROTOCOL *This,
749 IN EFI_HANDLE Controller,
750 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
751 )
752 {
753 EFI_USB_IO_PROTOCOL *UsbIo;
754 EFI_USB_INTERFACE_DESCRIPTOR Interface;
755 USB_MASS_TRANSPORT *Transport;
756 EFI_STATUS Status;
757 UINTN Index;
758
759 Status = gBS->OpenProtocol (
760 Controller,
761 &gEfiUsbIoProtocolGuid,
762 (VOID **) &UsbIo,
763 This->DriverBindingHandle,
764 Controller,
765 EFI_OPEN_PROTOCOL_BY_DRIVER
766 );
767 if (EFI_ERROR (Status)) {
768 return Status;
769 }
770
771 //
772 // Get the interface descriptor to check the USB class and find a transport
773 // protocol handler.
774 //
775 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
776 if (EFI_ERROR (Status)) {
777 goto ON_EXIT;
778 }
779
780 Status = EFI_UNSUPPORTED;
781
782 if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
783 goto ON_EXIT;
784 }
785
786 //
787 // Traverse the USB_MASS_TRANSPORT arrary and try to find the
788 // matching transport method.
789 // If not found, return EFI_UNSUPPORTED.
790 // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
791 //
792 for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
793 Transport = mUsbMassTransport[Index];
794 if (Interface.InterfaceProtocol == Transport->Protocol) {
795 Status = Transport->Init (UsbIo, NULL);
796 break;
797 }
798 }
799
800 ON_EXIT:
801 gBS->CloseProtocol (
802 Controller,
803 &gEfiUsbIoProtocolGuid,
804 This->DriverBindingHandle,
805 Controller
806 );
807
808 return Status;
809 }
810
811 /**
812 Starts the USB mass storage device with this driver.
813
814 This function consumes USB I/O Portocol, intializes USB mass storage device,
815 installs Block I/O Protocol, and submits Asynchronous Interrupt
816 Transfer to manage the USB mass storage device.
817
818 @param This The USB mass storage driver binding protocol.
819 @param Controller The USB mass storage device to start on
820 @param RemainingDevicePath The remaining device path.
821
822 @retval EFI_SUCCESS This driver supports this device.
823 @retval EFI_UNSUPPORTED This driver does not support this device.
824 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
825 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
826 @retval EFI_ALREADY_STARTED This driver has been started.
827
828 **/
829 EFI_STATUS
830 EFIAPI
831 USBMassDriverBindingStart (
832 IN EFI_DRIVER_BINDING_PROTOCOL *This,
833 IN EFI_HANDLE Controller,
834 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
835 )
836 {
837 USB_MASS_TRANSPORT *Transport;
838 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
839 VOID *Context;
840 UINT8 MaxLun;
841 EFI_STATUS Status;
842 EFI_USB_IO_PROTOCOL *UsbIo;
843 EFI_TPL OldTpl;
844
845 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
846
847 Transport = NULL;
848 Context = NULL;
849 MaxLun = 0;
850
851 Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
852
853 if (EFI_ERROR (Status)) {
854 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
855 goto Exit;
856 }
857 if (MaxLun == 0) {
858 //
859 // Initialize data for device that does not support multiple LUNSs.
860 //
861 Status = UsbMassInitNonLun (This, Controller, Transport, Context);
862 if (EFI_ERROR (Status)) {
863 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
864 }
865 } else {
866 //
867 // Open device path to prepare for appending Device Logic Unit node.
868 //
869 Status = gBS->OpenProtocol (
870 Controller,
871 &gEfiDevicePathProtocolGuid,
872 (VOID **) &DevicePath,
873 This->DriverBindingHandle,
874 Controller,
875 EFI_OPEN_PROTOCOL_BY_DRIVER
876 );
877
878 if (EFI_ERROR (Status)) {
879 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
880 goto Exit;
881 }
882
883 Status = gBS->OpenProtocol (
884 Controller,
885 &gEfiUsbIoProtocolGuid,
886 (VOID **) &UsbIo,
887 This->DriverBindingHandle,
888 Controller,
889 EFI_OPEN_PROTOCOL_BY_DRIVER
890 );
891
892 if (EFI_ERROR (Status)) {
893 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));
894 gBS->CloseProtocol (
895 Controller,
896 &gEfiDevicePathProtocolGuid,
897 This->DriverBindingHandle,
898 Controller
899 );
900 goto Exit;
901 }
902
903 //
904 // Initialize data for device that supports multiple LUNSs.
905 // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.
906 //
907 Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
908 if (EFI_ERROR (Status)) {
909 gBS->CloseProtocol (
910 Controller,
911 &gEfiDevicePathProtocolGuid,
912 This->DriverBindingHandle,
913 Controller
914 );
915 gBS->CloseProtocol (
916 Controller,
917 &gEfiUsbIoProtocolGuid,
918 This->DriverBindingHandle,
919 Controller
920 );
921 DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
922 }
923 }
924 Exit:
925 gBS->RestoreTPL (OldTpl);
926 return Status;
927 }
928
929
930 /**
931 Stop controlling the device.
932
933 @param This The USB mass storage driver binding
934 @param Controller The device controller controlled by the driver.
935 @param NumberOfChildren The number of children of this device
936 @param ChildHandleBuffer The buffer of children handle.
937
938 @retval EFI_SUCCESS The driver stopped from controlling the device.
939 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
940 @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller.
941 @retval Others Failed to stop the driver
942
943 **/
944 EFI_STATUS
945 EFIAPI
946 USBMassDriverBindingStop (
947 IN EFI_DRIVER_BINDING_PROTOCOL *This,
948 IN EFI_HANDLE Controller,
949 IN UINTN NumberOfChildren,
950 IN EFI_HANDLE *ChildHandleBuffer
951 )
952 {
953 EFI_STATUS Status;
954 USB_MASS_DEVICE *UsbMass;
955 EFI_USB_IO_PROTOCOL *UsbIo;
956 EFI_BLOCK_IO_PROTOCOL *BlockIo;
957 UINTN Index;
958 BOOLEAN AllChildrenStopped;
959
960 //
961 // This is a bus driver stop function since multi-lun is supported.
962 // There are three kinds of device handles that might be passed:
963 // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)
964 // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)
965 // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).
966 //
967 if (NumberOfChildren == 0) {
968 //
969 // A handle without any children, might be 1st and 2nd type.
970 //
971 Status = gBS->OpenProtocol (
972 Controller,
973 &gEfiBlockIoProtocolGuid,
974 (VOID **) &BlockIo,
975 This->DriverBindingHandle,
976 Controller,
977 EFI_OPEN_PROTOCOL_GET_PROTOCOL
978 );
979
980 if (EFI_ERROR(Status)) {
981 //
982 // This is a 2nd type handle(multi-lun root), it needs to close devicepath
983 // and usbio protocol.
984 //
985 gBS->CloseProtocol (
986 Controller,
987 &gEfiDevicePathProtocolGuid,
988 This->DriverBindingHandle,
989 Controller
990 );
991 gBS->CloseProtocol (
992 Controller,
993 &gEfiUsbIoProtocolGuid,
994 This->DriverBindingHandle,
995 Controller
996 );
997 DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
998 return EFI_SUCCESS;
999 }
1000
1001 //
1002 // This is a 1st type handle(non-multi-lun), which only needs to uninstall
1003 // Block I/O Protocol, close USB I/O Protocol and free mass device.
1004 //
1005 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
1006
1007 //
1008 // Uninstall Block I/O protocol from the device handle,
1009 // then call the transport protocol to stop itself.
1010 //
1011 Status = gBS->UninstallMultipleProtocolInterfaces (
1012 Controller,
1013 &gEfiBlockIoProtocolGuid,
1014 &UsbMass->BlockIo,
1015 &gEfiDiskInfoProtocolGuid,
1016 &UsbMass->DiskInfo,
1017 NULL
1018 );
1019 if (EFI_ERROR (Status)) {
1020 return Status;
1021 }
1022
1023 gBS->CloseProtocol (
1024 Controller,
1025 &gEfiUsbIoProtocolGuid,
1026 This->DriverBindingHandle,
1027 Controller
1028 );
1029
1030 UsbMass->Transport->CleanUp (UsbMass->Context);
1031 FreePool (UsbMass);
1032
1033 DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
1034 return EFI_SUCCESS;
1035 }
1036
1037 //
1038 // This is a 3rd type handle(multi-lun), which needs uninstall
1039 // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and
1040 // free mass device for all children.
1041 //
1042 AllChildrenStopped = TRUE;
1043
1044 for (Index = 0; Index < NumberOfChildren; Index++) {
1045
1046 Status = gBS->OpenProtocol (
1047 ChildHandleBuffer[Index],
1048 &gEfiBlockIoProtocolGuid,
1049 (VOID **) &BlockIo,
1050 This->DriverBindingHandle,
1051 Controller,
1052 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1053 );
1054 if (EFI_ERROR (Status)) {
1055 AllChildrenStopped = FALSE;
1056 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
1057 continue;
1058 }
1059
1060 UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
1061
1062 gBS->CloseProtocol (
1063 Controller,
1064 &gEfiUsbIoProtocolGuid,
1065 This->DriverBindingHandle,
1066 ChildHandleBuffer[Index]
1067 );
1068
1069 Status = gBS->UninstallMultipleProtocolInterfaces (
1070 ChildHandleBuffer[Index],
1071 &gEfiDevicePathProtocolGuid,
1072 UsbMass->DevicePath,
1073 &gEfiBlockIoProtocolGuid,
1074 &UsbMass->BlockIo,
1075 &gEfiDiskInfoProtocolGuid,
1076 &UsbMass->DiskInfo,
1077 NULL
1078 );
1079
1080 if (EFI_ERROR (Status)) {
1081 //
1082 // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.
1083 //
1084 AllChildrenStopped = FALSE;
1085 DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
1086
1087 gBS->OpenProtocol (
1088 Controller,
1089 &gEfiUsbIoProtocolGuid,
1090 (VOID **) &UsbIo,
1091 This->DriverBindingHandle,
1092 ChildHandleBuffer[Index],
1093 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1094 );
1095 } else {
1096 //
1097 // Succeed to stop this multi-lun handle, so go on with next child.
1098 //
1099 if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
1100 UsbMass->Transport->CleanUp (UsbMass->Context);
1101 }
1102 FreePool (UsbMass);
1103 }
1104 }
1105
1106 if (!AllChildrenStopped) {
1107 return EFI_DEVICE_ERROR;
1108 }
1109
1110 DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));
1111 return EFI_SUCCESS;
1112 }
1113
1114 /**
1115 Entrypoint of USB Mass Storage Driver.
1116
1117 This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding
1118 Protocol together with Component Name Protocols.
1119
1120 @param ImageHandle The firmware allocated handle for the EFI image.
1121 @param SystemTable A pointer to the EFI System Table.
1122
1123 @retval EFI_SUCCESS The entry point is executed successfully.
1124
1125 **/
1126 EFI_STATUS
1127 EFIAPI
1128 USBMassStorageEntryPoint (
1129 IN EFI_HANDLE ImageHandle,
1130 IN EFI_SYSTEM_TABLE *SystemTable
1131 )
1132 {
1133 EFI_STATUS Status;
1134
1135 //
1136 // Install driver binding protocol
1137 //
1138 Status = EfiLibInstallDriverBindingComponentName2 (
1139 ImageHandle,
1140 SystemTable,
1141 &gUSBMassDriverBinding,
1142 ImageHandle,
1143 &gUsbMassStorageComponentName,
1144 &gUsbMassStorageComponentName2
1145 );
1146 ASSERT_EFI_ERROR (Status);
1147
1148 return EFI_SUCCESS;
1149 }