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