]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/ScsiBusDxe: don't produce ScsiIo for nonexistent LUNs, part 2
authorLaszlo Ersek <lersek@redhat.com>
Fri, 18 Aug 2017 02:30:40 +0000 (04:30 +0200)
committerLaszlo Ersek <lersek@redhat.com>
Fri, 18 Aug 2017 22:39:05 +0000 (00:39 +0200)
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>
Reviewed-by: Star Zeng <star.zeng@intel.com>
MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c

index 1068770cd87f02903ca28e31b4ae94da09487fcc..21034aab19f7266fb37a255dff451f0cacb3ff40 100644 (file)
@@ -1298,12 +1298,14 @@ DiscoverScsiDevice (
   UINT8                 HostAdapterStatus;\r
   UINT8                 TargetStatus;\r
   EFI_SCSI_INQUIRY_DATA *InquiryData;\r
   UINT8                 HostAdapterStatus;\r
   UINT8                 TargetStatus;\r
   EFI_SCSI_INQUIRY_DATA *InquiryData;\r
+  EFI_SCSI_SENSE_DATA   *SenseData;\r
   UINT8                 MaxRetry;\r
   UINT8                 Index;\r
   BOOLEAN               ScsiDeviceFound;\r
 \r
   HostAdapterStatus = 0;\r
   TargetStatus      = 0;\r
   UINT8                 MaxRetry;\r
   UINT8                 Index;\r
   BOOLEAN               ScsiDeviceFound;\r
 \r
   HostAdapterStatus = 0;\r
   TargetStatus      = 0;\r
+  SenseData         = NULL;\r
 \r
   InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));\r
   if (InquiryData == NULL) {\r
 \r
   InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));\r
   if (InquiryData == NULL) {\r
@@ -1311,19 +1313,29 @@ DiscoverScsiDevice (
     goto Done;\r
   }\r
 \r
     goto Done;\r
   }\r
 \r
+  SenseData = AllocateAlignedBuffer (\r
+                ScsiIoDevice,\r
+                sizeof (EFI_SCSI_SENSE_DATA)\r
+                );\r
+  if (SenseData == NULL) {\r
+    ScsiDeviceFound = FALSE;\r
+    goto Done;\r
+  }\r
+\r
   //\r
   // Using Inquiry command to scan for the device\r
   //\r
   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
   //\r
   // Using Inquiry command to scan for the device\r
   //\r
   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
-  SenseDataLength   = 0;\r
+  SenseDataLength   = sizeof (EFI_SCSI_SENSE_DATA);\r
   ZeroMem (InquiryData, InquiryDataLength);\r
   ZeroMem (InquiryData, InquiryDataLength);\r
+  ZeroMem (SenseData, SenseDataLength);\r
 \r
   MaxRetry = 2;\r
   for (Index = 0; Index < MaxRetry; Index++) {\r
     Status = ScsiInquiryCommand (\r
               &ScsiIoDevice->ScsiIo,\r
               SCSI_BUS_TIMEOUT,\r
 \r
   MaxRetry = 2;\r
   for (Index = 0; Index < MaxRetry; Index++) {\r
     Status = ScsiInquiryCommand (\r
               &ScsiIoDevice->ScsiIo,\r
               SCSI_BUS_TIMEOUT,\r
-              NULL,\r
+              SenseData,\r
               &SenseDataLength,\r
               &HostAdapterStatus,\r
               &TargetStatus,\r
               &SenseDataLength,\r
               &HostAdapterStatus,\r
               &TargetStatus,\r
@@ -1332,6 +1344,13 @@ DiscoverScsiDevice (
               FALSE\r
               );\r
     if (!EFI_ERROR (Status)) {\r
               FALSE\r
               );\r
     if (!EFI_ERROR (Status)) {\r
+      if ((HostAdapterStatus == EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK) &&\r
+          (TargetStatus == EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION) &&\r
+          (SenseData->Error_Code == 0x70) &&\r
+          (SenseData->Sense_Key == EFI_SCSI_SK_ILLEGAL_REQUEST)) {\r
+        ScsiDeviceFound = FALSE;\r
+        goto Done;\r
+      }\r
       break;\r
     }\r
     if ((Status == EFI_BAD_BUFFER_SIZE) ||\r
       break;\r
     }\r
     if ((Status == EFI_BAD_BUFFER_SIZE) ||\r
@@ -1377,6 +1396,7 @@ DiscoverScsiDevice (
   ScsiDeviceFound = TRUE;\r
 \r
 Done:\r
   ScsiDeviceFound = TRUE;\r
 \r
 Done:\r
+  FreeAlignedBuffer (SenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
   FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));\r
 \r
   return ScsiDeviceFound;\r
   FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));\r
 \r
   return ScsiDeviceFound;\r