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