summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/debug_menu.c202
-rw-r--r--apps/gui/list.h4
-rw-r--r--firmware/export/ata.h106
-rw-r--r--firmware/export/config/ipod6g.h2
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c59
5 files changed, 373 insertions, 0 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index e602b713c3..2b9702299b 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1507,6 +1507,205 @@ static int disk_callback(int btn, struct gui_synclist *lists)
1507#endif /* HAVE_ATA_DMA */ 1507#endif /* HAVE_ATA_DMA */
1508 return btn; 1508 return btn;
1509} 1509}
1510
1511#ifdef HAVE_ATA_SMART
1512static struct ata_smart_values *smart_data = NULL;
1513
1514static const char * ata_smart_get_attr_name(unsigned char id)
1515{
1516 switch (id)
1517 {
1518 case 1: return "Raw Read Error Rate";
1519 case 2: return "Throughput Performance";
1520 case 3: return "Spin-Up Time";
1521 case 4: return "Start/Stop Count";
1522 case 5: return "Reallocated Sector Count";
1523 case 7: return "Seek Error Rate";
1524 case 8: return "Seek Time Performance";
1525 case 9: return "Power-On Hours Count";
1526 case 10: return "Spin-Up Retry Count";
1527 case 12: return "Power Cycle Count";
1528 case 192: return "Power-Off Retract Count";
1529 case 193: return "Load/Unload Cycle Count";
1530 case 194: return "HDA Temperature";
1531 case 196: return "Reallocated Event Count";
1532 case 197: return "Current Pending Sector Count";
1533 case 198: return "Uncorrectable Sector Count";
1534 case 199: return "UltraDMA CRC Error Count";
1535 case 220: return "Disk Shift";
1536 case 222: return "Loaded Hours";
1537 case 223: return "Load/Unload Retry Count";
1538 case 224: return "Load Friction";
1539 case 226: return "Load-In Time";
1540 case 240: return "Transfer Error Rate"; /* Fujitsu */
1541 /*case 240: return "Head Flying Hours";*/
1542 default: return "Unknown Attribute";
1543 }
1544};
1545
1546static int ata_smart_get_attr_rawfmt(unsigned char id)
1547{
1548 switch (id)
1549 {
1550 case 3: /* Spin-up time */
1551 return RAWFMT_RAW16_OPT_AVG16;
1552
1553 case 5: /* Reallocated sector count */
1554 case 196: /* Reallocated event count */
1555 return RAWFMT_RAW16_OPT_RAW16;
1556
1557 case 190: /* Airflow Temperature */
1558 case 194: /* HDA Temperature */
1559 return RAWFMT_TEMPMINMAX;
1560
1561 default:
1562 return RAWFMT_RAW48;
1563 }
1564};
1565
1566static int ata_smart_attr_to_string(
1567 struct ata_smart_attribute *attr, char *str, int size)
1568{
1569 uint16_t w[3]; /* 3 words to store 6 bytes of raw data */
1570 char buf[size]; /* temp string to store attribute data */
1571 int len, slen;
1572 int id = attr->id;
1573
1574 if (id == 0)
1575 return 0; /* null attribute */
1576
1577 /* align and convert raw data */
1578 memcpy(w, attr->raw, 6);
1579 w[0] = letoh16(w[0]);
1580 w[1] = letoh16(w[1]);
1581 w[2] = letoh16(w[2]);
1582
1583 len = snprintf(buf, size, ": %u,%u ", attr->current, attr->worst);
1584
1585 switch (ata_smart_get_attr_rawfmt(id))
1586 {
1587 case RAWFMT_RAW16_OPT_RAW16:
1588 len += snprintf(buf+len, size-len, "%u", w[0]);
1589 if ((w[1] || w[2]) && (len < size))
1590 len += snprintf(buf+len, size-len, " %u %u", w[1],w[2]);
1591 break;
1592
1593 case RAWFMT_RAW16_OPT_AVG16:
1594 len += snprintf(buf+len, size-len, "%u", w[0]);
1595 if (w[1] && (len < size))
1596 len += snprintf(buf+len, size-len, " Avg: %u", w[1]);
1597 break;
1598
1599 case RAWFMT_TEMPMINMAX:
1600 len += snprintf(buf+len, size-len, "%u -/+: %u/%u", w[0],w[1],w[2]);
1601 break;
1602
1603 case RAWFMT_RAW48:
1604 default:
1605 /* shows first 4 bytes of raw data as uint32 LE,
1606 and the ramaining 2 bytes as uint16 LE */
1607 len += snprintf(buf+len, size-len, "%lu", letoh32(*((uint32_t*)w)));
1608 if (w[2] && (len < size))
1609 len += snprintf(buf+len, size-len, " %u", w[2]);
1610 break;
1611 }
1612 /* ignore trailing \0 when truncated */
1613 if (len >= size) len = size-1;
1614
1615 /* fill return string; when max. size is exceded: first truncate
1616 attribute name, then attribute data and finally attribute id */
1617 slen = snprintf(str, size, "%d ", id);
1618 if (slen < size) {
1619 /* maximum space disponible for attribute name,
1620 including initial space separator */
1621 int name_sz = size - (slen + len);
1622 if (name_sz > 1) {
1623 len = snprintf(str+slen, name_sz, " %s",
1624 ata_smart_get_attr_name(id));
1625 if (len >= name_sz) len = name_sz-1;
1626 slen += len;
1627 }
1628 snprintf(str+slen, size-slen, "%s", buf);
1629 }
1630
1631 return 1; /* ok */
1632}
1633
1634static bool ata_smart_dump(void)
1635{
1636 int fd;
1637
1638 fd = creat("/smart_data.bin", 0666);
1639 if(fd >= 0)
1640 {
1641 write(fd, smart_data, sizeof(struct ata_smart_values));
1642 close(fd);
1643 }
1644
1645 fd = creat("/smart_data.txt", 0666);
1646 if(fd >= 0)
1647 {
1648 int i;
1649 char buf[128];
1650 for (i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
1651 {
1652 if (ata_smart_attr_to_string(
1653 &smart_data->vendor_attributes[i], buf, sizeof(buf)))
1654 {
1655 write(fd, buf, strlen(buf));
1656 write(fd, "\n", 1);
1657 }
1658 }
1659 close(fd);
1660 }
1661
1662 return false;
1663}
1664
1665static int ata_smart_callback(int btn, struct gui_synclist *lists)
1666{
1667 (void)lists;
1668
1669 if (btn == ACTION_STD_CANCEL)
1670 {
1671 smart_data = NULL;
1672 return btn;
1673 }
1674
1675 /* read S.M.A.R.T. data only on first redraw */
1676 if (!smart_data)
1677 {
1678 int i;
1679 char buf[SIMPLELIST_MAX_LINELENGTH];
1680 smart_data = ata_read_smart();
1681 simplelist_set_line_count(0);
1682 simplelist_addline("Id Name: Current,Worst Raw");
1683 for (i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
1684 if (ata_smart_attr_to_string(
1685 &smart_data->vendor_attributes[i], buf, sizeof(buf)))
1686 simplelist_addline(buf);
1687 }
1688 }
1689
1690 if (btn == ACTION_STD_CONTEXT)
1691 {
1692 ata_smart_dump();
1693 splashf(HZ, "S.M.A.R.T. data dumped");
1694 }
1695
1696 return btn;
1697}
1698
1699static bool dbg_ata_smart(void)
1700{
1701 struct simplelist_info info;
1702 simplelist_info_init(&info, "S.M.A.R.T. Data [CONTEXT to dump]", 1, NULL);
1703 info.action_callback = ata_smart_callback;
1704 info.hide_selection = true;
1705 info.scroll_all = true;
1706 return simplelist_show_list(&info);
1707}
1708#endif /* HAVE_ATA_SMART */
1510#else /* No SD, MMC or ATA */ 1709#else /* No SD, MMC or ATA */
1511static int disk_callback(int btn, struct gui_synclist *lists) 1710static int disk_callback(int btn, struct gui_synclist *lists)
1512{ 1711{
@@ -2383,6 +2582,9 @@ static const struct {
2383 { "View disk info", dbg_disk_info }, 2582 { "View disk info", dbg_disk_info },
2384#if (CONFIG_STORAGE & STORAGE_ATA) 2583#if (CONFIG_STORAGE & STORAGE_ATA)
2385 { "Dump ATA identify info", dbg_identify_info}, 2584 { "Dump ATA identify info", dbg_identify_info},
2585#ifdef HAVE_ATA_SMART
2586 { "View/Dump S.M.A.R.T. data", dbg_ata_smart},
2587#endif
2386#endif 2588#endif
2387#endif 2589#endif
2388 { "Metadata log", dbg_metadatalog }, 2590 { "Metadata log", dbg_metadatalog },
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 0f2f51a424..ef08a9e220 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -257,7 +257,11 @@ struct simplelist_info {
257}; 257};
258 258
259#define SIMPLELIST_MAX_LINES 32 259#define SIMPLELIST_MAX_LINES 32
260#ifdef HAVE_ATA_SMART
261#define SIMPLELIST_MAX_LINELENGTH 48
262#else
260#define SIMPLELIST_MAX_LINELENGTH 32 263#define SIMPLELIST_MAX_LINELENGTH 32
264#endif
261 265
262/** The next three functions are used if the text is mostly static. 266/** The next three functions are used if the text is mostly static.
263 These should be called in the action callback for the list. 267 These should be called in the action callback for the list.
diff --git a/firmware/export/ata.h b/firmware/export/ata.h
index 0bcb144e63..6f0d0b699f 100644
--- a/firmware/export/ata.h
+++ b/firmware/export/ata.h
@@ -25,6 +25,107 @@
25#include "config.h" /* for HAVE_MULTIVOLUME or not */ 25#include "config.h" /* for HAVE_MULTIVOLUME or not */
26#include "mv.h" /* for IF_MV() and friends */ 26#include "mv.h" /* for IF_MV() and friends */
27 27
28#ifdef HAVE_ATA_SMART
29/* S.M.A.R.T. headers from smartmontools-5.42 */
30#define NUMBER_ATA_SMART_ATTRIBUTES 30
31
32struct ata_smart_attribute {
33 unsigned char id;
34 /* meaning of flag bits: see MACROS just below */
35 /* WARNING: MISALIGNED! */
36 unsigned short flags;
37 unsigned char current;
38 unsigned char worst;
39 unsigned char raw[6];
40 unsigned char reserv;
41} __attribute__((packed));
42
43/* MACROS to interpret the flags bits in the previous structure. */
44/* These have not been implemented using bitflags and a union, to make */
45/* it portable across bit/little endian and different platforms. */
46
47/* 0: Prefailure bit */
48
49/* From SFF 8035i Revision 2 page 19: Bit 0 (pre-failure/advisory bit) */
50/* - If the value of this bit equals zero, an attribute value less */
51/* than or equal to its corresponding attribute threshold indicates an */
52/* advisory condition where the usage or age of the device has */
53/* exceeded its intended design life period. If the value of this bit */
54/* equals one, an attribute value less than or equal to its */
55/* corresponding attribute threshold indicates a prefailure condition */
56/* where imminent loss of data is being predicted. */
57#define ATTRIBUTE_FLAGS_PREFAILURE(x) (x & 0x01)
58
59/* 1: Online bit */
60
61/* From SFF 8035i Revision 2 page 19: Bit 1 (on-line data collection */
62/* bit) - If the value of this bit equals zero, then the attribute */
63/* value is updated only during off-line data collection */
64/* activities. If the value of this bit equals one, then the attribute */
65/* value is updated during normal operation of the device or during */
66/* both normal operation and off-line testing. */
67#define ATTRIBUTE_FLAGS_ONLINE(x) (x & 0x02)
68
69/* The following are (probably) IBM's, Maxtors and Quantum's definitions for the */
70/* vendor-specific bits: */
71/* 2: Performance type bit */
72#define ATTRIBUTE_FLAGS_PERFORMANCE(x) (x & 0x04)
73
74/* 3: Errorrate type bit */
75#define ATTRIBUTE_FLAGS_ERRORRATE(x) (x & 0x08)
76
77/* 4: Eventcount bit */
78#define ATTRIBUTE_FLAGS_EVENTCOUNT(x) (x & 0x10)
79
80/* 5: Selfpereserving bit */
81#define ATTRIBUTE_FLAGS_SELFPRESERVING(x) (x & 0x20)
82
83/* 6-15: Reserved for future use */
84#define ATTRIBUTE_FLAGS_OTHER(x) ((x) & 0xffc0)
85
86struct ata_smart_values
87{
88 unsigned short int revnumber;
89 struct ata_smart_attribute vendor_attributes [NUMBER_ATA_SMART_ATTRIBUTES];
90 unsigned char offline_data_collection_status;
91 unsigned char self_test_exec_status;
92 unsigned short int total_time_to_complete_off_line;
93 unsigned char vendor_specific_366;
94 unsigned char offline_data_collection_capability;
95 unsigned short int smart_capability;
96 unsigned char errorlog_capability;
97 unsigned char vendor_specific_371;
98 unsigned char short_test_completion_time;
99 unsigned char extend_test_completion_time;
100 unsigned char conveyance_test_completion_time;
101 unsigned char reserved_375_385[11];
102 unsigned char vendor_specific_386_510[125];
103 unsigned char chksum;
104} __attribute__((packed));
105
106/* Raw attribute value print formats */
107enum ata_attr_raw_format
108{
109 RAWFMT_DEFAULT,
110 RAWFMT_RAW8,
111 RAWFMT_RAW16,
112 RAWFMT_RAW48,
113 RAWFMT_HEX48,
114 RAWFMT_RAW64,
115 RAWFMT_HEX64,
116 RAWFMT_RAW16_OPT_RAW16,
117 RAWFMT_RAW16_OPT_AVG16,
118 RAWFMT_RAW24_DIV_RAW24,
119 RAWFMT_RAW24_DIV_RAW32,
120 RAWFMT_SEC2HOUR,
121 RAWFMT_MIN2HOUR,
122 RAWFMT_HALFMIN2HOUR,
123 RAWFMT_MSEC24_HOUR32,
124 RAWFMT_TEMPMINMAX,
125 RAWFMT_TEMP10X,
126};
127#endif /* HAVE_ATA_SMART */
128
28struct storage_info; 129struct storage_info;
29 130
30void ata_enable(bool on); 131void ata_enable(bool on);
@@ -69,4 +170,9 @@ int ata_spinup_time(void); /* ticks */
69int ata_get_dma_mode(void); 170int ata_get_dma_mode(void);
70#endif /* HAVE_ATA_DMA */ 171#endif /* HAVE_ATA_DMA */
71 172
173#ifdef HAVE_ATA_SMART
174/* Returns current S.M.A.R.T. data */
175void* ata_read_smart(void);
176#endif
177
72#endif /* __ATA_H__ */ 178#endif /* __ATA_H__ */
diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h
index 7e7025e157..0a40108699 100644
--- a/firmware/export/config/ipod6g.h
+++ b/firmware/export/config/ipod6g.h
@@ -201,6 +201,8 @@
201 201
202#define STORAGE_NEEDS_ALIGN 202#define STORAGE_NEEDS_ALIGN
203 203
204#define HAVE_ATA_SMART
205
204/* define this if the device has larger sectors when accessed via USB */ 206/* define this if the device has larger sectors when accessed via USB */
205/* (only relevant in disk.c, fat.c now always supports large virtual sectors) */ 207/* (only relevant in disk.c, fat.c now always supports large virtual sectors) */
206//#define MAX_LOG_SECTOR_SIZE 4096 208//#define MAX_LOG_SECTOR_SIZE 4096
diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
index c629fd583a..53ec45ec6d 100644
--- a/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
@@ -50,6 +50,9 @@
50/** static, private data **/ 50/** static, private data **/
51static uint8_t ceata_taskfile[16] STORAGE_ALIGN_ATTR; 51static uint8_t ceata_taskfile[16] STORAGE_ALIGN_ATTR;
52static uint16_t ata_identify_data[0x100] STORAGE_ALIGN_ATTR; 52static uint16_t ata_identify_data[0x100] STORAGE_ALIGN_ATTR;
53#ifdef HAVE_ATA_SMART
54static uint16_t ata_smart_data[0x100] STORAGE_ALIGN_ATTR;
55#endif
53static bool ceata; 56static bool ceata;
54static bool ata_swap; 57static bool ata_swap;
55static bool ata_lba48; 58static bool ata_lba48;
@@ -1211,6 +1214,62 @@ int ata_init(void)
1211 return 0; 1214 return 0;
1212} 1215}
1213 1216
1217#ifdef HAVE_ATA_SMART
1218static int ata_smart(uint16_t* buf)
1219{
1220 mutex_lock(&ata_mutex);
1221 ata_power_up();
1222
1223 if (ceata)
1224 {
1225 memset(ceata_taskfile, 0, 16);
1226 ceata_taskfile[0xc] = 0x4f;
1227 ceata_taskfile[0xd] = 0xc2;
1228 ceata_taskfile[0xe] = 0x40; /* Device/Head Register, bit6: 0->CHS, 1->LBA */
1229 ceata_taskfile[0xf] = 0xb0;
1230 PASS_RC(ceata_wait_idle(), 3, 0);
1231 if (((uint8_t*)ata_identify_data)[54] != 'A') /* Model != aAmsung */
1232 {
1233 ceata_taskfile[0x9] = 0xd8; /* SMART enable operations */
1234 PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 1);
1235 PASS_RC(ceata_check_error(), 3, 2);
1236 }
1237 ceata_taskfile[0x9] = 0xd0; /* SMART read data */
1238 PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 3, 3);
1239 PASS_RC(ceata_rw_multiple_block(false, buf, 1, CEATA_COMMAND_TIMEOUT * HZ / 1000000), 3, 4);
1240 }
1241 else
1242 {
1243 int i;
1244 uint32_t old = ATA_CFG;
1245 ATA_CFG |= BIT(6); /* 16bit big-endian */
1246 PASS_RC(ata_wait_for_not_bsy(10000000), 3, 5);
1247 ata_write_cbr(&ATA_PIO_DAD, 0);
1248 ata_write_cbr(&ATA_PIO_FED, 0xd0);
1249 ata_write_cbr(&ATA_PIO_SCR, 0);
1250 ata_write_cbr(&ATA_PIO_LLR, 0);
1251 ata_write_cbr(&ATA_PIO_LMR, 0x4f);
1252 ata_write_cbr(&ATA_PIO_LHR, 0xc2);
1253 ata_write_cbr(&ATA_PIO_DVR, BIT(6));
1254 ata_write_cbr(&ATA_PIO_CSD, 0xb0);
1255 PASS_RC(ata_wait_for_start_of_transfer(10000000), 3, 6);
1256 for (i = 0; i < 0x100; i++) buf[i] = ata_read_cbr(&ATA_PIO_DTR);
1257 ATA_CFG = old;
1258 }
1259
1260 ata_set_active();
1261 mutex_unlock(&ata_mutex);
1262
1263 return 0;
1264}
1265
1266void* ata_read_smart(void)
1267{
1268 ata_smart(ata_smart_data);
1269 return ata_smart_data;
1270}
1271#endif /* HAVE_ATA_SMART */
1272
1214#ifdef CONFIG_STORAGE_MULTI 1273#ifdef CONFIG_STORAGE_MULTI
1215static int ata_num_drives(int first_drive) 1274static int ata_num_drives(int first_drive)
1216{ 1275{