atapipassthru.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,442 行 · 第 1/5 页
C
2,442 行
Lun: The LUN of the ATAPI device to send the SCSI Request
Packet. To the ATAPI device, Lun is always 0.
Packet: The SCSI Request Packet to send to the ATAPI device
specified by Target and Lun.
Event: If non-blocking I/O is not supported then Event is ignored,
and blocking I/O is performed.
If Event is NULL, then blocking I/O is performed.
If Event is not NULL and non blocking I/O is supported,
then non-blocking I/O is performed, and Event will be signaled
when the SCSI Request Packet completes.
Returns:
EFI_STATUS
--*/
{
ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
EFI_STATUS Status;
#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET CommandPacket;
EFI_SCSI_IO_SCSI_REQUEST_PACKET *RequestPacket;
//
//Transfer EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
//
RequestPacket = (EFI_SCSI_IO_SCSI_REQUEST_PACKET*)Packet;
Status = PacketSwitch (RequestPacket, &CommandPacket);
if (EFI_ERROR (Status)) {
return Status;
}
#endif
AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
//
// Target is not allowed beyond MAX_TARGET_ID
//
if (Target > MAX_TARGET_ID) {
return EFI_INVALID_PARAMETER;
}
//
// check the data fields in Packet parameter.
//
#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
Status = CheckSCSIRequestPacket (&CommandPacket);
#else
Status = CheckSCSIRequestPacket (Packet);
#endif
if (EFI_ERROR (Status)) {
return Status;
}
//
// If Request Packet targets at the IDE channel itself,
// do nothing.
//
if (Target == This->Mode->AdapterId) {
#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
CommandPacket.TransferLength = 0;
#else
Packet->TransferLength = 0;
#endif
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 ((Target / 2) == 0) {
AtapiScsiPrivate->IoPort = &AtapiIoPortRegisters[0];
} else {
AtapiScsiPrivate->IoPort = &AtapiIoPortRegisters[1];
}
//
// the ATAPI SCSI interface does not support non-blocking I/O
// ignore the Event parameter
//
// Performs blocking I/O.
//
#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &CommandPacket);
#else
Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);
#endif
return Status;
}
EFI_STATUS
EFIAPI
AtapiScsiPassThruGetNextDevice (
IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
IN OUT UINT32 *Target,
IN OUT UINT64 *Lun
)
/*++
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().
--*/
{
ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
//
// Retrieve Device Private Data Structure.
//
AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
//
// Check whether Target is valid.
//
if (Target == NULL || Lun == NULL) {
return EFI_INVALID_PARAMETER;
}
if ((*Target != 0xFFFFFFFF) &&
((*Target != AtapiScsiPrivate->LatestTargetId) ||
(*Lun != AtapiScsiPrivate->LatestLun))) {
return EFI_INVALID_PARAMETER;
}
if (*Target == MAX_TARGET_ID) {
return EFI_NOT_FOUND;
}
if (*Target == 0xFFFFFFFF) {
*Target = 0;
} else {
*Target = AtapiScsiPrivate->LatestTargetId + 1;
}
*Lun = 0;
//
// Update the LatestTargetId.
//
AtapiScsiPrivate->LatestTargetId = *Target;
AtapiScsiPrivate->LatestLun = *Lun;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AtapiScsiPassThruBuildDevicePath (
IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
IN UINT32 Target,
IN UINT64 Lun,
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
)
/*++
Routine Description:
Used to allocate and build a device path node for a SCSI device
on a SCSI channel. Would not build device path for a SCSI Host Controller.
Arguments:
This - Protocol instance pointer.
Target - The Target ID of the SCSI device for which
a device path node is to be allocated and built.
Lun - The LUN of the SCSI device for which a device
path node is to be allocated and built.
DevicePath - A pointer to a single device path node that
describes the SCSI device specified by
Target and Lun. This function is responsible
for allocating the buffer DevicePath with the boot
service AllocatePool(). It is the caller's
responsibility to free DevicePath when the caller
is finished with DevicePath.
Returns:
EFI_SUCCESS - The device path node that describes the SCSI device
specified by Target and Lun was allocated and
returned in DevicePath.
EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
not exist on the SCSI channel.
EFI_INVALID_PARAMETER - DevicePath is NULL.
EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
DevicePath.
--*/
{
ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
EFI_DEV_PATH *Node;
//
// Retrieve Device Private Data Structure.
//
AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
//
// Validate parameters passed in.
//
if (DevicePath == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// can not build device path for the SCSI Host Controller.
//
if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
return EFI_NOT_FOUND;
}
Node = EfiLibAllocateZeroPool (sizeof (EFI_DEV_PATH));
if (Node == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Node->DevPath.Type = MESSAGING_DEVICE_PATH;
Node->DevPath.SubType = MSG_ATAPI_DP;
SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
Node->Atapi.PrimarySecondary = (UINT8) (Target / 2);
Node->Atapi.SlaveMaster = (UINT8) (Target % 2);
Node->Atapi.Lun = (UINT16) Lun;
*DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AtapiScsiPassThruGetTargetLun (
IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
OUT UINT32 *Target,
OUT UINT64 *Lun
)
/*++
Routine Description:
Used to translate a device path node to a Target ID and LUN.
Arguments:
This - Protocol instance pointer.
DevicePath - A pointer to the device path node that
describes a SCSI device on the SCSI channel.
Target - A pointer to the Target ID of a SCSI device
on the SCSI channel.
Lun - A pointer to the LUN of a SCSI device on
the SCSI channel.
Returns:
EFI_SUCCESS - DevicePath was successfully translated to a
Target ID and LUN, and they were returned
in Target and Lun.
EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
EFI_UNSUPPORTED - This driver does not support the device path
node type in DevicePath.
EFI_NOT_FOUND - A valid translation from DevicePath to a
Target ID and LUN does not exist.
--*/
{
EFI_DEV_PATH *Node;
//
// Validate parameters passed in.
//
if (DevicePath == NULL || Target == NULL || Lun == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check whether the DevicePath belongs to SCSI_DEVICE_PATH
//
if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
(DevicePath->SubType != MSG_ATAPI_DP) ||
(DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
return EFI_UNSUPPORTED;
}
Node = (EFI_DEV_PATH *) DevicePath;
*Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;
*Lun = Node->Atapi.Lun;
if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AtapiScsiPassThruResetChannel (
IN EFI_SCSI_PASS_THRU_PROTOCOL *This
)
/*++
Routine Description:
Resets a SCSI channel.This operation resets all the
SCSI devices connected to the SCSI channel.
Arguments:
This - Protocol instance pointer.
Returns:
EFI_SUCCESS - The SCSI channel was reset.
EFI_UNSUPPORTED - The SCSI channel does not support
a channel reset operation.
EFI_DEVICE_ERROR - A device error occurred while
attempting to reset the SCSI channel.
EFI_TIMEOUT - A timeout occurred while attempting
to reset the SCSI channel.
--*/
{
UINT8 DeviceControlValue;
ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
UINT8 Index;
AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
//
// Reset both Primary channel and Secondary channel.
// so, the IoPort pointer must point to the right I/O Register group
//
for (Index = 0; Index < 2; Index++) {
//
// Reset
//
AtapiScsiPrivate->IoPort = &AtapiIoPortRegisters[Index];
DeviceControlValue = 0;
//
// set SRST bit to initiate soft reset
//
DeviceControlValue |= SRST;
//
// disable Interrupt
//
DeviceControlValue |= bit (1);
WritePortB (
AtapiScsiPrivate->PciIo,
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
AtapiScsiPassThruResetTarget (
IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
IN UINT32 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.
--*/
{
ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
UINT8 Command;
UINT8 DeviceSelect;
AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
if (Target > MAX_TARGET_ID) {
return EFI_INVALID_PARAMETER;
}
//
// Directly return EFI_SUCCESS if want to reset the host controller
//
if (Target == 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 ((Target / 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)) | (Target << 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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?