From: David Zeuthen Date: Tue, 23 Oct 2012 18:25:13 +0000 (-0400) Subject: Factor out ATA routines X-Git-Tag: upstream/2.1.2~98 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=17681dc2ae8f963cdd3b2e1dd2a0550c9aa98b65;p=platform%2Fupstream%2Fudisks2.git Factor out ATA routines Signed-off-by: David Zeuthen --- diff --git a/doc/udisks2-docs.xml b/doc/udisks2-docs.xml index 97e5e63..01721f7 100644 --- a/doc/udisks2-docs.xml +++ b/doc/udisks2-docs.xml @@ -387,6 +387,7 @@ + State and Configuration diff --git a/doc/udisks2-sections.txt b/doc/udisks2-sections.txt index af9258a..8749579 100644 --- a/doc/udisks2-sections.txt +++ b/doc/udisks2-sections.txt @@ -341,6 +341,14 @@ udisks_cleanup_get_type
+udisksata +UDisksAtaCommandProtocol +UDisksAtaCommandInput +UDisksAtaCommandOutput +udisks_ata_send_command_sync +
+ +
udisksdaemonutil udisks_decode_udev_string udisks_safe_append_to_object_path diff --git a/src/Makefile.am b/src/Makefile.am index 25ca034..11543f9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,7 @@ libudisks_daemon_la_SOURCES = \ udisksfstabmonitor.h udisksfstabmonitor.c \ udiskscrypttabentry.h udiskscrypttabentry.c \ udiskscrypttabmonitor.h udiskscrypttabmonitor.c \ + udisksata.h udisksata.c \ $(BUILT_SOURCES) \ $(NULL) diff --git a/src/udisksdaemontypes.h b/src/udisksdaemontypes.h index c2290e5..858abce 100644 --- a/src/udisksdaemontypes.h +++ b/src/udisksdaemontypes.h @@ -172,4 +172,25 @@ typedef enum UDISKS_LOG_LEVEL_ERROR } UDisksLogLevel; +struct _UDisksAtaCommandOutput; +typedef struct _UDisksAtaCommandOutput UDisksAtaCommandOutput; + +struct _UDisksAtaCommandInput; +typedef struct _UDisksAtaCommandInput UDisksAtaCommandInput; + +/** + * UDisksAtaCommandProtocol: + * @UDISKS_ATA_COMMAND_PROTOCOL_NONE: Non-data + * @UDISKS_ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST: PIO Data-In + * @UDISKS_ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE: PIO Data-Out + * + * Enumeration used to specify the protocol of an ATA command + */ +typedef enum +{ + UDISKS_ATA_COMMAND_PROTOCOL_NONE, + UDISKS_ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST, + UDISKS_ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE +} UDisksAtaCommandProtocol; + #endif /* __UDISKS_DAEMON_TYPES_H__ */ diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c index b9b735e..f37a09c 100644 --- a/src/udiskslinuxdriveata.c +++ b/src/udiskslinuxdriveata.c @@ -25,11 +25,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include @@ -54,6 +49,7 @@ #include "udisksbasejob.h" #include "udiskssimplejob.h" #include "udisksthreadedjob.h" +#include "udisksata.h" /** * SECTION:udiskslinuxdriveata @@ -1131,283 +1127,6 @@ handle_smart_selftest_start (UDisksDriveAta *_drive, /* ---------------------------------------------------------------------------------------------------- */ -#define ATA_DEFAULT_COMMAND_TIMEOUT_MSEC (5 * 1000) - -typedef struct -{ - guint8 command; - guint8 feature; - guint8 count; - guint8 device; - guint32 lba; - gsize buffer_size; - guchar *buffer; -} AtaCommandInput; - -typedef struct -{ - guint8 error; - guint8 count; - guint8 device; - guint8 status; - guint32 lba; - gsize buffer_size; - guchar *buffer; -} AtaCommandOutput; - -typedef enum -{ - ATA_COMMAND_PROTOCOL_NONE, /* Non-data */ - ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST, /* PIO Data-In */ - ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE, /* PIO Data-Out */ -} AtaCommandProtocol; - -static gboolean -ata_send_command (gint fd, - gint timeout_msec, - AtaCommandProtocol protocol, - AtaCommandInput *input, - AtaCommandOutput *output, - GError **error) -{ - struct sg_io_v4 io_v4; - uint8_t cdb[16]; - gint cdb_len = 16; - uint8_t sense[32]; - uint8_t *desc = sense+8; - gboolean use_ata12 = FALSE; - gboolean ret = FALSE; - gint rc; - - g_return_val_if_fail (fd != -1, FALSE); - g_return_val_if_fail (timeout_msec == -1 || timeout_msec > 0, FALSE); - g_return_val_if_fail (/* protocol >= 0 && */ protocol <= 2, FALSE); - g_return_val_if_fail (input != NULL, FALSE); - g_return_val_if_fail (input->buffer_size == 0 || input->buffer != NULL, FALSE); - g_return_val_if_fail (output != NULL, FALSE); - g_return_val_if_fail (output->buffer_size == 0 || output->buffer != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if (timeout_msec == -1) - timeout_msec = ATA_DEFAULT_COMMAND_TIMEOUT_MSEC; - - /* zero outputs, even if returning an error */ - output->error = 0; - output->count = 0; - output->device = 0; - output->status = 0; - output->lba = 0; - if (output->buffer != NULL) - memset (output->buffer, 0, output->buffer_size); - - memset (cdb, 0, sizeof (cdb)); - - /* Prefer ATA PASS-THROUGH (16) to ATA PASS-THROUGH (12) since the op-code - * for the latter clashes with the MMC blank command. - * - * TODO: this is hard-coded to FALSE for now - should retry with the 12-byte - * version only if the 16-byte version fails. But we don't do that - * right now - */ - use_ata12 = FALSE; - - if (use_ata12) - { - /* Do not confuse optical drive firmware with ATA commands - * some drives are reported to blank CD-RWs because the op-code - * for ATA PASS-THROUGH (12) clashes with the MMC blank command. - * - * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635 - */ - if (ioctl (fd, CDROM_GET_CAPABILITY, NULL) >= 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Refusing to send ATA PASS-THROUGH (12) to optical drive"); - goto out; - } - - /* - * ATA Pass-Through 12 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - cdb[0] = 0xa1; /* OPERATION CODE: 12 byte pass through */ - switch (protocol) - { - case ATA_COMMAND_PROTOCOL_NONE: - cdb[1] = 3 << 1; /* PROTOCOL: Non-data */ - cdb[2] = 0x20; /* OFF_LINE=0, CK_COND=1, T_DIR=0, BYT_BLOK=0, T_LENGTH=0 */ - break; - case ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST: - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-In */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - break; - case ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE: - cdb[1] = 5 << 1; /* PROTOCOL: PIO Data-Out */ - cdb[2] = 0x26; /* OFF_LINE=0, CK_COND=1, T_DIR=0, BYT_BLOK=1, T_LENGTH=2 */ - break; - default: - g_assert_not_reached (); - break; - } - cdb[3] = input->feature; /* FEATURES */ - cdb[4] = input->count; /* SECTORS */ - cdb[5] = (input->lba >> 0) & 0xff; /* LBA LOW */ - cdb[6] = (input->lba >> 8) & 0xff; /* LBA MID */ - cdb[7] = (input->lba >> 16) & 0xff; /* LBA HIGH */ - cdb[8] = input->device; /* SELECT */ - cdb[9] = input->command; /* ATA COMMAND */ - cdb_len = 12; - } - else - { - /* - * ATA Pass-Through 16 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - cdb[0] = 0x85; /* OPERATION CODE: 16 byte pass through */ - switch (protocol) - { - case ATA_COMMAND_PROTOCOL_NONE: - cdb[1] = 3 << 1; /* PROTOCOL: Non-data */ - cdb[2] = 0x20; /* OFF_LINE=0, CK_COND=1, T_DIR=0, BYT_BLOK=0, T_LENGTH=0 */ - break; - case ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST: - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-In */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - break; - case ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE: - cdb[1] = 5 << 1; /* PROTOCOL: PIO Data-Out */ - cdb[2] = 0x26; /* OFF_LINE=0, CK_COND=1, T_DIR=0, BYT_BLOK=1, T_LENGTH=2 */ - break; - default: - g_assert_not_reached (); - break; - } - cdb[ 3] = (input->feature >> 8) & 0xff; /* FEATURES */ - cdb[ 4] = (input->feature >> 0) & 0xff; /* FEATURES */ - cdb[ 5] = (input->count >> 8) & 0xff; /* SECTORS */ - cdb[ 6] = (input->count >> 0) & 0xff; /* SECTORS */ - cdb[ 8] = (input->lba >> 16) & 0xff; /* LBA HIGH */ - cdb[10] = (input->lba >> 8) & 0xff; /* LBA MID */ - cdb[12] = (input->lba >> 0) & 0xff; /* LBA LOW */ - cdb[13] = input->device; /* SELECT */ - cdb[14] = input->command; /* ATA COMMAND */ - cdb_len = 16; - } - - /* See http://sg.danny.cz/sg/sg_io.html and http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html - * for detailed information about how the SG_IO ioctl work - */ - - memset (sense, 0, sizeof (sense)); - memset (&io_v4, 0, sizeof (io_v4)); - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = cdb_len; - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof (sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = output->buffer_size; - io_v4.din_xferp = (uintptr_t) output->buffer; - io_v4.dout_xfer_len = input->buffer_size; - io_v4.dout_xferp = (uintptr_t) input->buffer; - if (timeout_msec == G_MAXINT) - io_v4.timeout = G_MAXUINT; - else - io_v4.timeout = timeout_msec; - - rc = ioctl (fd, SG_IO, &io_v4); - if (rc != 0) - { - /* could be that the driver doesn't do version 4, try version 3 */ - if (errno == EINVAL) - { - struct sg_io_hdr io_hdr; - - memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char*) cdb; - io_hdr.cmd_len = cdb_len; - switch (protocol) - { - case ATA_COMMAND_PROTOCOL_NONE: - io_hdr.dxfer_direction = SG_DXFER_NONE; - break; - - case ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST: - io_hdr.dxferp = output->buffer; - io_hdr.dxfer_len = output->buffer_size; - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - break; - - case ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE: - io_hdr.dxferp = input->buffer; - io_hdr.dxfer_len = input->buffer_size; - io_hdr.dxfer_direction = SG_DXFER_TO_DEV; - break; - } - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof (sense); - if (timeout_msec == G_MAXINT) - io_hdr.timeout = G_MAXUINT; - else - io_hdr.timeout = timeout_msec; - - rc = ioctl(fd, SG_IO, &io_hdr); - if (rc != 0) - { - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), - "SGIO v3 ioctl failed (v4 not supported): %m"); - goto out; - } - } - else - { - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), - "SGIO v4 ioctl failed: %m"); - goto out; - } - } - - if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) - { - gchar *s = udisks_daemon_util_hexdump (sense, 32); - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Unexpected sense data returned:\n%s", s); - g_free (s); - goto out; - } - - output->error = desc[3]; - output->count = desc[5]; - output->device = desc[12]; - output->status = desc[13]; - output->lba = (desc[11] << 16) | (desc[9] << 8) | desc[7]; - - /* TODO: be more exact with the error code perhaps? */ - if (output->error != 0 || output->status & 0x01) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "ATA command failed: error=0x%02x count=0x%02x status=0x%02x", - output->error, output->count, output->status); - goto out; - } - - ret = TRUE; - - out: - return ret; -} - -/* ---------------------------------------------------------------------------------------------------- */ - static gboolean handle_pm_get_state (UDisksDriveAta *_drive, GDBusMethodInvocation *invocation, @@ -1489,14 +1208,14 @@ handle_pm_get_state (UDisksDriveAta *_drive, { /* ATA8: 7.8 CHECK POWER MODE - E5h, Non-Data */ - AtaCommandInput input = {.command = 0xe5}; - AtaCommandOutput output = {0}; - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_NONE, - &input, - &output, - &error)) + UDisksAtaCommandInput input = {.command = 0xe5}; + UDisksAtaCommandOutput output = {0}; + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_NONE, + &input, + &output, + &error)) { g_prefix_error (&error, "Error sending ATA command CHECK POWER MODE: "); g_dbus_method_invocation_take_error (invocation, error); @@ -1620,14 +1339,14 @@ handle_pm_standby (UDisksDriveAta *_drive, { /* ATA8: 7.55 STANDBY IMMEDIATE - E0h, Non-Data */ - AtaCommandInput input = {.command = 0xe0}; - AtaCommandOutput output = {0}; - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_NONE, - &input, - &output, - &error)) + UDisksAtaCommandInput input = {.command = 0xe0}; + UDisksAtaCommandOutput output = {0}; + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_NONE, + &input, + &output, + &error)) { g_prefix_error (&error, "Error sending ATA command STANDBY IMMEDIATE: "); g_dbus_method_invocation_take_error (invocation, error); @@ -1865,14 +1584,14 @@ apply_configuration_thread_func (gpointer user_data) if (data->ata_pm_standby != -1) { /* ATA8: 7.18 IDLE - E3h, Non-Data */ - AtaCommandInput input = {.command = 0xe3, .count = data->ata_pm_standby}; - AtaCommandOutput output = {0}; - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_NONE, - &input, - &output, - &error)) + UDisksAtaCommandInput input = {.command = 0xe3, .count = data->ata_pm_standby}; + UDisksAtaCommandOutput output = {0}; + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_NONE, + &input, + &output, + &error)) { udisks_error ("Error sending ATA command IDLE (timeout=%d) to %s: %s (%s, %d)", data->ata_pm_standby, device_file, @@ -1893,19 +1612,19 @@ apply_configuration_thread_func (gpointer user_data) /* ATA8: 7.48 SET FEATURES - EFh, Non-Data * 7.48.6 Enable/disable the APM feature set */ - AtaCommandInput input = {.command = 0xef, .feature = 0x05, .count = data->ata_apm_level}; - AtaCommandOutput output = {0}; + UDisksAtaCommandInput input = {.command = 0xef, .feature = 0x05, .count = data->ata_apm_level}; + UDisksAtaCommandOutput output = {0}; if (data->ata_apm_level == 0xff) { input.feature = 0x85; input.count = 0x00; } - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_NONE, - &input, - &output, - &error)) + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_NONE, + &input, + &output, + &error)) { udisks_error ("Error sending ATA command SET FEATURES, sub-command 0x%02x (ata_apm_level=%d) to %s: %s (%s, %d)", input.feature, data->ata_apm_level, device_file, @@ -1924,19 +1643,19 @@ apply_configuration_thread_func (gpointer user_data) /* ATA8: 7.48 SET FEATURES - EFh, Non-Data * 7.48.11 Enable/disable the AAM feature set */ - AtaCommandInput input = {.command = 0xef, .feature = 0x42, .count = data->ata_aam_level}; - AtaCommandOutput output = {0}; + UDisksAtaCommandInput input = {.command = 0xef, .feature = 0x42, .count = data->ata_aam_level}; + UDisksAtaCommandOutput output = {0}; if (data->ata_apm_level == 0xff) { input.feature = 0xc2; input.count = 0x00; } - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_NONE, - &input, - &output, - &error)) + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_NONE, + &input, + &output, + &error)) { udisks_error ("Error sending ATA command SET FEATURES, sub-command 0x%02x (ata_aam_level=%d) to %s: %s (%s, %d)", input.feature, data->ata_aam_level, device_file, @@ -2137,14 +1856,14 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta *drive, /* First get the IDENTIFY data directly from the drive, for sanity checks */ { /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */ - AtaCommandInput input = {.command = 0xec}; - AtaCommandOutput output = {.buffer = identify.buf, .buffer_size = sizeof (identify.buf)}; - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST, - &input, - &output, - &local_error)) + UDisksAtaCommandInput input = {.command = 0xec}; + UDisksAtaCommandOutput output = {.buffer = identify.buf, .buffer_size = sizeof (identify.buf)}; + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_DRIVE_TO_HOST, + &input, + &output, + &local_error)) { g_prefix_error (&local_error, "Error sending ATA command IDENTIFY DEVICE: "); goto out; @@ -2229,16 +1948,16 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta *drive, { /* ATA8: 7.45 SECURITY SET PASSWORD - F1h, PIO Data-Out */ guchar buf[512]; - AtaCommandInput input = {.command = 0xf1, .buffer = buf, .buffer_size = sizeof (buf)}; - AtaCommandOutput output = {0}; + UDisksAtaCommandInput input = {.command = 0xf1, .buffer = buf, .buffer_size = sizeof (buf)}; + UDisksAtaCommandOutput output = {0}; memset (buf, 0, sizeof (buf)); memcpy (buf + 2, pass, strlen (pass)); - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE, - &input, - &output, - &local_error)) + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE, + &input, + &output, + &local_error)) { g_prefix_error (&local_error, "Error sending ATA command SECURITY SET PASSWORD: "); goto out; @@ -2256,14 +1975,14 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta *drive, /* Third... do SECURITY ERASE PREPARE */ { /* ATA8: 7.42 SECURITY ERASE PREPARE - F3h, Non-Data */ - AtaCommandInput input = {.command = 0xf3}; - AtaCommandOutput output = {0}; - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_NONE, - &input, - &output, - &local_error)) + UDisksAtaCommandInput input = {.command = 0xf3}; + UDisksAtaCommandOutput output = {0}; + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_NONE, + &input, + &output, + &local_error)) { g_prefix_error (&local_error, "Error sending ATA command SECURITY ERASE PREPARE: "); goto out; @@ -2274,18 +1993,18 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta *drive, { /* ATA8: 7.43 SECURITY ERASE UNIT - F4h, PIO Data-Out */ guchar buf[512]; - AtaCommandInput input = {.command = 0xf4, .buffer = buf, .buffer_size = sizeof (buf)}; - AtaCommandOutput output = {0}; + UDisksAtaCommandInput input = {.command = 0xf4, .buffer = buf, .buffer_size = sizeof (buf)}; + UDisksAtaCommandOutput output = {0}; memset (buf, 0, sizeof (buf)); if (enhanced) buf[0] |= 0x02; memcpy (buf + 2, pass, strlen (pass)); - if (!ata_send_command (fd, - G_MAXINT, /* disable timeout */ - ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE, - &input, - &output, - &local_error)) + if (!udisks_ata_send_command_sync (fd, + G_MAXINT, /* disable timeout */ + UDISKS_ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE, + &input, + &output, + &local_error)) { g_prefix_error (&local_error, "Error sending ATA command SECURITY ERASE UNIT (enhanced=%d): ", enhanced ? 1 : 0); @@ -2305,17 +2024,17 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta *drive, { /* ATA8: 7.41 SECURITY DISABLE PASSWORD - F6h, PIO Data-Out */ guchar buf[512]; - AtaCommandInput input = {.command = 0xf6, .buffer = buf, .buffer_size = sizeof (buf)}; - AtaCommandOutput output = {0}; + UDisksAtaCommandInput input = {.command = 0xf6, .buffer = buf, .buffer_size = sizeof (buf)}; + UDisksAtaCommandOutput output = {0}; GError *cleanup_error = NULL; memset (buf, 0, sizeof (buf)); memcpy (buf + 2, pass, strlen (pass)); - if (!ata_send_command (fd, - -1, - ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE, - &input, - &output, - &cleanup_error)) + if (!udisks_ata_send_command_sync (fd, + -1, + UDISKS_ATA_COMMAND_PROTOCOL_HOST_TO_DRIVE, + &input, + &output, + &cleanup_error)) { udisks_error ("Failed to clear user password '%s' on %s (%s) while attemping clean-up after a failed secure erase operation. You may need to manually unlock the drive. The error was: %s (%s, %d)", pass,