]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
MdeModulePkg/UsbMassStorageDxe: Fix USB Mass Storage detection
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassBoot.c
CommitLineData
e237e7ae 1/** @file\r
d80ed2a7 2 Implementation of the command set of USB Mass Storage Specification\r
3 for Bootability, Revision 1.0.\r
cc5166ff 4\r
275b96da 5Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 6This program and the accompanying materials\r
e237e7ae 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
cc5166ff 14**/\r
e237e7ae 15\r
39840c50 16#include "UsbMass.h"\r
e237e7ae 17\r
e237e7ae 18/**\r
d80ed2a7 19 Execute REQUEST SENSE Command to retrieve sense data from device.\r
e237e7ae 20\r
d80ed2a7 21 @param UsbMass The device whose sense data is requested.\r
e237e7ae 22\r
ed356b9e 23 @retval EFI_SUCCESS The command is executed successfully.\r
cc5166ff 24 @retval EFI_DEVICE_ERROR Failed to request sense.\r
25 @retval EFI_NO_RESPONSE The device media doesn't response this request.\r
26 @retval EFI_INVALID_PARAMETER The command has some invalid parameters.\r
27 @retval EFI_WRITE_PROTECTED The device is write protected.\r
28 @retval EFI_MEDIA_CHANGED The device media has been changed.\r
e237e7ae 29\r
30**/\r
31EFI_STATUS\r
32UsbBootRequestSense (\r
33 IN USB_MASS_DEVICE *UsbMass\r
34 )\r
35{\r
36 USB_BOOT_REQUEST_SENSE_CMD SenseCmd;\r
37 USB_BOOT_REQUEST_SENSE_DATA SenseData;\r
38 EFI_BLOCK_IO_MEDIA *Media;\r
39 USB_MASS_TRANSPORT *Transport;\r
40 EFI_STATUS Status;\r
41 UINT32 CmdResult;\r
42\r
43 Transport = UsbMass->Transport;\r
44\r
45 //\r
d80ed2a7 46 // Request the sense data from the device\r
e237e7ae 47 //\r
48 ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));\r
49 ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));\r
50\r
51 SenseCmd.OpCode = USB_BOOT_REQUEST_SENSE_OPCODE;\r
c52fa98c 52 SenseCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
c9325700 53 SenseCmd.AllocLen = (UINT8) sizeof (USB_BOOT_REQUEST_SENSE_DATA);\r
e237e7ae 54\r
55 Status = Transport->ExecCommand (\r
56 UsbMass->Context,\r
57 &SenseCmd,\r
58 sizeof (USB_BOOT_REQUEST_SENSE_CMD),\r
59 EfiUsbDataIn,\r
60 &SenseData,\r
61 sizeof (USB_BOOT_REQUEST_SENSE_DATA),\r
c7e39923 62 UsbMass->Lun,\r
e237e7ae 63 USB_BOOT_GENERAL_CMD_TIMEOUT,\r
64 &CmdResult\r
65 );\r
66 if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {\r
1c619535 67 DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));\r
88e349f1 68 if (!EFI_ERROR (Status)) {\r
69 Status = EFI_DEVICE_ERROR;\r
70 }\r
50fa1b3a 71 return Status;\r
e237e7ae 72 }\r
73\r
74 //\r
d80ed2a7 75 // If sense data is retrieved successfully, interpret the sense data\r
76 // and update the media status if necessary.\r
e237e7ae 77 //\r
78 Media = &UsbMass->BlockIoMedia;\r
79\r
80 switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {\r
81\r
82 case USB_BOOT_SENSE_NO_SENSE:\r
275b96da
MK
83 if (SenseData.Asc == USB_BOOT_ASC_NO_ADDITIONAL_SENSE_INFORMATION) {\r
84 //\r
85 // It is not an error if a device does not have additional sense information\r
86 //\r
87 Status = EFI_SUCCESS;\r
88 } else {\r
89 Status = EFI_NO_RESPONSE;\r
90 }\r
50fa1b3a 91 break;\r
92\r
e237e7ae 93 case USB_BOOT_SENSE_RECOVERED:\r
94 //\r
95 // Suppose hardware can handle this case, and recover later by itself\r
96 //\r
97 Status = EFI_NOT_READY;\r
98 break;\r
99\r
100 case USB_BOOT_SENSE_NOT_READY:\r
50fa1b3a 101 Status = EFI_DEVICE_ERROR;\r
1ccdbf2a 102 if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {\r
d80ed2a7 103 Media->MediaPresent = FALSE;\r
104 Status = EFI_NO_MEDIA;\r
1ccdbf2a 105 } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {\r
d80ed2a7 106 Status = EFI_NOT_READY;\r
e237e7ae 107 }\r
108 break;\r
109\r
110 case USB_BOOT_SENSE_ILLEGAL_REQUEST:\r
111 Status = EFI_INVALID_PARAMETER;\r
112 break;\r
113\r
114 case USB_BOOT_SENSE_UNIT_ATTENTION:\r
115 Status = EFI_DEVICE_ERROR;\r
1ccdbf2a 116 if (SenseData.Asc == USB_BOOT_ASC_MEDIA_CHANGE) {\r
50fa1b3a 117 //\r
d80ed2a7 118 // If MediaChange, reset ReadOnly and new MediaId\r
50fa1b3a 119 //\r
d80ed2a7 120 Status = EFI_MEDIA_CHANGED;\r
50fa1b3a 121 Media->ReadOnly = FALSE;\r
122 Media->MediaId++;\r
e237e7ae 123 }\r
124 break;\r
125\r
d80ed2a7 126 case USB_BOOT_SENSE_DATA_PROTECT:\r
127 Status = EFI_WRITE_PROTECTED;\r
50fa1b3a 128 Media->ReadOnly = TRUE;\r
e237e7ae 129 break;\r
130\r
131 default:\r
132 Status = EFI_DEVICE_ERROR;\r
133 break;\r
134 }\r
135\r
1c619535 136 DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",\r
e237e7ae 137 Status,\r
138 USB_BOOT_SENSE_KEY (SenseData.SenseKey),\r
1ccdbf2a 139 SenseData.Asc,\r
140 SenseData.Ascq\r
e237e7ae 141 ));\r
142\r
143 return Status;\r
144}\r
145\r
146\r
147/**\r
d80ed2a7 148 Execute the USB mass storage bootability commands.\r
149\r
150 This function executes the USB mass storage bootability commands.\r
151 If execution failed, retrieve the error by REQUEST_SENSE, then\r
152 update the device's status, such as ReadyOnly.\r
e237e7ae 153\r
154 @param UsbMass The device to issue commands to\r
155 @param Cmd The command to execute\r
156 @param CmdLen The length of the command\r
157 @param DataDir The direction of data transfer\r
158 @param Data The buffer to hold the data\r
159 @param DataLen The length of expected data\r
160 @param Timeout The timeout used to transfer\r
161\r
ed356b9e 162 @retval EFI_SUCCESS Command is executed successfully\r
d80ed2a7 163 @retval Others Command execution failed.\r
e237e7ae 164\r
165**/\r
e237e7ae 166EFI_STATUS\r
167UsbBootExecCmd (\r
168 IN USB_MASS_DEVICE *UsbMass,\r
169 IN VOID *Cmd,\r
170 IN UINT8 CmdLen,\r
171 IN EFI_USB_DATA_DIRECTION DataDir,\r
172 IN VOID *Data,\r
173 IN UINT32 DataLen,\r
174 IN UINT32 Timeout\r
175 )\r
176{\r
177 USB_MASS_TRANSPORT *Transport;\r
178 EFI_STATUS Status;\r
179 UINT32 CmdResult;\r
180\r
181 Transport = UsbMass->Transport;\r
182 Status = Transport->ExecCommand (\r
183 UsbMass->Context,\r
184 Cmd,\r
185 CmdLen,\r
186 DataDir,\r
187 Data,\r
188 DataLen,\r
c7e39923 189 UsbMass->Lun,\r
e237e7ae 190 Timeout,\r
191 &CmdResult\r
192 );\r
19bc8527 193\r
194 if (Status == EFI_TIMEOUT) {\r
195 DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: Timeout to Exec 0x%x Cmd\n", *(UINT8 *)Cmd));\r
196 return EFI_TIMEOUT;\r
197 }\r
198\r
e237e7ae 199 //\r
d80ed2a7 200 // If ExecCommand() returns no error and CmdResult is success,\r
201 // then the commnad transfer is successful.\r
e237e7ae 202 //\r
d80ed2a7 203 if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {\r
e237e7ae 204 return EFI_SUCCESS;\r
205 }\r
206\r
d80ed2a7 207 //\r
208 // If command execution failed, then retrieve error info via sense request.\r
209 //\r
e237e7ae 210 return UsbBootRequestSense (UsbMass);\r
211}\r
212\r
213\r
214/**\r
d80ed2a7 215 Execute the USB mass storage bootability commands with retrial.\r
e237e7ae 216\r
d80ed2a7 217 This function executes USB mass storage bootability commands.\r
218 If the device isn't ready, wait for it. If the device is ready\r
219 and error occurs, retry the command again until it exceeds the\r
220 limit of retrial times.\r
221 \r
e237e7ae 222 @param UsbMass The device to issue commands to\r
223 @param Cmd The command to execute\r
224 @param CmdLen The length of the command\r
225 @param DataDir The direction of data transfer\r
226 @param Data The buffer to hold the data\r
227 @param DataLen The length of expected data\r
cc5166ff 228 @param Timeout The timeout used to transfer\r
e237e7ae 229\r
d80ed2a7 230 @retval EFI_SUCCESS The command is executed successfully.\r
231 @retval EFI_MEDIA_CHANGED The device media has been changed.\r
232 @retval Others Command execution failed after retrial.\r
e237e7ae 233\r
234**/\r
e237e7ae 235EFI_STATUS\r
236UsbBootExecCmdWithRetry (\r
237 IN USB_MASS_DEVICE *UsbMass,\r
238 IN VOID *Cmd,\r
239 IN UINT8 CmdLen,\r
240 IN EFI_USB_DATA_DIRECTION DataDir,\r
241 IN VOID *Data,\r
242 IN UINT32 DataLen,\r
243 IN UINT32 Timeout\r
244 )\r
245{\r
246 EFI_STATUS Status;\r
d80ed2a7 247 UINTN Retry;\r
19bc8527 248 EFI_EVENT TimeoutEvt;\r
249\r
250 Retry = 0;\r
251 Status = EFI_SUCCESS;\r
252 Status = gBS->CreateEvent (\r
253 EVT_TIMER,\r
254 TPL_CALLBACK,\r
255 NULL,\r
256 NULL,\r
257 &TimeoutEvt\r
258 );\r
259 if (EFI_ERROR (Status)) {\r
260 return Status;\r
261 }\r
e237e7ae 262\r
19bc8527 263 Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(60));\r
264 if (EFI_ERROR (Status)) {\r
265 goto EXIT;\r
266 }\r
e237e7ae 267\r
19bc8527 268 //\r
269 // Execute the cmd and retry if it fails.\r
270 //\r
271 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {\r
e237e7ae 272 Status = UsbBootExecCmd (\r
273 UsbMass,\r
274 Cmd,\r
275 CmdLen,\r
276 DataDir,\r
277 Data,\r
278 DataLen,\r
1c619535 279 Timeout\r
e237e7ae 280 );\r
b17d5507 281 if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {\r
e237e7ae 282 break;\r
283 }\r
284 //\r
19bc8527 285 // If the sense data shows the drive is not ready, we need execute the cmd again.\r
286 // We limit the upper boundary to 60 seconds.\r
e237e7ae 287 //\r
19bc8527 288 if (Status == EFI_NOT_READY) {\r
289 continue;\r
e237e7ae 290 }\r
19bc8527 291 //\r
292 // If the status is other error, then just retry 5 times.\r
293 //\r
294 if (Retry++ >= USB_BOOT_COMMAND_RETRY) {\r
295 break;\r
296 }\r
297 }\r
298\r
299EXIT:\r
300 if (TimeoutEvt != NULL) {\r
301 gBS->CloseEvent (TimeoutEvt);\r
e237e7ae 302 }\r
303\r
304 return Status;\r
305}\r
306\r
307\r
e237e7ae 308/**\r
d80ed2a7 309 Execute TEST UNIT READY command to check if the device is ready.\r
e237e7ae 310\r
311 @param UsbMass The device to test\r
312\r
d80ed2a7 313 @retval EFI_SUCCESS The device is ready.\r
e237e7ae 314 @retval Others Device not ready.\r
315\r
316**/\r
317EFI_STATUS\r
318UsbBootIsUnitReady (\r
319 IN USB_MASS_DEVICE *UsbMass\r
320 )\r
321{\r
322 USB_BOOT_TEST_UNIT_READY_CMD TestCmd;\r
323\r
324 ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));\r
325\r
326 TestCmd.OpCode = USB_BOOT_TEST_UNIT_READY_OPCODE;\r
c52fa98c 327 TestCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
e237e7ae 328\r
329 return UsbBootExecCmdWithRetry (\r
330 UsbMass,\r
331 &TestCmd,\r
c9325700 332 (UINT8) sizeof (USB_BOOT_TEST_UNIT_READY_CMD),\r
e237e7ae 333 EfiUsbNoData,\r
334 NULL,\r
335 0,\r
336 USB_BOOT_GENERAL_CMD_TIMEOUT\r
337 );\r
338}\r
339\r
340\r
341/**\r
d80ed2a7 342 Execute INQUIRY Command to request information regarding parameters of\r
343 the device be sent to the host computer.\r
e237e7ae 344\r
d80ed2a7 345 @param UsbMass The device to inquire.\r
e237e7ae 346\r
d80ed2a7 347 @retval EFI_SUCCESS INQUIRY Command is executed successfully.\r
348 @retval Others INQUIRY Command is not executed successfully.\r
e237e7ae 349\r
350**/\r
351EFI_STATUS\r
352UsbBootInquiry (\r
353 IN USB_MASS_DEVICE *UsbMass\r
354 )\r
355{\r
356 USB_BOOT_INQUIRY_CMD InquiryCmd;\r
e237e7ae 357 EFI_BLOCK_IO_MEDIA *Media;\r
358 EFI_STATUS Status;\r
359\r
360 Media = &(UsbMass->BlockIoMedia);\r
361\r
e237e7ae 362 ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));\r
39840c50 363 ZeroMem (&UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));\r
e237e7ae 364\r
365 InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;\r
c52fa98c 366 InquiryCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
39840c50 367 InquiryCmd.AllocLen = (UINT8) sizeof (USB_BOOT_INQUIRY_DATA);\r
e237e7ae 368\r
369 Status = UsbBootExecCmdWithRetry (\r
370 UsbMass,\r
371 &InquiryCmd,\r
c9325700 372 (UINT8) sizeof (USB_BOOT_INQUIRY_CMD),\r
e237e7ae 373 EfiUsbDataIn,\r
39840c50 374 &UsbMass->InquiryData,\r
e237e7ae 375 sizeof (USB_BOOT_INQUIRY_DATA),\r
50fa1b3a 376 USB_BOOT_GENERAL_CMD_TIMEOUT\r
e237e7ae 377 );\r
378 if (EFI_ERROR (Status)) {\r
379 return Status;\r
380 }\r
381\r
d80ed2a7 382 //\r
383 // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit\r
384 // from the inquiry data.\r
385 //\r
39840c50 386 UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (UsbMass->InquiryData.Pdt));\r
387 Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (UsbMass->InquiryData.Removable));\r
e237e7ae 388 //\r
d80ed2a7 389 // Set block size to the default value of 512 Bytes, in case no media is present at first time.\r
e237e7ae 390 //\r
391 Media->BlockSize = 0x0200;\r
392\r
393 return Status;\r
394}\r
395\r
99c1725e 396/**\r
397 Execute READ CAPACITY 16 bytes command to request information regarding\r
398 the capacity of the installed medium of the device.\r
399\r
400 This function executes READ CAPACITY 16 bytes command to get the capacity\r
401 of the USB mass storage media, including the presence, block size,\r
402 and last block number.\r
403\r
404 @param UsbMass The device to retireve disk gemotric.\r
405\r
406 @retval EFI_SUCCESS The disk geometry is successfully retrieved.\r
407 @retval EFI_NOT_READY The returned block size is zero.\r
408 @retval Other READ CAPACITY 16 bytes command execution failed.\r
409 \r
410**/\r
411EFI_STATUS\r
412UsbBootReadCapacity16 (\r
413 IN USB_MASS_DEVICE *UsbMass\r
414 )\r
415{\r
416 UINT8 CapacityCmd[16];\r
417 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData;\r
418 EFI_BLOCK_IO_MEDIA *Media;\r
419 EFI_STATUS Status;\r
420 UINT32 BlockSize;\r
421\r
422 Media = &UsbMass->BlockIoMedia;\r
423\r
424 Media->MediaPresent = FALSE;\r
425 Media->LastBlock = 0;\r
426 Media->BlockSize = 0;\r
427\r
428 ZeroMem (CapacityCmd, sizeof (CapacityCmd));\r
429 ZeroMem (&CapacityData, sizeof (CapacityData));\r
430\r
431 CapacityCmd[0] = EFI_SCSI_OP_READ_CAPACITY16;\r
432 CapacityCmd[1] = 0x10;\r
433 //\r
434 // Partial medium indicator, set the bytes 2 ~ 9 of the Cdb as ZERO.\r
435 //\r
436 ZeroMem ((CapacityCmd + 2), 8);\r
437\r
438 CapacityCmd[13] = sizeof (CapacityData);\r
439 \r
440 Status = UsbBootExecCmdWithRetry (\r
441 UsbMass,\r
442 CapacityCmd,\r
443 (UINT8) sizeof (CapacityCmd),\r
444 EfiUsbDataIn,\r
445 &CapacityData,\r
446 sizeof (CapacityData),\r
447 USB_BOOT_GENERAL_CMD_TIMEOUT\r
448 );\r
449 if (EFI_ERROR (Status)) {\r
450 return Status;\r
451 }\r
452\r
453 //\r
454 // Get the information on media presence, block size, and last block number\r
455 // from READ CAPACITY data.\r
456 //\r
457 Media->MediaPresent = TRUE;\r
458 Media->LastBlock = SwapBytes64 (ReadUnaligned64 ((CONST UINT64 *) &(CapacityData.LastLba7)));\r
459\r
460 BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) &(CapacityData.BlockSize3)));\r
461 \r
462 Media->LowestAlignedLba = (CapacityData.LowestAlignLogic2 << 8) |\r
463 CapacityData.LowestAlignLogic1;\r
464 Media->LogicalBlocksPerPhysicalBlock = (1 << CapacityData.LogicPerPhysical);\r
465 if (BlockSize == 0) {\r
466 //\r
467 // Get sense data \r
468 //\r
469 return UsbBootRequestSense (UsbMass);\r
470 } else {\r
471 Media->BlockSize = BlockSize;\r
472 }\r
473\r
474 return Status;\r
475}\r
476\r
e237e7ae 477\r
478/**\r
d80ed2a7 479 Execute READ CAPACITY command to request information regarding\r
480 the capacity of the installed medium of the device.\r
481\r
482 This function executes READ CAPACITY command to get the capacity\r
483 of the USB mass storage media, including the presence, block size,\r
484 and last block number.\r
e237e7ae 485\r
486 @param UsbMass The device to retireve disk gemotric.\r
487\r
d80ed2a7 488 @retval EFI_SUCCESS The disk geometry is successfully retrieved.\r
489 @retval EFI_NOT_READY The returned block size is zero.\r
490 @retval Other READ CAPACITY command execution failed.\r
cc5166ff 491 \r
e237e7ae 492**/\r
493EFI_STATUS\r
494UsbBootReadCapacity (\r
495 IN USB_MASS_DEVICE *UsbMass\r
496 )\r
497{\r
498 USB_BOOT_READ_CAPACITY_CMD CapacityCmd;\r
499 USB_BOOT_READ_CAPACITY_DATA CapacityData;\r
500 EFI_BLOCK_IO_MEDIA *Media;\r
501 EFI_STATUS Status;\r
88e349f1 502 UINT32 BlockSize;\r
e237e7ae 503\r
504 Media = &UsbMass->BlockIoMedia;\r
505\r
e237e7ae 506 ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));\r
507 ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));\r
508\r
509 CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;\r
c52fa98c 510 CapacityCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
e237e7ae 511\r
512 Status = UsbBootExecCmdWithRetry (\r
513 UsbMass,\r
514 &CapacityCmd,\r
c9325700 515 (UINT8) sizeof (USB_BOOT_READ_CAPACITY_CMD),\r
e237e7ae 516 EfiUsbDataIn,\r
517 &CapacityData,\r
518 sizeof (USB_BOOT_READ_CAPACITY_DATA),\r
519 USB_BOOT_GENERAL_CMD_TIMEOUT\r
520 );\r
521 if (EFI_ERROR (Status)) {\r
522 return Status;\r
523 }\r
524\r
d80ed2a7 525 //\r
526 // Get the information on media presence, block size, and last block number\r
527 // from READ CAPACITY data.\r
528 //\r
e237e7ae 529 Media->MediaPresent = TRUE;\r
d80ed2a7 530 Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));\r
e237e7ae 531\r
88e349f1 532 BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));\r
533 if (BlockSize == 0) {\r
efe9186f 534 //\r
535 // Get sense data \r
536 //\r
537 return UsbBootRequestSense (UsbMass);\r
88e349f1 538 } else {\r
539 Media->BlockSize = BlockSize;\r
50fa1b3a 540 }\r
541\r
99c1725e 542 if (Media->LastBlock == 0xFFFFFFFF) {\r
543 Status = UsbBootReadCapacity16 (UsbMass);\r
544 if (!EFI_ERROR (Status)) {\r
545 UsbMass->Cdb16Byte = TRUE;\r
546 }\r
547 }\r
548\r
efe9186f 549 return Status;\r
e237e7ae 550}\r
551\r
e237e7ae 552/**\r
d80ed2a7 553 Retrieves SCSI mode sense information via MODE SENSE(6) command.\r
e237e7ae 554\r
d80ed2a7 555 @param UsbMass The device whose sense data is requested.\r
e237e7ae 556\r
d80ed2a7 557 @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.\r
558 @retval Other Command execution failed.\r
e237e7ae 559\r
560**/\r
561EFI_STATUS\r
50fa1b3a 562UsbScsiModeSense (\r
e237e7ae 563 IN USB_MASS_DEVICE *UsbMass\r
564 )\r
565{\r
ca12415a 566 EFI_STATUS Status;\r
50fa1b3a 567 USB_SCSI_MODE_SENSE6_CMD ModeSenseCmd;\r
568 USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;\r
569 EFI_BLOCK_IO_MEDIA *Media;\r
570\r
ca12415a 571 Media = &UsbMass->BlockIoMedia;\r
e237e7ae 572\r
50fa1b3a 573 ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));\r
574 ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));\r
e237e7ae 575\r
576 //\r
d80ed2a7 577 // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec\r
e237e7ae 578 //\r
50fa1b3a 579 ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;\r
687a2e5f 580 ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);\r
50fa1b3a 581 ModeSenseCmd.PageCode = 0x3F;\r
582 ModeSenseCmd.AllocateLen = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);\r
e237e7ae 583\r
584 Status = UsbBootExecCmdWithRetry (\r
585 UsbMass,\r
586 &ModeSenseCmd,\r
c9325700 587 (UINT8) sizeof (USB_SCSI_MODE_SENSE6_CMD),\r
e237e7ae 588 EfiUsbDataIn,\r
589 &ModeParaHeader,\r
50fa1b3a 590 sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),\r
e237e7ae 591 USB_BOOT_GENERAL_CMD_TIMEOUT\r
592 );\r
50fa1b3a 593\r
e237e7ae 594 //\r
d80ed2a7 595 // Format of device-specific parameter byte of the mode parameter header is defined in\r
596 // Section 8.2.10 of SCSI-2 Spec.\r
597 // BIT7 of this byte is indicates whether the medium is write protected.\r
e237e7ae 598 //\r
50fa1b3a 599 if (!EFI_ERROR (Status)) {\r
d80ed2a7 600 Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);\r
50fa1b3a 601 }\r
e237e7ae 602\r
603 return Status;\r
604}\r
605\r
606\r
607/**\r
d80ed2a7 608 Get the parameters for the USB mass storage media.\r
609\r
610 This function get the parameters for the USB mass storage media,\r
611 It is used both to initialize the media during the Start() phase\r
612 of Driver Binding Protocol and to re-initialize it when the media is\r
e237e7ae 613 changed. Althought the RemoveableMedia is unlikely to change,\r
d80ed2a7 614 it is also included here.\r
e237e7ae 615\r
d80ed2a7 616 @param UsbMass The device to retrieve disk gemotric.\r
e237e7ae 617\r
618 @retval EFI_SUCCESS The disk gemotric is successfully retrieved.\r
d80ed2a7 619 @retval Other Failed to get the parameters.\r
e237e7ae 620\r
621**/\r
622EFI_STATUS\r
623UsbBootGetParams (\r
624 IN USB_MASS_DEVICE *UsbMass\r
625 )\r
626{\r
627 EFI_BLOCK_IO_MEDIA *Media;\r
628 EFI_STATUS Status;\r
50fa1b3a 629\r
ca12415a 630 Media = &(UsbMass->BlockIoMedia);\r
e237e7ae 631\r
632 Status = UsbBootInquiry (UsbMass);\r
633 if (EFI_ERROR (Status)) {\r
1c619535 634 DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));\r
e237e7ae 635 return Status;\r
636 }\r
637\r
66a5771e
TF
638 //\r
639 // According to USB Mass Storage Specification for Bootability, only following\r
640 // 4 Peripheral Device Types are in spec.\r
641 //\r
642 if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&\r
643 (UsbMass->Pdt != USB_PDT_CDROM) &&\r
644 (UsbMass->Pdt != USB_PDT_OPTICAL) &&\r
645 (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {\r
646 DEBUG ((EFI_D_ERROR, "UsbBootGetParams: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));\r
647 return EFI_UNSUPPORTED;\r
648 }\r
649\r
e237e7ae 650 //\r
d80ed2a7 651 // Don't use the Removable bit in inquiry data to test whether the media\r
e237e7ae 652 // is removable because many flash disks wrongly set this bit.\r
653 //\r
654 if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {\r
655 //\r
50fa1b3a 656 // CD-Rom device and Non-CD optical device\r
e237e7ae 657 //\r
658 UsbMass->OpticalStorage = TRUE;\r
659 //\r
660 // Default value 2048 Bytes, in case no media present at first time\r
661 //\r
662 Media->BlockSize = 0x0800;\r
50fa1b3a 663 }\r
664\r
19bc8527 665 Status = UsbBootDetectMedia (UsbMass);\r
e237e7ae 666\r
19bc8527 667 return Status;\r
e237e7ae 668}\r
669\r
670\r
671/**\r
672 Detect whether the removable media is present and whether it has changed.\r
e237e7ae 673\r
d80ed2a7 674 @param UsbMass The device to check.\r
e237e7ae 675\r
d80ed2a7 676 @retval EFI_SUCCESS The media status is successfully checked.\r
677 @retval Other Failed to detect media.\r
e237e7ae 678\r
679**/\r
680EFI_STATUS\r
681UsbBootDetectMedia (\r
682 IN USB_MASS_DEVICE *UsbMass\r
683 )\r
684{\r
685 EFI_BLOCK_IO_MEDIA OldMedia;\r
686 EFI_BLOCK_IO_MEDIA *Media;\r
50fa1b3a 687 UINT8 CmdSet;\r
688 EFI_TPL OldTpl;\r
e237e7ae 689 EFI_STATUS Status;\r
690\r
691 Media = &UsbMass->BlockIoMedia;\r
e61d30b0 692\r
d80ed2a7 693 CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));\r
e237e7ae 694\r
50fa1b3a 695 CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
696\r
e237e7ae 697 Status = UsbBootIsUnitReady (UsbMass);\r
19bc8527 698 if (EFI_ERROR (Status) && (Status != EFI_MEDIA_CHANGED)) {\r
50fa1b3a 699 goto ON_ERROR;\r
e237e7ae 700 }\r
50fa1b3a 701\r
702 if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {\r
703 //\r
d80ed2a7 704 // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,\r
705 // according to Section 4 of USB Mass Storage Specification for Bootability.\r
706 // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI\r
707 // could get the information of Write Protected.\r
708 // Since not all device support this command, skip if fail.\r
50fa1b3a 709 //\r
710 UsbScsiModeSense (UsbMass);\r
711 }\r
712\r
713 Status = UsbBootReadCapacity (UsbMass);\r
e237e7ae 714 if (EFI_ERROR (Status)) {\r
1c619535 715 DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));\r
50fa1b3a 716 goto ON_ERROR;\r
e237e7ae 717 }\r
718\r
50fa1b3a 719 return EFI_SUCCESS;\r
720\r
721ON_ERROR:\r
e237e7ae 722 //\r
d80ed2a7 723 // Detect whether it is necessary to reinstall the Block I/O Protocol.\r
e237e7ae 724 //\r
50fa1b3a 725 // MediaId may change in RequestSense for MediaChanged\r
726 // MediaPresent may change in RequestSense for NoMedia\r
727 // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged\r
728 // MediaPresent/BlockSize/LastBlock may change in ReadCapacity\r
729 //\r
e237e7ae 730 if ((Media->MediaId != OldMedia.MediaId) ||\r
731 (Media->MediaPresent != OldMedia.MediaPresent) ||\r
732 (Media->ReadOnly != OldMedia.ReadOnly) ||\r
733 (Media->BlockSize != OldMedia.BlockSize) ||\r
734 (Media->LastBlock != OldMedia.LastBlock)) {\r
50fa1b3a 735\r
d80ed2a7 736 //\r
737 // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY.\r
738 // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface().\r
739 //\r
740 OldTpl = EfiGetCurrentTpl ();\r
50fa1b3a 741 gBS->RestoreTPL (TPL_CALLBACK);\r
742\r
e237e7ae 743 gBS->ReinstallProtocolInterface (\r
744 UsbMass->Controller,\r
745 &gEfiBlockIoProtocolGuid,\r
746 &UsbMass->BlockIo,\r
747 &UsbMass->BlockIo\r
748 );\r
50fa1b3a 749\r
d80ed2a7 750 ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);\r
50fa1b3a 751 gBS->RaiseTPL (OldTpl);\r
752\r
e237e7ae 753 //\r
d80ed2a7 754 // Update MediaId after reinstalling Block I/O Protocol.\r
e237e7ae 755 //\r
50fa1b3a 756 if (Media->MediaPresent != OldMedia.MediaPresent) {\r
d80ed2a7 757 if (Media->MediaPresent) {\r
50fa1b3a 758 Media->MediaId = 1;\r
759 } else {\r
760 Media->MediaId = 0;\r
761 }\r
e237e7ae 762 }\r
50fa1b3a 763\r
764 if ((Media->ReadOnly != OldMedia.ReadOnly) ||\r
765 (Media->BlockSize != OldMedia.BlockSize) ||\r
766 (Media->LastBlock != OldMedia.LastBlock)) {\r
767 Media->MediaId++;\r
e237e7ae 768 }\r
769 }\r
770\r
771 return Status;\r
772}\r
773\r
774\r
775/**\r
776 Read some blocks from the device.\r
777\r
778 @param UsbMass The USB mass storage device to read from\r
779 @param Lba The start block number\r
780 @param TotalBlock Total block number to read\r
781 @param Buffer The buffer to read to\r
782\r
783 @retval EFI_SUCCESS Data are read into the buffer\r
784 @retval Others Failed to read all the data\r
785\r
786**/\r
787EFI_STATUS\r
788UsbBootReadBlocks (\r
789 IN USB_MASS_DEVICE *UsbMass,\r
790 IN UINT32 Lba,\r
791 IN UINTN TotalBlock,\r
792 OUT UINT8 *Buffer\r
793 )\r
794{\r
795 USB_BOOT_READ10_CMD ReadCmd;\r
796 EFI_STATUS Status;\r
797 UINT16 Count;\r
798 UINT32 BlockSize;\r
799 UINT32 ByteSize;\r
800 UINT32 Timeout;\r
801\r
802 BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
803 Status = EFI_SUCCESS;\r
804\r
805 while (TotalBlock > 0) {\r
806 //\r
807 // Split the total blocks into smaller pieces to ease the pressure\r
808 // on the device. We must split the total block because the READ10\r
809 // command only has 16 bit transfer length (in the unit of block).\r
810 //\r
811 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
812 ByteSize = (UINT32)Count * BlockSize;\r
813\r
814 //\r
50fa1b3a 815 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
e237e7ae 816 //\r
50fa1b3a 817 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
e237e7ae 818\r
819 //\r
820 // Fill in the command then execute\r
821 //\r
822 ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));\r
823\r
824 ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;\r
c52fa98c 825 ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
d80ed2a7 826 WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba));\r
827 WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count));\r
e237e7ae 828\r
829 Status = UsbBootExecCmdWithRetry (\r
830 UsbMass,\r
831 &ReadCmd,\r
c9325700 832 (UINT8) sizeof (USB_BOOT_READ10_CMD),\r
e237e7ae 833 EfiUsbDataIn,\r
834 Buffer,\r
835 ByteSize,\r
836 Timeout\r
837 );\r
838 if (EFI_ERROR (Status)) {\r
839 return Status;\r
840 }\r
99c1725e 841 DEBUG ((EFI_D_BLKIO, "UsbBootReadBlocks: LBA (0x%x), Blk (0x%x)\n", Lba, Count));\r
e237e7ae 842 Lba += Count;\r
843 Buffer += Count * BlockSize;\r
844 TotalBlock -= Count;\r
845 }\r
846\r
847 return Status;\r
848}\r
849\r
850\r
851/**\r
852 Write some blocks to the device.\r
853\r
854 @param UsbMass The USB mass storage device to write to\r
855 @param Lba The start block number\r
856 @param TotalBlock Total block number to write\r
d80ed2a7 857 @param Buffer Pointer to the source buffer for the data.\r
e237e7ae 858\r
859 @retval EFI_SUCCESS Data are written into the buffer\r
860 @retval Others Failed to write all the data\r
861\r
862**/\r
863EFI_STATUS\r
864UsbBootWriteBlocks (\r
865 IN USB_MASS_DEVICE *UsbMass,\r
866 IN UINT32 Lba,\r
867 IN UINTN TotalBlock,\r
d80ed2a7 868 IN UINT8 *Buffer\r
e237e7ae 869 )\r
870{\r
871 USB_BOOT_WRITE10_CMD WriteCmd;\r
872 EFI_STATUS Status;\r
873 UINT16 Count;\r
874 UINT32 BlockSize;\r
875 UINT32 ByteSize;\r
876 UINT32 Timeout;\r
877\r
878 BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
879 Status = EFI_SUCCESS;\r
880\r
881 while (TotalBlock > 0) {\r
882 //\r
883 // Split the total blocks into smaller pieces to ease the pressure\r
884 // on the device. We must split the total block because the WRITE10\r
885 // command only has 16 bit transfer length (in the unit of block).\r
886 //\r
887 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
888 ByteSize = (UINT32)Count * BlockSize;\r
889\r
890 //\r
50fa1b3a 891 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
e237e7ae 892 //\r
50fa1b3a 893 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
e237e7ae 894\r
895 //\r
896 // Fill in the write10 command block\r
897 //\r
898 ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));\r
899\r
900 WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;\r
c52fa98c 901 WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
d80ed2a7 902 WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba));\r
903 WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count));\r
e237e7ae 904\r
905 Status = UsbBootExecCmdWithRetry (\r
906 UsbMass,\r
907 &WriteCmd,\r
c9325700 908 (UINT8) sizeof (USB_BOOT_WRITE10_CMD),\r
e237e7ae 909 EfiUsbDataOut,\r
910 Buffer,\r
911 ByteSize,\r
912 Timeout\r
913 );\r
914 if (EFI_ERROR (Status)) {\r
915 return Status;\r
916 }\r
99c1725e 917 DEBUG ((EFI_D_BLKIO, "UsbBootWriteBlocks: LBA (0x%x), Blk (0x%x)\n", Lba, Count));\r
918\r
919 Lba += Count;\r
920 Buffer += Count * BlockSize;\r
921 TotalBlock -= Count;\r
922 }\r
923\r
924 return Status;\r
925}\r
926\r
927/**\r
928 Read some blocks from the device by SCSI 16 byte cmd.\r
929\r
930 @param UsbMass The USB mass storage device to read from\r
931 @param Lba The start block number\r
932 @param TotalBlock Total block number to read\r
933 @param Buffer The buffer to read to\r
934\r
935 @retval EFI_SUCCESS Data are read into the buffer\r
936 @retval Others Failed to read all the data\r
937\r
938**/\r
939EFI_STATUS\r
940UsbBootReadBlocks16 (\r
941 IN USB_MASS_DEVICE *UsbMass,\r
942 IN UINT64 Lba,\r
943 IN UINTN TotalBlock,\r
944 OUT UINT8 *Buffer\r
945 )\r
946{\r
947 UINT8 ReadCmd[16];\r
948 EFI_STATUS Status;\r
949 UINT16 Count;\r
950 UINT32 BlockSize;\r
951 UINT32 ByteSize;\r
952 UINT32 Timeout;\r
953\r
954 BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
955 Status = EFI_SUCCESS;\r
956\r
957 while (TotalBlock > 0) {\r
958 //\r
959 // Split the total blocks into smaller pieces.\r
960 //\r
961 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
962 ByteSize = (UINT32)Count * BlockSize;\r
963\r
964 //\r
965 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
966 //\r
967 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
968\r
969 //\r
970 // Fill in the command then execute\r
971 //\r
972 ZeroMem (ReadCmd, sizeof (ReadCmd));\r
973\r
974 ReadCmd[0] = EFI_SCSI_OP_READ16;\r
975 ReadCmd[1] = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));\r
976 WriteUnaligned64 ((UINT64 *) &ReadCmd[2], SwapBytes64 (Lba));\r
977 WriteUnaligned32 ((UINT32 *) &ReadCmd[10], SwapBytes32 (Count));\r
978\r
979 Status = UsbBootExecCmdWithRetry (\r
980 UsbMass,\r
981 ReadCmd,\r
982 (UINT8) sizeof (ReadCmd),\r
983 EfiUsbDataIn,\r
984 Buffer,\r
985 ByteSize,\r
986 Timeout\r
987 );\r
988 if (EFI_ERROR (Status)) {\r
989 return Status;\r
990 }\r
991 DEBUG ((EFI_D_BLKIO, "UsbBootReadBlocks16: LBA (0x%lx), Blk (0x%x)\n", Lba, Count));\r
992 Lba += Count;\r
993 Buffer += Count * BlockSize;\r
994 TotalBlock -= Count;\r
995 }\r
996\r
997 return Status;\r
998}\r
999\r
1000\r
1001/**\r
1002 Write some blocks to the device by SCSI 16 byte cmd.\r
1003\r
1004 @param UsbMass The USB mass storage device to write to\r
1005 @param Lba The start block number\r
1006 @param TotalBlock Total block number to write\r
1007 @param Buffer Pointer to the source buffer for the data.\r
1008\r
1009 @retval EFI_SUCCESS Data are written into the buffer\r
1010 @retval Others Failed to write all the data\r
1011\r
1012**/\r
1013EFI_STATUS\r
1014UsbBootWriteBlocks16 (\r
1015 IN USB_MASS_DEVICE *UsbMass,\r
1016 IN UINT64 Lba,\r
1017 IN UINTN TotalBlock,\r
1018 IN UINT8 *Buffer\r
1019 )\r
1020{\r
1021 UINT8 WriteCmd[16];\r
1022 EFI_STATUS Status;\r
1023 UINT16 Count;\r
1024 UINT32 BlockSize;\r
1025 UINT32 ByteSize;\r
1026 UINT32 Timeout;\r
1027\r
1028 BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
1029 Status = EFI_SUCCESS;\r
1030\r
1031 while (TotalBlock > 0) {\r
1032 //\r
1033 // Split the total blocks into smaller pieces.\r
1034 //\r
1035 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
1036 ByteSize = (UINT32)Count * BlockSize;\r
1037\r
1038 //\r
1039 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
1040 //\r
1041 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
1042\r
1043 //\r
1044 // Fill in the write16 command block\r
1045 //\r
1046 ZeroMem (WriteCmd, sizeof (WriteCmd));\r
1047\r
1048 WriteCmd[0] = EFI_SCSI_OP_WRITE16;\r
1049 WriteCmd[1] = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));\r
1050 WriteUnaligned64 ((UINT64 *) &WriteCmd[2], SwapBytes64 (Lba));\r
1051 WriteUnaligned32 ((UINT32 *) &WriteCmd[10], SwapBytes32 (Count));\r
1052\r
1053 Status = UsbBootExecCmdWithRetry (\r
1054 UsbMass,\r
1055 WriteCmd,\r
1056 (UINT8) sizeof (WriteCmd),\r
1057 EfiUsbDataOut,\r
1058 Buffer,\r
1059 ByteSize,\r
1060 Timeout\r
1061 );\r
1062 if (EFI_ERROR (Status)) {\r
1063 return Status;\r
1064 }\r
1065 DEBUG ((EFI_D_BLKIO, "UsbBootWriteBlocks: LBA (0x%lx), Blk (0x%x)\n", Lba, Count));\r
e237e7ae 1066 Lba += Count;\r
1067 Buffer += Count * BlockSize;\r
1068 TotalBlock -= Count;\r
1069 }\r
1070\r
1071 return Status;\r
1072}\r
1073\r
e237e7ae 1074/**\r
d80ed2a7 1075 Use the USB clear feature control transfer to clear the endpoint stall condition.\r
e237e7ae 1076\r
d80ed2a7 1077 @param UsbIo The USB I/O Protocol instance\r
e237e7ae 1078 @param EndpointAddr The endpoint to clear stall for\r
1079\r
d80ed2a7 1080 @retval EFI_SUCCESS The endpoint stall condition is cleared.\r
1081 @retval Others Failed to clear the endpoint stall condition.\r
e237e7ae 1082\r
1083**/\r
1084EFI_STATUS\r
1085UsbClearEndpointStall (\r
1086 IN EFI_USB_IO_PROTOCOL *UsbIo,\r
1087 IN UINT8 EndpointAddr\r
1088 )\r
1089{\r
1090 EFI_USB_DEVICE_REQUEST Request;\r
1091 EFI_STATUS Status;\r
1092 UINT32 CmdResult;\r
1093 UINT32 Timeout;\r
1094\r
1095 Request.RequestType = 0x02;\r
1096 Request.Request = USB_REQ_CLEAR_FEATURE;\r
1097 Request.Value = USB_FEATURE_ENDPOINT_HALT;\r
1098 Request.Index = EndpointAddr;\r
1099 Request.Length = 0;\r
41e8ff27 1100 Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_1_MILLISECOND;\r
e237e7ae 1101\r
1102 Status = UsbIo->UsbControlTransfer (\r
1103 UsbIo,\r
1104 &Request,\r
1105 EfiUsbNoData,\r
1106 Timeout,\r
1107 NULL,\r
1108 0,\r
1109 &CmdResult\r
1110 );\r
1111\r
1112 return Status;\r
1113}\r