]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
Fixed unexpected timeout in Usb MassStorage Driver.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassImpl.c
1 /** @file
2
3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 UsbMassImpl.c
15
16 Abstract:
17
18 The implementation of USB mass storage class device driver.
19 The command set supported is "USB Mass Storage Specification
20 for Bootability".
21
22 Revision History
23
24
25 **/
26
27 #include "UsbMassImpl.h"
28
29 //
30 // The underlying transport protocol. CBI support isn't included
31 // in the current build. It is being obseleted by the standard
32 // body. If you want to enable it, remove the if directive here,
33 // then add the UsbMassCbi.c/.h to the driver's inf file.
34 //
35 STATIC
36 USB_MASS_TRANSPORT *mUsbMassTransport[] = {
37 &mUsbCbi0Transport,
38 &mUsbCbi1Transport,
39 &mUsbBotTransport,
40 NULL
41 };
42
43 UINTN mUsbMscInfo = DEBUG_INFO;
44 UINTN mUsbMscError = DEBUG_ERROR;
45
46
47 /**
48 Retrieve the media parameters such as disk gemotric for the
49 device's BLOCK IO protocol.
50
51 @param UsbMass The USB mass storage device
52
53 @retval EFI_SUCCESS The media parameters is updated successfully.
54 @retval Others Failed to get the media parameters.
55
56 **/
57 EFI_STATUS
58 UsbMassInitMedia (
59 IN USB_MASS_DEVICE *UsbMass
60 )
61 {
62 EFI_BLOCK_IO_MEDIA *Media;
63 EFI_STATUS Status;
64 UINTN Index;
65
66 Media = &UsbMass->BlockIoMedia;
67
68 //
69 // Initialize the MediaPrsent/ReadOnly and others to the default.
70 // We are not forced to get it right at this time, check UEFI2.0
71 // spec for more information:
72 //
73 // MediaPresent: This field shows the media present status as
74 // of the most recent ReadBlocks or WriteBlocks call.
75 //
76 // ReadOnly : This field shows the read-only status as of the
77 // recent WriteBlocks call.
78 //
79 // but remember to update MediaId/MediaPresent/ReadOnly status
80 // after ReadBlocks and WriteBlocks
81 //
82 Media->MediaPresent = FALSE;
83 Media->LogicalPartition = FALSE;
84 Media->ReadOnly = FALSE;
85 Media->WriteCaching = FALSE;
86 Media->IoAlign = 0;
87
88 //
89 // Some device may spend several seconds before it is ready.
90 // Try several times before giving up. Wait 5s at most.
91 //
92 Status = EFI_SUCCESS;
93
94 for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) {
95
96 Status = UsbBootGetParams (UsbMass);
97 if ((Status != EFI_MEDIA_CHANGED)
98 && (Status != EFI_NOT_READY)
99 && (Status != EFI_TIMEOUT)) {
100 break;
101 }
102
103 Status = UsbBootIsUnitReady (UsbMass);
104 if (EFI_ERROR (Status)) {
105 gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1));
106 }
107
108 }
109
110 return Status;
111 }
112
113
114 /**
115 Reset the block device. ExtendedVerification is ignored for this.
116
117 @param This The BLOCK IO protocol
118 @param ExtendedVerification Whether to execute extended verfication.
119
120 @retval EFI_SUCCESS The device is successfully resetted.
121 @retval Others Failed to reset the device.
122
123 **/
124 EFI_STATUS
125 UsbMassReset (
126 IN EFI_BLOCK_IO_PROTOCOL *This,
127 IN BOOLEAN ExtendedVerification
128 )
129 {
130 USB_MASS_DEVICE *UsbMass;
131 EFI_TPL OldTpl;
132 EFI_STATUS Status;
133
134 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
135
136 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
137 Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
138
139 gBS->RestoreTPL (OldTpl);
140
141 return Status;
142 }
143
144
145 /**
146 Read some blocks of data from the block device.
147
148 @param This The Block IO protocol
149 @param MediaId The media's ID of the device for current request
150 @param Lba The start block number
151 @param BufferSize The size of buffer to read data in
152 @param Buffer The buffer to read data to
153
154 @retval EFI_SUCCESS The data is successfully read
155 @retval EFI_NO_MEDIA Media isn't present
156 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
157 MediaId changed
158 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
159 NULL.
160 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
161 size, or overflow the last block number.
162
163 **/
164 EFI_STATUS
165 UsbMassReadBlocks (
166 IN EFI_BLOCK_IO_PROTOCOL *This,
167 IN UINT32 MediaId,
168 IN EFI_LBA Lba,
169 IN UINTN BufferSize,
170 OUT VOID *Buffer
171 )
172 {
173 USB_MASS_DEVICE *UsbMass;
174 EFI_BLOCK_IO_MEDIA *Media;
175 EFI_STATUS Status;
176 EFI_TPL OldTpl;
177 UINTN TotalBlock;
178
179 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
180 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
181 Media = &UsbMass->BlockIoMedia;
182
183 //
184 // First, validate the parameters
185 //
186 if ((Buffer == NULL) || (BufferSize == 0)) {
187 Status = EFI_INVALID_PARAMETER;
188 goto ON_EXIT;
189 }
190
191 //
192 // If it is a removable media, such as CD-Rom or Usb-Floppy,
193 // need to detect the media before each rw. While some of
194 // Usb-Flash is marked as removable media.
195 //
196 //
197 if (Media->RemovableMedia == TRUE) {
198 Status = UsbBootDetectMedia (UsbMass);
199 if (EFI_ERROR (Status)) {
200 DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));
201 goto ON_EXIT;
202 }
203 }
204
205 //
206 // Make sure BlockSize and LBA is consistent with BufferSize
207 //
208 if ((BufferSize % Media->BlockSize) != 0) {
209 Status = EFI_BAD_BUFFER_SIZE;
210 goto ON_EXIT;
211 }
212
213 TotalBlock = BufferSize / Media->BlockSize;
214
215 if (Lba + TotalBlock - 1 > Media->LastBlock) {
216 Status = EFI_BAD_BUFFER_SIZE;
217 goto ON_EXIT;
218 }
219
220 Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
221 if (EFI_ERROR (Status)) {
222 DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
223 UsbMassReset (This, TRUE);
224 }
225
226 ON_EXIT:
227 gBS->RestoreTPL (OldTpl);
228 return Status;
229 }
230
231
232 /**
233 Write some blocks of data to the block device.
234
235 @param This The Block IO protocol
236 @param MediaId The media's ID of the device for current request
237 @param Lba The start block number
238 @param BufferSize The size of buffer to write data to
239 @param Buffer The buffer to write data to
240
241 @retval EFI_SUCCESS The data is successfully written
242 @retval EFI_NO_MEDIA Media isn't present
243 @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
244 MediaId changed
245 @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
246 NULL.
247 @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
248 size,
249
250 **/
251 EFI_STATUS
252 UsbMassWriteBlocks (
253 IN EFI_BLOCK_IO_PROTOCOL *This,
254 IN UINT32 MediaId,
255 IN EFI_LBA Lba,
256 IN UINTN BufferSize,
257 IN VOID *Buffer
258 )
259 {
260 USB_MASS_DEVICE *UsbMass;
261 EFI_BLOCK_IO_MEDIA *Media;
262 EFI_STATUS Status;
263 EFI_TPL OldTpl;
264 UINTN TotalBlock;
265
266 OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
267 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
268 Media = &UsbMass->BlockIoMedia;
269
270 //
271 // First, validate the parameters
272 //
273 if ((Buffer == NULL) || (BufferSize == 0)) {
274 Status = EFI_INVALID_PARAMETER;
275 goto ON_EXIT;
276 }
277
278 //
279 // If it is a removable media, such as CD-Rom or Usb-Floppy,
280 // need to detect the media before each rw. While some of
281 // Usb-Flash is marked as removable media.
282 //
283 //
284 if (Media->RemovableMedia == TRUE) {
285 Status = UsbBootDetectMedia (UsbMass);
286 if (EFI_ERROR (Status)) {
287 DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));
288 goto ON_EXIT;
289 }
290 }
291
292 //
293 // Make sure BlockSize and LBA is consistent with BufferSize
294 //
295 if ((BufferSize % Media->BlockSize) != 0) {
296 Status = EFI_BAD_BUFFER_SIZE;
297 goto ON_EXIT;
298 }
299
300 TotalBlock = BufferSize / Media->BlockSize;
301
302 if (Lba + TotalBlock - 1 > Media->LastBlock) {
303 Status = EFI_BAD_BUFFER_SIZE;
304 goto ON_EXIT;
305 }
306
307 //
308 // Try to write the data even the device is marked as ReadOnly,
309 // and clear the status should the write succeed.
310 //
311 Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
312 if (EFI_ERROR (Status)) {
313 DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
314 UsbMassReset (This, TRUE);
315 }
316
317 ON_EXIT:
318 gBS->RestoreTPL (OldTpl);
319 return Status;
320 }
321
322
323 /**
324 Flush the cached writes to disks. USB mass storage device doesn't
325 support write cache, so return EFI_SUCCESS directly.
326
327 @param This The BLOCK IO protocol
328
329 @retval EFI_SUCCESS Always returns success
330
331 **/
332 EFI_STATUS
333 UsbMassFlushBlocks (
334 IN EFI_BLOCK_IO_PROTOCOL *This
335 )
336 {
337 return EFI_SUCCESS;
338 }
339
340
341 /**
342 Check whether the controller is a supported USB mass storage.
343
344 @param This The USB mass driver's driver binding.
345 @param Controller The device to test against.
346 @param RemainingDevicePath The remaining device path
347
348 @retval EFI_SUCCESS This device is a supported USB mass storage.
349 @retval EFI_UNSUPPORTED The device isn't supported
350 @retval Others Some error happened.
351
352 **/
353 EFI_STATUS
354 EFIAPI
355 USBMassDriverBindingSupported (
356 IN EFI_DRIVER_BINDING_PROTOCOL *This,
357 IN EFI_HANDLE Controller,
358 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
359 )
360 {
361 EFI_USB_IO_PROTOCOL *UsbIo;
362 EFI_USB_INTERFACE_DESCRIPTOR Interface;
363 USB_MASS_TRANSPORT *Transport;
364 EFI_STATUS Status;
365 INTN Index;
366
367 //
368 // Check whether the controlelr support USB_IO
369 //
370 Status = gBS->OpenProtocol (
371 Controller,
372 &gEfiUsbIoProtocolGuid,
373 (VOID **) &UsbIo,
374 This->DriverBindingHandle,
375 Controller,
376 EFI_OPEN_PROTOCOL_BY_DRIVER
377 );
378 if (EFI_ERROR (Status)) {
379 return Status;
380 }
381
382 //
383 // Get the interface to check the USB class and find a transport
384 // protocol handler.
385 //
386 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
387 if (EFI_ERROR (Status)) {
388 goto ON_EXIT;
389 }
390
391 Status = EFI_UNSUPPORTED;
392
393 if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
394 goto ON_EXIT;
395 }
396
397 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
398 Transport = mUsbMassTransport[Index];
399 if (Interface.InterfaceProtocol == Transport->Protocol) {
400 Status = Transport->Init (UsbIo, Controller, NULL);
401 break;
402 }
403 }
404
405 DEBUG ((mUsbMscInfo, "Found a USB mass store device %r\n", Status));
406
407 ON_EXIT:
408 gBS->CloseProtocol (
409 Controller,
410 &gEfiUsbIoProtocolGuid,
411 This->DriverBindingHandle,
412 Controller
413 );
414
415 return Status;
416 }
417
418
419 /**
420 Start the USB mass storage device on the controller. It will
421 install a BLOCK_IO protocol on the device if everything is OK.
422
423 @param This The USB mass storage driver binding.
424 @param Controller The USB mass storage device to start on
425 @param RemainingDevicePath The remaining device path.
426
427 @retval EFI_SUCCESS The driver has started on the device.
428 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
429 @retval Others Failed to start the driver on the device.
430
431 **/
432 EFI_STATUS
433 EFIAPI
434 USBMassDriverBindingStart (
435 IN EFI_DRIVER_BINDING_PROTOCOL *This,
436 IN EFI_HANDLE Controller,
437 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
438 )
439 {
440 EFI_USB_IO_PROTOCOL *UsbIo;
441 EFI_USB_INTERFACE_DESCRIPTOR Interface;
442 USB_MASS_DEVICE *UsbMass;
443 USB_MASS_TRANSPORT *Transport;
444 EFI_STATUS Status;
445 UINTN Index;
446
447 Status = gBS->OpenProtocol (
448 Controller,
449 &gEfiUsbIoProtocolGuid,
450 (VOID **) &UsbIo,
451 This->DriverBindingHandle,
452 Controller,
453 EFI_OPEN_PROTOCOL_BY_DRIVER
454 );
455
456 if (EFI_ERROR (Status)) {
457 return Status;
458 }
459
460 UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
461 if (UsbMass == NULL) {
462 return EFI_OUT_OF_RESOURCES;
463 }
464
465 //
466 // Initialize the transport protocols
467 //
468 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
469 if (EFI_ERROR (Status)) {
470 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));
471 goto ON_ERROR;
472 }
473
474 Status = EFI_UNSUPPORTED;
475
476 for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
477 Transport = mUsbMassTransport[Index];
478
479 if (Interface.InterfaceProtocol == Transport->Protocol) {
480 UsbMass->Transport = Transport;
481 Status = Transport->Init (UsbIo, Controller, &UsbMass->Context);
482 break;
483 }
484 }
485
486 if (EFI_ERROR (Status)) {
487 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status));
488 goto ON_ERROR;
489 }
490
491 UsbMass->Signature = USB_MASS_SIGNATURE;
492 UsbMass->Controller = Controller;
493 UsbMass->UsbIo = UsbIo;
494 UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
495 UsbMass->BlockIo.Reset = UsbMassReset;
496 UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
497 UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
498 UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
499 UsbMass->OpticalStorage = FALSE;
500
501 //
502 // Get the storage's parameters, such as last block number.
503 // then install the BLOCK_IO
504 //
505 Status = UsbMassInitMedia (UsbMass);
506 if (!EFI_ERROR (Status)) {
507 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
508 (UsbMass->Pdt != USB_PDT_CDROM) &&
509 (UsbMass->Pdt != USB_PDT_OPTICAL) &&
510 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
511 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
512 goto ON_ERROR;
513 }
514 } else if (Status != EFI_NO_MEDIA){
515 DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status));
516 goto ON_ERROR;
517 }
518
519 Status = gBS->InstallProtocolInterface (
520 &Controller,
521 &gEfiBlockIoProtocolGuid,
522 EFI_NATIVE_INTERFACE,
523 &UsbMass->BlockIo
524 );
525 if (EFI_ERROR (Status)) {
526 goto ON_ERROR;
527 }
528
529 return EFI_SUCCESS;
530
531 ON_ERROR:
532 gBS->FreePool (UsbMass);
533
534 gBS->CloseProtocol (
535 Controller,
536 &gEfiUsbIoProtocolGuid,
537 This->DriverBindingHandle,
538 Controller
539 );
540
541 return Status;
542 }
543
544
545 /**
546 Stop controlling the device.
547
548 @param This The USB mass storage driver binding
549 @param Controller The device controller controlled by the driver.
550 @param NumberOfChildren The number of children of this device
551 @param ChildHandleBuffer The buffer of children handle.
552
553 @retval EFI_SUCCESS The driver stopped from controlling the device.
554 @retval Others Failed to stop the driver
555
556 **/
557 EFI_STATUS
558 EFIAPI
559 USBMassDriverBindingStop (
560 IN EFI_DRIVER_BINDING_PROTOCOL *This,
561 IN EFI_HANDLE Controller,
562 IN UINTN NumberOfChildren,
563 IN EFI_HANDLE *ChildHandleBuffer
564 )
565 {
566 EFI_STATUS Status;
567 USB_MASS_DEVICE *UsbMass;
568 EFI_BLOCK_IO_PROTOCOL *BlockIo;
569
570 //
571 // First, get our context back from the BLOCK_IO
572 //
573 Status = gBS->OpenProtocol (
574 Controller,
575 &gEfiBlockIoProtocolGuid,
576 (VOID **) &BlockIo,
577 This->DriverBindingHandle,
578 Controller,
579 EFI_OPEN_PROTOCOL_GET_PROTOCOL
580 );
581
582 if (EFI_ERROR (Status)) {
583 return Status;
584 }
585
586 UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);
587
588 //
589 // Uninstall Block I/O protocol from the device handle,
590 // then call the transport protocol to stop itself.
591 //
592 Status = gBS->UninstallProtocolInterface (
593 Controller,
594 &gEfiBlockIoProtocolGuid,
595 &UsbMass->BlockIo
596 );
597 if (EFI_ERROR (Status)) {
598 return Status;
599 }
600
601 gBS->CloseProtocol (
602 Controller,
603 &gEfiUsbIoProtocolGuid,
604 This->DriverBindingHandle,
605 Controller
606 );
607
608 UsbMass->Transport->Fini (UsbMass->Context);
609 gBS->FreePool (UsbMass);
610
611 return EFI_SUCCESS;
612 }
613
614 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
615 USBMassDriverBindingSupported,
616 USBMassDriverBindingStart,
617 USBMassDriverBindingStop,
618 0x11,
619 NULL,
620 NULL
621 };
622
623 EFI_STATUS
624 EFIAPI
625 USBMassStorageEntryPoint (
626 IN EFI_HANDLE ImageHandle,
627 IN EFI_SYSTEM_TABLE *SystemTable
628 )
629 /*++
630
631 Routine Description:
632
633 The entry point for the driver, which will install the driver binding and
634 component name protocol
635
636 Arguments:
637
638 ImageHandle - The image handle of this driver
639 SystemTable - The system table
640
641 Returns:
642
643 EFI_SUCCESS - the protocols are installed OK
644 Others - Failed to install protocols.
645
646 --*/
647 {
648 EFI_STATUS Status;
649
650 //
651 // Install driver binding protocol
652 //
653 Status = EfiLibInstallDriverBindingComponentName2 (
654 ImageHandle,
655 SystemTable,
656 &gUSBMassDriverBinding,
657 ImageHandle,
658 &gUsbMassStorageComponentName,
659 &gUsbMassStorageComponentName2
660 );
661
662 return Status;
663 }