audk/EdkModulePkg/Library/EdkScsiLib/ScsiLib.c

652 lines
25 KiB
C
Raw Normal View History

/*++
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:
ScsiLib.c
Abstract:
Revision History
--*/
#include <IndustryStandard/scsi.h>
EFI_STATUS
SubmitTestUnitReadyCommand (
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
IN UINT64 Timeout,
OUT VOID *SenseData,
OUT UINT8 *SenseDataLength,
OUT UINT8 *HostAdapterStatus,
OUT UINT8 *TargetStatus
)
/*++
Routine Description:
Function tests the ready status of SCSI unit.
Arguments:
ScsiIo - A pointer to SCSI IO protocol.
Timeout - The length of timeout period.
SenseData - A pointer to output sense data.
SenseDataLength - The length of output sense data.
HostAdapterStatus - The status of Host Adapter.
TargetStatus - The status of the target.
Returns:
Returns:
EFI_SUCCESS - The status of the unit is tested successfully.
EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
but the entire DataBuffer could not be transferred.
The actual number of bytes transferred is returned
in InTransferLength.
EFI_NOT_READY - The SCSI Request Packet could not be sent because
there are too many SCSI Command Packets already
queued.
EFI_DEVICE_ERROR - A device error occurred while attempting to send
the SCSI Request Packet.
EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
EFI_UNSUPPORTED - The command described by the SCSI Request Packet
is not supported by the SCSI initiator(i.e., SCSI
Host Controller).
EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
Request Packet to execute.
--*/
{
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
UINT64 Lun;
UINT8 *Target;
EFI_STATUS Status;
UINT8 Cdb[6];
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
ZeroMem (Cdb, 6);
CommandPacket.Timeout = Timeout;
CommandPacket.InDataBuffer = NULL;
CommandPacket.SenseData = SenseData;
CommandPacket.InTransferLength= 0;
CommandPacket.Cdb = Cdb;
//
// Fill Cdb for Test Unit Ready Command
//
ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
Cdb[1] = (UINT8) (Lun & 0xe0);
CommandPacket.CdbLength = (UINT8) 6;
CommandPacket.SenseDataLength = *SenseDataLength;
Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL);
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
*TargetStatus = CommandPacket.TargetStatus;
*SenseDataLength = CommandPacket.SenseDataLength;
return Status;
}
EFI_STATUS
SubmitInquiryCommand (
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
IN UINT64 Timeout,
IN VOID *SenseData,
IN OUT UINT8 *SenseDataLength,
OUT UINT8 *HostAdapterStatus,
OUT UINT8 *TargetStatus,
IN OUT VOID *InquiryDataBuffer,
IN OUT UINT32 *InquiryDataLength,
IN BOOLEAN EnableVitalProductData
)
/*++
Routine Description:
Function to submit SCSI inquiry command.
Arguments:
ScsiIo - A pointer to SCSI IO protocol.
Timeout - The length of timeout period.
SenseData - A pointer to output sense data.
SenseDataLength - The length of output sense data.
HostAdapterStatus - The status of Host Adapter.
TargetStatus - The status of the target.
InquiryDataBuffer - A pointer to inquiry data buffer.
InquiryDataLength - The length of inquiry data buffer.
EnableVitalProductData - Boolean to enable Vital Product Data.
Returns:
Returns:
EFI_SUCCESS - The status of the unit is tested successfully.
EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
but the entire DataBuffer could not be transferred.
The actual number of bytes transferred is returned
in TransferLength.
EFI_NOT_READY - The SCSI Request Packet could not be sent because
there are too many SCSI Command Packets already
queued.
EFI_DEVICE_ERROR - A device error occurred while attempting to send
the SCSI Request Packet.
EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
EFI_UNSUPPORTED - The command described by the SCSI Request Packet
is not supported by the SCSI initiator(i.e., SCSI
Host Controller).
EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
Request Packet to execute.
--*/
{
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
UINT64 Lun;
UINT8 *Target;
EFI_STATUS Status;
UINT8 Cdb[6];
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
ZeroMem (Cdb, 6);
CommandPacket.Timeout = Timeout;
CommandPacket.InDataBuffer = InquiryDataBuffer;
CommandPacket.InTransferLength= *InquiryDataLength;
CommandPacket.SenseData = SenseData;
CommandPacket.SenseDataLength = *SenseDataLength;
CommandPacket.Cdb = Cdb;
ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
Cdb[0] = EFI_SCSI_OP_INQUIRY;
Cdb[1] = (UINT8) (Lun & 0xe0);
if (EnableVitalProductData) {
Cdb[1] |= 0x01;
}
if (*InquiryDataLength > 0xff) {
*InquiryDataLength = 0xff;
}
Cdb[4] = (UINT8) (*InquiryDataLength);
CommandPacket.CdbLength = (UINT8) 6;
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL);
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
*TargetStatus = CommandPacket.TargetStatus;
*SenseDataLength = CommandPacket.SenseDataLength;
*InquiryDataLength = CommandPacket.InTransferLength;
return Status;
}
EFI_STATUS
SubmitModeSense10Command (
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
IN UINT64 Timeout,
IN VOID *SenseData,
IN OUT UINT8 *SenseDataLength,
OUT UINT8 *HostAdapterStatus,
OUT UINT8 *TargetStatus,
IN VOID *DataBuffer,
IN OUT UINT32 *DataLength,
IN UINT8 DBDField, OPTIONAL
IN UINT8 PageControl,
IN UINT8 PageCode
)
/*++
Routine Description:
Function to submit SCSI mode sense 10 command.
Arguments:
ScsiIo - A pointer to SCSI IO protocol.
Timeout - The length of timeout period.
SenseData - A pointer to output sense data.
SenseDataLength - The length of output sense data.
HostAdapterStatus - The status of Host Adapter.
TargetStatus - The status of the target.
DataBuffer - A pointer to input data buffer.
DataLength - The length of input data buffer.
DBDField - The DBD Field (Optional).
PageControl - Page Control.
PageCode - Page code.
Returns:
Returns:
EFI_SUCCESS - The status of the unit is tested successfully.
EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
but the entire DataBuffer could not be transferred.
The actual number of bytes transferred is returned
in TransferLength.
EFI_NOT_READY - The SCSI Request Packet could not be sent because
there are too many SCSI Command Packets already
queued.
EFI_DEVICE_ERROR - A device error occurred while attempting to send
the SCSI Request Packet.
EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
EFI_UNSUPPORTED - The command described by the SCSI Request Packet
is not supported by the SCSI initiator(i.e., SCSI
Host Controller).
EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
Request Packet to execute.
--*/
{
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
UINT64 Lun;
UINT8 *Target;
EFI_STATUS Status;
UINT8 Cdb[10];
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
ZeroMem (Cdb, 10);
CommandPacket.Timeout = Timeout;
CommandPacket.InDataBuffer = DataBuffer;
CommandPacket.SenseData = SenseData;
CommandPacket.InTransferLength= *DataLength;
CommandPacket.Cdb = Cdb;
//
// Fill Cdb for Mode Sense (10) Command
//
ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
Cdb[0] = EFI_SCSI_OP_MODE_SEN10;
Cdb[1] = (UINT8) ((Lun & 0xe0) + ((DBDField << 3) & 0x08));
Cdb[2] = (UINT8) ((PageControl & 0xc0) | (PageCode & 0x3f));
Cdb[7] = (UINT8) (*DataLength >> 8);
Cdb[8] = (UINT8) (*DataLength);
CommandPacket.CdbLength = 10;
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
CommandPacket.SenseDataLength = *SenseDataLength;
Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL);
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
*TargetStatus = CommandPacket.TargetStatus;
*SenseDataLength = CommandPacket.SenseDataLength;
*DataLength = CommandPacket.InTransferLength;
return Status;
}
EFI_STATUS
SubmitRequestSenseCommand (
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
IN UINT64 Timeout,
IN VOID *SenseData,
IN OUT UINT8 *SenseDataLength,
OUT UINT8 *HostAdapterStatus,
OUT UINT8 *TargetStatus
)
/*++
Routine Description:
Function to submit SCSI request sense command.
Arguments:
ScsiIo - A pointer to SCSI IO protocol.
Timeout - The length of timeout period.
SenseData - A pointer to output sense data.
SenseDataLength - The length of output sense data.
HostAdapterStatus - The status of Host Adapter.
TargetStatus - The status of the target.
Returns:
Returns:
EFI_SUCCESS - The status of the unit is tested successfully.
EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
but the entire DataBuffer could not be transferred.
The actual number of bytes transferred is returned
in TransferLength.
EFI_NOT_READY - The SCSI Request Packet could not be sent because
there are too many SCSI Command Packets already
queued.
EFI_DEVICE_ERROR - A device error occurred while attempting to send
the SCSI Request Packet.
EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
EFI_UNSUPPORTED - The command described by the SCSI Request Packet
is not supported by the SCSI initiator(i.e., SCSI
Host Controller).
EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
Request Packet to execute.
--*/
{
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
UINT64 Lun;
UINT8 *Target;
EFI_STATUS Status;
UINT8 Cdb[6];
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
ZeroMem (Cdb, 6);
/*
if (*SenseDataLength > 0xff) {
*SenseDataLength = 0xff;
}
*/
CommandPacket.Timeout = Timeout;
CommandPacket.InDataBuffer = SenseData;
CommandPacket.SenseData = NULL;
CommandPacket.InTransferLength= *SenseDataLength;
CommandPacket.Cdb = Cdb;
//
// Fill Cdb for Request Sense Command
//
ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE;
Cdb[1] = (UINT8) (Lun & 0xe0);
Cdb[4] = (UINT8) (*SenseDataLength);
CommandPacket.CdbLength = (UINT8) 6;
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
CommandPacket.SenseDataLength = 0;
Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL);
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
*TargetStatus = CommandPacket.TargetStatus;
*SenseDataLength = (UINT8) CommandPacket.InTransferLength;
return Status;
}
EFI_STATUS
SubmitReadCapacityCommand (
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
IN UINT64 Timeout,
IN VOID *SenseData,
IN OUT UINT8 *SenseDataLength,
OUT UINT8 *HostAdapterStatus,
OUT UINT8 *TargetStatus,
OUT VOID *DataBuffer,
IN OUT UINT32 *DataLength,
IN BOOLEAN PMI
)
/*++
Routine Description:
Function to submit read capacity command.
Arguments:
ScsiIo - A pointer to SCSI IO protocol.
Timeout - The length of timeout period.
SenseData - A pointer to output sense data.
SenseDataLength - The length of output sense data.
HostAdapterStatus - The status of Host Adapter.
TargetStatus - The status of the target.
DataBuffer - A pointer to a data buffer.
DataLength - The length of data buffer.
PMI - Partial medium indicator.
Returns:
Returns:
EFI_SUCCESS - The status of the unit is tested successfully.
EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
but the entire DataBuffer could not be transferred.
The actual number of bytes transferred is returned
in TransferLength.
EFI_NOT_READY - The SCSI Request Packet could not be sent because
there are too many SCSI Command Packets already
queued.
EFI_DEVICE_ERROR - A device error occurred while attempting to send
the SCSI Request Packet.
EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
EFI_UNSUPPORTED - The command described by the SCSI Request Packet
is not supported by the SCSI initiator(i.e., SCSI
Host Controller).
EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
Request Packet to execute.
--*/
{
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
UINT64 Lun;
UINT8 *Target;
EFI_STATUS Status;
UINT8 Cdb[10];
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
ZeroMem (Cdb, 10);
CommandPacket.Timeout = Timeout;
CommandPacket.InDataBuffer = DataBuffer;
CommandPacket.SenseData = SenseData;
CommandPacket.InTransferLength= *DataLength;
CommandPacket.Cdb = Cdb;
//
// Fill Cdb for Read Capacity Command
//
ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
Cdb[1] = (UINT8) (Lun & 0xe0);
if (!PMI) {
//
// Partial medium indicator,if PMI is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO.
//
ZeroMem ((Cdb + 2), 4);
} else {
Cdb[8] |= 0x01;
}
CommandPacket.CdbLength = 10;
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
CommandPacket.SenseDataLength = *SenseDataLength;
Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL);
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
*TargetStatus = CommandPacket.TargetStatus;
*SenseDataLength = CommandPacket.SenseDataLength;
*DataLength = CommandPacket.InTransferLength;
return Status;
}
EFI_STATUS
SubmitRead10Command (
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
IN UINT64 Timeout,
IN VOID *SenseData,
IN OUT UINT8 *SenseDataLength,
OUT UINT8 *HostAdapterStatus,
OUT UINT8 *TargetStatus,
OUT VOID *DataBuffer,
IN OUT UINT32 *DataLength,
IN UINT32 StartLba,
IN UINT32 SectorSize
)
/*++
Routine Description:
Function to submit read 10 command.
Arguments:
ScsiIo - A pointer to SCSI IO protocol.
Timeout - The length of timeout period.
SenseData - A pointer to output sense data.
SenseDataLength - The length of output sense data.
HostAdapterStatus - The status of Host Adapter.
TargetStatus - The status of the target.
DataBuffer - A pointer to a data buffer.
DataLength - The length of data buffer.
StartLba - The start address of LBA.
SectorSize - The sector size.
Returns:
Returns:
EFI_SUCCESS - The status of the unit is tested successfully.
EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
but the entire DataBuffer could not be transferred.
The actual number of bytes transferred is returned
in TransferLength.
EFI_NOT_READY - The SCSI Request Packet could not be sent because
there are too many SCSI Command Packets already
queued.
EFI_DEVICE_ERROR - A device error occurred while attempting to send
the SCSI Request Packet.
EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
EFI_UNSUPPORTED - The command described by the SCSI Request Packet
is not supported by the SCSI initiator(i.e., SCSI
Host Controller).
EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
Request Packet to execute.
--*/
{
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
UINT64 Lun;
UINT8 *Target;
EFI_STATUS Status;
UINT8 Cdb[10];
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
ZeroMem (Cdb, 10);
CommandPacket.Timeout = Timeout;
CommandPacket.InDataBuffer = DataBuffer;
CommandPacket.SenseData = SenseData;
CommandPacket.InTransferLength= *DataLength;
CommandPacket.Cdb = Cdb;
//
// Fill Cdb for Read (10) Command
//
ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
Cdb[0] = EFI_SCSI_OP_READ10;
Cdb[1] = (UINT8) (Lun & 0xe0);
Cdb[2] = (UINT8) (StartLba >> 24);
Cdb[3] = (UINT8) (StartLba >> 16);
Cdb[4] = (UINT8) (StartLba >> 8);
Cdb[5] = (UINT8) StartLba;
Cdb[7] = (UINT8) (SectorSize >> 8);
Cdb[8] = (UINT8) SectorSize;
CommandPacket.CdbLength = 10;
CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
CommandPacket.SenseDataLength = *SenseDataLength;
Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL);
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
*TargetStatus = CommandPacket.TargetStatus;
*SenseDataLength = CommandPacket.SenseDataLength;
*DataLength = CommandPacket.InTransferLength;
return Status;
}
EFI_STATUS
SubmitWrite10Command (
IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
IN UINT64 Timeout,
IN VOID *SenseData,
IN OUT UINT8 *SenseDataLength,
OUT UINT8 *HostAdapterStatus,
OUT UINT8 *TargetStatus,
OUT VOID *DataBuffer,
IN OUT UINT32 *DataLength,
IN UINT32 StartLba,
IN UINT32 SectorSize
)
/*++
Routine Description:
Function to submit SCSI write 10 command.
Arguments:
ScsiIo - A pointer to SCSI IO protocol.
Timeout - The length of timeout period.
SenseData - A pointer to output sense data.
SenseDataLength - The length of output sense data.
HostAdapterStatus - The status of Host Adapter.
TargetStatus - The status of the target.
DataBuffer - A pointer to a data buffer.
DataLength - The length of data buffer.
StartLba - The start address of LBA.
SectorSize - The sector size.
Returns:
Returns:
EFI_SUCCESS - The status of the unit is tested successfully.
EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
but the entire DataBuffer could not be transferred.
The actual number of bytes transferred is returned
in InTransferLength.
EFI_NOT_READY - The SCSI Request Packet could not be sent because
there are too many SCSI Command Packets already
queued.
EFI_DEVICE_ERROR - A device error occurred while attempting to send
the SCSI Request Packet.
EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
EFI_UNSUPPORTED - The command described by the SCSI Request Packet
is not supported by the SCSI initiator(i.e., SCSI
Host Controller).
EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
Request Packet to execute.
--*/
{
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
UINT64 Lun;
UINT8 *Target;
EFI_STATUS Status;
UINT8 Cdb[10];
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
ZeroMem (Cdb, 10);
CommandPacket.Timeout = Timeout;
CommandPacket.InDataBuffer = DataBuffer;
CommandPacket.SenseData = SenseData;
CommandPacket.InTransferLength= *DataLength;
CommandPacket.Cdb = Cdb;
//
// Fill Cdb for Write (10) Command
//
ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
Cdb[0] = EFI_SCSI_OP_WRITE10;
Cdb[1] = (UINT8) (Lun & 0xe0);
Cdb[2] = (UINT8) (StartLba >> 24);
Cdb[3] = (UINT8) (StartLba >> 16);
Cdb[4] = (UINT8) (StartLba >> 8);
Cdb[5] = (UINT8) StartLba;
Cdb[7] = (UINT8) (SectorSize >> 8);
Cdb[8] = (UINT8) SectorSize;
CommandPacket.CdbLength = 10;
CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
CommandPacket.SenseDataLength = *SenseDataLength;
Status = ScsiIo->ExecuteSCSICommand (ScsiIo, &CommandPacket, NULL);
*HostAdapterStatus = CommandPacket.HostAdapterStatus;
*TargetStatus = CommandPacket.TargetStatus;
*SenseDataLength = CommandPacket.SenseDataLength;
*DataLength = CommandPacket.InTransferLength;
return Status;
}