atapiextpassthru.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,448 行 · 第 1/5 页
C
2,448 行
AtapiScsiPrivate->IoPort->Alt.DeviceControl,
DeviceControlValue
);
//
// Wait 10us
//
gBS->Stall (10);
//
// Clear SRST bit
// 0xfb:1111,1011
//
DeviceControlValue &= 0xfb;
WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
//
// slave device needs at most 31s to clear BSY
//
if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000) == EFI_TIMEOUT) {
return EFI_DEVICE_ERROR;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AtapiExtScsiPassThruResetTarget (
IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
IN UINT8 *Target,
IN UINT64 Lun
)
/*++
Routine Description:
Resets a SCSI device that is connected to a SCSI channel.
Arguments:
This - Protocol instance pointer.
Target - The Target ID of the SCSI device to reset.
Lun - The LUN of the SCSI device to reset.
Returns:
EFI_SUCCESS - The SCSI device specified by Target and
Lun was reset.
EFI_UNSUPPORTED - The SCSI channel does not support a target
reset operation.
EFI_INVALID_PARAMETER - Target or Lun are invalid.
EFI_DEVICE_ERROR - A device error occurred while attempting
to reset the SCSI device specified by Target
and Lun.
EFI_TIMEOUT - A timeout occurred while attempting to reset
the SCSI device specified by Target and Lun.
--*/
{
UINT8 Command;
UINT8 DeviceSelect;
UINT32 TargetId;
ATAPI_EXT_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
TargetId = *(UINT32*)Target;
if (TargetId > MAX_TARGET_ID) {
return EFI_INVALID_PARAMETER;
}
//
// Directly return EFI_SUCCESS if want to reset the host controller
//
if (TargetId == This->Mode->AdapterId) {
return EFI_SUCCESS;
}
//
// According to Target ID, reset the Atapi I/O Register mapping
// (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
// Target Id in [2,3] area, using AtapiIoPortRegisters[1]
//
if ((TargetId / 2) == 0) {
AtapiScsiPrivate->IoPort = &AtapiIoPortRegisters[0];
} else {
AtapiScsiPrivate->IoPort = &AtapiIoPortRegisters[1];
}
//
// for ATAPI device, no need to wait DRDY ready after device selecting.
//
// bit7 and bit5 are both set to 1 for backward compatibility
//
DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (TargetId << 4)));
WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
Command = ATAPI_SOFT_RESET_CMD;
WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
//
// BSY clear is the only status return to the host by the device
// when reset is complete.
// slave device needs at most 31s to clear BSY
//
if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000))) {
return EFI_DEVICE_ERROR;
}
//
// stall 5 seconds to make the device status stable
//
gBS->Stall (5000000);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AtapiExtScsiPassThruGetNextTarget (
IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
IN OUT UINT8 **Target
)
/*++
Routine Description:
Used to retrieve the list of legal Target IDs for SCSI devices
on a SCSI channel.
Arguments:
This - Protocol instance pointer.
Target - On input, a pointer to the Target ID of a SCSI
device present on the SCSI channel. On output,
a pointer to the Target ID of the next SCSI device
present on a SCSI channel. An input value of
0xFFFFFFFF retrieves the Target ID of the first
SCSI device present on a SCSI channel.
Lun - On input, a pointer to the LUN of a SCSI device
present on the SCSI channel. On output, a pointer
to the LUN of the next SCSI device present on
a SCSI channel.
Returns:
EFI_SUCCESS - The Target ID and Lun of the next SCSI device
on the SCSI channel was returned in Target and Lun.
EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
returned on a previous call to GetNextDevice().
--*/
{
UINT32 TargetId;
ATAPI_EXT_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
//
// Retrieve Device Private Data Structure.
//
AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
//
// Check whether Target is valid.
//
TargetId = *(UINT32*)(*Target);
if (*Target == NULL ) {
return EFI_INVALID_PARAMETER;
}
if ((TargetId != 0xFFFFFFFF) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {
return EFI_INVALID_PARAMETER;
}
if (TargetId == MAX_TARGET_ID) {
return EFI_NOT_FOUND;
}
if (TargetId == 0xFFFFFFFF) {
*(UINT32*)(*Target) = 0x0;
} else {
*(UINT32*)(*Target) = AtapiScsiPrivate->LatestTargetId + 1;
}
//
// Update the LatestTargetId.
//
AtapiScsiPrivate->LatestTargetId = *(UINT32*)(*Target);
AtapiScsiPrivate->LatestLun = 0;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
CheckSCSIRequestPacket (
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
)
/*++
Routine Description:
Checks the parameters in the SCSI Request Packet to make sure
they are valid for a SCSI Pass Thru request.
Arguments:
Packet - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
Returns:
EFI_STATUS
--*/
{
if (Packet == NULL) {
return EFI_INVALID_PARAMETER;
}
if (!ValidCdbLength (Packet->CdbLength)) {
return EFI_INVALID_PARAMETER;
}
if (Packet->Cdb == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Checks whether the request command is supported.
//
if (!IsCommandValid (Packet)) {
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}
STATIC
BOOLEAN
IsCommandValid (
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
)
/*++
Routine Description:
Checks the requested SCSI command:
Is it supported by this driver?
Is the Data transfer direction reasonable?
Arguments:
Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
Returns:
EFI_STATUS
--*/
{
UINT8 Index;
UINT8 *OpCode;
OpCode = (UINT8 *) (Packet->Cdb);
for (Index = 0; EfiCompareMem (&SupportedATAPICommands[Index], &EndTable, sizeof (SCSI_COMMAND_SET)); Index++) {
if (*OpCode == SupportedATAPICommands[Index].OpCode) {
//
// Check whether the requested Command is supported by this driver
//
if (Packet->DataDirection == DataIn) {
//
// Check whether the requested data direction conforms to
// what it should be.
//
if (SupportedATAPICommands[Index].Direction == DataOut) {
return FALSE;
}
}
if (Packet->DataDirection == DataOut) {
//
// Check whether the requested data direction conforms to
// what it should be.
//
if (SupportedATAPICommands[Index].Direction == DataIn) {
return FALSE;
}
}
return TRUE;
}
}
return FALSE;
}
STATIC
EFI_STATUS
SubmitBlockingIoCommand (
ATAPI_EXT_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
UINT32 Target,
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
)
/*++
Routine Description:
Performs blocking I/O request.
Arguments:
AtapiScsiPrivate: Private data structure for the specified channel.
Target: The Target ID of the ATAPI device to send the SCSI
Request Packet. To ATAPI devices attached on an IDE
Channel, Target ID 0 indicates Master device;Target
ID 1 indicates Slave device.
Packet: The SCSI Request Packet to send to the ATAPI device
specified by Target.
Returns: EFI_STATUS
--*/
{
UINT8 PacketCommand[12];
UINT64 TimeoutInMicroSeconds;
EFI_STATUS PacketCommandStatus;
UINTN Remainder;
//
// Fill ATAPI Command Packet according to CDB
//
EfiZeroMem (&PacketCommand, 12);
EfiCopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
//
// Timeout is 100ns unit, convert it to 1000ns (1us) unit.
//
TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10, &Remainder);
//
// Submit ATAPI Command Packet
//
if (Packet->DataDirection == DataIn) {
PacketCommandStatus = AtapiPacketCommand (
AtapiScsiPrivate,
Target,
PacketCommand,
Packet->InDataBuffer,
&(Packet->InTransferLength),
DataIn,
TimeoutInMicroSeconds
);
} else {
PacketCommandStatus = AtapiPacketCommand (
AtapiScsiPrivate,
Target,
PacketCommand,
Packet->OutDataBuffer,
&(Packet->OutTransferLength),
DataOut,
TimeoutInMicroSeconds
);
}
if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
Packet->SenseDataLength = 0;
return PacketCommandStatus;
}
//
// Return SenseData if PacketCommandStatus matches
// the following return codes.
//
if ((PacketCommandStatus == EFI_WARN_BUFFER_TOO_SMALL) ||
(PacketCommandStatus == EFI_DEVICE_ERROR) ||
(PacketCommandStatus == EFI_TIMEOUT)) {
//
// avoid submit request sense command continuously.
//
if (PacketCommand[0] == OP_REQUEST_SENSE) {
Packet->SenseDataLength = 0;
return PacketCommandStatus;
}
RequestSenseCommand (
AtapiScsiPrivate,
Target,
Packet->Timeout,
Packet->SenseData,
&Packet->SenseDataLength
);
}
return PacketCommandStatus;
}
STATIC
EFI_STATUS
RequestSenseCommand (
ATAPI_EXT_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
UINT32 Target,
UINT64 Timeout,
VOID *SenseData,
UINT8 *SenseDataLength
)
/*++
Routine Description:
Sumbit request sense command
Arguments:
AtapiScsiPrivate - The pionter of ATAPI_SCSI_PASS_THRU_DEV
Target - The target ID
Timeout - The time to complete the command
SenseData - The buffer to fill in sense data
SenseDataLength - The length of buffer
Returns:
EFI_STATUS
--*/
{
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
UINT8 Cdb[12];
EFI_STATUS Status;
EfiZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
EfiZeroMem (Cdb, 12);
Cdb[0] = OP_REQUEST_SENSE;
Cdb[4] = (UINT8) (*SenseDataLength);
Packet.Timeout = Timeout;
Packet.InDataBuffer = SenseData;
Packet.SenseData = NULL;
Packet.Cdb = Cdb;
Packet.InTransferLength = *SenseDataLength;
Packet.CdbLength = 12;
Packet.DataDirection = DataIn;
Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);
*SenseDataLength = (UINT8) (Packet.InTransferLength);
return Status;
}
STATIC
EFI_STATUS
AtapiPacketCommand (
ATAPI_EXT_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
UINT32 Target,
UINT8 *PacketCommand,
VOID *Buffer,
UINT32 *ByteCount,
DATA_DIRECTION Direction,
UINT64 TimeoutInMicroSeconds
)
/*++
Routine Description:
Submits ATAPI command packet to the specified ATAPI device.
Arguments:
AtapiScsiPrivate: Private data structure for the specified channel.
Target: The Target ID of the ATAPI device to send the SCSI
Request Packet. To ATAPI devices attached on an IDE
Channel, Target ID 0 indicates Master device;Target
ID 1 indicates Slave device.
PacketCommand: Points to the ATAPI command packet.
Buffer: Points to the transferred data.
ByteCount: When input,indicates the buffer size; when output,
indicates the actually transferred data size.
Direction: Indicates the data transfer direction.
TimeoutInMicroSeconds:
The timeout, in micro second units, to use for the
execution of this ATAPI command.
A TimeoutInMicroSeconds value of 0 means that
this function will wait indefinitely for the ATAPI
command to execute.
If TimeoutInMicroSeconds is greater than zero, then
this function will return EFI_TIMEOUT if the time
required to execute the ATAPI command is greater
than TimeoutInMicroSeconds.
Returns:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?