1 /** @file
2   USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
3 
4 Copyright (c) 2007 - 2014, 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
UsbMassReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
UsbMassReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)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
UsbMassWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)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
UsbMassFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)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
UsbMassInitMedia(IN USB_MASS_DEVICE * UsbMass)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
UsbMassInitTransport(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,OUT USB_MASS_TRANSPORT ** Transport,OUT VOID ** Context,OUT UINT8 * MaxLun)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_NOT_FOUND        Fail to initialize any of multiple LUNs.
468 
469 **/
470 EFI_STATUS
UsbMassInitMultiLun(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN USB_MASS_TRANSPORT * Transport,IN VOID * Context,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINT8 MaxLun)471 UsbMassInitMultiLun (
472   IN EFI_DRIVER_BINDING_PROTOCOL   *This,
473   IN EFI_HANDLE                    Controller,
474   IN USB_MASS_TRANSPORT            *Transport,
475   IN VOID                          *Context,
476   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
477   IN UINT8                         MaxLun
478   )
479 {
480   USB_MASS_DEVICE                  *UsbMass;
481   EFI_USB_IO_PROTOCOL              *UsbIo;
482   DEVICE_LOGICAL_UNIT_DEVICE_PATH  LunNode;
483   UINT8                            Index;
484   EFI_STATUS                       Status;
485   EFI_STATUS                       ReturnStatus;
486 
487   ASSERT (MaxLun > 0);
488   ReturnStatus = EFI_NOT_FOUND;
489 
490   for (Index = 0; Index <= MaxLun; Index++) {
491 
492     DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
493 
494     UsbIo   = NULL;
495     UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
496     ASSERT (UsbMass != NULL);
497 
498     UsbMass->Signature            = USB_MASS_SIGNATURE;
499     UsbMass->UsbIo                = UsbIo;
500     UsbMass->BlockIo.Media        = &UsbMass->BlockIoMedia;
501     UsbMass->BlockIo.Reset        = UsbMassReset;
502     UsbMass->BlockIo.ReadBlocks   = UsbMassReadBlocks;
503     UsbMass->BlockIo.WriteBlocks  = UsbMassWriteBlocks;
504     UsbMass->BlockIo.FlushBlocks  = UsbMassFlushBlocks;
505     UsbMass->OpticalStorage       = FALSE;
506     UsbMass->Transport            = Transport;
507     UsbMass->Context              = Context;
508     UsbMass->Lun                  = Index;
509 
510     //
511     // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
512     //
513     Status = UsbMassInitMedia (UsbMass);
514     if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
515       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
516       FreePool (UsbMass);
517       continue;
518     }
519 
520     //
521     // Create a device path node for device logic unit, and append it.
522     //
523     LunNode.Header.Type    = MESSAGING_DEVICE_PATH;
524     LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
525     LunNode.Lun            = UsbMass->Lun;
526 
527     SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
528 
529     UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
530 
531     if (UsbMass->DevicePath == NULL) {
532       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
533       Status = EFI_OUT_OF_RESOURCES;
534       FreePool (UsbMass);
535       continue;
536     }
537 
538     InitializeDiskInfo (UsbMass);
539 
540     //
541     // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.
542     //
543     Status = gBS->InstallMultipleProtocolInterfaces (
544                     &UsbMass->Controller,
545                     &gEfiDevicePathProtocolGuid,
546                     UsbMass->DevicePath,
547                     &gEfiBlockIoProtocolGuid,
548                     &UsbMass->BlockIo,
549                     &gEfiDiskInfoProtocolGuid,
550                     &UsbMass->DiskInfo,
551                     NULL
552                     );
553 
554     if (EFI_ERROR (Status)) {
555       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
556       FreePool (UsbMass->DevicePath);
557       FreePool (UsbMass);
558       continue;
559     }
560 
561     //
562     // Open USB I/O Protocol by child to setup a parent-child relationship.
563     //
564     Status = gBS->OpenProtocol (
565                     Controller,
566                     &gEfiUsbIoProtocolGuid,
567                     (VOID **) &UsbIo,
568                     This->DriverBindingHandle,
569                     UsbMass->Controller,
570                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
571                     );
572 
573     if (EFI_ERROR (Status)) {
574       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
575       gBS->UninstallMultipleProtocolInterfaces (
576              &UsbMass->Controller,
577              &gEfiDevicePathProtocolGuid,
578              UsbMass->DevicePath,
579              &gEfiBlockIoProtocolGuid,
580              &UsbMass->BlockIo,
581              &gEfiDiskInfoProtocolGuid,
582              &UsbMass->DiskInfo,
583              NULL
584              );
585       FreePool (UsbMass->DevicePath);
586       FreePool (UsbMass);
587       continue;
588     }
589     ReturnStatus = EFI_SUCCESS;
590     DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
591   }
592 
593   return ReturnStatus;
594 }
595 
596 /**
597   Initialize data for device that does not support multiple LUNSs.
598 
599   @param  This            The Driver Binding Protocol instance.
600   @param  Controller      The device to initialize.
601   @param  Transport       Pointer to USB_MASS_TRANSPORT.
602   @param  Context         Parameter for USB_MASS_DEVICE.Context.
603 
604   @retval EFI_SUCCESS     Initialization succeeds.
605   @retval Other           Initialization fails.
606 
607 **/
608 EFI_STATUS
UsbMassInitNonLun(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN USB_MASS_TRANSPORT * Transport,IN VOID * Context)609 UsbMassInitNonLun (
610   IN EFI_DRIVER_BINDING_PROTOCOL   *This,
611   IN EFI_HANDLE                    Controller,
612   IN USB_MASS_TRANSPORT            *Transport,
613   IN VOID                          *Context
614   )
615 {
616   USB_MASS_DEVICE             *UsbMass;
617   EFI_USB_IO_PROTOCOL         *UsbIo;
618   EFI_STATUS                  Status;
619 
620   UsbIo   = NULL;
621   UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
622   ASSERT (UsbMass != NULL);
623 
624   Status = gBS->OpenProtocol (
625                   Controller,
626                   &gEfiUsbIoProtocolGuid,
627                   (VOID **) &UsbIo,
628                   This->DriverBindingHandle,
629                   Controller,
630                   EFI_OPEN_PROTOCOL_BY_DRIVER
631                   );
632 
633   if (EFI_ERROR (Status)) {
634     DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));
635     goto ON_ERROR;
636   }
637 
638   UsbMass->Signature            = USB_MASS_SIGNATURE;
639   UsbMass->Controller           = Controller;
640   UsbMass->UsbIo                = UsbIo;
641   UsbMass->BlockIo.Media        = &UsbMass->BlockIoMedia;
642   UsbMass->BlockIo.Reset        = UsbMassReset;
643   UsbMass->BlockIo.ReadBlocks   = UsbMassReadBlocks;
644   UsbMass->BlockIo.WriteBlocks  = UsbMassWriteBlocks;
645   UsbMass->BlockIo.FlushBlocks  = UsbMassFlushBlocks;
646   UsbMass->OpticalStorage       = FALSE;
647   UsbMass->Transport            = Transport;
648   UsbMass->Context              = Context;
649 
650   //
651   // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
652   //
653   Status = UsbMassInitMedia (UsbMass);
654   if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
655     DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
656     goto ON_ERROR;
657   }
658 
659   InitializeDiskInfo (UsbMass);
660 
661   Status = gBS->InstallMultipleProtocolInterfaces (
662                   &Controller,
663                   &gEfiBlockIoProtocolGuid,
664                   &UsbMass->BlockIo,
665                   &gEfiDiskInfoProtocolGuid,
666                   &UsbMass->DiskInfo,
667                   NULL
668                   );
669   if (EFI_ERROR (Status)) {
670     goto ON_ERROR;
671   }
672 
673   return EFI_SUCCESS;
674 
675 ON_ERROR:
676   if (UsbMass != NULL) {
677     FreePool (UsbMass);
678   }
679   if (UsbIo != NULL) {
680     gBS->CloseProtocol (
681            Controller,
682            &gEfiUsbIoProtocolGuid,
683            This->DriverBindingHandle,
684            Controller
685            );
686   }
687   return Status;
688 }
689 
690 
691 /**
692   Check whether the controller is a supported USB mass storage.
693 
694   @param  This                   The USB mass storage driver binding protocol.
695   @param  Controller             The controller handle to check.
696   @param  RemainingDevicePath    The remaining device path.
697 
698   @retval EFI_SUCCESS            The driver supports this controller.
699   @retval other                  This device isn't supported.
700 
701 **/
702 EFI_STATUS
703 EFIAPI
USBMassDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)704 USBMassDriverBindingSupported (
705   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
706   IN EFI_HANDLE                   Controller,
707   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
708   )
709 {
710   EFI_USB_IO_PROTOCOL           *UsbIo;
711   EFI_USB_INTERFACE_DESCRIPTOR  Interface;
712   USB_MASS_TRANSPORT            *Transport;
713   EFI_STATUS                    Status;
714   UINTN                         Index;
715 
716   Status = gBS->OpenProtocol (
717                   Controller,
718                   &gEfiUsbIoProtocolGuid,
719                   (VOID **) &UsbIo,
720                   This->DriverBindingHandle,
721                   Controller,
722                   EFI_OPEN_PROTOCOL_BY_DRIVER
723                   );
724   if (EFI_ERROR (Status)) {
725     return Status;
726   }
727 
728   //
729   // Get the interface descriptor to check the USB class and find a transport
730   // protocol handler.
731   //
732   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
733   if (EFI_ERROR (Status)) {
734     goto ON_EXIT;
735   }
736 
737   Status = EFI_UNSUPPORTED;
738 
739   if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
740     goto ON_EXIT;
741   }
742 
743   //
744   // Traverse the USB_MASS_TRANSPORT arrary and try to find the
745   // matching transport method.
746   // If not found, return EFI_UNSUPPORTED.
747   // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
748   //
749   for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
750     Transport = mUsbMassTransport[Index];
751     if (Interface.InterfaceProtocol == Transport->Protocol) {
752       Status = Transport->Init (UsbIo, NULL);
753       break;
754     }
755   }
756 
757 ON_EXIT:
758   gBS->CloseProtocol (
759          Controller,
760          &gEfiUsbIoProtocolGuid,
761          This->DriverBindingHandle,
762          Controller
763          );
764 
765   return Status;
766 }
767 
768 /**
769   Starts the USB mass storage device with this driver.
770 
771   This function consumes USB I/O Portocol, intializes USB mass storage device,
772   installs Block I/O Protocol, and submits Asynchronous Interrupt
773   Transfer to manage the USB mass storage device.
774 
775   @param  This                  The USB mass storage driver binding protocol.
776   @param  Controller            The USB mass storage device to start on
777   @param  RemainingDevicePath   The remaining device path.
778 
779   @retval EFI_SUCCESS           This driver supports this device.
780   @retval EFI_UNSUPPORTED       This driver does not support this device.
781   @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
782   @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
783   @retval EFI_ALREADY_STARTED   This driver has been started.
784 
785 **/
786 EFI_STATUS
787 EFIAPI
USBMassDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)788 USBMassDriverBindingStart (
789   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
790   IN EFI_HANDLE                   Controller,
791   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
792   )
793 {
794   USB_MASS_TRANSPORT            *Transport;
795   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
796   VOID                          *Context;
797   UINT8                         MaxLun;
798   EFI_STATUS                    Status;
799   EFI_USB_IO_PROTOCOL           *UsbIo;
800   EFI_TPL                       OldTpl;
801 
802   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
803 
804   Transport = NULL;
805   Context   = NULL;
806   MaxLun    = 0;
807 
808   Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
809 
810   if (EFI_ERROR (Status)) {
811     DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
812     goto Exit;
813   }
814   if (MaxLun == 0) {
815     //
816     // Initialize data for device that does not support multiple LUNSs.
817     //
818     Status = UsbMassInitNonLun (This, Controller, Transport, Context);
819     if (EFI_ERROR (Status)) {
820       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
821     }
822   } else {
823     //
824     // Open device path to prepare for appending Device Logic Unit node.
825     //
826     Status = gBS->OpenProtocol (
827                     Controller,
828                     &gEfiDevicePathProtocolGuid,
829                     (VOID **) &DevicePath,
830                     This->DriverBindingHandle,
831                     Controller,
832                     EFI_OPEN_PROTOCOL_BY_DRIVER
833                     );
834 
835     if (EFI_ERROR (Status)) {
836       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
837       goto Exit;
838     }
839 
840     Status = gBS->OpenProtocol (
841                     Controller,
842                     &gEfiUsbIoProtocolGuid,
843                     (VOID **) &UsbIo,
844                     This->DriverBindingHandle,
845                     Controller,
846                     EFI_OPEN_PROTOCOL_BY_DRIVER
847                     );
848 
849     if (EFI_ERROR (Status)) {
850       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));
851       gBS->CloseProtocol (
852              Controller,
853              &gEfiDevicePathProtocolGuid,
854              This->DriverBindingHandle,
855              Controller
856              );
857       goto Exit;
858     }
859 
860     //
861     // Initialize data for device that supports multiple LUNs.
862     // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.
863     //
864     Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
865     if (EFI_ERROR (Status)) {
866       gBS->CloseProtocol (
867               Controller,
868               &gEfiDevicePathProtocolGuid,
869               This->DriverBindingHandle,
870               Controller
871               );
872       gBS->CloseProtocol (
873               Controller,
874               &gEfiUsbIoProtocolGuid,
875               This->DriverBindingHandle,
876               Controller
877               );
878       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
879     }
880   }
881 Exit:
882   gBS->RestoreTPL (OldTpl);
883   return Status;
884 }
885 
886 
887 /**
888   Stop controlling the device.
889 
890   @param  This                   The USB mass storage driver binding
891   @param  Controller             The device controller controlled by the driver.
892   @param  NumberOfChildren       The number of children of this device
893   @param  ChildHandleBuffer      The buffer of children handle.
894 
895   @retval EFI_SUCCESS            The driver stopped from controlling the device.
896   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
897   @retval EFI_UNSUPPORTED        Block I/O Protocol is not installed on Controller.
898   @retval Others                 Failed to stop the driver
899 
900 **/
901 EFI_STATUS
902 EFIAPI
USBMassDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)903 USBMassDriverBindingStop (
904   IN  EFI_DRIVER_BINDING_PROTOCOL *This,
905   IN  EFI_HANDLE                  Controller,
906   IN  UINTN                       NumberOfChildren,
907   IN  EFI_HANDLE                  *ChildHandleBuffer
908   )
909 {
910   EFI_STATUS            Status;
911   USB_MASS_DEVICE       *UsbMass;
912   EFI_USB_IO_PROTOCOL   *UsbIo;
913   EFI_BLOCK_IO_PROTOCOL *BlockIo;
914   UINTN                 Index;
915   BOOLEAN               AllChildrenStopped;
916 
917   //
918   // This is a bus driver stop function since multi-lun is supported.
919   // There are three kinds of device handles that might be passed:
920   // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)
921   // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)
922   // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).
923   //
924   if (NumberOfChildren == 0) {
925     //
926     // A handle without any children, might be 1st and 2nd type.
927     //
928     Status = gBS->OpenProtocol (
929                     Controller,
930                     &gEfiBlockIoProtocolGuid,
931                     (VOID **) &BlockIo,
932                     This->DriverBindingHandle,
933                     Controller,
934                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
935                     );
936 
937     if (EFI_ERROR(Status)) {
938       //
939       // This is a 2nd type handle(multi-lun root), it needs to close devicepath
940       // and usbio protocol.
941       //
942       gBS->CloseProtocol (
943             Controller,
944             &gEfiDevicePathProtocolGuid,
945             This->DriverBindingHandle,
946             Controller
947             );
948       gBS->CloseProtocol (
949             Controller,
950             &gEfiUsbIoProtocolGuid,
951             This->DriverBindingHandle,
952             Controller
953             );
954       DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
955       return EFI_SUCCESS;
956     }
957 
958     //
959     // This is a 1st type handle(non-multi-lun), which only needs to uninstall
960     // Block I/O Protocol, close USB I/O Protocol and free mass device.
961     //
962     UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
963 
964     //
965     // Uninstall Block I/O protocol from the device handle,
966     // then call the transport protocol to stop itself.
967     //
968     Status = gBS->UninstallMultipleProtocolInterfaces (
969                     Controller,
970                     &gEfiBlockIoProtocolGuid,
971                     &UsbMass->BlockIo,
972                     &gEfiDiskInfoProtocolGuid,
973                     &UsbMass->DiskInfo,
974                     NULL
975                     );
976     if (EFI_ERROR (Status)) {
977       return Status;
978     }
979 
980     gBS->CloseProtocol (
981           Controller,
982           &gEfiUsbIoProtocolGuid,
983           This->DriverBindingHandle,
984           Controller
985           );
986 
987     UsbMass->Transport->CleanUp (UsbMass->Context);
988     FreePool (UsbMass);
989 
990     DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
991     return EFI_SUCCESS;
992   }
993 
994   //
995   // This is a 3rd type handle(multi-lun), which needs uninstall
996   // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and
997   // free mass device for all children.
998   //
999   AllChildrenStopped = TRUE;
1000 
1001   for (Index = 0; Index < NumberOfChildren; Index++) {
1002 
1003     Status = gBS->OpenProtocol (
1004                     ChildHandleBuffer[Index],
1005                     &gEfiBlockIoProtocolGuid,
1006                     (VOID **) &BlockIo,
1007                     This->DriverBindingHandle,
1008                     Controller,
1009                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
1010                     );
1011     if (EFI_ERROR (Status)) {
1012       AllChildrenStopped = FALSE;
1013       DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
1014       continue;
1015     }
1016 
1017     UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
1018 
1019     gBS->CloseProtocol (
1020            Controller,
1021            &gEfiUsbIoProtocolGuid,
1022            This->DriverBindingHandle,
1023            ChildHandleBuffer[Index]
1024            );
1025 
1026     Status = gBS->UninstallMultipleProtocolInterfaces (
1027                     ChildHandleBuffer[Index],
1028                     &gEfiDevicePathProtocolGuid,
1029                     UsbMass->DevicePath,
1030                     &gEfiBlockIoProtocolGuid,
1031                     &UsbMass->BlockIo,
1032                     &gEfiDiskInfoProtocolGuid,
1033                     &UsbMass->DiskInfo,
1034                     NULL
1035                     );
1036 
1037     if (EFI_ERROR (Status)) {
1038       //
1039       // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.
1040       //
1041       AllChildrenStopped = FALSE;
1042       DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
1043 
1044       gBS->OpenProtocol (
1045              Controller,
1046              &gEfiUsbIoProtocolGuid,
1047              (VOID **) &UsbIo,
1048              This->DriverBindingHandle,
1049              ChildHandleBuffer[Index],
1050              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1051              );
1052     } else {
1053       //
1054       // Succeed to stop this multi-lun handle, so go on with next child.
1055       //
1056       if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
1057         UsbMass->Transport->CleanUp (UsbMass->Context);
1058       }
1059       FreePool (UsbMass);
1060     }
1061   }
1062 
1063   if (!AllChildrenStopped) {
1064     return EFI_DEVICE_ERROR;
1065   }
1066 
1067   DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));
1068   return EFI_SUCCESS;
1069 }
1070 
1071 /**
1072   Entrypoint of USB Mass Storage Driver.
1073 
1074   This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding
1075   Protocol together with Component Name Protocols.
1076 
1077   @param  ImageHandle       The firmware allocated handle for the EFI image.
1078   @param  SystemTable       A pointer to the EFI System Table.
1079 
1080   @retval EFI_SUCCESS       The entry point is executed successfully.
1081 
1082 **/
1083 EFI_STATUS
1084 EFIAPI
USBMassStorageEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1085 USBMassStorageEntryPoint (
1086   IN EFI_HANDLE               ImageHandle,
1087   IN EFI_SYSTEM_TABLE         *SystemTable
1088   )
1089 {
1090   EFI_STATUS  Status;
1091 
1092   //
1093   // Install driver binding protocol
1094   //
1095   Status = EfiLibInstallDriverBindingComponentName2 (
1096              ImageHandle,
1097              SystemTable,
1098              &gUSBMassDriverBinding,
1099              ImageHandle,
1100              &gUsbMassStorageComponentName,
1101              &gUsbMassStorageComponentName2
1102              );
1103   ASSERT_EFI_ERROR (Status);
1104 
1105   return EFI_SUCCESS;
1106 }
1107