The SPC-4 says about INQUIRY,
> In response to an INQUIRY command received by an incorrect logical unit,
> the SCSI target device shall return the INQUIRY data with the peripheral
> qualifier set to the value defined in 6.4.2. The INQUIRY command shall
> return CHECK CONDITION status only when the device server is unable to
> return the requested INQUIRY data.
When a device server takes the second branch, and returns CHECK CONDITION
for a nonexistent LUN, the InquiryData structure in the
DiscoverScsiDevice() function remains filled with the original zeros.
DiscoverScsiDevice() then sees zero in both Peripheral_Qualifier and
Peripheral_Type, and therefore ScsiBusDxe produces a ScsiIo protocol
instance with device type zero, for the nonexistent LUN.
Device type zero is EFI_SCSI_TYPE_DISK. Thus ScsiDiskDxe binds the bogus
ScsiIo protocol interface, and produces a similarly bogus BlockIo
interface on top. This ripples up to BDS, where UefiBootManagerLib can
auto-generate bogus UEFI boot options for the nonexistent LUNs.
This has been encountered with QEMU, after commit ded6ddc5a7b9 ("scsi:
clarify sense codes for LUN0 emulation", 2017-08-04). QEMU now answers
INQUIRY commands that were directed to nonexistent LUNs with:
> DiscoverScsiDevice:1361: Lun=2 HostAdapterStatus=0 TargetStatus=2
> SenseDataLength=18 InquiryDataLength=96
> Sense {
> Sense 000000 70 00 05 00 00 00 00 0A 00 00 00 00 25 00 00 00
> Sense 000010 00 00
> Sense }
> Inquiry {
> Inquiry 000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Inquiry 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Inquiry 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Inquiry 000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Inquiry 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Inquiry 000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Inquiry }
The interesting fields are:
- HostAdapterStatus=0 (OK),
- TargetStatus=2 (CHECK CONDITION),
- Sense/Error_Code=0x70 (Current error, Fixed description)
- Sense/Sense_Key=0x05 (ILLEGAL REQUEST)
According to SPC-4 "Table 41 -- Sense key descriptions (part 2 of 2)",
ILLEGAL REQUEST is justified when "the command was addressed to an
incorrect logical unit number".
Thus, recognize this kind of answer for nonexistent LUNs.
(
Checking the status fields and the sense data is justified anyway,
according to the documentation of ScsiInquiryCommand():
> @retval EFI_SUCCESS The command was executed
> successfully. See
> HostAdapterStatus,
> TargetStatus, SenseDataLength,
> and SenseData in that order for
> additional status information.
)
Cc: Eric Dong <eric.dong@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Hannes Reinecke <hare@suse.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c | 24 ++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
index 1068770cd87f..21034aab19f7 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
@@ -1297,42 +1297,61 @@ DiscoverScsiDevice (
UINT8 SenseDataLength;
UINT8 HostAdapterStatus;
UINT8 TargetStatus;
EFI_SCSI_INQUIRY_DATA *InquiryData;
+ EFI_SCSI_SENSE_DATA *SenseData;
UINT8 MaxRetry;
UINT8 Index;
BOOLEAN ScsiDeviceFound;
HostAdapterStatus = 0;
TargetStatus = 0;
+ SenseData = NULL;
InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));
if (InquiryData == NULL) {
ScsiDeviceFound = FALSE;
goto Done;
}
+ SenseData = AllocateAlignedBuffer (
+ ScsiIoDevice,
+ sizeof (EFI_SCSI_SENSE_DATA)
+ );
+ if (SenseData == NULL) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
+
//
// Using Inquiry command to scan for the device
//
InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
- SenseDataLength = 0;
+ SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
ZeroMem (InquiryData, InquiryDataLength);
+ ZeroMem (SenseData, SenseDataLength);
MaxRetry = 2;
for (Index = 0; Index < MaxRetry; Index++) {
Status = ScsiInquiryCommand (
&ScsiIoDevice->ScsiIo,
SCSI_BUS_TIMEOUT,
- NULL,
+ SenseData,
&SenseDataLength,
&HostAdapterStatus,
&TargetStatus,
(VOID *) InquiryData,
&InquiryDataLength,
FALSE
);
if (!EFI_ERROR (Status)) {
+ if ((HostAdapterStatus == EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK) &&
+ (TargetStatus == EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION) &&
+ (SenseData->Error_Code == 0x70) &&
+ (SenseData->Sense_Key == EFI_SCSI_SK_ILLEGAL_REQUEST)) {
+ ScsiDeviceFound = FALSE;
+ goto Done;
+ }
break;
}
if ((Status == EFI_BAD_BUFFER_SIZE) ||
(Status == EFI_INVALID_PARAMETER) ||
@@ -1376,8 +1395,9 @@ DiscoverScsiDevice (
ScsiDeviceFound = TRUE;
Done:
+ FreeAlignedBuffer (SenseData, sizeof (EFI_SCSI_SENSE_DATA));
FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
return ScsiDeviceFound;
}
--
2.14.1.3.gb7cf6e02401b
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.