diff options
author | David Zeuthen <zeuthen@gmail.com> | 2014-03-25 22:57:25 -0700 |
---|---|---|
committer | David Zeuthen <zeuthen@gmail.com> | 2014-03-25 22:57:25 -0700 |
commit | 429892f2ec39d66732bee0f78d093eb6d2c5433f (patch) | |
tree | 0f64e3472023eb08fa4dcfbedf9dbb5336cad65a | |
parent | 25f83ee6beaa0daa8f7e84ce5df4563797e10490 (diff) |
Send SCSI SYNCHRONIZE CACHE before powering down a drive
It looks like some disks need this in addition to the SCSI START STOP
UNIT command. However some disks don't implement this command so make
the failure non-fatal. See bug 71802 for details.
https://bugs.freedesktop.org/show_bug.cgi?id=71802
Signed-off-by: David Zeuthen <zeuthen@gmail.com>
-rw-r--r-- | src/udiskslinuxdrive.c | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c index ed541ff..b782c7e 100644 --- a/src/udiskslinuxdrive.c +++ b/src/udiskslinuxdrive.c @@ -1299,8 +1299,22 @@ send_scsi_command_sync (gint fd, } static gboolean -send_scsi_start_stop_command_sync (gint fd, - GError **error) +send_scsi_synchronize_cache_command_sync (gint fd, + GError **error) +{ + uint8_t cdb[10]; + + /* SBC3 (SCSI Block Commands), 5.18 SYNCHRONIZE CACHE (10) command + */ + memset (cdb, 0, sizeof cdb); + cdb[0] = 0x35; /* OPERATION CODE: SYNCHRONIZE CACHE (10) */ + + return send_scsi_command_sync (fd, cdb, sizeof cdb, error); +} + +static gboolean +send_scsi_start_stop_unit_command_sync (gint fd, + GError **error) { uint8_t cdb[6]; @@ -1479,10 +1493,11 @@ handle_power_off (UDisksDrive *_drive, } } - /* Send the "SCSI START STOP UNIT" command to request that the unit - * be stopped but don't treat failure as fatal. In fact some - * USB-attached hard-disks fails with this command, probably due to - * the SCSI/SATA translation layer. + /* Send the "SCSI SYNCHRONIZE CACHE" and then the "SCSI START STOP + * UNIT" command to request that the unit be stopped. Don't treat + * failures as fatal. In fact some USB-attached hard-disks fails + * with one or both of these commands, probably due to the SCSI/SATA + * translation layer. */ fd = open (udisks_block_get_device (block), O_RDONLY|O_NONBLOCK|O_EXCL); if (fd == -1) @@ -1494,7 +1509,21 @@ handle_power_off (UDisksDrive *_drive, udisks_block_get_device (block)); goto out; } - if (!send_scsi_start_stop_command_sync (fd, &error)) + + if (!send_scsi_synchronize_cache_command_sync (fd, &error)) + { + udisks_warning ("Ignoring SCSI command SYNCHRONIZE CACHE failure (%s) on %s", + error->message, + udisks_block_get_device (block)); + g_clear_error (&error); + } + else + { + udisks_notice ("Successfully sent SCSI command SYNCHRONIZE CACHE to %s", + udisks_block_get_device (block)); + } + + if (!send_scsi_start_stop_unit_command_sync (fd, &error)) { udisks_warning ("Ignoring SCSI command START STOP UNIT failure (%s) on %s", error->message, @@ -1503,9 +1532,10 @@ handle_power_off (UDisksDrive *_drive, } else { - udisks_notice ("Powering off %s - successfully sent SCSI command START STOP UNIT", + udisks_notice ("Successfully sent SCSI command START STOP UNIT to %s", udisks_block_get_device (block)); } + if (close (fd) != 0) { g_dbus_method_invocation_return_error (invocation, |