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