Skip to content

Commit 29a3a10

Browse files
feat: add scsi mode sense operation to detect write protection (#1524)
## Description We encountered some errors where on attaching a ReadOnly disk led to write failures. We RCA'd the failure to the Volume protocol not being set to be write protected. We are proposing this change to update the blockIo protocol's media property to set Write protections based on performing a MODE SENSE operation. For details on how to complete these options and their meaning refer to [CONTRIBUTING.md](https://github.com/microsoft/mu/blob/HEAD/CONTRIBUTING.md). - [ ] Impacts functionality? - [ ] Impacts security? - [ ] Breaking change? - [ ] Includes tests? - [ ] Includes documentation? ## How This Was Tested We tested the change while booting a VM with VHD attached as read only mode and then without read-only mode. We don't encounter any errors which we were hitting earlier. ## Integration Instructions NA --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent ad2505e commit 29a3a10

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,67 @@ ScsiDiskDriverBindingSupported (
196196
return Status;
197197
}
198198

199+
// MU_CHANGE Begin: Add function to check whether the disk is write protected
200+
201+
/**
202+
Check whether the SCSI disk is write protected.
203+
@param[in] ScsiDiskDevice The SCSI disk device.
204+
@param[out] WriteProtectionEnabled A pointer to a Boolean that will be set to TRUE if the disk is write protected,
205+
FALSE otherwise.
206+
@retval EFI_SUCCESS The operation completed successfully.
207+
@retval EFI_INVALID_PARAMETER One of the input parameters was invalid.
208+
@retval other An error occurred while executing the SCSI command.
209+
*/
210+
STATIC
211+
EFI_STATUS
212+
IsWriteProtected (
213+
IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
214+
OUT BOOLEAN *WriteProtectionEnabled
215+
)
216+
{
217+
EFI_STATUS Status;
218+
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
219+
UINT8 Cdb[6];
220+
UINT8 DataBuffer[64];
221+
222+
if ((ScsiDiskDevice == NULL) || (WriteProtectionEnabled == NULL) || (ScsiDiskDevice->ScsiIo == NULL)) {
223+
return EFI_INVALID_PARAMETER;
224+
}
225+
226+
//
227+
// Initialize SCSI REQUEST_PACKET and 6-byte Cdb
228+
//
229+
ZeroMem (&CommandPacket, sizeof (CommandPacket));
230+
ZeroMem (Cdb, sizeof (Cdb));
231+
232+
// Initialize output parameter to default value
233+
*WriteProtectionEnabled = FALSE;
234+
235+
Cdb[0] = ATA_CMD_MODE_SENSE6;
236+
Cdb[1] = BIT3; // Setting the bit for Disable Block Descriptor
237+
Cdb[2] = ATA_PAGE_CODE_RETURN_ALL_PAGES;
238+
Cdb[4] = sizeof (DataBuffer);
239+
240+
CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
241+
CommandPacket.Cdb = Cdb;
242+
CommandPacket.CdbLength = (UINT8)sizeof (Cdb);
243+
CommandPacket.InDataBuffer = &DataBuffer;
244+
CommandPacket.InTransferLength = sizeof (DataBuffer);
245+
246+
Status = ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
247+
248+
if (EFI_ERROR (Status)) {
249+
return Status;
250+
}
251+
252+
// Mode Sense 6 Byte Command returns the Write Protection status in the 3rd byte
253+
// Bit 7 of the 3rd byte indicates the Write Protection status
254+
*WriteProtectionEnabled = (DataBuffer[2] & BIT7) != 0;
255+
return EFI_SUCCESS;
256+
}
257+
258+
// MU_CHANGE End: Add function to check whether the disk is write protected
259+
199260
/**
200261
Start this driver on ControllerHandle.
201262
@@ -234,6 +295,8 @@ ScsiDiskDriverBindingStart (
234295
CHAR8 VendorStr[VENDOR_IDENTIFICATION_LENGTH + 1];
235296
CHAR8 ProductStr[PRODUCT_IDENTIFICATION_LENGTH + 1];
236297
CHAR16 DeviceStr[VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2];
298+
// MU_CHANGE: Add variable to check whether the disk is write protected
299+
BOOLEAN WriteProtectionEnabled = FALSE;
237300

238301
MustReadCapacity = TRUE;
239302

@@ -297,6 +360,20 @@ ScsiDiskDriverBindingStart (
297360
break;
298361
}
299362

363+
// MU_CHANGE Begin: Check whether the disk is write protected and set the ReadOnly flag accordingly
364+
if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
365+
Status = IsWriteProtected (ScsiDiskDevice, &WriteProtectionEnabled);
366+
if (EFI_ERROR (Status)) {
367+
DEBUG ((DEBUG_ERROR, "ScsiDisk: IsWriteProtected() fails. Status = %r\n", Status));
368+
}
369+
370+
if (WriteProtectionEnabled) {
371+
ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;
372+
}
373+
}
374+
375+
// MU_CHANGE End: Check whether the disk is write protected and set the ReadOnly flag accordingly
376+
300377
//
301378
// The Sense Data Array's initial size is 6
302379
//

MdePkg/Include/IndustryStandard/Atapi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,8 @@ typedef union {
503503
#define ATA_CMD_PREVENT_ALLOW_MEDIA_REMOVAL 0x1E ///< defined in ATAPI Removable Rewritable Media Devices
504504
#define ATA_CMD_MODE_SELECT 0x55 ///< defined in ATAPI Removable Rewritable Media Devices
505505

506+
// MU_CHANGE: Add some definitions for MODE SENSE (6-Byte) command
507+
#define ATA_CMD_MODE_SENSE6 0x1A ///< defined in ATAPI Removable Rewritable Media Devices
506508
#define ATA_CMD_MODE_SENSE 0x5A ///< defined in ATAPI Removable Rewritable Media Devices
507509
#define ATA_PAGE_CODE_READ_WRITE_ERROR 0x01 ///< defined in ATAPI Removable Rewritable Media Devices
508510
#define ATA_PAGE_CODE_CACHING_PAGE 0x08 ///< defined in ATAPI Removable Rewritable Media Devices

0 commit comments

Comments
 (0)