]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
Produce DiskInfo for usb mass storage device
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassBoot.c
1 /** @file
2 Implementation of the command set of USB Mass Storage Specification
3 for Bootability, Revision 1.0.
4
5 Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "UsbMass.h"
17
18 /**
19 Execute REQUEST SENSE Command to retrieve sense data from device.
20
21 @param UsbMass The device whose sense data is requested.
22
23 @retval EFI_SUCCESS The command is excuted successfully.
24 @retval EFI_DEVICE_ERROR Failed to request sense.
25 @retval EFI_NO_RESPONSE The device media doesn't response this request.
26 @retval EFI_INVALID_PARAMETER The command has some invalid parameters.
27 @retval EFI_WRITE_PROTECTED The device is write protected.
28 @retval EFI_MEDIA_CHANGED The device media has been changed.
29
30 **/
31 EFI_STATUS
32 UsbBootRequestSense (
33 IN USB_MASS_DEVICE *UsbMass
34 )
35 {
36 USB_BOOT_REQUEST_SENSE_CMD SenseCmd;
37 USB_BOOT_REQUEST_SENSE_DATA SenseData;
38 EFI_BLOCK_IO_MEDIA *Media;
39 USB_MASS_TRANSPORT *Transport;
40 EFI_STATUS Status;
41 UINT32 CmdResult;
42
43 Transport = UsbMass->Transport;
44
45 //
46 // Request the sense data from the device
47 //
48 ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
49 ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
50
51 SenseCmd.OpCode = USB_BOOT_REQUEST_SENSE_OPCODE;
52 SenseCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
53 SenseCmd.AllocLen = (UINT8) sizeof (USB_BOOT_REQUEST_SENSE_DATA);
54
55 Status = Transport->ExecCommand (
56 UsbMass->Context,
57 &SenseCmd,
58 sizeof (USB_BOOT_REQUEST_SENSE_CMD),
59 EfiUsbDataIn,
60 &SenseData,
61 sizeof (USB_BOOT_REQUEST_SENSE_DATA),
62 UsbMass->Lun,
63 USB_BOOT_GENERAL_CMD_TIMEOUT,
64 &CmdResult
65 );
66 if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
67 DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
68 if (!EFI_ERROR (Status)) {
69 Status = EFI_DEVICE_ERROR;
70 }
71 return Status;
72 }
73
74 //
75 // If sense data is retrieved successfully, interpret the sense data
76 // and update the media status if necessary.
77 //
78 Media = &UsbMass->BlockIoMedia;
79
80 switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {
81
82 case USB_BOOT_SENSE_NO_SENSE:
83 Status = EFI_NO_RESPONSE;
84 break;
85
86 case USB_BOOT_SENSE_RECOVERED:
87 //
88 // Suppose hardware can handle this case, and recover later by itself
89 //
90 Status = EFI_NOT_READY;
91 break;
92
93 case USB_BOOT_SENSE_NOT_READY:
94 Status = EFI_DEVICE_ERROR;
95 if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
96 Media->MediaPresent = FALSE;
97 Status = EFI_NO_MEDIA;
98 } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
99 Status = EFI_NOT_READY;
100 }
101 break;
102
103 case USB_BOOT_SENSE_ILLEGAL_REQUEST:
104 Status = EFI_INVALID_PARAMETER;
105 break;
106
107 case USB_BOOT_SENSE_UNIT_ATTENTION:
108 Status = EFI_DEVICE_ERROR;
109 if (SenseData.Asc == USB_BOOT_ASC_MEDIA_CHANGE) {
110 //
111 // If MediaChange, reset ReadOnly and new MediaId
112 //
113 Status = EFI_MEDIA_CHANGED;
114 Media->ReadOnly = FALSE;
115 Media->MediaId++;
116 }
117 break;
118
119 case USB_BOOT_SENSE_DATA_PROTECT:
120 Status = EFI_WRITE_PROTECTED;
121 Media->ReadOnly = TRUE;
122 break;
123
124 default:
125 Status = EFI_DEVICE_ERROR;
126 break;
127 }
128
129 DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",
130 Status,
131 USB_BOOT_SENSE_KEY (SenseData.SenseKey),
132 SenseData.Asc,
133 SenseData.Ascq
134 ));
135
136 return Status;
137 }
138
139
140 /**
141 Execute the USB mass storage bootability commands.
142
143 This function executes the USB mass storage bootability commands.
144 If execution failed, retrieve the error by REQUEST_SENSE, then
145 update the device's status, such as ReadyOnly.
146
147 @param UsbMass The device to issue commands to
148 @param Cmd The command to execute
149 @param CmdLen The length of the command
150 @param DataDir The direction of data transfer
151 @param Data The buffer to hold the data
152 @param DataLen The length of expected data
153 @param Timeout The timeout used to transfer
154
155 @retval EFI_SUCCESS Command is excuted successfully
156 @retval Others Command execution failed.
157
158 **/
159 EFI_STATUS
160 UsbBootExecCmd (
161 IN USB_MASS_DEVICE *UsbMass,
162 IN VOID *Cmd,
163 IN UINT8 CmdLen,
164 IN EFI_USB_DATA_DIRECTION DataDir,
165 IN VOID *Data,
166 IN UINT32 DataLen,
167 IN UINT32 Timeout
168 )
169 {
170 USB_MASS_TRANSPORT *Transport;
171 EFI_STATUS Status;
172 UINT32 CmdResult;
173
174 Transport = UsbMass->Transport;
175 Status = Transport->ExecCommand (
176 UsbMass->Context,
177 Cmd,
178 CmdLen,
179 DataDir,
180 Data,
181 DataLen,
182 UsbMass->Lun,
183 Timeout,
184 &CmdResult
185 );
186 //
187 // If ExecCommand() returns no error and CmdResult is success,
188 // then the commnad transfer is successful.
189 //
190 if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {
191 return EFI_SUCCESS;
192 }
193
194 DEBUG ((EFI_D_INFO, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n",
195 *(UINT8 *)Cmd ,Status));
196
197 //
198 // If command execution failed, then retrieve error info via sense request.
199 //
200 return UsbBootRequestSense (UsbMass);
201 }
202
203
204 /**
205 Execute the USB mass storage bootability commands with retrial.
206
207 This function executes USB mass storage bootability commands.
208 If the device isn't ready, wait for it. If the device is ready
209 and error occurs, retry the command again until it exceeds the
210 limit of retrial times.
211
212 @param UsbMass The device to issue commands to
213 @param Cmd The command to execute
214 @param CmdLen The length of the command
215 @param DataDir The direction of data transfer
216 @param Data The buffer to hold the data
217 @param DataLen The length of expected data
218 @param Timeout The timeout used to transfer
219
220 @retval EFI_SUCCESS The command is executed successfully.
221 @retval EFI_MEDIA_CHANGED The device media has been changed.
222 @retval Others Command execution failed after retrial.
223
224 **/
225 EFI_STATUS
226 UsbBootExecCmdWithRetry (
227 IN USB_MASS_DEVICE *UsbMass,
228 IN VOID *Cmd,
229 IN UINT8 CmdLen,
230 IN EFI_USB_DATA_DIRECTION DataDir,
231 IN VOID *Data,
232 IN UINT32 DataLen,
233 IN UINT32 Timeout
234 )
235 {
236 EFI_STATUS Status;
237 UINTN Retry;
238 UINT8 Terminate;
239
240 Status = EFI_SUCCESS;
241
242 for (Retry = 0, Terminate = 0; Retry < USB_BOOT_COMMAND_RETRY; Retry++) {
243 Status = UsbBootExecCmd (
244 UsbMass,
245 Cmd,
246 CmdLen,
247 DataDir,
248 Data,
249 DataLen,
250 Timeout
251 );
252 if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED) {
253 break;
254 }
255 //
256 // If the device isn't ready, just wait for it without limit on retrial times.
257 //
258 if (Status == EFI_NOT_READY && Terminate < 3) {
259 Retry = 0;
260 Terminate++;
261 }
262 }
263
264 return Status;
265 }
266
267
268 /**
269 Execute TEST UNIT READY command to check if the device is ready.
270
271 @param UsbMass The device to test
272
273 @retval EFI_SUCCESS The device is ready.
274 @retval Others Device not ready.
275
276 **/
277 EFI_STATUS
278 UsbBootIsUnitReady (
279 IN USB_MASS_DEVICE *UsbMass
280 )
281 {
282 USB_BOOT_TEST_UNIT_READY_CMD TestCmd;
283
284 ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));
285
286 TestCmd.OpCode = USB_BOOT_TEST_UNIT_READY_OPCODE;
287 TestCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
288
289 return UsbBootExecCmdWithRetry (
290 UsbMass,
291 &TestCmd,
292 (UINT8) sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
293 EfiUsbNoData,
294 NULL,
295 0,
296 USB_BOOT_GENERAL_CMD_TIMEOUT
297 );
298 }
299
300
301 /**
302 Execute INQUIRY Command to request information regarding parameters of
303 the device be sent to the host computer.
304
305 @param UsbMass The device to inquire.
306
307 @retval EFI_SUCCESS INQUIRY Command is executed successfully.
308 @retval Others INQUIRY Command is not executed successfully.
309
310 **/
311 EFI_STATUS
312 UsbBootInquiry (
313 IN USB_MASS_DEVICE *UsbMass
314 )
315 {
316 USB_BOOT_INQUIRY_CMD InquiryCmd;
317 EFI_BLOCK_IO_MEDIA *Media;
318 EFI_STATUS Status;
319
320 Media = &(UsbMass->BlockIoMedia);
321
322 ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
323 ZeroMem (&UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
324
325 InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;
326 InquiryCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
327 InquiryCmd.AllocLen = (UINT8) sizeof (USB_BOOT_INQUIRY_DATA);
328
329 Status = UsbBootExecCmdWithRetry (
330 UsbMass,
331 &InquiryCmd,
332 (UINT8) sizeof (USB_BOOT_INQUIRY_CMD),
333 EfiUsbDataIn,
334 &UsbMass->InquiryData,
335 sizeof (USB_BOOT_INQUIRY_DATA),
336 USB_BOOT_GENERAL_CMD_TIMEOUT
337 );
338 if (EFI_ERROR (Status)) {
339 return Status;
340 }
341
342 //
343 // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit
344 // from the inquiry data.
345 //
346 UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (UsbMass->InquiryData.Pdt));
347 Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (UsbMass->InquiryData.Removable));
348 //
349 // Set block size to the default value of 512 Bytes, in case no media is present at first time.
350 //
351 Media->BlockSize = 0x0200;
352
353 return Status;
354 }
355
356
357 /**
358 Execute READ CAPACITY command to request information regarding
359 the capacity of the installed medium of the device.
360
361 This function executes READ CAPACITY command to get the capacity
362 of the USB mass storage media, including the presence, block size,
363 and last block number.
364
365 @param UsbMass The device to retireve disk gemotric.
366
367 @retval EFI_SUCCESS The disk geometry is successfully retrieved.
368 @retval EFI_NOT_READY The returned block size is zero.
369 @retval Other READ CAPACITY command execution failed.
370
371 **/
372 EFI_STATUS
373 UsbBootReadCapacity (
374 IN USB_MASS_DEVICE *UsbMass
375 )
376 {
377 USB_BOOT_READ_CAPACITY_CMD CapacityCmd;
378 USB_BOOT_READ_CAPACITY_DATA CapacityData;
379 EFI_BLOCK_IO_MEDIA *Media;
380 EFI_STATUS Status;
381 UINT32 BlockSize;
382
383 Media = &UsbMass->BlockIoMedia;
384
385 ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
386 ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
387
388 CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;
389 CapacityCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
390
391 Status = UsbBootExecCmdWithRetry (
392 UsbMass,
393 &CapacityCmd,
394 (UINT8) sizeof (USB_BOOT_READ_CAPACITY_CMD),
395 EfiUsbDataIn,
396 &CapacityData,
397 sizeof (USB_BOOT_READ_CAPACITY_DATA),
398 USB_BOOT_GENERAL_CMD_TIMEOUT
399 );
400 if (EFI_ERROR (Status)) {
401 return Status;
402 }
403
404 //
405 // Get the information on media presence, block size, and last block number
406 // from READ CAPACITY data.
407 //
408 Media->MediaPresent = TRUE;
409 Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));
410
411 BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));
412 if (BlockSize == 0) {
413 //
414 // Get sense data
415 //
416 return UsbBootRequestSense (UsbMass);
417 } else {
418 Media->BlockSize = BlockSize;
419 }
420
421 DEBUG ((EFI_D_INFO, "UsbBootReadCapacity Success LBA=%ld BlockSize=%d\n",
422 Media->LastBlock, Media->BlockSize));
423
424 return Status;
425 }
426
427 /**
428 Retrieves SCSI mode sense information via MODE SENSE(6) command.
429
430 @param UsbMass The device whose sense data is requested.
431
432 @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.
433 @retval Other Command execution failed.
434
435 **/
436 EFI_STATUS
437 UsbScsiModeSense (
438 IN USB_MASS_DEVICE *UsbMass
439 )
440 {
441 EFI_STATUS Status;
442 USB_SCSI_MODE_SENSE6_CMD ModeSenseCmd;
443 USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;
444 EFI_BLOCK_IO_MEDIA *Media;
445
446 Media = &UsbMass->BlockIoMedia;
447
448 ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));
449 ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));
450
451 //
452 // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec
453 //
454 ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;
455 ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);
456 ModeSenseCmd.PageCode = 0x3F;
457 ModeSenseCmd.AllocateLen = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);
458
459 Status = UsbBootExecCmdWithRetry (
460 UsbMass,
461 &ModeSenseCmd,
462 (UINT8) sizeof (USB_SCSI_MODE_SENSE6_CMD),
463 EfiUsbDataIn,
464 &ModeParaHeader,
465 sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),
466 USB_BOOT_GENERAL_CMD_TIMEOUT
467 );
468
469 //
470 // Format of device-specific parameter byte of the mode parameter header is defined in
471 // Section 8.2.10 of SCSI-2 Spec.
472 // BIT7 of this byte is indicates whether the medium is write protected.
473 //
474 if (!EFI_ERROR (Status)) {
475 Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);
476 }
477
478 return Status;
479 }
480
481
482 /**
483 Get the parameters for the USB mass storage media.
484
485 This function get the parameters for the USB mass storage media,
486 It is used both to initialize the media during the Start() phase
487 of Driver Binding Protocol and to re-initialize it when the media is
488 changed. Althought the RemoveableMedia is unlikely to change,
489 it is also included here.
490
491 @param UsbMass The device to retrieve disk gemotric.
492
493 @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
494 @retval Other Failed to get the parameters.
495
496 **/
497 EFI_STATUS
498 UsbBootGetParams (
499 IN USB_MASS_DEVICE *UsbMass
500 )
501 {
502 EFI_BLOCK_IO_MEDIA *Media;
503 EFI_STATUS Status;
504 UINT8 CmdSet;
505
506 Media = &(UsbMass->BlockIoMedia);
507 CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
508
509 Status = UsbBootInquiry (UsbMass);
510 if (EFI_ERROR (Status)) {
511 DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
512 return Status;
513 }
514
515 //
516 // Don't use the Removable bit in inquiry data to test whether the media
517 // is removable because many flash disks wrongly set this bit.
518 //
519 if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
520 //
521 // CD-Rom device and Non-CD optical device
522 //
523 UsbMass->OpticalStorage = TRUE;
524 //
525 // Default value 2048 Bytes, in case no media present at first time
526 //
527 Media->BlockSize = 0x0800;
528 }
529
530 if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
531 //
532 // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,
533 // which is from [MassStorageBootabilitySpec-Page7].
534 // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI
535 // could get the information of WriteProtected.
536 // Since not all device support this command, so skip if fail.
537 //
538 UsbScsiModeSense (UsbMass);
539 }
540
541 return UsbBootReadCapacity (UsbMass);
542 }
543
544
545 /**
546 Detect whether the removable media is present and whether it has changed.
547
548 @param UsbMass The device to check.
549
550 @retval EFI_SUCCESS The media status is successfully checked.
551 @retval Other Failed to detect media.
552
553 **/
554 EFI_STATUS
555 UsbBootDetectMedia (
556 IN USB_MASS_DEVICE *UsbMass
557 )
558 {
559 EFI_BLOCK_IO_MEDIA OldMedia;
560 EFI_BLOCK_IO_MEDIA *Media;
561 UINT8 CmdSet;
562 EFI_TPL OldTpl;
563 EFI_STATUS Status;
564
565 Media = &UsbMass->BlockIoMedia;
566
567 CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));
568
569 CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
570
571 Status = UsbBootIsUnitReady (UsbMass);
572 if (EFI_ERROR (Status)) {
573 goto ON_ERROR;
574 }
575
576 if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
577 //
578 // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,
579 // according to Section 4 of USB Mass Storage Specification for Bootability.
580 // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI
581 // could get the information of Write Protected.
582 // Since not all device support this command, skip if fail.
583 //
584 UsbScsiModeSense (UsbMass);
585 }
586
587 Status = UsbBootReadCapacity (UsbMass);
588 if (EFI_ERROR (Status)) {
589 DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));
590 goto ON_ERROR;
591 }
592
593 return EFI_SUCCESS;
594
595 ON_ERROR:
596 //
597 // Detect whether it is necessary to reinstall the Block I/O Protocol.
598 //
599 // MediaId may change in RequestSense for MediaChanged
600 // MediaPresent may change in RequestSense for NoMedia
601 // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged
602 // MediaPresent/BlockSize/LastBlock may change in ReadCapacity
603 //
604 if ((Media->MediaId != OldMedia.MediaId) ||
605 (Media->MediaPresent != OldMedia.MediaPresent) ||
606 (Media->ReadOnly != OldMedia.ReadOnly) ||
607 (Media->BlockSize != OldMedia.BlockSize) ||
608 (Media->LastBlock != OldMedia.LastBlock)) {
609
610 //
611 // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY.
612 // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface().
613 //
614 OldTpl = EfiGetCurrentTpl ();
615 gBS->RestoreTPL (TPL_CALLBACK);
616
617 gBS->ReinstallProtocolInterface (
618 UsbMass->Controller,
619 &gEfiBlockIoProtocolGuid,
620 &UsbMass->BlockIo,
621 &UsbMass->BlockIo
622 );
623
624 ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);
625 gBS->RaiseTPL (OldTpl);
626
627 //
628 // Update MediaId after reinstalling Block I/O Protocol.
629 //
630 if (Media->MediaPresent != OldMedia.MediaPresent) {
631 if (Media->MediaPresent) {
632 Media->MediaId = 1;
633 } else {
634 Media->MediaId = 0;
635 }
636 }
637
638 if ((Media->ReadOnly != OldMedia.ReadOnly) ||
639 (Media->BlockSize != OldMedia.BlockSize) ||
640 (Media->LastBlock != OldMedia.LastBlock)) {
641 Media->MediaId++;
642 }
643 }
644
645 return Status;
646 }
647
648
649 /**
650 Read some blocks from the device.
651
652 @param UsbMass The USB mass storage device to read from
653 @param Lba The start block number
654 @param TotalBlock Total block number to read
655 @param Buffer The buffer to read to
656
657 @retval EFI_SUCCESS Data are read into the buffer
658 @retval Others Failed to read all the data
659
660 **/
661 EFI_STATUS
662 UsbBootReadBlocks (
663 IN USB_MASS_DEVICE *UsbMass,
664 IN UINT32 Lba,
665 IN UINTN TotalBlock,
666 OUT UINT8 *Buffer
667 )
668 {
669 USB_BOOT_READ10_CMD ReadCmd;
670 EFI_STATUS Status;
671 UINT16 Count;
672 UINT32 BlockSize;
673 UINT32 ByteSize;
674 UINT32 Timeout;
675
676 BlockSize = UsbMass->BlockIoMedia.BlockSize;
677 Status = EFI_SUCCESS;
678
679 while (TotalBlock > 0) {
680 //
681 // Split the total blocks into smaller pieces to ease the pressure
682 // on the device. We must split the total block because the READ10
683 // command only has 16 bit transfer length (in the unit of block).
684 //
685 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
686 ByteSize = (UINT32)Count * BlockSize;
687
688 //
689 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
690 //
691 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
692
693 //
694 // Fill in the command then execute
695 //
696 ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));
697
698 ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;
699 ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
700 WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba));
701 WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count));
702
703 Status = UsbBootExecCmdWithRetry (
704 UsbMass,
705 &ReadCmd,
706 (UINT8) sizeof (USB_BOOT_READ10_CMD),
707 EfiUsbDataIn,
708 Buffer,
709 ByteSize,
710 Timeout
711 );
712 if (EFI_ERROR (Status)) {
713 return Status;
714 }
715
716 Lba += Count;
717 Buffer += Count * BlockSize;
718 TotalBlock -= Count;
719 }
720
721 return Status;
722 }
723
724
725 /**
726 Write some blocks to the device.
727
728 @param UsbMass The USB mass storage device to write to
729 @param Lba The start block number
730 @param TotalBlock Total block number to write
731 @param Buffer Pointer to the source buffer for the data.
732
733 @retval EFI_SUCCESS Data are written into the buffer
734 @retval Others Failed to write all the data
735
736 **/
737 EFI_STATUS
738 UsbBootWriteBlocks (
739 IN USB_MASS_DEVICE *UsbMass,
740 IN UINT32 Lba,
741 IN UINTN TotalBlock,
742 IN UINT8 *Buffer
743 )
744 {
745 USB_BOOT_WRITE10_CMD WriteCmd;
746 EFI_STATUS Status;
747 UINT16 Count;
748 UINT32 BlockSize;
749 UINT32 ByteSize;
750 UINT32 Timeout;
751
752 BlockSize = UsbMass->BlockIoMedia.BlockSize;
753 Status = EFI_SUCCESS;
754
755 while (TotalBlock > 0) {
756 //
757 // Split the total blocks into smaller pieces to ease the pressure
758 // on the device. We must split the total block because the WRITE10
759 // command only has 16 bit transfer length (in the unit of block).
760 //
761 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
762 ByteSize = (UINT32)Count * BlockSize;
763
764 //
765 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
766 //
767 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
768
769 //
770 // Fill in the write10 command block
771 //
772 ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));
773
774 WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;
775 WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
776 WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba));
777 WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count));
778
779 Status = UsbBootExecCmdWithRetry (
780 UsbMass,
781 &WriteCmd,
782 (UINT8) sizeof (USB_BOOT_WRITE10_CMD),
783 EfiUsbDataOut,
784 Buffer,
785 ByteSize,
786 Timeout
787 );
788 if (EFI_ERROR (Status)) {
789 return Status;
790 }
791
792 Lba += Count;
793 Buffer += Count * BlockSize;
794 TotalBlock -= Count;
795 }
796
797 return Status;
798 }
799
800 /**
801 Use the USB clear feature control transfer to clear the endpoint stall condition.
802
803 @param UsbIo The USB I/O Protocol instance
804 @param EndpointAddr The endpoint to clear stall for
805
806 @retval EFI_SUCCESS The endpoint stall condition is cleared.
807 @retval Others Failed to clear the endpoint stall condition.
808
809 **/
810 EFI_STATUS
811 UsbClearEndpointStall (
812 IN EFI_USB_IO_PROTOCOL *UsbIo,
813 IN UINT8 EndpointAddr
814 )
815 {
816 EFI_USB_DEVICE_REQUEST Request;
817 EFI_STATUS Status;
818 UINT32 CmdResult;
819 UINT32 Timeout;
820
821 Request.RequestType = 0x02;
822 Request.Request = USB_REQ_CLEAR_FEATURE;
823 Request.Value = USB_FEATURE_ENDPOINT_HALT;
824 Request.Index = EndpointAddr;
825 Request.Length = 0;
826 Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_1_MILLISECOND;
827
828 Status = UsbIo->UsbControlTransfer (
829 UsbIo,
830 &Request,
831 EfiUsbNoData,
832 Timeout,
833 NULL,
834 0,
835 &CmdResult
836 );
837
838 return Status;
839 }