static bool cmd_smart(IDEState *s, uint8_t cmd) { int n; if (s->hcyl != 0xc2 || s->lcyl != 0x4f) { goto abort_cmd; } if (!s->smart_enabled && s->feature != SMART_ENABLE) { goto abort_cmd; } switch (s->feature) { case SMART_DISABLE: s->smart_enabled = 0; return true; case SMART_ENABLE: s->smart_enabled = 1; return true; case SMART_ATTR_AUTOSAVE: switch (s->sector) { case 0x00: s->smart_autosave = 0; break; case 0xf1: s->smart_autosave = 1; break; default: goto abort_cmd; } return true; case SMART_STATUS: if (!s->smart_errors) { s->hcyl = 0xc2; s->lcyl = 0x4f; } else { s->hcyl = 0x2c; s->lcyl = 0xf4; } return true; case SMART_READ_THRESH: memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { s->io_buffer[2 + 0 + (n * 12)] = smart_attributes[n][0]; s->io_buffer[2 + 1 + (n * 12)] = smart_attributes[n][11]; } /* checksum */ for (n = 0; n < 511; n++) { s->io_buffer[511] += s->io_buffer[n]; } s->io_buffer[511] = 0x100 - s->io_buffer[511]; s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); ide_set_irq(s->bus); return false; case SMART_READ_DATA: memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { int i; for (i = 0; i < 11; i++) { s->io_buffer[2 + i + (n * 12)] = smart_attributes[n][i]; } } s->io_buffer[362] = 0x02 | (s->smart_autosave ? 0x80 : 0x00); if (s->smart_selftest_count == 0) { s->io_buffer[363] = 0; } else { s->io_buffer[363] = s->smart_selftest_data[3 + (s->smart_selftest_count - 1) * 24]; } s->io_buffer[364] = 0x20; s->io_buffer[365] = 0x01; /* offline data collection capacity: execute + self-test*/ s->io_buffer[367] = (1 << 4 | 1 << 3 | 1); s->io_buffer[368] = 0x03; /* smart capability (1) */ s->io_buffer[369] = 0x00; /* smart capability (2) */ s->io_buffer[370] = 0x01; /* error logging supported */ s->io_buffer[372] = 0x02; /* minutes for poll short test */ s->io_buffer[373] = 0x36; /* minutes for poll ext test */ s->io_buffer[374] = 0x01; /* minutes for poll conveyance */ for (n = 0; n < 511; n++) { s->io_buffer[511] += s->io_buffer[n]; } s->io_buffer[511] = 0x100 - s->io_buffer[511]; s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); ide_set_irq(s->bus); return false; case SMART_READ_LOG: switch (s->sector) { case 0x01: /* summary smart error log */ memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; s->io_buffer[1] = 0x00; /* no error entries */ s->io_buffer[452] = s->smart_errors & 0xff; s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8; for (n = 0; n < 511; n++) { s->io_buffer[511] += s->io_buffer[n]; } s->io_buffer[511] = 0x100 - s->io_buffer[511]; break; case 0x06: /* smart self test log */ memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; if (s->smart_selftest_count == 0) { s->io_buffer[508] = 0; } else { s->io_buffer[508] = s->smart_selftest_count; for (n = 2; n < 506; n++) { s->io_buffer[n] = s->smart_selftest_data[n]; } } for (n = 0; n < 511; n++) { s->io_buffer[511] += s->io_buffer[n]; } s->io_buffer[511] = 0x100 - s->io_buffer[511]; break; default: goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); ide_set_irq(s->bus); return false; case SMART_EXECUTE_OFFLINE: switch (s->sector) { case 0: /* off-line routine */ case 1: /* short self test */ case 2: /* extended self test */ s->smart_selftest_count++; if (s->smart_selftest_count > 21) { s->smart_selftest_count = 0; } n = 2 + (s->smart_selftest_count - 1) * 24; s->smart_selftest_data[n] = s->sector; s->smart_selftest_data[n + 1] = 0x00; /* OK and finished */ s->smart_selftest_data[n + 2] = 0x34; /* hour count lsb */ s->smart_selftest_data[n + 3] = 0x12; /* hour count msb */ break; default: goto abort_cmd; } return true; } abort_cmd: ide_abort_command(s); return true; }