]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
Add '0x' prefix to indicate hex number
[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
c7e39923 5Copyright (c) 2007 - 2008, Intel Corporation\r
e237e7ae 6All rights reserved. This program and the accompanying materials\r
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
cc5166ff 16#include "UsbMassImpl.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
e237e7ae 53 SenseCmd.AllocLen = sizeof (USB_BOOT_REQUEST_SENSE_DATA);\r
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
95 if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) {\r
d80ed2a7 96 Media->MediaPresent = FALSE;\r
97 Status = EFI_NO_MEDIA;\r
50fa1b3a 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
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
132 SenseData.ASC,\r
133 SenseData.ASCQ\r
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
e237e7ae 238\r
e237e7ae 239 Status = EFI_SUCCESS;\r
240\r
d80ed2a7 241 for (Retry = 0; Retry < USB_BOOT_COMMAND_RETRY; Retry++) {\r
242\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
258 if (Status == EFI_NOT_READY) {\r
d80ed2a7 259 Retry = 0;\r
e237e7ae 260 }\r
261 }\r
262\r
263 return Status;\r
264}\r
265\r
266\r
e237e7ae 267/**\r
d80ed2a7 268 Execute TEST UNIT READY command to check if the device is ready.\r
e237e7ae 269\r
270 @param UsbMass The device to test\r
271\r
d80ed2a7 272 @retval EFI_SUCCESS The device is ready.\r
e237e7ae 273 @retval Others Device not ready.\r
274\r
275**/\r
276EFI_STATUS\r
277UsbBootIsUnitReady (\r
278 IN USB_MASS_DEVICE *UsbMass\r
279 )\r
280{\r
281 USB_BOOT_TEST_UNIT_READY_CMD TestCmd;\r
282\r
283 ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));\r
284\r
285 TestCmd.OpCode = USB_BOOT_TEST_UNIT_READY_OPCODE;\r
c52fa98c 286 TestCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
e237e7ae 287\r
288 return UsbBootExecCmdWithRetry (\r
289 UsbMass,\r
290 &TestCmd,\r
291 sizeof (USB_BOOT_TEST_UNIT_READY_CMD),\r
292 EfiUsbNoData,\r
293 NULL,\r
294 0,\r
295 USB_BOOT_GENERAL_CMD_TIMEOUT\r
296 );\r
297}\r
298\r
299\r
300/**\r
d80ed2a7 301 Execute INQUIRY Command to request information regarding parameters of\r
302 the device be sent to the host computer.\r
e237e7ae 303\r
d80ed2a7 304 @param UsbMass The device to inquire.\r
e237e7ae 305\r
d80ed2a7 306 @retval EFI_SUCCESS INQUIRY Command is executed successfully.\r
307 @retval Others INQUIRY Command is not executed successfully.\r
e237e7ae 308\r
309**/\r
310EFI_STATUS\r
311UsbBootInquiry (\r
312 IN USB_MASS_DEVICE *UsbMass\r
313 )\r
314{\r
315 USB_BOOT_INQUIRY_CMD InquiryCmd;\r
316 USB_BOOT_INQUIRY_DATA InquiryData;\r
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
323 ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));\r
324\r
325 InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;\r
c52fa98c 326 InquiryCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
e237e7ae 327 InquiryCmd.AllocLen = sizeof (InquiryData);\r
328\r
329 Status = UsbBootExecCmdWithRetry (\r
330 UsbMass,\r
331 &InquiryCmd,\r
332 sizeof (USB_BOOT_INQUIRY_CMD),\r
333 EfiUsbDataIn,\r
334 &InquiryData,\r
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
c52fa98c 346 UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (InquiryData.Pdt));\r
347 Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (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
394 sizeof (USB_BOOT_READ_CAPACITY_CMD),\r
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
50fa1b3a 413 return EFI_NOT_READY;\r
88e349f1 414 } else {\r
415 Media->BlockSize = BlockSize;\r
50fa1b3a 416 }\r
417\r
1c619535 418 DEBUG ((EFI_D_INFO, "UsbBootReadCapacity Success LBA=%ld BlockSize=%d\n",\r
50fa1b3a 419 Media->LastBlock, Media->BlockSize));\r
e237e7ae 420\r
421 return EFI_SUCCESS;\r
422}\r
423\r
e237e7ae 424/**\r
d80ed2a7 425 Retrieves SCSI mode sense information via MODE SENSE(6) command.\r
e237e7ae 426\r
d80ed2a7 427 @param UsbMass The device whose sense data is requested.\r
e237e7ae 428\r
d80ed2a7 429 @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.\r
430 @retval Other Command execution failed.\r
e237e7ae 431\r
432**/\r
433EFI_STATUS\r
50fa1b3a 434UsbScsiModeSense (\r
e237e7ae 435 IN USB_MASS_DEVICE *UsbMass\r
436 )\r
437{\r
ca12415a 438 EFI_STATUS Status;\r
50fa1b3a 439 USB_SCSI_MODE_SENSE6_CMD ModeSenseCmd;\r
440 USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;\r
441 EFI_BLOCK_IO_MEDIA *Media;\r
442\r
ca12415a 443 Media = &UsbMass->BlockIoMedia;\r
e237e7ae 444\r
50fa1b3a 445 ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));\r
446 ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));\r
e237e7ae 447\r
448 //\r
d80ed2a7 449 // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec\r
e237e7ae 450 //\r
50fa1b3a 451 ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;\r
687a2e5f 452 ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);\r
50fa1b3a 453 ModeSenseCmd.PageCode = 0x3F;\r
454 ModeSenseCmd.AllocateLen = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);\r
e237e7ae 455\r
456 Status = UsbBootExecCmdWithRetry (\r
457 UsbMass,\r
458 &ModeSenseCmd,\r
50fa1b3a 459 sizeof (USB_SCSI_MODE_SENSE6_CMD),\r
e237e7ae 460 EfiUsbDataIn,\r
461 &ModeParaHeader,\r
50fa1b3a 462 sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),\r
e237e7ae 463 USB_BOOT_GENERAL_CMD_TIMEOUT\r
464 );\r
50fa1b3a 465\r
e237e7ae 466 //\r
d80ed2a7 467 // Format of device-specific parameter byte of the mode parameter header is defined in\r
468 // Section 8.2.10 of SCSI-2 Spec.\r
469 // BIT7 of this byte is indicates whether the medium is write protected.\r
e237e7ae 470 //\r
50fa1b3a 471 if (!EFI_ERROR (Status)) {\r
d80ed2a7 472 Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);\r
50fa1b3a 473 }\r
e237e7ae 474\r
475 return Status;\r
476}\r
477\r
478\r
479/**\r
d80ed2a7 480 Get the parameters for the USB mass storage media.\r
481\r
482 This function get the parameters for the USB mass storage media,\r
483 It is used both to initialize the media during the Start() phase\r
484 of Driver Binding Protocol and to re-initialize it when the media is\r
e237e7ae 485 changed. Althought the RemoveableMedia is unlikely to change,\r
d80ed2a7 486 it is also included here.\r
e237e7ae 487\r
d80ed2a7 488 @param UsbMass The device to retrieve disk gemotric.\r
e237e7ae 489\r
490 @retval EFI_SUCCESS The disk gemotric is successfully retrieved.\r
d80ed2a7 491 @retval Other Failed to get the parameters.\r
e237e7ae 492\r
493**/\r
494EFI_STATUS\r
495UsbBootGetParams (\r
496 IN USB_MASS_DEVICE *UsbMass\r
497 )\r
498{\r
499 EFI_BLOCK_IO_MEDIA *Media;\r
500 EFI_STATUS Status;\r
50fa1b3a 501 UINT8 CmdSet;\r
502\r
ca12415a 503 Media = &(UsbMass->BlockIoMedia);\r
50fa1b3a 504 CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
e237e7ae 505\r
506 Status = UsbBootInquiry (UsbMass);\r
507 if (EFI_ERROR (Status)) {\r
1c619535 508 DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));\r
e237e7ae 509 return Status;\r
510 }\r
511\r
e237e7ae 512 //\r
d80ed2a7 513 // Don't use the Removable bit in inquiry data to test whether the media\r
e237e7ae 514 // is removable because many flash disks wrongly set this bit.\r
515 //\r
516 if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {\r
517 //\r
50fa1b3a 518 // CD-Rom device and Non-CD optical device\r
e237e7ae 519 //\r
520 UsbMass->OpticalStorage = TRUE;\r
521 //\r
522 // Default value 2048 Bytes, in case no media present at first time\r
523 //\r
524 Media->BlockSize = 0x0800;\r
50fa1b3a 525 }\r
526\r
527 if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {\r
e237e7ae 528 //\r
50fa1b3a 529 // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,\r
530 // which is from [MassStorageBootabilitySpec-Page7].\r
531 // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI\r
532 // could get the information of WriteProtected.\r
533 // Since not all device support this command, so skip if fail.\r
e237e7ae 534 //\r
50fa1b3a 535 UsbScsiModeSense (UsbMass);\r
e237e7ae 536 }\r
537\r
538 return UsbBootReadCapacity (UsbMass);\r
539}\r
540\r
541\r
542/**\r
543 Detect whether the removable media is present and whether it has changed.\r
e237e7ae 544\r
d80ed2a7 545 @param UsbMass The device to check.\r
e237e7ae 546\r
d80ed2a7 547 @retval EFI_SUCCESS The media status is successfully checked.\r
548 @retval Other Failed to detect media.\r
e237e7ae 549\r
550**/\r
551EFI_STATUS\r
552UsbBootDetectMedia (\r
553 IN USB_MASS_DEVICE *UsbMass\r
554 )\r
555{\r
556 EFI_BLOCK_IO_MEDIA OldMedia;\r
557 EFI_BLOCK_IO_MEDIA *Media;\r
50fa1b3a 558 UINT8 CmdSet;\r
559 EFI_TPL OldTpl;\r
e237e7ae 560 EFI_STATUS Status;\r
561\r
562 Media = &UsbMass->BlockIoMedia;\r
e61d30b0 563\r
d80ed2a7 564 CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));\r
e237e7ae 565\r
50fa1b3a 566 CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
567\r
e237e7ae 568 Status = UsbBootIsUnitReady (UsbMass);\r
50fa1b3a 569 if (EFI_ERROR (Status)) {\r
50fa1b3a 570 goto ON_ERROR;\r
e237e7ae 571 }\r
50fa1b3a 572\r
573 if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {\r
574 //\r
d80ed2a7 575 // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,\r
576 // according to Section 4 of USB Mass Storage Specification for Bootability.\r
577 // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI\r
578 // could get the information of Write Protected.\r
579 // Since not all device support this command, skip if fail.\r
50fa1b3a 580 //\r
581 UsbScsiModeSense (UsbMass);\r
582 }\r
583\r
584 Status = UsbBootReadCapacity (UsbMass);\r
e237e7ae 585 if (EFI_ERROR (Status)) {\r
1c619535 586 DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));\r
50fa1b3a 587 goto ON_ERROR;\r
e237e7ae 588 }\r
589\r
50fa1b3a 590 return EFI_SUCCESS;\r
591\r
592ON_ERROR:\r
e237e7ae 593 //\r
d80ed2a7 594 // Detect whether it is necessary to reinstall the Block I/O Protocol.\r
e237e7ae 595 //\r
50fa1b3a 596 // MediaId may change in RequestSense for MediaChanged\r
597 // MediaPresent may change in RequestSense for NoMedia\r
598 // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged\r
599 // MediaPresent/BlockSize/LastBlock may change in ReadCapacity\r
600 //\r
e237e7ae 601 if ((Media->MediaId != OldMedia.MediaId) ||\r
602 (Media->MediaPresent != OldMedia.MediaPresent) ||\r
603 (Media->ReadOnly != OldMedia.ReadOnly) ||\r
604 (Media->BlockSize != OldMedia.BlockSize) ||\r
605 (Media->LastBlock != OldMedia.LastBlock)) {\r
50fa1b3a 606\r
d80ed2a7 607 //\r
608 // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY.\r
609 // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface().\r
610 //\r
611 OldTpl = EfiGetCurrentTpl ();\r
50fa1b3a 612 gBS->RestoreTPL (TPL_CALLBACK);\r
613\r
e237e7ae 614 gBS->ReinstallProtocolInterface (\r
615 UsbMass->Controller,\r
616 &gEfiBlockIoProtocolGuid,\r
617 &UsbMass->BlockIo,\r
618 &UsbMass->BlockIo\r
619 );\r
50fa1b3a 620\r
d80ed2a7 621 ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);\r
50fa1b3a 622 gBS->RaiseTPL (OldTpl);\r
623\r
e237e7ae 624 //\r
d80ed2a7 625 // Update MediaId after reinstalling Block I/O Protocol.\r
e237e7ae 626 //\r
50fa1b3a 627 if (Media->MediaPresent != OldMedia.MediaPresent) {\r
d80ed2a7 628 if (Media->MediaPresent) {\r
50fa1b3a 629 Media->MediaId = 1;\r
630 } else {\r
631 Media->MediaId = 0;\r
632 }\r
e237e7ae 633 }\r
50fa1b3a 634\r
635 if ((Media->ReadOnly != OldMedia.ReadOnly) ||\r
636 (Media->BlockSize != OldMedia.BlockSize) ||\r
637 (Media->LastBlock != OldMedia.LastBlock)) {\r
638 Media->MediaId++;\r
e237e7ae 639 }\r
640 }\r
641\r
642 return Status;\r
643}\r
644\r
645\r
646/**\r
647 Read some blocks from the device.\r
648\r
649 @param UsbMass The USB mass storage device to read from\r
650 @param Lba The start block number\r
651 @param TotalBlock Total block number to read\r
652 @param Buffer The buffer to read to\r
653\r
654 @retval EFI_SUCCESS Data are read into the buffer\r
655 @retval Others Failed to read all the data\r
656\r
657**/\r
658EFI_STATUS\r
659UsbBootReadBlocks (\r
660 IN USB_MASS_DEVICE *UsbMass,\r
661 IN UINT32 Lba,\r
662 IN UINTN TotalBlock,\r
663 OUT UINT8 *Buffer\r
664 )\r
665{\r
666 USB_BOOT_READ10_CMD ReadCmd;\r
667 EFI_STATUS Status;\r
668 UINT16 Count;\r
669 UINT32 BlockSize;\r
670 UINT32 ByteSize;\r
671 UINT32 Timeout;\r
672\r
673 BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
674 Status = EFI_SUCCESS;\r
675\r
676 while (TotalBlock > 0) {\r
677 //\r
678 // Split the total blocks into smaller pieces to ease the pressure\r
679 // on the device. We must split the total block because the READ10\r
680 // command only has 16 bit transfer length (in the unit of block).\r
681 //\r
682 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
683 ByteSize = (UINT32)Count * BlockSize;\r
684\r
685 //\r
50fa1b3a 686 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
e237e7ae 687 //\r
50fa1b3a 688 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
e237e7ae 689\r
690 //\r
691 // Fill in the command then execute\r
692 //\r
693 ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));\r
694\r
695 ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;\r
c52fa98c 696 ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
d80ed2a7 697 WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba));\r
698 WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count));\r
e237e7ae 699\r
700 Status = UsbBootExecCmdWithRetry (\r
701 UsbMass,\r
702 &ReadCmd,\r
703 sizeof (USB_BOOT_READ10_CMD),\r
704 EfiUsbDataIn,\r
705 Buffer,\r
706 ByteSize,\r
707 Timeout\r
708 );\r
709 if (EFI_ERROR (Status)) {\r
710 return Status;\r
711 }\r
712\r
713 Lba += Count;\r
714 Buffer += Count * BlockSize;\r
715 TotalBlock -= Count;\r
716 }\r
717\r
718 return Status;\r
719}\r
720\r
721\r
722/**\r
723 Write some blocks to the device.\r
724\r
725 @param UsbMass The USB mass storage device to write to\r
726 @param Lba The start block number\r
727 @param TotalBlock Total block number to write\r
d80ed2a7 728 @param Buffer Pointer to the source buffer for the data.\r
e237e7ae 729\r
730 @retval EFI_SUCCESS Data are written into the buffer\r
731 @retval Others Failed to write all the data\r
732\r
733**/\r
734EFI_STATUS\r
735UsbBootWriteBlocks (\r
736 IN USB_MASS_DEVICE *UsbMass,\r
737 IN UINT32 Lba,\r
738 IN UINTN TotalBlock,\r
d80ed2a7 739 IN UINT8 *Buffer\r
e237e7ae 740 )\r
741{\r
742 USB_BOOT_WRITE10_CMD WriteCmd;\r
743 EFI_STATUS Status;\r
744 UINT16 Count;\r
745 UINT32 BlockSize;\r
746 UINT32 ByteSize;\r
747 UINT32 Timeout;\r
748\r
749 BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
750 Status = EFI_SUCCESS;\r
751\r
752 while (TotalBlock > 0) {\r
753 //\r
754 // Split the total blocks into smaller pieces to ease the pressure\r
755 // on the device. We must split the total block because the WRITE10\r
756 // command only has 16 bit transfer length (in the unit of block).\r
757 //\r
758 Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
759 ByteSize = (UINT32)Count * BlockSize;\r
760\r
761 //\r
50fa1b3a 762 // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]\r
e237e7ae 763 //\r
50fa1b3a 764 Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;\r
e237e7ae 765\r
766 //\r
767 // Fill in the write10 command block\r
768 //\r
769 ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));\r
770\r
771 WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;\r
c52fa98c 772 WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
d80ed2a7 773 WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba));\r
774 WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count));\r
e237e7ae 775\r
776 Status = UsbBootExecCmdWithRetry (\r
777 UsbMass,\r
778 &WriteCmd,\r
779 sizeof (USB_BOOT_WRITE10_CMD),\r
780 EfiUsbDataOut,\r
781 Buffer,\r
782 ByteSize,\r
783 Timeout\r
784 );\r
785 if (EFI_ERROR (Status)) {\r
786 return Status;\r
787 }\r
788\r
789 Lba += Count;\r
790 Buffer += Count * BlockSize;\r
791 TotalBlock -= Count;\r
792 }\r
793\r
794 return Status;\r
795}\r
796\r
e237e7ae 797/**\r
d80ed2a7 798 Use the USB clear feature control transfer to clear the endpoint stall condition.\r
e237e7ae 799\r
d80ed2a7 800 @param UsbIo The USB I/O Protocol instance\r
e237e7ae 801 @param EndpointAddr The endpoint to clear stall for\r
802\r
d80ed2a7 803 @retval EFI_SUCCESS The endpoint stall condition is cleared.\r
804 @retval Others Failed to clear the endpoint stall condition.\r
e237e7ae 805\r
806**/\r
807EFI_STATUS\r
808UsbClearEndpointStall (\r
809 IN EFI_USB_IO_PROTOCOL *UsbIo,\r
810 IN UINT8 EndpointAddr\r
811 )\r
812{\r
813 EFI_USB_DEVICE_REQUEST Request;\r
814 EFI_STATUS Status;\r
815 UINT32 CmdResult;\r
816 UINT32 Timeout;\r
817\r
818 Request.RequestType = 0x02;\r
819 Request.Request = USB_REQ_CLEAR_FEATURE;\r
820 Request.Value = USB_FEATURE_ENDPOINT_HALT;\r
821 Request.Index = EndpointAddr;\r
822 Request.Length = 0;\r
41e8ff27 823 Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_1_MILLISECOND;\r
e237e7ae 824\r
825 Status = UsbIo->UsbControlTransfer (\r
826 UsbIo,\r
827 &Request,\r
828 EfiUsbNoData,\r
829 Timeout,\r
830 NULL,\r
831 0,\r
832 &CmdResult\r
833 );\r
834\r
835 return Status;\r
836}\r