2011-06-28 01:30:55 +02:00
|
|
|
/** @file
|
2020-02-07 02:07:35 +01:00
|
|
|
Pei USB ATAPI command implementations.
|
2011-06-28 01:30:55 +02:00
|
|
|
|
2018-06-27 15:08:52 +02:00
|
|
|
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
|
|
|
2019-04-04 01:05:13 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "UsbBotPeim.h"
|
|
|
|
#include "BotPeim.h"
|
|
|
|
|
|
|
|
#define MAXSENSEKEY 5
|
|
|
|
|
|
|
|
/**
|
|
|
|
Sends out ATAPI Inquiry Packet Command to the specified device. This command will
|
|
|
|
return INQUIRY data of the device.
|
|
|
|
|
|
|
|
@param PeiServices The pointer of EFI_PEI_SERVICES.
|
|
|
|
@param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Inquiry command completes successfully.
|
|
|
|
@retval EFI_DEVICE_ERROR Inquiry command failed.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PeiUsbInquiry (
|
|
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN PEI_BOT_DEVICE *PeiBotDevice
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ATAPI_PACKET_COMMAND Packet;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
ATAPI_INQUIRY_DATA Idata;
|
|
|
|
|
|
|
|
//
|
|
|
|
// fill command packet
|
|
|
|
//
|
|
|
|
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
|
|
|
|
ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));
|
|
|
|
|
|
|
|
Packet.Inquiry.opcode = ATA_CMD_INQUIRY;
|
|
|
|
Packet.Inquiry.page_code = 0;
|
|
|
|
Packet.Inquiry.allocation_length = 36;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Send scsi INQUIRY command packet.
|
|
|
|
// According to SCSI Primary Commands-2 spec, host only needs to
|
|
|
|
// retrieve the first 36 bytes for standard INQUIRY data.
|
|
|
|
//
|
|
|
|
Status = PeiAtapiCommand (
|
|
|
|
PeiServices,
|
|
|
|
PeiBotDevice,
|
|
|
|
&Packet,
|
|
|
|
(UINT8) sizeof (ATAPI_PACKET_COMMAND),
|
|
|
|
&Idata,
|
|
|
|
36,
|
|
|
|
EfiUsbDataIn,
|
|
|
|
2000
|
|
|
|
);
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((Idata.peripheral_type & 0x1f) == 0x05) {
|
|
|
|
PeiBotDevice->DeviceType = USBCDROM;
|
|
|
|
PeiBotDevice->Media.BlockSize = 0x800;
|
2015-05-20 08:31:28 +02:00
|
|
|
PeiBotDevice->Media2.ReadOnly = TRUE;
|
|
|
|
PeiBotDevice->Media2.RemovableMedia = TRUE;
|
|
|
|
PeiBotDevice->Media2.BlockSize = 0x800;
|
2011-06-28 01:30:55 +02:00
|
|
|
} else {
|
|
|
|
PeiBotDevice->DeviceType = USBFLOPPY;
|
|
|
|
PeiBotDevice->Media.BlockSize = 0x200;
|
2015-05-20 08:31:28 +02:00
|
|
|
PeiBotDevice->Media2.ReadOnly = FALSE;
|
|
|
|
PeiBotDevice->Media2.RemovableMedia = TRUE;
|
|
|
|
PeiBotDevice->Media2.BlockSize = 0x200;
|
2011-06-28 01:30:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Sends out ATAPI Test Unit Ready Packet Command to the specified device
|
|
|
|
to find out whether device is accessible.
|
|
|
|
|
|
|
|
@param PeiServices The pointer of EFI_PEI_SERVICES.
|
|
|
|
@param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS TestUnit command executed successfully.
|
|
|
|
@retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PeiUsbTestUnitReady (
|
|
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN PEI_BOT_DEVICE *PeiBotDevice
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ATAPI_PACKET_COMMAND Packet;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
//
|
|
|
|
// fill command packet
|
|
|
|
//
|
|
|
|
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
|
|
|
|
Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
|
|
|
|
|
|
|
|
//
|
|
|
|
// send command packet
|
|
|
|
//
|
|
|
|
Status = PeiAtapiCommand (
|
|
|
|
PeiServices,
|
|
|
|
PeiBotDevice,
|
|
|
|
&Packet,
|
|
|
|
(UINT8) sizeof (ATAPI_PACKET_COMMAND),
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
EfiUsbNoData,
|
|
|
|
2000
|
|
|
|
);
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Sends out ATAPI Request Sense Packet Command to the specified device.
|
|
|
|
|
|
|
|
@param PeiServices The pointer of EFI_PEI_SERVICES.
|
|
|
|
@param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
|
|
|
|
@param SenseCounts Length of sense buffer.
|
|
|
|
@param SenseKeyBuffer Pointer to sense buffer.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Command executed successfully.
|
|
|
|
@retval EFI_DEVICE_ERROR Some device errors happen.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PeiUsbRequestSense (
|
|
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN PEI_BOT_DEVICE *PeiBotDevice,
|
|
|
|
OUT UINTN *SenseCounts,
|
|
|
|
IN UINT8 *SenseKeyBuffer
|
|
|
|
)
|
|
|
|
{
|
2015-05-20 08:31:28 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
ATAPI_PACKET_COMMAND Packet;
|
|
|
|
UINT8 *Ptr;
|
|
|
|
BOOLEAN SenseReq;
|
2011-06-28 01:30:55 +02:00
|
|
|
ATAPI_REQUEST_SENSE_DATA *Sense;
|
|
|
|
|
|
|
|
*SenseCounts = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// fill command packet for Request Sense Packet Command
|
|
|
|
//
|
|
|
|
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
|
|
|
|
Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;
|
|
|
|
Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);
|
|
|
|
|
|
|
|
Ptr = SenseKeyBuffer;
|
|
|
|
|
|
|
|
SenseReq = TRUE;
|
|
|
|
|
|
|
|
//
|
|
|
|
// request sense data from device continuously
|
|
|
|
// until no sense data exists in the device.
|
|
|
|
//
|
|
|
|
while (SenseReq) {
|
|
|
|
Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
|
|
|
|
|
|
|
|
//
|
|
|
|
// send out Request Sense Packet Command and get one Sense
|
|
|
|
// data form device.
|
|
|
|
//
|
|
|
|
Status = PeiAtapiCommand (
|
|
|
|
PeiServices,
|
|
|
|
PeiBotDevice,
|
|
|
|
&Packet,
|
|
|
|
(UINT8) sizeof (ATAPI_PACKET_COMMAND),
|
|
|
|
(VOID *) Ptr,
|
|
|
|
sizeof (ATAPI_REQUEST_SENSE_DATA),
|
|
|
|
EfiUsbDataIn,
|
|
|
|
2000
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// failed to get Sense data
|
|
|
|
//
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
if (*SenseCounts == 0) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
} else {
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Sense->sense_key != ATA_SK_NO_SENSE) {
|
|
|
|
|
|
|
|
Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);
|
|
|
|
//
|
|
|
|
// Ptr is byte based pointer
|
|
|
|
//
|
|
|
|
(*SenseCounts)++;
|
|
|
|
|
|
|
|
if (*SenseCounts == MAXSENSEKEY) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// when no sense key, skip out the loop
|
|
|
|
//
|
|
|
|
SenseReq = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Sends out ATAPI Read Capacity Packet Command to the specified device.
|
|
|
|
This command will return the information regarding the capacity of the
|
|
|
|
media in the device.
|
|
|
|
|
|
|
|
@param PeiServices The pointer of EFI_PEI_SERVICES.
|
|
|
|
@param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Command executed successfully.
|
|
|
|
@retval EFI_DEVICE_ERROR Some device errors happen.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PeiUsbReadCapacity (
|
|
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN PEI_BOT_DEVICE *PeiBotDevice
|
|
|
|
)
|
|
|
|
{
|
2015-05-20 08:31:28 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
ATAPI_PACKET_COMMAND Packet;
|
2011-06-28 01:30:55 +02:00
|
|
|
ATAPI_READ_CAPACITY_DATA Data;
|
2015-05-20 08:31:28 +02:00
|
|
|
UINT32 LastBlock;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));
|
|
|
|
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
|
|
|
|
|
|
|
|
Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
|
|
|
|
|
|
|
|
//
|
|
|
|
// send command packet
|
|
|
|
//
|
|
|
|
Status = PeiAtapiCommand (
|
|
|
|
PeiServices,
|
|
|
|
PeiBotDevice,
|
|
|
|
&Packet,
|
|
|
|
(UINT8) sizeof (ATAPI_PACKET_COMMAND),
|
|
|
|
(VOID *) &Data,
|
|
|
|
sizeof (ATAPI_READ_CAPACITY_DATA),
|
|
|
|
EfiUsbDataIn,
|
|
|
|
2000
|
|
|
|
);
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
MdeModulePkg/UsbBotPei: Fix undefined behavior in signed left shift
In function PeiUsbReadCapacity(), the following expression:
LastBlock = (Data.LastLba3 << 24) |
(Data.LastLba2 << 16) |
(Data.LastLba1 << 8) |
Data.LastLba0;
(There is also a similar case in function PeiUsbReadFormattedCapacity().)
will involve undefined behavior in signed left shift operations.
Since Data.LastLbaX is of type UINT8, they will be promoted to int (32
bits, signed) first, and then perform the left shift operation.
According to the C11 spec, Section 6.5.7:
4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated
bits are filled with zeros. If E1 has an unsigned type, the value
of the result is E1 * 2^E2 , reduced modulo one more than the
maximum value representable in the result type. If E1 has a signed
type and nonnegative value, and E1 * 2^E2 is representable in the
result type, then that is the resulting value; otherwise, the
behavior is undefined.
So if bit 7 of Data.LastLba3 is 1, (Data.LastLba3 << 24) will be out of
the range within int type. The undefined behavior of the signed left shift
might incur potential issues.
This commit will add an explicit UINT32 type cast for Data.LastLba3 to
refine the codes.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
2017-04-12 03:06:36 +02:00
|
|
|
LastBlock = ((UINT32) Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
2015-05-20 08:31:28 +02:00
|
|
|
if (LastBlock == 0xFFFFFFFF) {
|
|
|
|
DEBUG ((EFI_D_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
PeiBotDevice->Media.LastBlock = LastBlock;
|
|
|
|
PeiBotDevice->Media.MediaPresent = TRUE;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
2015-05-20 08:31:28 +02:00
|
|
|
PeiBotDevice->Media2.LastBlock = LastBlock;
|
|
|
|
PeiBotDevice->Media2.MediaPresent = TRUE;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Sends out ATAPI Read Format Capacity Data Command to the specified device.
|
|
|
|
This command will return the information regarding the capacity of the
|
|
|
|
media in the device.
|
|
|
|
|
|
|
|
@param PeiServices The pointer of EFI_PEI_SERVICES.
|
|
|
|
@param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Command executed successfully.
|
|
|
|
@retval EFI_DEVICE_ERROR Some device errors happen.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PeiUsbReadFormattedCapacity (
|
|
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN PEI_BOT_DEVICE *PeiBotDevice
|
|
|
|
)
|
|
|
|
{
|
2015-05-20 08:31:28 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
ATAPI_PACKET_COMMAND Packet;
|
2011-06-28 01:30:55 +02:00
|
|
|
ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
|
2015-05-20 08:31:28 +02:00
|
|
|
UINT32 LastBlock;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));
|
|
|
|
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
|
|
|
|
|
|
|
|
Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;
|
|
|
|
Packet.ReadFormatCapacity.allocation_length_lo = 12;
|
|
|
|
|
|
|
|
//
|
|
|
|
// send command packet
|
|
|
|
//
|
|
|
|
Status = PeiAtapiCommand (
|
|
|
|
PeiServices,
|
|
|
|
PeiBotDevice,
|
|
|
|
&Packet,
|
|
|
|
(UINT8) sizeof (ATAPI_PACKET_COMMAND),
|
|
|
|
(VOID *) &FormatData,
|
|
|
|
sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
|
|
|
|
EfiUsbDataIn,
|
|
|
|
2000
|
|
|
|
);
|
|
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FormatData.DesCode == 3) {
|
|
|
|
//
|
|
|
|
// Media is not present
|
|
|
|
//
|
|
|
|
PeiBotDevice->Media.MediaPresent = FALSE;
|
|
|
|
PeiBotDevice->Media.LastBlock = 0;
|
2015-05-20 08:31:28 +02:00
|
|
|
PeiBotDevice->Media2.MediaPresent = FALSE;
|
|
|
|
PeiBotDevice->Media2.LastBlock = 0;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
} else {
|
MdeModulePkg/UsbBotPei: Fix undefined behavior in signed left shift
In function PeiUsbReadCapacity(), the following expression:
LastBlock = (Data.LastLba3 << 24) |
(Data.LastLba2 << 16) |
(Data.LastLba1 << 8) |
Data.LastLba0;
(There is also a similar case in function PeiUsbReadFormattedCapacity().)
will involve undefined behavior in signed left shift operations.
Since Data.LastLbaX is of type UINT8, they will be promoted to int (32
bits, signed) first, and then perform the left shift operation.
According to the C11 spec, Section 6.5.7:
4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated
bits are filled with zeros. If E1 has an unsigned type, the value
of the result is E1 * 2^E2 , reduced modulo one more than the
maximum value representable in the result type. If E1 has a signed
type and nonnegative value, and E1 * 2^E2 is representable in the
result type, then that is the resulting value; otherwise, the
behavior is undefined.
So if bit 7 of Data.LastLba3 is 1, (Data.LastLba3 << 24) will be out of
the range within int type. The undefined behavior of the signed left shift
might incur potential issues.
This commit will add an explicit UINT32 type cast for Data.LastLba3 to
refine the codes.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
2017-04-12 03:06:36 +02:00
|
|
|
LastBlock = ((UINT32) FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;
|
2015-05-20 08:31:28 +02:00
|
|
|
if (LastBlock == 0xFFFFFFFF) {
|
|
|
|
DEBUG ((EFI_D_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
|
|
|
|
}
|
2011-06-28 01:30:55 +02:00
|
|
|
|
2015-05-20 08:31:28 +02:00
|
|
|
PeiBotDevice->Media.LastBlock = LastBlock;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
PeiBotDevice->Media.LastBlock--;
|
|
|
|
|
|
|
|
PeiBotDevice->Media.MediaPresent = TRUE;
|
2015-05-20 08:31:28 +02:00
|
|
|
|
|
|
|
PeiBotDevice->Media2.MediaPresent = TRUE;
|
|
|
|
PeiBotDevice->Media2.LastBlock = PeiBotDevice->Media.LastBlock;
|
2011-06-28 01:30:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Execute Read(10) ATAPI command on a specific SCSI target.
|
|
|
|
|
|
|
|
Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
|
|
|
|
|
|
|
|
@param PeiServices The pointer of EFI_PEI_SERVICES.
|
|
|
|
@param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
|
|
|
|
@param Buffer The pointer to data buffer.
|
|
|
|
@param Lba The start logic block address of reading.
|
|
|
|
@param NumberOfBlocks The block number of reading.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Command executed successfully.
|
|
|
|
@retval EFI_DEVICE_ERROR Some device errors happen.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PeiUsbRead10 (
|
|
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN PEI_BOT_DEVICE *PeiBotDevice,
|
|
|
|
IN VOID *Buffer,
|
|
|
|
IN EFI_PEI_LBA Lba,
|
|
|
|
IN UINTN NumberOfBlocks
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ATAPI_PACKET_COMMAND Packet;
|
|
|
|
ATAPI_READ10_CMD *Read10Packet;
|
|
|
|
UINT16 MaxBlock;
|
|
|
|
UINT16 BlocksRemaining;
|
|
|
|
UINT16 SectorCount;
|
|
|
|
UINT32 Lba32;
|
|
|
|
UINT32 BlockSize;
|
|
|
|
UINT32 ByteCount;
|
|
|
|
VOID *PtrBuffer;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT16 TimeOut;
|
|
|
|
|
|
|
|
//
|
|
|
|
// prepare command packet for the Inquiry Packet Command.
|
|
|
|
//
|
|
|
|
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
|
|
|
|
Read10Packet = &Packet.Read10;
|
|
|
|
Lba32 = (UINT32) Lba;
|
|
|
|
PtrBuffer = Buffer;
|
|
|
|
|
|
|
|
BlockSize = (UINT32) PeiBotDevice->Media.BlockSize;
|
|
|
|
|
|
|
|
MaxBlock = (UINT16) (65535 / BlockSize);
|
|
|
|
BlocksRemaining = (UINT16) NumberOfBlocks;
|
|
|
|
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
while (BlocksRemaining > 0) {
|
|
|
|
|
|
|
|
if (BlocksRemaining <= MaxBlock) {
|
|
|
|
|
|
|
|
SectorCount = BlocksRemaining;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
SectorCount = MaxBlock;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// fill the Packet data structure
|
|
|
|
//
|
|
|
|
Read10Packet->opcode = ATA_CMD_READ_10;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Lba0 ~ Lba3 specify the start logical block address of the data transfer.
|
|
|
|
// Lba0 is MSB, Lba3 is LSB
|
|
|
|
//
|
|
|
|
Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
|
|
|
|
Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);
|
|
|
|
Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);
|
|
|
|
Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);
|
|
|
|
|
|
|
|
//
|
|
|
|
// TranLen0 ~ TranLen1 specify the transfer length in block unit.
|
|
|
|
// TranLen0 is MSB, TranLen is LSB
|
|
|
|
//
|
|
|
|
Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
|
|
|
|
Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
|
|
|
|
|
|
|
|
ByteCount = SectorCount * BlockSize;
|
|
|
|
|
|
|
|
TimeOut = (UINT16) (SectorCount * 2000);
|
|
|
|
|
|
|
|
//
|
|
|
|
// send command packet
|
|
|
|
//
|
|
|
|
Status = PeiAtapiCommand (
|
|
|
|
PeiServices,
|
|
|
|
PeiBotDevice,
|
|
|
|
&Packet,
|
|
|
|
(UINT8) sizeof (ATAPI_PACKET_COMMAND),
|
|
|
|
(VOID *) PtrBuffer,
|
|
|
|
ByteCount,
|
|
|
|
EfiUsbDataIn,
|
|
|
|
TimeOut
|
|
|
|
);
|
|
|
|
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Lba32 += SectorCount;
|
|
|
|
PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
|
|
|
|
BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2018-06-27 15:08:52 +02:00
|
|
|
/**
|
2011-06-28 01:30:55 +02:00
|
|
|
Check if there is media according to sense data.
|
|
|
|
|
|
|
|
@param SenseData Pointer to sense data.
|
|
|
|
@param SenseCounts Count of sense data.
|
|
|
|
|
|
|
|
@retval TRUE No media
|
|
|
|
@retval FALSE Media exists
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
IsNoMedia (
|
|
|
|
IN ATAPI_REQUEST_SENSE_DATA *SenseData,
|
|
|
|
IN UINTN SenseCounts
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ATAPI_REQUEST_SENSE_DATA *SensePtr;
|
2015-05-20 08:31:28 +02:00
|
|
|
UINTN Index;
|
|
|
|
BOOLEAN NoMedia;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
NoMedia = FALSE;
|
|
|
|
SensePtr = SenseData;
|
|
|
|
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
|
|
|
|
switch (SensePtr->sense_key) {
|
|
|
|
|
|
|
|
case ATA_SK_NOT_READY:
|
|
|
|
switch (SensePtr->addnl_sense_code) {
|
|
|
|
//
|
|
|
|
// if no media, fill IdeDev parameter with specific info.
|
|
|
|
//
|
|
|
|
case ATA_ASC_NO_MEDIA:
|
|
|
|
NoMedia = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SensePtr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NoMedia;
|
|
|
|
}
|
|
|
|
|
2018-06-27 15:08:52 +02:00
|
|
|
/**
|
2011-06-28 01:30:55 +02:00
|
|
|
Check if there is media error according to sense data.
|
|
|
|
|
|
|
|
@param SenseData Pointer to sense data.
|
|
|
|
@param SenseCounts Count of sense data.
|
|
|
|
|
|
|
|
@retval TRUE Media error
|
|
|
|
@retval FALSE No media error
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
IsMediaError (
|
|
|
|
IN ATAPI_REQUEST_SENSE_DATA *SenseData,
|
2015-05-20 08:31:28 +02:00
|
|
|
IN UINTN SenseCounts
|
2011-06-28 01:30:55 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
ATAPI_REQUEST_SENSE_DATA *SensePtr;
|
2015-05-20 08:31:28 +02:00
|
|
|
UINTN Index;
|
|
|
|
BOOLEAN Error;
|
2011-06-28 01:30:55 +02:00
|
|
|
|
|
|
|
SensePtr = SenseData;
|
|
|
|
Error = FALSE;
|
|
|
|
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
|
|
|
|
switch (SensePtr->sense_key) {
|
|
|
|
//
|
|
|
|
// Medium error case
|
|
|
|
//
|
|
|
|
case ATA_SK_MEDIUM_ERROR:
|
|
|
|
switch (SensePtr->addnl_sense_code) {
|
|
|
|
case ATA_ASC_MEDIA_ERR1:
|
|
|
|
//
|
|
|
|
// fall through
|
|
|
|
//
|
|
|
|
case ATA_ASC_MEDIA_ERR2:
|
|
|
|
//
|
|
|
|
// fall through
|
|
|
|
//
|
|
|
|
case ATA_ASC_MEDIA_ERR3:
|
|
|
|
//
|
|
|
|
// fall through
|
|
|
|
//
|
|
|
|
case ATA_ASC_MEDIA_ERR4:
|
|
|
|
Error = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Medium upside-down case
|
|
|
|
//
|
|
|
|
case ATA_SK_NOT_READY:
|
|
|
|
switch (SensePtr->addnl_sense_code) {
|
|
|
|
case ATA_ASC_MEDIA_UPSIDE_DOWN:
|
|
|
|
Error = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SensePtr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Error;
|
|
|
|
}
|
|
|
|
|
2018-06-27 15:08:52 +02:00
|
|
|
/**
|
2011-06-28 01:30:55 +02:00
|
|
|
Check if media is changed according to sense data.
|
|
|
|
|
|
|
|
@param SenseData Pointer to sense data.
|
|
|
|
@param SenseCounts Count of sense data.
|
|
|
|
|
|
|
|
@retval TRUE There is media change event.
|
|
|
|
@retval FALSE media is NOT changed.
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
IsMediaChange (
|
|
|
|
IN ATAPI_REQUEST_SENSE_DATA *SenseData,
|
|
|
|
IN UINTN SenseCounts
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ATAPI_REQUEST_SENSE_DATA *SensePtr;
|
|
|
|
UINTN Index;
|
|
|
|
BOOLEAN MediaChange;
|
|
|
|
|
|
|
|
MediaChange = FALSE;
|
|
|
|
|
|
|
|
SensePtr = SenseData;
|
|
|
|
|
|
|
|
for (Index = 0; Index < SenseCounts; Index++) {
|
|
|
|
//
|
|
|
|
// catch media change sense key and addition sense data
|
|
|
|
//
|
|
|
|
switch (SensePtr->sense_key) {
|
|
|
|
case ATA_SK_UNIT_ATTENTION:
|
|
|
|
switch (SensePtr->addnl_sense_code) {
|
|
|
|
case ATA_ASC_MEDIA_CHANGE:
|
|
|
|
MediaChange = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SensePtr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MediaChange;
|
|
|
|
}
|