summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <zeuthen@gmail.com>2014-03-25 22:57:25 -0700
committerDavid Zeuthen <zeuthen@gmail.com>2014-03-25 22:57:25 -0700
commit429892f2ec39d66732bee0f78d093eb6d2c5433f (patch)
tree0f64e3472023eb08fa4dcfbedf9dbb5336cad65a
parent25f83ee6beaa0daa8f7e84ce5df4563797e10490 (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.c46
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,