/** @file\r
-\r
- This file implement the command set of "USB Mass Storage Specification\r
- for Bootability".\r
+ Implementation of the command set of USB Mass Storage Specification\r
+ for Bootability, Revision 1.0.\r
\r
Copyright (c) 2007 - 2008, Intel Corporation\r
All rights reserved. This program and the accompanying materials\r
\r
#include "UsbMassImpl.h"\r
\r
-\r
-/**\r
- Return the current TPL.\r
-\r
- @return Current TPL.\r
-\r
-**/\r
-EFI_TPL\r
-UsbGetCurrentTpl (\r
- VOID\r
- )\r
-{\r
- EFI_TPL Tpl;\r
-\r
- Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
- gBS->RestoreTPL (Tpl);\r
-\r
- return Tpl;\r
-}\r
-\r
-/**\r
- Read an UINT32 from the buffer to avoid byte alignment problems, then\r
- convert that to the little endia. The USB mass storage bootability spec\r
- use big endia.\r
-\r
- @param Buf The buffer contains the first byte of the UINT32\r
- in big endia.\r
-\r
- @return The UINT32 value read from the buffer in little endia.\r
-\r
-**/\r
-UINT32\r
-UsbBootGetUint32 (\r
- IN UINT8 *Buf\r
- )\r
-{\r
- UINT32 Value;\r
-\r
- CopyMem (&Value, Buf, sizeof (UINT32));\r
- return USB_BOOT_SWAP32 (Value);\r
-}\r
-\r
-\r
/**\r
- Put an UINT32 in little endia to the buffer. The data is converted to\r
- big endia before writing.\r
-\r
- @param Buf The buffer to write data to.\r
- @param Data32 The data to write.\r
+ Execute REQUEST SENSE Command to retrieve sense data from device.\r
\r
- @return None.\r
-\r
-**/\r
-VOID\r
-UsbBootPutUint32 (\r
- IN UINT8 *Buf,\r
- IN UINT32 Data32\r
- )\r
-{\r
- Data32 = USB_BOOT_SWAP32 (Data32);\r
- CopyMem (Buf, &Data32, sizeof (UINT32));\r
-}\r
-\r
-/**\r
- Put an UINT16 in little endia to the buffer. The data is converted to\r
- big endia before writing.\r
-\r
- @param Buf The buffer to write data to.\r
- @param Data16 The data to write.\r
-\r
- @return None.\r
-\r
-**/\r
-VOID\r
-UsbBootPutUint16 (\r
- IN UINT8 *Buf,\r
- IN UINT16 Data16\r
- )\r
-{\r
- Data16 = (UINT16) (USB_BOOT_SWAP16 (Data16));\r
- CopyMem (Buf, &Data16, sizeof (UINT16));\r
-}\r
+ @param UsbMass The device whose sense data is requested.\r
\r
-/**\r
- Request sense information via sending Request Sense\r
- Packet Command.\r
-\r
- @param UsbMass The device to be requested sense data.\r
-\r
- @retval EFI_SUCCESS The command is excuted OK.\r
+ @retval EFI_SUCCESS The command is excuted successfully.\r
@retval EFI_DEVICE_ERROR Failed to request sense.\r
@retval EFI_NO_RESPONSE The device media doesn't response this request.\r
@retval EFI_INVALID_PARAMETER The command has some invalid parameters.\r
Transport = UsbMass->Transport;\r
\r
//\r
- // Request the sense data from the device if command failed\r
+ // Request the sense data from the device\r
//\r
ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));\r
ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));\r
}\r
\r
//\r
- // Interpret the sense data and update the media status if necessary.\r
+ // If sense data is retrieved successfully, interpret the sense data\r
+ // and update the media status if necessary.\r
//\r
Media = &UsbMass->BlockIoMedia;\r
\r
case USB_BOOT_SENSE_NOT_READY:\r
Status = EFI_DEVICE_ERROR;\r
if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) {\r
- Media->MediaPresent = FALSE;\r
- Status = EFI_NO_MEDIA;\r
+ Media->MediaPresent = FALSE;\r
+ Status = EFI_NO_MEDIA;\r
} else if (SenseData.ASC == USB_BOOT_ASC_NOT_READY) {\r
- Status = EFI_NOT_READY;\r
+ Status = EFI_NOT_READY;\r
}\r
break;\r
\r
Status = EFI_DEVICE_ERROR;\r
if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) {\r
//\r
- // If MediaChange, reset ReadOnly and new MediId\r
+ // If MediaChange, reset ReadOnly and new MediaId\r
//\r
- Status = EFI_MEDIA_CHANGED;\r
+ Status = EFI_MEDIA_CHANGED;\r
Media->ReadOnly = FALSE;\r
Media->MediaId++;\r
}\r
break;\r
\r
- case USB_BOOT_SNESE_DATA_PROTECT:\r
- Status = EFI_WRITE_PROTECTED;\r
+ case USB_BOOT_SENSE_DATA_PROTECT:\r
+ Status = EFI_WRITE_PROTECTED;\r
Media->ReadOnly = TRUE;\r
break;\r
\r
\r
\r
/**\r
- Execute the USB mass storage bootability commands. If execution\r
- failed, retrieve the error by REQUEST_SENSE then update the device's\r
- status, such as ReadyOnly.\r
+ Execute the USB mass storage bootability commands.\r
+\r
+ This function executes the USB mass storage bootability commands.\r
+ If execution failed, retrieve the error by REQUEST_SENSE, then\r
+ update the device's status, such as ReadyOnly.\r
\r
@param UsbMass The device to issue commands to\r
@param Cmd The command to execute\r
@param DataLen The length of expected data\r
@param Timeout The timeout used to transfer\r
\r
- @retval EFI_SUCCESS The command is excuted OK\r
- @retval EFI_DEVICE_ERROR Failed to request sense\r
- @retval EFI_INVALID_PARAMETER The command has some invalid parameters\r
- @retval EFI_WRITE_PROTECTED The device is write protected\r
- @retval EFI_MEDIA_CHANGED The device media has been changed\r
+ @retval EFI_SUCCESS Command is excuted successfully\r
+ @retval Others Command execution failed.\r
\r
**/\r
EFI_STATUS\r
&CmdResult\r
);\r
//\r
- // ExecCommand return success and get the right CmdResult means\r
- // the commnad transfer is OK.\r
+ // If ExecCommand() returns no error and CmdResult is success,\r
+ // then the commnad transfer is successful.\r
//\r
- if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR(Status)) {\r
+ if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {\r
return EFI_SUCCESS;\r
}\r
\r
DEBUG ((EFI_D_INFO, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n",\r
*(UINT8 *)Cmd ,Status));\r
\r
+ //\r
+ // If command execution failed, then retrieve error info via sense request.\r
+ //\r
return UsbBootRequestSense (UsbMass);\r
}\r
\r
\r
/**\r
- Execute the USB mass storage bootability commands. If execution\r
- failed, retrieve the error by REQUEST_SENSE then update the device's\r
- status, such as ReadyOnly.\r
+ Execute the USB mass storage bootability commands with retrial.\r
\r
+ This function executes USB mass storage bootability commands.\r
+ If the device isn't ready, wait for it. If the device is ready\r
+ and error occurs, retry the command again until it exceeds the\r
+ limit of retrial times.\r
+ \r
@param UsbMass The device to issue commands to\r
@param Cmd The command to execute\r
@param CmdLen The length of the command\r
@param DataLen The length of expected data\r
@param Timeout The timeout used to transfer\r
\r
- @retval EFI_SUCCESS The command is excuted OK\r
- @retval EFI_DEVICE_ERROR Failed to request sense\r
- @retval EFI_INVALID_PARAMETER The command has some invalid parameters\r
- @retval EFI_WRITE_PROTECTED The device is write protected\r
- @retval EFI_MEDIA_CHANGED The device media has been changed\r
+ @retval EFI_SUCCESS The command is executed successfully.\r
+ @retval EFI_MEDIA_CHANGED The device media has been changed.\r
+ @retval Others Command execution failed after retrial.\r
\r
**/\r
EFI_STATUS\r
)\r
{\r
EFI_STATUS Status;\r
- INT16 Index;\r
+ UINTN Retry;\r
\r
- //\r
- // If the device isn't ready, wait some time. If the device is ready,\r
- // retry the command again.\r
- //\r
Status = EFI_SUCCESS;\r
\r
- for (Index = 0; Index < USB_BOOT_COMMAND_RETRY; Index++) {\r
- //\r
- // Execute the command with an increasingly larger timeout value.\r
- //\r
+ for (Retry = 0; Retry < USB_BOOT_COMMAND_RETRY; Retry++) {\r
+\r
Status = UsbBootExecCmd (\r
UsbMass,\r
Cmd,\r
DataLen,\r
Timeout\r
);\r
- if (Status == EFI_SUCCESS ||\r
- Status == EFI_MEDIA_CHANGED) {\r
+ if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED) {\r
break;\r
}\r
//\r
- // Need retry once more, so reset index\r
+ // If the device isn't ready, just wait for it without limit on retrial times.\r
//\r
if (Status == EFI_NOT_READY) {\r
- Index = 0;\r
+ Retry = 0;\r
}\r
}\r
\r
\r
\r
/**\r
- Use the TEST UNIT READY command to check whether it is ready.\r
- If it is ready, update the parameters.\r
+ Execute TEST UNIT READY command to check if the device is ready.\r
\r
@param UsbMass The device to test\r
\r
- @retval EFI_SUCCESS The device is ready and parameters are updated.\r
+ @retval EFI_SUCCESS The device is ready.\r
@retval Others Device not ready.\r
\r
**/\r
\r
\r
/**\r
- Inquiry Command requests that information regrarding parameters of\r
- the Device be sent to the Host.\r
+ Execute INQUIRY Command to request information regarding parameters of\r
+ the device be sent to the host computer.\r
\r
- @param UsbMass The device to inquiry.\r
+ @param UsbMass The device to inquire.\r
\r
- @retval EFI_SUCCESS The device is ready and parameters are updated.\r
- @retval Others Device not ready.\r
+ @retval EFI_SUCCESS INQUIRY Command is executed successfully.\r
+ @retval Others INQUIRY Command is not executed successfully.\r
\r
**/\r
EFI_STATUS\r
\r
Media = &(UsbMass->BlockIoMedia);\r
\r
- //\r
- // Use the Inquiry command to get the RemovableMedia setting.\r
- //\r
ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));\r
ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));\r
\r
return Status;\r
}\r
\r
+ //\r
+ // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit\r
+ // from the inquiry data.\r
+ //\r
UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (InquiryData.Pdt));\r
Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (InquiryData.Removable));\r
//\r
- // Default value 512 Bytes, in case no media present at first time\r
+ // Set block size to the default value of 512 Bytes, in case no media is present at first time.\r
//\r
Media->BlockSize = 0x0200;\r
\r
\r
\r
/**\r
- Get the capacity of the USB mass storage media, including\r
- the presentation, block size, and last block number. This\r
- function is used to get the disk parameters at the start if\r
- it is a non-removable media or to detect the media if it is\r
- removable.\r
+ Execute READ CAPACITY command to request information regarding\r
+ the capacity of the installed medium of the device.\r
+\r
+ This function executes READ CAPACITY command to get the capacity\r
+ of the USB mass storage media, including the presence, block size,\r
+ and last block number.\r
\r
@param UsbMass The device to retireve disk gemotric.\r
\r
- @retval EFI_SUCCESS The disk gemotric is successfully retrieved.\r
- @retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.\r
- @retval Other Read capacity request fails.\r
+ @retval EFI_SUCCESS The disk geometry is successfully retrieved.\r
+ @retval EFI_NOT_READY The returned block size is zero.\r
+ @retval Other READ CAPACITY command execution failed.\r
\r
**/\r
EFI_STATUS\r
\r
Media = &UsbMass->BlockIoMedia;\r
\r
- //\r
- // Use the READ CAPACITY command to get the block length and last blockno\r
- //\r
ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));\r
ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));\r
\r
return Status;\r
}\r
\r
+ //\r
+ // Get the information on media presence, block size, and last block number\r
+ // from READ CAPACITY data.\r
+ //\r
Media->MediaPresent = TRUE;\r
- Media->LastBlock = UsbBootGetUint32 (CapacityData.LastLba);\r
- Media->BlockSize = UsbBootGetUint32 (CapacityData.BlockLen);\r
+ Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));\r
+ Media->BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));\r
\r
if (Media->BlockSize == 0) {\r
return EFI_NOT_READY;\r
}\r
\r
/**\r
- Retrieves mode sense information via sending Mode Sense\r
- Packet Command.\r
+ Retrieves SCSI mode sense information via MODE SENSE(6) command.\r
\r
- @param UsbMass The USB_FLOPPY_DEV instance.\r
+ @param UsbMass The device whose sense data is requested.\r
\r
- @retval EFI_SUCCESS Success\r
- @retval Other Execute Request command fails.\r
+ @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.\r
+ @retval Other Command execution failed.\r
\r
**/\r
EFI_STATUS\r
ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));\r
\r
//\r
- // ModeSense6 command is defined in [SCSI2Spec-Page151]\r
+ // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec\r
//\r
ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;\r
ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);\r
);\r
\r
//\r
- // ModeSense(6) is used to get the information of WriteProtected. While only some of\r
- // devices support this command, so have a try here.\r
+ // Format of device-specific parameter byte of the mode parameter header is defined in\r
+ // Section 8.2.10 of SCSI-2 Spec.\r
+ // BIT7 of this byte is indicates whether the medium is write protected.\r
//\r
if (!EFI_ERROR (Status)) {\r
- Media->ReadOnly = (BOOLEAN) (((ModeParaHeader.DevicePara & 0x80) != 0) ? TRUE : FALSE);\r
+ Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);\r
}\r
\r
return Status;\r
\r
\r
/**\r
- Get the parameters for the USB mass storage media, including\r
- the RemovableMedia, block size, and last block number. This\r
- function is used both to initialize the media during the\r
- DriverBindingStart and to re-initialize it when the media is\r
+ Get the parameters for the USB mass storage media.\r
+\r
+ This function get the parameters for the USB mass storage media,\r
+ It is used both to initialize the media during the Start() phase\r
+ of Driver Binding Protocol and to re-initialize it when the media is\r
changed. Althought the RemoveableMedia is unlikely to change,\r
- I include it here.\r
+ it is also included here.\r
\r
- @param UsbMass The device to retireve disk gemotric.\r
+ @param UsbMass The device to retrieve disk gemotric.\r
\r
@retval EFI_SUCCESS The disk gemotric is successfully retrieved.\r
- @retval Other Get the parameters failed.\r
+ @retval Other Failed to get the parameters.\r
\r
**/\r
EFI_STATUS\r
}\r
\r
//\r
- // Don't use the Removable bit in inquirydata to test whether the media\r
+ // Don't use the Removable bit in inquiry data to test whether the media\r
// is removable because many flash disks wrongly set this bit.\r
//\r
if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {\r
\r
/**\r
Detect whether the removable media is present and whether it has changed.\r
- The Non-removable media doesn't need it.\r
\r
- @param UsbMass The device to retireve disk gemotric.\r
+ @param UsbMass The device to check.\r
\r
- @retval EFI_SUCCESS The disk gemotric is successfully retrieved.\r
- @retval Other Decect media fails.\r
+ @retval EFI_SUCCESS The media status is successfully checked.\r
+ @retval Other Failed to detect media.\r
\r
**/\r
EFI_STATUS\r
\r
Media = &UsbMass->BlockIoMedia;\r
\r
- CopyMem (\r
- &OldMedia,\r
- &(UsbMass->BlockIoMedia),\r
- sizeof (EFI_BLOCK_IO_MEDIA)\r
- );\r
+ CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));\r
\r
CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
\r
Status = UsbBootIsUnitReady (UsbMass);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status));\r
goto ON_ERROR;\r
}\r
\r
if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {\r
//\r
- // ModeSense is required for the device with PDT of 0x00/0x07/0x0E,\r
- // which is from [MassStorageBootabilitySpec-Page7].\r
- // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI\r
- // could get the information of WriteProtected.\r
- // Since not all device support this command, so skip if fail.\r
+ // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,\r
+ // according to Section 4 of USB Mass Storage Specification for Bootability.\r
+ // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI\r
+ // could get the information of Write Protected.\r
+ // Since not all device support this command, skip if fail.\r
//\r
UsbScsiModeSense (UsbMass);\r
}\r
\r
ON_ERROR:\r
//\r
- // Detect whether it is necessary to reinstall the BlockIO\r
+ // Detect whether it is necessary to reinstall the Block I/O Protocol.\r
//\r
// MediaId may change in RequestSense for MediaChanged\r
// MediaPresent may change in RequestSense for NoMedia\r
(Media->BlockSize != OldMedia.BlockSize) ||\r
(Media->LastBlock != OldMedia.LastBlock)) {\r
\r
- OldTpl = UsbGetCurrentTpl ();\r
- DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL before reinstall BlockIoProtocol is %d\n", OldTpl));\r
-\r
+ //\r
+ // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY.\r
+ // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface().\r
+ //\r
+ OldTpl = EfiGetCurrentTpl ();\r
gBS->RestoreTPL (TPL_CALLBACK);\r
\r
gBS->ReinstallProtocolInterface (\r
&UsbMass->BlockIo\r
);\r
\r
- DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL after reinstall is %d\n", UsbGetCurrentTpl()));\r
- ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
-\r
+ ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);\r
gBS->RaiseTPL (OldTpl);\r
\r
//\r
- // Update MediaId after reinstall BLOCK_IO_PROTOCOL\r
+ // Update MediaId after reinstalling Block I/O Protocol.\r
//\r
if (Media->MediaPresent != OldMedia.MediaPresent) {\r
- if (Media->MediaPresent == TRUE) {\r
+ if (Media->MediaPresent) {\r
Media->MediaId = 1;\r
} else {\r
Media->MediaId = 0;\r
\r
ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;\r
ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
- UsbBootPutUint32 (ReadCmd.Lba, Lba);\r
- UsbBootPutUint16 (ReadCmd.TransferLen, Count);\r
+ WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba));\r
+ WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count));\r
\r
Status = UsbBootExecCmdWithRetry (\r
UsbMass,\r
@param UsbMass The USB mass storage device to write to\r
@param Lba The start block number\r
@param TotalBlock Total block number to write\r
- @param Buffer The buffer to write to\r
+ @param Buffer Pointer to the source buffer for the data.\r
\r
@retval EFI_SUCCESS Data are written into the buffer\r
@retval Others Failed to write all the data\r
IN USB_MASS_DEVICE *UsbMass,\r
IN UINT32 Lba,\r
IN UINTN TotalBlock,\r
- OUT UINT8 *Buffer\r
+ IN UINT8 *Buffer\r
)\r
{\r
USB_BOOT_WRITE10_CMD WriteCmd;\r
\r
WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;\r
WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));\r
- UsbBootPutUint32 (WriteCmd.Lba, Lba);\r
- UsbBootPutUint16 (WriteCmd.TransferLen, Count);\r
+ WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba));\r
+ WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count));\r
\r
Status = UsbBootExecCmdWithRetry (\r
UsbMass,\r
return Status;\r
}\r
\r
-\r
/**\r
- Use the USB clear feature control transfer to clear the endpoint\r
- stall condition.\r
+ Use the USB clear feature control transfer to clear the endpoint stall condition.\r
\r
- @param UsbIo The USB IO protocol to use\r
+ @param UsbIo The USB I/O Protocol instance\r
@param EndpointAddr The endpoint to clear stall for\r
\r
- @retval EFI_SUCCESS The endpoint stall condtion is clear\r
- @retval Others Failed to clear the endpoint stall condtion\r
+ @retval EFI_SUCCESS The endpoint stall condition is cleared.\r
+ @retval Others Failed to clear the endpoint stall condition.\r
\r
**/\r
EFI_STATUS\r