[edk2] [PATCH 3/3] MdeModulePkg/ScsiBusDxe: don't produce ScsiIo for nonexistent LUNs, part 2

Laszlo Ersek posted 3 patches 7 years, 4 months ago
[edk2] [PATCH 3/3] MdeModulePkg/ScsiBusDxe: don't produce ScsiIo for nonexistent LUNs, part 2
Posted by Laszlo Ersek 7 years, 4 months ago
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