/*++ | |
Copyright (c) 2006, Intel Corporation | |
All rights reserved. This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
Module Name: | |
UsbMassStorageHelper.c | |
Abstract: | |
Helper functions for USB Mass Storage Driver | |
Revision History | |
--*/ | |
#include "UsbMassStorageHelper.h" | |
STATIC | |
BOOLEAN | |
IsNoMedia ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
); | |
STATIC | |
BOOLEAN | |
IsMediaError ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
); | |
STATIC | |
BOOLEAN | |
IsMediaChange ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
); | |
STATIC | |
BOOLEAN | |
IsDriveReady ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts, | |
OUT BOOLEAN *NeedRetry | |
); | |
STATIC | |
BOOLEAN | |
IsMediaWriteProtected ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
); | |
STATIC | |
BOOLEAN | |
IsLogicalUnitCommunicationOverRun ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
); | |
EFI_STATUS | |
USBFloppyPacketCommand ( | |
USB_FLOPPY_DEV *UsbFloppyDevice, | |
VOID *Command, | |
UINT8 CommandSize, | |
VOID *DataBuffer, | |
UINT32 BufferLength, | |
EFI_USB_DATA_DIRECTION Direction, | |
UINT16 TimeOutInMilliSeconds | |
) | |
/*++ | |
Routine Description: | |
Sends Packet Command to USB Floppy Drive. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Command - A pointer to the command packet. | |
CommandSize - Indicates the size of the command packet. | |
DataBuffer - A pointer to the buffer for the data transfer | |
after the command packet. | |
BufferLength - Indicates the size of the Data Buffer. | |
Direction - Transfer Direction | |
TimeOutInMilliSeconds - Timeout Value | |
Returns: | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
EFI_STATUS Status; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
// | |
// Directly calling EFI_USB_ATAPI_PROTOCOL.UsbAtapiPacketCmd() | |
// to perform the command request. | |
// | |
Status = UsbAtapiInterface->UsbAtapiPacketCmd ( | |
UsbAtapiInterface, | |
Command, | |
CommandSize, | |
DataBuffer, | |
BufferLength, | |
Direction, | |
TimeOutInMilliSeconds | |
); | |
return Status; | |
} | |
EFI_STATUS | |
USBFloppyIdentify ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Retrieves device information to tell the device type. | |
Arguments: | |
UsbFloppyDevice The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
EFI_STATUS Status; | |
USB_INQUIRY_DATA *Idata; | |
BOOLEAN MediaChange; | |
// | |
// Send Inquiry Packet Command to get INQUIRY data. | |
// | |
Status = USBFloppyInquiry (UsbFloppyDevice, &Idata); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Get media removable info from INQUIRY data. | |
// | |
UsbFloppyDevice->BlkIo.Media->RemovableMedia = (UINT8) ((Idata->RMB & 0x80) == 0x80); | |
// | |
// Identify device type via INQUIRY data. | |
// | |
switch ((Idata->peripheral_type) & 0x1f) { | |
// | |
// Floppy | |
// | |
case 0x00: | |
UsbFloppyDevice->DeviceType = USBFLOPPY; | |
UsbFloppyDevice->BlkIo.Media->MediaId = 0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = 0; | |
UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; | |
break; | |
// | |
// CD-ROM | |
// | |
case 0x05: | |
UsbFloppyDevice->DeviceType = USBCDROM; | |
UsbFloppyDevice->BlkIo.Media->MediaId = 0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = 0; | |
UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800; | |
UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; | |
break; | |
default: | |
gBS->FreePool (Idata); | |
return EFI_DEVICE_ERROR; | |
}; | |
// | |
// Initialize some device specific data. | |
// | |
// | |
// original sense data numbers | |
// | |
UsbFloppyDevice->SenseDataNumber = 6; | |
if (UsbFloppyDevice->SenseData != NULL) { | |
gBS->FreePool (UsbFloppyDevice->SenseData); | |
UsbFloppyDevice->SenseData = NULL; | |
} | |
UsbFloppyDevice->SenseData = AllocatePool (UsbFloppyDevice->SenseDataNumber * sizeof (REQUEST_SENSE_DATA)); | |
if (UsbFloppyDevice->SenseData == NULL) { | |
gBS->FreePool (Idata); | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Get media information. | |
// | |
UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange); | |
gBS->FreePool (Idata); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
USBFloppyInquiry ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice, | |
OUT USB_INQUIRY_DATA **Idata | |
) | |
/*++ | |
Routine Description: | |
Send Inquiry Packet Command to device and retrieve Inquiry Data. | |
Arguments: | |
UsbFloppyDevice The USB_FLOPPY_DEV instance. | |
Idata A pointer pointing to the address of | |
Inquiry Data. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_STATUS Status; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
// | |
// prepare command packet for the Inquiry Packet Command. | |
// | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.Inquiry.opcode = INQUIRY; | |
Packet.Inquiry.page_code = 0; | |
Packet.Inquiry.allocation_length = sizeof (USB_INQUIRY_DATA); | |
*Idata = AllocateZeroPool (sizeof (USB_INQUIRY_DATA)); | |
if (*Idata == NULL) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Send command packet and retrieve requested Inquiry Data. | |
// | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) (*Idata), | |
sizeof (USB_INQUIRY_DATA), | |
EfiUsbDataIn, | |
USBFLPTIMEOUT * 3 | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->FreePool (*Idata); | |
return EFI_DEVICE_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
USBFloppyRead10 ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice, | |
IN VOID *Buffer, | |
IN EFI_LBA Lba, | |
IN UINTN NumberOfBlocks | |
) | |
/*++ | |
Routine Description: | |
Sends Read10 Packet Command to device to perform data transfer | |
from device to host. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Buffer - A pointer to the destination buffer for the data. | |
The caller is responsible for either having implicit | |
or explicit ownership of the buffer. | |
Lba - The starting logical block address to read from | |
on the device. | |
NumberOfBlocks - Indicates the number of blocks that the read | |
operation requests. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
ATAPI_PACKET_COMMAND Packet; | |
READ10_CMD *Read10Packet; | |
UINT16 MaxBlock; | |
UINT16 BlocksRemaining; | |
UINT16 SectorCount; | |
UINT32 Lba32; | |
UINT32 BlockSize; | |
UINT32 ByteCount; | |
VOID *ptrBuffer; | |
EFI_STATUS Status; | |
UINT16 TimeOut; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UINTN SenseCounts; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
// | |
// prepare command packet for the Inquiry Packet Command. | |
// | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Read10Packet = &Packet.Read10; | |
Lba32 = (UINT32) Lba; | |
ptrBuffer = Buffer; | |
BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize; | |
MaxBlock = (UINT16) (65536 / 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 = 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 * USBFLPTIMEOUT); | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) ptrBuffer, | |
ByteCount, | |
EfiUsbDataIn, | |
TimeOut | |
); | |
if (EFI_ERROR (Status)) { | |
Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); | |
if (!EFI_ERROR (Status)) { | |
if (IsLogicalUnitCommunicationOverRun ( | |
UsbFloppyDevice->SenseData, | |
SenseCounts | |
)) { | |
Lba32 = (UINT32) Lba; | |
ptrBuffer = Buffer; | |
BlocksRemaining = (UINT16) NumberOfBlocks; | |
MaxBlock = (UINT16) (MaxBlock / 4); | |
if (MaxBlock < 1) { | |
MaxBlock = 1; | |
} | |
continue; | |
} | |
} else { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// retry read10 command | |
// | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) ptrBuffer, | |
ByteCount, | |
EfiUsbDataIn, | |
TimeOut | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
} | |
Lba32 += SectorCount; | |
ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize; | |
BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); | |
} | |
return Status; | |
} | |
EFI_STATUS | |
USBFloppyReadCapacity ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Retrieves media capacity information via | |
sending Read Capacity Packet Command. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
// | |
// status returned by Read Capacity Packet Command | |
// | |
EFI_STATUS Status; | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
// | |
// used for capacity data returned from Usb Floppy | |
// | |
READ_CAPACITY_DATA Data; | |
ZeroMem (&Data, sizeof (Data)); | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.Inquiry.opcode = READ_CAPACITY; | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) &Data, | |
sizeof (READ_CAPACITY_DATA), | |
EfiUsbDataIn, | |
USBFLPTIMEOUT | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
UsbFloppyDevice->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) | | |
(Data.LastLba2 << 16) | | |
(Data.LastLba1 << 8) | | |
Data.LastLba0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; | |
UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
USBFloppyReadFormatCapacity ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Retrieves media capacity information via sending Read Format | |
Capacity Packet Command. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
// | |
// status returned by Read Capacity Packet Command | |
// | |
EFI_STATUS Status; | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
// | |
// used for capacity data returned from Usb Floppy | |
// | |
READ_FORMAT_CAPACITY_DATA FormatData; | |
ZeroMem (&FormatData, sizeof (FormatData)); | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY; | |
Packet.ReadFormatCapacity.allocation_length_lo = 12; | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) &FormatData, | |
sizeof (READ_FORMAT_CAPACITY_DATA), | |
EfiUsbDataIn, | |
USBFLPTIMEOUT | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
if (FormatData.DesCode == 3) { | |
// | |
// Media is not present | |
// | |
UsbFloppyDevice->BlkIo.Media->MediaId = 0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = 0; | |
} else { | |
UsbFloppyDevice->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) | | |
(FormatData.LastLba2 << 16) | | |
(FormatData.LastLba1 << 8) | | |
FormatData.LastLba0; | |
UsbFloppyDevice->BlkIo.Media->LastBlock--; | |
UsbFloppyDevice->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) | | |
(FormatData.BlockSize1 << 8) | | |
FormatData.BlockSize0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; | |
UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UsbFloppyRequestSense ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice, | |
OUT UINTN *SenseCounts | |
) | |
/*++ | |
Routine Description: | |
Retrieves Sense Data from device via | |
sending Request Sense Packet Command. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
SenseCounts - A pointer to the number of Sense Data returned. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
EFI_STATUS Status; | |
REQUEST_SENSE_DATA *Sense; | |
UINT8 *Ptr; | |
BOOLEAN SenseReq; | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
*SenseCounts = 0; | |
ZeroMem ( | |
UsbFloppyDevice->SenseData, | |
sizeof (REQUEST_SENSE_DATA) * (UsbFloppyDevice->SenseDataNumber) | |
); | |
// | |
// fill command packet for Request Sense Packet Command | |
// | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.RequestSense.opcode = REQUEST_SENSE; | |
Packet.RequestSense.allocation_length = sizeof (REQUEST_SENSE_DATA); | |
// | |
// initialize pointer | |
// | |
Ptr = (UINT8 *) (UsbFloppyDevice->SenseData); | |
// | |
// request sense data from device continuously | |
// until no sense data exists in the device. | |
// | |
for (SenseReq = TRUE; SenseReq;) { | |
Sense = (REQUEST_SENSE_DATA *) Ptr; | |
// | |
// send out Request Sense Packet Command and get one Sense | |
// data from device. | |
// | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) Ptr, | |
sizeof (REQUEST_SENSE_DATA), | |
EfiUsbDataIn, | |
USBFLPTIMEOUT | |
); | |
// | |
// failed to get Sense data | |
// | |
if (EFI_ERROR (Status)) { | |
// | |
// Recovery the device back to normal state. | |
// | |
UsbFloppyDevice->AtapiProtocol->UsbAtapiReset ( | |
UsbFloppyDevice->AtapiProtocol, | |
TRUE | |
); | |
if (*SenseCounts == 0) { | |
// | |
// never retrieved any sense data from device, | |
// just return error. | |
// | |
return EFI_DEVICE_ERROR; | |
} else { | |
// | |
// has retrieved some sense data from device, | |
// so return success. | |
// | |
return EFI_SUCCESS; | |
} | |
} | |
if (Sense->sense_key != SK_NO_SENSE) { | |
// | |
// Ptr is byte based pointer | |
// | |
Ptr += sizeof (REQUEST_SENSE_DATA); | |
(*SenseCounts)++; | |
} else { | |
// | |
// when no sense key, skip out the loop | |
// | |
SenseReq = FALSE; | |
} | |
// | |
// If the sense key numbers exceed Sense Data Buffer size, | |
// just skip the loop and do not fetch the sense key in this function. | |
// | |
if (*SenseCounts == UsbFloppyDevice->SenseDataNumber) { | |
SenseReq = FALSE; | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UsbFloppyTestUnitReady ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Sends Test Unit ReadyPacket Command to the device. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_STATUS Status; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UINT32 RetryIndex; | |
UINT32 MaximumRetryTimes; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
MaximumRetryTimes = 2; | |
// | |
// fill command packet | |
// | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.TestUnitReady.opcode = TEST_UNIT_READY; | |
// | |
// send command packet | |
// | |
Status = EFI_DEVICE_ERROR; | |
for (RetryIndex = 0; RetryIndex < MaximumRetryTimes && EFI_ERROR (Status); RetryIndex++) { | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
NULL, | |
0, | |
EfiUsbNoData, | |
USBFLPTIMEOUT | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->Stall (100 * STALL_1_MILLI_SECOND); | |
} | |
} | |
return Status; | |
} | |
EFI_STATUS | |
USBFloppyWrite10 ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice, | |
IN VOID *Buffer, | |
IN EFI_LBA Lba, | |
IN UINTN NumberOfBlocks | |
) | |
/*++ | |
Routine Description: | |
Sends Write10 Packet Command to device to perform data transfer | |
from host to device. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Buffer - A pointer to the source buffer for the data. | |
The caller is responsible for either having implicit | |
or explicit ownership of the buffer. | |
Lba - The starting logical block address to written to | |
the device. | |
NumberOfBlocks - Indicates the number of blocks that the write | |
operation requests. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
ATAPI_PACKET_COMMAND Packet; | |
READ10_CMD *Write10Packet; | |
UINT16 MaxBlock; | |
UINT16 BlocksRemaining; | |
UINT16 SectorCount; | |
UINT32 Lba32; | |
UINT32 BlockSize; | |
UINT32 ByteCount; | |
VOID *ptrBuffer; | |
EFI_STATUS Status; | |
UINT16 TimeOut; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UINTN SenseCounts; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
// | |
// prepare command packet for the Write10 Packet Command. | |
// | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Write10Packet = &Packet.Read10; | |
Lba32 = (UINT32) Lba; | |
ptrBuffer = Buffer; | |
BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize; | |
MaxBlock = (UINT16) (65536 / BlockSize); | |
BlocksRemaining = (UINT16) NumberOfBlocks; | |
Status = EFI_SUCCESS; | |
while (BlocksRemaining > 0) { | |
if (BlocksRemaining <= MaxBlock) { | |
SectorCount = BlocksRemaining; | |
} else { | |
SectorCount = MaxBlock; | |
} | |
// | |
// fill the Packet data structure | |
// | |
Write10Packet->opcode = WRITE_10; | |
// | |
// Lba0 ~ Lba3 specify the start logical block address | |
// of the data transfer. | |
// Lba0 is MSB, Lba3 is LSB | |
// | |
Write10Packet->Lba3 = (UINT8) (Lba32 & 0xff); | |
Write10Packet->Lba2 = (UINT8) (Lba32 >> 8); | |
Write10Packet->Lba1 = (UINT8) (Lba32 >> 16); | |
Write10Packet->Lba0 = (UINT8) (Lba32 >> 24); | |
// | |
// TranLen0 ~ TranLen1 specify the transfer length in block unit. | |
// TranLen0 is MSB, TranLen is LSB | |
// | |
Write10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); | |
Write10Packet->TranLen0 = (UINT8) (SectorCount >> 8); | |
ByteCount = SectorCount * BlockSize; | |
TimeOut = (UINT16) (SectorCount * USBFLPTIMEOUT); | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) ptrBuffer, | |
ByteCount, | |
EfiUsbDataOut, | |
TimeOut | |
); | |
if (EFI_ERROR (Status)) { | |
Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); | |
if (!EFI_ERROR (Status)) { | |
if (IsLogicalUnitCommunicationOverRun ( | |
UsbFloppyDevice->SenseData, | |
SenseCounts | |
)) { | |
Lba32 = (UINT32) Lba; | |
ptrBuffer = Buffer; | |
BlocksRemaining = (UINT16) NumberOfBlocks; | |
MaxBlock = (UINT16) (MaxBlock / 4); | |
if (MaxBlock < 1) { | |
MaxBlock = 1; | |
} | |
continue; | |
} | |
} | |
// | |
// retry write10 command | |
// | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) ptrBuffer, | |
ByteCount, | |
EfiUsbDataOut, | |
TimeOut | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
} | |
Lba32 += SectorCount; | |
ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize; | |
BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); | |
} | |
return Status; | |
} | |
EFI_STATUS | |
UsbFloppyDetectMedia ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice, | |
OUT BOOLEAN *MediaChange | |
) | |
/*++ | |
Routine Description: | |
Retrieves media information. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
MediaChange - Indicates whether media was changed. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
EFI_INVALID_PARAMETER - Parameter is error | |
--*/ | |
{ | |
EFI_STATUS Status; | |
EFI_STATUS FloppyStatus; | |
// | |
// the following variables are used to record previous media information | |
// | |
EFI_BLOCK_IO_MEDIA OldMediaInfo; | |
UINTN SenseCounts; | |
UINTN RetryIndex; | |
UINTN RetryTimes; | |
UINTN MaximumRetryTimes; | |
BOOLEAN NeedRetry; | |
// | |
// a flag used to determine whether need to perform Read Capacity command. | |
// | |
BOOLEAN NeedReadCapacity; | |
REQUEST_SENSE_DATA *SensePtr; | |
// | |
// init | |
// | |
Status = EFI_SUCCESS; | |
FloppyStatus = EFI_SUCCESS; | |
CopyMem (&OldMediaInfo, UsbFloppyDevice->BlkIo.Media, sizeof (OldMediaInfo)); | |
//OldMediaInfo = *UsbFloppyDevice->BlkIo.Media; | |
*MediaChange = FALSE; | |
NeedReadCapacity = TRUE; | |
// | |
// if there is no media present,or media not changed, | |
// the request sense command will detect faster than read capacity command. | |
// read capacity command can be bypassed, thus improve performance. | |
// | |
SenseCounts = 0; | |
Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); | |
if (!EFI_ERROR (Status)) { | |
SensePtr = UsbFloppyDevice->SenseData; | |
// | |
// No Media | |
// | |
if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) { | |
NeedReadCapacity = FALSE; | |
UsbFloppyDevice->BlkIo.Media->MediaId = 0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = 0; | |
} else { | |
// | |
// Media Changed | |
// | |
if (IsMediaChange (UsbFloppyDevice->SenseData, SenseCounts)) { | |
UsbFloppyDevice->BlkIo.Media->MediaId++; | |
} | |
// | |
// Media Write-protected | |
// | |
if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) { | |
UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; | |
} | |
// | |
// Media Error | |
// | |
if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) { | |
// | |
// if media error encountered, make it look like no media present. | |
// | |
UsbFloppyDevice->BlkIo.Media->MediaId = 0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = 0; | |
} | |
} | |
} | |
if (NeedReadCapacity) { | |
// | |
// at most retry 5 times | |
// | |
MaximumRetryTimes = 5; | |
// | |
// initial retry twice | |
// | |
RetryTimes = 2; | |
for (RetryIndex = 0; (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); RetryIndex++) { | |
// | |
// Using different command to retrieve media capacity. | |
// | |
switch (UsbFloppyDevice->DeviceType) { | |
case USBCDROM: | |
Status = USBFloppyReadCapacity (UsbFloppyDevice); | |
break; | |
case USBFLOPPY: | |
UsbMassStorageModeSense (UsbFloppyDevice); | |
Status = USBFloppyReadFormatCapacity (UsbFloppyDevice); | |
if (EFI_ERROR (Status) || !UsbFloppyDevice->BlkMedia.MediaPresent) { | |
// | |
// retry the ReadCapacity command | |
// | |
UsbFloppyDevice->DeviceType = USBFLOPPY2; | |
Status = EFI_DEVICE_ERROR; | |
} | |
break; | |
case USBFLOPPY2: | |
UsbMassStorageModeSense (UsbFloppyDevice); | |
Status = USBFloppyReadCapacity (UsbFloppyDevice); | |
if (EFI_ERROR (Status)) { | |
// | |
// retry the ReadFormatCapacity command | |
// | |
UsbFloppyDevice->DeviceType = USBFLOPPY; | |
} | |
// | |
// force the BlockSize to be 0x200. | |
// | |
UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; | |
break; | |
default: | |
return EFI_INVALID_PARAMETER; | |
} | |
if (!EFI_ERROR (Status)) { | |
// | |
// skip the loop when read capacity succeeds. | |
// | |
break; | |
} | |
SenseCounts = 0; | |
FloppyStatus = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); | |
// | |
// If Request Sense data failed,retry. | |
// | |
if (EFI_ERROR (FloppyStatus)) { | |
// | |
// retry once more | |
// | |
RetryTimes++; | |
continue; | |
} | |
// | |
// No Media | |
// | |
if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) { | |
UsbFloppyDevice->BlkIo.Media->MediaId = 0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = 0; | |
break; | |
} | |
if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) { | |
// | |
// if media error encountered, make it look like no media present. | |
// | |
UsbFloppyDevice->BlkIo.Media->MediaId = 0; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = 0; | |
break; | |
} | |
if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) { | |
UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; | |
continue; | |
} | |
if (!IsDriveReady (UsbFloppyDevice->SenseData, SenseCounts, &NeedRetry)) { | |
// | |
// Drive not ready: if NeedRetry, then retry once more; | |
// else return error | |
// | |
if (NeedRetry) { | |
// | |
// Stall 0.1 second to wait for drive becoming ready | |
// | |
gBS->Stall (100 * STALL_1_MILLI_SECOND); | |
// | |
// reset retry variable to zero, | |
// to make it retry for "drive in progress of becoming ready". | |
// | |
RetryIndex = 0; | |
continue; | |
} else { | |
return EFI_DEVICE_ERROR; | |
} | |
} | |
// | |
// if read capacity fail not for above reasons, retry once more | |
// | |
RetryTimes++; | |
} | |
// | |
// ENDFOR | |
// | |
// | |
// tell whether the readcapacity process is successful or not | |
// ("Status" variable record the latest status returned | |
// by ReadCapacity AND "FloppyStatus" record the latest status | |
// returned by RequestSense) | |
// | |
if (EFI_ERROR (Status) && EFI_ERROR (FloppyStatus)) { | |
return EFI_DEVICE_ERROR; | |
} | |
} | |
if (UsbFloppyDevice->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) { | |
if (UsbFloppyDevice->BlkIo.Media->MediaPresent) { | |
UsbFloppyDevice->BlkIo.Media->MediaId = 1; | |
} | |
*MediaChange = TRUE; | |
} | |
if (UsbFloppyDevice->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) { | |
*MediaChange = TRUE; | |
UsbFloppyDevice->BlkIo.Media->MediaId += 1; | |
} | |
if (UsbFloppyDevice->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) { | |
*MediaChange = TRUE; | |
UsbFloppyDevice->BlkIo.Media->MediaId += 1; | |
} | |
if (UsbFloppyDevice->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) { | |
*MediaChange = TRUE; | |
UsbFloppyDevice->BlkIo.Media->MediaId += 1; | |
} | |
if (UsbFloppyDevice->BlkIo.Media->MediaId != OldMediaInfo.MediaId) { | |
*MediaChange = TRUE; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UsbFloppyModeSense5APage5 ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Retrieves media capacity information via sending Read Format | |
Capacity Packet Command. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
// | |
// status returned by Read Capacity Packet Command | |
// | |
EFI_STATUS Status; | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UFI_MODE_PARAMETER_PAGE_5 ModePage5; | |
EFI_LBA LastBlock; | |
UINT32 SectorsPerTrack; | |
UINT32 NumberOfCylinders; | |
UINT32 NumberOfHeads; | |
UINT32 DataBytesPerSector; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
ZeroMem (&ModePage5, sizeof (UFI_MODE_PARAMETER_PAGE_5)); | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; | |
// | |
// Flexible Disk Page | |
// | |
Packet.ModeSenseUFI.page_code = 5; | |
// | |
// current values | |
// | |
Packet.ModeSenseUFI.page_control = 0; | |
Packet.ModeSenseUFI.parameter_list_length_hi = 0; | |
Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_5); | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) &ModePage5, | |
sizeof (UFI_MODE_PARAMETER_PAGE_5), | |
EfiUsbDataIn, | |
USBFLPTIMEOUT | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
NumberOfHeads = ModePage5.flex_disk_page.number_of_heads; | |
SectorsPerTrack = ModePage5.flex_disk_page.sectors_per_track; | |
NumberOfCylinders = ModePage5.flex_disk_page.number_of_cylinders_msb << 8 | | |
ModePage5.flex_disk_page.number_of_cylinders_lsb; | |
LastBlock = SectorsPerTrack * NumberOfHeads * NumberOfCylinders; | |
DataBytesPerSector = ModePage5.flex_disk_page.databytes_per_sector_msb << 8 | | |
ModePage5.flex_disk_page.databytes_per_sector_lsb; | |
UsbFloppyDevice->BlkIo.Media->LastBlock = LastBlock; | |
UsbFloppyDevice->BlkIo.Media->LastBlock--; | |
UsbFloppyDevice->BlkIo.Media->BlockSize = DataBytesPerSector; | |
UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; | |
UsbFloppyDevice->BlkIo.Media->ReadOnly = | |
ModePage5.mode_param_header.write_protected; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UsbFloppyModeSense5APage1C ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Retrieves media capacity information via sending Read Format | |
Capacity Packet Command. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
// | |
// status returned by Read Capacity Packet Command | |
// | |
EFI_STATUS Status; | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UFI_MODE_PARAMETER_PAGE_1C ModePage1C; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
ZeroMem (&ModePage1C, sizeof (UFI_MODE_PARAMETER_PAGE_1C)); | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; | |
// | |
// Flexible Disk Page | |
// | |
Packet.ModeSenseUFI.page_code = 0x1C; | |
// | |
// current values | |
// | |
Packet.ModeSenseUFI.page_control = 0; | |
Packet.ModeSenseUFI.parameter_list_length_hi = 0; | |
Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_1C); | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
(VOID *) &ModePage1C, | |
sizeof (UFI_MODE_PARAMETER_PAGE_1C), | |
EfiUsbDataIn, | |
USBFLPTIMEOUT | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
UsbFloppyDevice->BlkIo.Media->ReadOnly = ModePage1C.mode_param_header.write_protected; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UsbMassStorageModeSense ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
{ | |
if (UsbFloppyDevice->AtapiProtocol->CommandProtocol == EFI_USB_SUBCLASS_SCSI) { | |
return UsbSCSIModeSense1APage3F (UsbFloppyDevice); | |
} else { | |
return UsbFloppyModeSense5APage3F (UsbFloppyDevice); | |
} | |
} | |
EFI_STATUS | |
UsbFloppyModeSense5APage3F ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Retrieves mode sense information via sending Mode Sense | |
Packet Command. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
// | |
// status returned by Read Capacity Packet Command | |
// | |
EFI_STATUS Status; | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
UFI_MODE_PARAMETER_HEADER Header; | |
UINT32 Size; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
Size = sizeof (UFI_MODE_PARAMETER_HEADER); | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; | |
Packet.ModeSenseUFI.page_code = 0x3F; | |
Packet.ModeSenseUFI.page_control = 0; | |
Packet.ModeSenseUFI.parameter_list_length_hi = 0; | |
Packet.ModeSenseUFI.parameter_list_length_lo = (UINT8) Size; | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (ATAPI_PACKET_COMMAND), | |
&Header, | |
Size, | |
EfiUsbDataIn, | |
USBFLPTIMEOUT | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UsbSCSIModeSense1APage3F ( | |
IN USB_FLOPPY_DEV *UsbFloppyDevice | |
) | |
/*++ | |
Routine Description: | |
Retrieves mode sense information via sending Mode Sense | |
Packet Command. | |
Arguments: | |
UsbFloppyDevice - The USB_FLOPPY_DEV instance. | |
Returns: | |
EFI_DEVICE_ERROR - Hardware error | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
// | |
// status returned by Read Capacity Packet Command | |
// | |
EFI_STATUS Status; | |
ATAPI_PACKET_COMMAND Packet; | |
EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; | |
SCSI_MODE_PARAMETER_HEADER6 Header; | |
UINT32 Size; | |
UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; | |
Size = sizeof (SCSI_MODE_PARAMETER_HEADER6); | |
ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); | |
Packet.ModeSenseSCSI.opcode = SCSI_MODE_SENSE1A; | |
Packet.ModeSenseSCSI.page_code = 0x3F; | |
Packet.ModeSenseSCSI.page_control = 0; | |
Packet.ModeSenseSCSI.allocation_length = (UINT8) Size; | |
Status = USBFloppyPacketCommand ( | |
UsbFloppyDevice, | |
&Packet, | |
sizeof (MODE_SENSE_CMD_SCSI), | |
&Header, | |
Size, | |
EfiUsbDataIn, | |
USBFLPTIMEOUT | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected; | |
return EFI_SUCCESS; | |
} | |
/*++ | |
The following functions are a set of helper functions, | |
which are used to parse sense key returned by the device. | |
--*/ | |
BOOLEAN | |
IsNoMedia ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
) | |
{ | |
REQUEST_SENSE_DATA *SensePtr; | |
UINTN Index; | |
BOOLEAN NoMedia; | |
NoMedia = FALSE; | |
SensePtr = SenseData; | |
for (Index = 0; Index < SenseCounts; Index++) { | |
if ((SensePtr->sense_key == SK_NOT_READY) && | |
(SensePtr->addnl_sense_code == ASC_NO_MEDIA)) { | |
NoMedia = TRUE; | |
} | |
SensePtr++; | |
} | |
return NoMedia; | |
} | |
BOOLEAN | |
IsMediaError ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
) | |
{ | |
REQUEST_SENSE_DATA *SensePtr; | |
UINTN Index; | |
BOOLEAN IsError; | |
IsError = FALSE; | |
SensePtr = SenseData; | |
for (Index = 0; Index < SenseCounts; Index++) { | |
switch (SensePtr->sense_key) { | |
// | |
// Medium error case | |
// | |
case SK_MEDIUM_ERROR: | |
switch (SensePtr->addnl_sense_code) { | |
case ASC_MEDIA_ERR1: | |
case ASC_MEDIA_ERR2: | |
case ASC_MEDIA_ERR3: | |
case ASC_MEDIA_ERR4: | |
IsError = TRUE; | |
break; | |
default: | |
break; | |
} | |
break; | |
// | |
// Medium upside-down case | |
// | |
case SK_NOT_READY: | |
switch (SensePtr->addnl_sense_code) { | |
case ASC_MEDIA_UPSIDE_DOWN: | |
IsError = TRUE; | |
break; | |
default: | |
break; | |
} | |
break; | |
default: | |
break; | |
} | |
SensePtr++; | |
} | |
return IsError; | |
} | |
BOOLEAN | |
IsMediaChange ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
) | |
{ | |
REQUEST_SENSE_DATA *SensePtr; | |
UINTN Index; | |
BOOLEAN MediaChanged; | |
MediaChanged = FALSE; | |
SensePtr = SenseData; | |
for (Index = 0; Index < SenseCounts; Index++) { | |
if ((SensePtr->sense_key == SK_UNIT_ATTENTION) && | |
(SensePtr->addnl_sense_code == ASC_MEDIA_CHANGE)) { | |
MediaChanged = TRUE; | |
} | |
SensePtr++; | |
} | |
return MediaChanged; | |
} | |
BOOLEAN | |
IsDriveReady ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts, | |
OUT BOOLEAN *NeedRetry | |
) | |
{ | |
REQUEST_SENSE_DATA *SensePtr; | |
UINTN Index; | |
BOOLEAN IsReady; | |
IsReady = TRUE; | |
*NeedRetry = FALSE; | |
SensePtr = SenseData; | |
for (Index = 0; Index < SenseCounts; Index++) { | |
if ((SensePtr->sense_key == SK_NOT_READY) && | |
(SensePtr->addnl_sense_code == ASC_NOT_READY)) { | |
switch (SensePtr->addnl_sense_code_qualifier) { | |
case ASCQ_IN_PROGRESS: | |
case ASCQ_DEVICE_BUSY: | |
IsReady = FALSE; | |
*NeedRetry = TRUE; | |
break; | |
default: | |
// | |
// Drive is in error condition, | |
// no need to retry. | |
// | |
IsReady = FALSE; | |
*NeedRetry = FALSE; | |
break; | |
} | |
} | |
SensePtr++; | |
} | |
return IsReady; | |
} | |
BOOLEAN | |
IsMediaWriteProtected ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
) | |
{ | |
REQUEST_SENSE_DATA *SensePtr; | |
UINTN Index; | |
BOOLEAN IsWriteProtected; | |
IsWriteProtected = FALSE; | |
SensePtr = SenseData; | |
for (Index = 0; Index < SenseCounts; Index++) { | |
// | |
// catch media write-protected condition. | |
// | |
if ((SensePtr->sense_key == SK_DATA_PROTECT) && | |
(SensePtr->addnl_sense_code == ASC_WRITE_PROTECTED)) { | |
IsWriteProtected = TRUE; | |
} | |
SensePtr++; | |
} | |
return IsWriteProtected; | |
} | |
BOOLEAN | |
IsLogicalUnitCommunicationOverRun ( | |
IN REQUEST_SENSE_DATA *SenseData, | |
IN UINTN SenseCounts | |
) | |
{ | |
REQUEST_SENSE_DATA *SensePtr; | |
UINTN Index; | |
BOOLEAN IsOverRun; | |
IsOverRun = FALSE; | |
SensePtr = SenseData; | |
for (Index = 0; Index < SenseCounts; Index++) { | |
if ((SensePtr->sense_key == SK_NOT_READY) && | |
(SensePtr->addnl_sense_code == ASC_LOGICAL_UNIT_STATUS) && | |
(SensePtr->addnl_sense_code_qualifier == ASCQ_LOGICAL_UNIT_OVERRUN)) { | |
IsOverRun = TRUE; | |
} | |
SensePtr++; | |
} | |
return IsOverRun; | |
} |