diff options
author | Laszlo Ersek <lersek@redhat.com> | 2017-08-18 04:30:40 +0200 |
---|---|---|
committer | Laszlo Ersek <lersek@redhat.com> | 2017-08-19 00:39:05 +0200 |
commit | ce13d2d8c81f0ba77ac15d1e9a395ef1b8e57a82 (patch) | |
tree | d3f5291d0c0bcef977f4943a1afbe38b2ae89984 /MdeModulePkg | |
parent | c09e481bbb34cb781b3d98f4ec781305e61dfda5 (diff) | |
download | edk2-ce13d2d8c81f0ba77ac15d1e9a395ef1b8e57a82.tar.gz edk2-ce13d2d8c81f0ba77ac15d1e9a395ef1b8e57a82.tar.bz2 edk2-ce13d2d8c81f0ba77ac15d1e9a395ef1b8e57a82.zip |
MdeModulePkg/ScsiBusDxe: don't produce ScsiIo for nonexistent LUNs, part 2
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>
Diffstat (limited to 'MdeModulePkg')
-rw-r--r-- | MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c index 1068770cd8..21034aab19 100644 --- a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c +++ b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c @@ -1298,12 +1298,14 @@ DiscoverScsiDevice ( 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) {
@@ -1311,19 +1313,29 @@ DiscoverScsiDevice ( 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,
@@ -1332,6 +1344,13 @@ DiscoverScsiDevice ( 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) ||
@@ -1377,6 +1396,7 @@ DiscoverScsiDevice ( ScsiDeviceFound = TRUE;
Done:
+ FreeAlignedBuffer (SenseData, sizeof (EFI_SCSI_SENSE_DATA));
FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
return ScsiDeviceFound;
|