From c307fd552501020423f23e63e0c80132f5149e45 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Tue, 16 Sep 2025 09:48:56 -0400 Subject: [PATCH] ata: Parameterize the SMART query, add support to primary ATA driver There are numerous sub-commands, this makes it possible to call the others. Also in this patch is the ability for the "default" ATA driver to query smart data too Change-Id: Ie3aaf9e0b2d7a5d25d09dea34e4f10ee29047e1b --- apps/debug_menu.c | 2 +- firmware/drivers/ata.c | 39 +++++++++++++++++++ firmware/export/ata.h | 4 +- .../arm/s5l8702/ipod6g/storage_ata-6g.c | 10 ++--- firmware/usbstack/usb_storage.c | 14 ++++--- 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 5dafb334cb..b8199ff0d1 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -1753,7 +1753,7 @@ static int ata_smart_callback(int btn, struct gui_synclist *lists) { int rc; memset(&smart_data, 0, sizeof(struct ata_smart_values)); - rc = ata_read_smart(&smart_data); + rc = ata_read_smart(&smart_data, ATA_SMART_READ_DATA); simplelist_reset_lines(); if (rc == 0) { diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 86b596bf99..9440053303 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c @@ -730,6 +730,45 @@ static int STORAGE_INIT_ATTR ata_hard_reset(void) return ret; } +#ifdef HAVE_ATA_SMART +static int ata_smart(uint16_t *buf, uint8_t cmd) +{ + int i; + + ATA_OUT8(ATA_SELECT, ata_device); + + if(!wait_for_rdy()) { + DEBUGF("identify() - not RDY\n"); + return -1; + } + + ATA_OUT8(&ATA_PIO_FED, cmd); + ATA_OUT8(&ATA_PIO_HCYL, 0xc2); + ATA_OUT8(&ATA_PIO_LCYL, 0x4f); + ATA_OUT8(ATA_SELECT, SELECT_LBA | ata_device); + ATA_OUT8(ATA_COMMAND, CMD_SMART); + + if (!wait_for_start_of_transfer()) + { + DEBUGF("identify() - CMD failed\n"); + return -2; + } + + for (i = 0 ; i < 256 ; i++) { + /* The SMART words are already swapped, so we need to treat + this info differently that normal sector data */ + buf[i] = ATA_SWAP_IDENTIFY(ATA_IN16(ATA_DATA)); + } +} +int ata_read_smart(struct ata_smart_values* smart_data, uint8_t cmd) +{ + mutex_lock(&ata_mutex); + int rc = ata_smart((uint16_t*)smart_data, cmd); + mutex_unlock(&ata_mutex); + return rc; +} +#endif /* HAVE_ATA_SMART */ + // not putting this into STORAGE_INIT_ATTR, as ATA spec recommends to // re-read identify_info after soft reset. So we'll do that. static int identify(void) diff --git a/firmware/export/ata.h b/firmware/export/ata.h index f29c052be3..cef5dce613 100644 --- a/firmware/export/ata.h +++ b/firmware/export/ata.h @@ -83,6 +83,8 @@ struct ata_smart_attribute { /* 6-15: Reserved for future use */ #define ATTRIBUTE_FLAGS_OTHER(x) ((x) & 0xffc0) +#define ATA_SMART_READ_DATA 0xD0 + struct ata_smart_values { unsigned short int revnumber; @@ -226,7 +228,7 @@ int ata_get_dma_mode(void); #ifdef HAVE_ATA_SMART /* Returns current S.M.A.R.T. data */ -int ata_read_smart(struct ata_smart_values*); +int ata_read_smart(struct ata_smart_values*, uint8_t cmd); #endif #ifdef BOOTLOADER diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c index 4b5143e623..73806c7303 100644 --- a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c @@ -1183,7 +1183,7 @@ int ata_init(void) } #ifdef HAVE_ATA_SMART -static int ata_smart(uint16_t* buf) +static int ata_smart(uint16_t* buf, uint8_t cmd) { if (!ata_powered) PASS_RC(ata_power_up(), 3, 0); if (ceata) @@ -1200,7 +1200,7 @@ static int ata_smart(uint16_t* buf) PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 2); PASS_RC(ceata_check_error(), 3, 3); } - ceata_taskfile[0x9] = 0xd0; /* SMART read data */ + ceata_taskfile[0x9] = cmd; PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 4); PASS_RC(ceata_rw_multiple_block(false, buf, 1, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 3, 5); } @@ -1208,7 +1208,7 @@ static int ata_smart(uint16_t* buf) { int i; PASS_RC(ata_wait_for_not_bsy(10000000), 3, 6); - ata_write_cbr(&ATA_PIO_FED, 0xd0); + ata_write_cbr(&ATA_PIO_FED, cmd); ata_write_cbr(&ATA_PIO_LMR, 0x4f); ata_write_cbr(&ATA_PIO_LHR, 0xc2); ata_write_cbr(&ATA_PIO_DVR, BIT(6)); @@ -1221,10 +1221,10 @@ static int ata_smart(uint16_t* buf) return 0; } -int ata_read_smart(struct ata_smart_values* smart_data) +int ata_read_smart(struct ata_smart_values* smart_data, uint8_t cmd) { mutex_lock(&ata_mutex); - int rc = ata_smart((uint16_t*)smart_data); + int rc = ata_smart((uint16_t*)smart_data, cmd); mutex_unlock(&ata_mutex); return rc; } diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index 4c0fc99655..75f71e7d3a 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c @@ -693,9 +693,9 @@ static void usb_storage_send_ata_identify(void) send_block_data(cur_cmd.data[0], 512); } #ifdef HAVE_ATA_SMART -static void usb_storage_send_smart(void) +static void usb_storage_send_smart(uint8_t cmd) { - ata_read_smart((struct ata_smart_values*) tb.transfer_buffer); + ata_read_smart((struct ata_smart_values*) tb.transfer_buffer, cmd); cur_cmd.count = 0; cur_cmd.last_result = 0; cur_cmd.data[0] = tb.transfer_buffer; @@ -1358,12 +1358,13 @@ static void handle_scsi(struct command_block_wrapper* cbw) if (cbw->command_block[1] == 0x08 && cbw->command_block[2] == 0x0e && cbw->command_block[4] == 0x01) { - if (cbw->command_block[9] == 0xa1) { // ??? suspicious + if (cbw->command_block[9] == 0xa1 || + cbw->command_block[9] == 0xec) { usb_storage_send_ata_identify(); break; #ifdef HAVE_ATA_SMART } else if (cbw->command_block[9] == 0xb0) { - usb_storage_send_smart(); + usb_storage_send_smart(cbw->command_block[3]); break; #endif } @@ -1377,12 +1378,13 @@ static void handle_scsi(struct command_block_wrapper* cbw) if (cbw->command_block[1] == 0x08 && cbw->command_block[2] == 0x0e && cbw->command_block[6] == 0x01) { - if (cbw->command_block[14] == 0xec) { + if (cbw->command_block[14] == 0xa1 || + cbw->command_block[14] == 0xec) { usb_storage_send_ata_identify(); break; #ifdef HAVE_ATA_SMART } else if (cbw->command_block[14] == 0xb0) { - usb_storage_send_smart(); + usb_storage_send_smart(cbw->command_block[4]); break; #endif }