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
This commit is contained in:
Solomon Peachy 2025-09-16 09:48:56 -04:00
parent e09829a71d
commit c307fd5525
5 changed files with 56 additions and 13 deletions

View file

@ -1753,7 +1753,7 @@ static int ata_smart_callback(int btn, struct gui_synclist *lists)
{ {
int rc; int rc;
memset(&smart_data, 0, sizeof(struct ata_smart_values)); 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(); simplelist_reset_lines();
if (rc == 0) if (rc == 0)
{ {

View file

@ -730,6 +730,45 @@ static int STORAGE_INIT_ATTR ata_hard_reset(void)
return ret; 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 // not putting this into STORAGE_INIT_ATTR, as ATA spec recommends to
// re-read identify_info after soft reset. So we'll do that. // re-read identify_info after soft reset. So we'll do that.
static int identify(void) static int identify(void)

View file

@ -83,6 +83,8 @@ struct ata_smart_attribute {
/* 6-15: Reserved for future use */ /* 6-15: Reserved for future use */
#define ATTRIBUTE_FLAGS_OTHER(x) ((x) & 0xffc0) #define ATTRIBUTE_FLAGS_OTHER(x) ((x) & 0xffc0)
#define ATA_SMART_READ_DATA 0xD0
struct ata_smart_values struct ata_smart_values
{ {
unsigned short int revnumber; unsigned short int revnumber;
@ -226,7 +228,7 @@ int ata_get_dma_mode(void);
#ifdef HAVE_ATA_SMART #ifdef HAVE_ATA_SMART
/* Returns current S.M.A.R.T. data */ /* 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 #endif
#ifdef BOOTLOADER #ifdef BOOTLOADER

View file

@ -1183,7 +1183,7 @@ int ata_init(void)
} }
#ifdef HAVE_ATA_SMART #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 (!ata_powered) PASS_RC(ata_power_up(), 3, 0);
if (ceata) 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_write_multiple_register(0, ceata_taskfile, 16), 3, 2);
PASS_RC(ceata_check_error(), 3, 3); 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_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); 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; int i;
PASS_RC(ata_wait_for_not_bsy(10000000), 3, 6); 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_LMR, 0x4f);
ata_write_cbr(&ATA_PIO_LHR, 0xc2); ata_write_cbr(&ATA_PIO_LHR, 0xc2);
ata_write_cbr(&ATA_PIO_DVR, BIT(6)); ata_write_cbr(&ATA_PIO_DVR, BIT(6));
@ -1221,10 +1221,10 @@ static int ata_smart(uint16_t* buf)
return 0; 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); 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); mutex_unlock(&ata_mutex);
return rc; return rc;
} }

View file

@ -693,9 +693,9 @@ static void usb_storage_send_ata_identify(void)
send_block_data(cur_cmd.data[0], 512); send_block_data(cur_cmd.data[0], 512);
} }
#ifdef HAVE_ATA_SMART #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.count = 0;
cur_cmd.last_result = 0; cur_cmd.last_result = 0;
cur_cmd.data[0] = tb.transfer_buffer; 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 && if (cbw->command_block[1] == 0x08 &&
cbw->command_block[2] == 0x0e && cbw->command_block[2] == 0x0e &&
cbw->command_block[4] == 0x01) { 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(); usb_storage_send_ata_identify();
break; break;
#ifdef HAVE_ATA_SMART #ifdef HAVE_ATA_SMART
} else if (cbw->command_block[9] == 0xb0) { } else if (cbw->command_block[9] == 0xb0) {
usb_storage_send_smart(); usb_storage_send_smart(cbw->command_block[3]);
break; break;
#endif #endif
} }
@ -1377,12 +1378,13 @@ static void handle_scsi(struct command_block_wrapper* cbw)
if (cbw->command_block[1] == 0x08 && if (cbw->command_block[1] == 0x08 &&
cbw->command_block[2] == 0x0e && cbw->command_block[2] == 0x0e &&
cbw->command_block[6] == 0x01) { 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(); usb_storage_send_ata_identify();
break; break;
#ifdef HAVE_ATA_SMART #ifdef HAVE_ATA_SMART
} else if (cbw->command_block[14] == 0xb0) { } else if (cbw->command_block[14] == 0xb0) {
usb_storage_send_smart(); usb_storage_send_smart(cbw->command_block[4]);
break; break;
#endif #endif
} }