Revision e8b54394
b/hw/ide.c | ||
---|---|---|
372 | 372 |
#define SENSE_ILLEGAL_REQUEST 5 |
373 | 373 |
#define SENSE_UNIT_ATTENTION 6 |
374 | 374 |
|
375 |
#define SMART_READ_DATA 0xd0 |
|
376 |
#define SMART_READ_THRESH 0xd1 |
|
377 |
#define SMART_ATTR_AUTOSAVE 0xd2 |
|
378 |
#define SMART_SAVE_ATTR 0xd3 |
|
379 |
#define SMART_EXECUTE_OFFLINE 0xd4 |
|
380 |
#define SMART_READ_LOG 0xd5 |
|
381 |
#define SMART_WRITE_LOG 0xd6 |
|
382 |
#define SMART_ENABLE 0xd8 |
|
383 |
#define SMART_DISABLE 0xd9 |
|
384 |
#define SMART_STATUS 0xda |
|
385 |
|
|
386 |
static int smart_attributes[][5] = { |
|
387 |
/* id, flags, val, wrst, thrsh */ |
|
388 |
{ 0x01, 0x03, 0x64, 0x64, 0x06}, /* raw read */ |
|
389 |
{ 0x03, 0x03, 0x64, 0x64, 0x46}, /* spin up */ |
|
390 |
{ 0x04, 0x02, 0x64, 0x64, 0x14}, /* start stop count */ |
|
391 |
{ 0x05, 0x03, 0x64, 0x64, 0x36}, /* remapped sectors */ |
|
392 |
{ 0x00, 0x00, 0x00, 0x00, 0x00} |
|
393 |
}; |
|
394 |
|
|
395 |
|
|
396 |
|
|
375 | 397 |
struct IDEState; |
376 | 398 |
|
377 | 399 |
typedef void EndTransferFunc(struct IDEState *); |
... | ... | |
444 | 466 |
int media_changed; |
445 | 467 |
/* for pmac */ |
446 | 468 |
int is_read; |
469 |
/* SMART */ |
|
470 |
uint8_t smart_enabled; |
|
471 |
uint8_t smart_autosave; |
|
472 |
int smart_errors; |
|
473 |
uint8_t smart_selftest_count; |
|
474 |
uint8_t *smart_selftest_data; |
|
475 |
|
|
447 | 476 |
} IDEState; |
448 | 477 |
|
449 | 478 |
/* XXX: DVDs that could fit on a CD will be reported as a CD */ |
... | ... | |
594 | 623 |
put_le16(p + 68, 120); |
595 | 624 |
put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ |
596 | 625 |
put_le16(p + 81, 0x16); /* conforms to ata5 */ |
597 |
put_le16(p + 82, (1 << 14)); |
|
626 |
/* 14=NOP supported, 0=SMART supported */ |
|
627 |
put_le16(p + 82, (1 << 14) | 1); |
|
598 | 628 |
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */ |
599 | 629 |
put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); |
600 |
put_le16(p + 84, (1 << 14)); |
|
601 |
put_le16(p + 85, (1 << 14)); |
|
630 |
/* 14=set to 1, 1=SMART self test, 0=SMART error logging */ |
|
631 |
put_le16(p + 84, (1 << 14) | 0); |
|
632 |
/* 14 = NOP supported, 0=SMART feature set enabled */ |
|
633 |
put_le16(p + 85, (1 << 14) | 1); |
|
602 | 634 |
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */ |
603 | 635 |
put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); |
604 |
put_le16(p + 87, (1 << 14)); |
|
636 |
/* 14=set to 1, 1=smart self test, 0=smart error logging */ |
|
637 |
put_le16(p + 87, (1 << 14) | 0); |
|
605 | 638 |
put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ |
606 | 639 |
put_le16(p + 93, 1 | (1 << 14) | 0x2000); |
607 | 640 |
put_le16(p + 100, s->nb_sectors); |
... | ... | |
2567 | 2600 |
s->status = READY_STAT | SEEK_STAT; |
2568 | 2601 |
ide_set_irq(s); |
2569 | 2602 |
break; |
2603 |
|
|
2604 |
case WIN_SMART: |
|
2605 |
if (s->is_cdrom) |
|
2606 |
goto abort_cmd; |
|
2607 |
if (s->hcyl != 0xc2 || s->lcyl != 0x4f) |
|
2608 |
goto abort_cmd; |
|
2609 |
if (!s->smart_enabled && s->feature != SMART_ENABLE) |
|
2610 |
goto abort_cmd; |
|
2611 |
switch (s->feature) { |
|
2612 |
case SMART_DISABLE: |
|
2613 |
s->smart_enabled = 0; |
|
2614 |
s->status = READY_STAT | SEEK_STAT; |
|
2615 |
ide_set_irq(s); |
|
2616 |
break; |
|
2617 |
case SMART_ENABLE: |
|
2618 |
s->smart_enabled = 1; |
|
2619 |
s->status = READY_STAT | SEEK_STAT; |
|
2620 |
ide_set_irq(s); |
|
2621 |
break; |
|
2622 |
case SMART_ATTR_AUTOSAVE: |
|
2623 |
switch (s->sector) { |
|
2624 |
case 0x00: |
|
2625 |
s->smart_autosave = 0; |
|
2626 |
break; |
|
2627 |
case 0xf1: |
|
2628 |
s->smart_autosave = 1; |
|
2629 |
break; |
|
2630 |
default: |
|
2631 |
goto abort_cmd; |
|
2632 |
} |
|
2633 |
s->status = READY_STAT | SEEK_STAT; |
|
2634 |
ide_set_irq(s); |
|
2635 |
break; |
|
2636 |
case SMART_STATUS: |
|
2637 |
if (!s->smart_errors) { |
|
2638 |
s->hcyl = 0xc2; |
|
2639 |
s->lcyl = 0x4f; |
|
2640 |
} else { |
|
2641 |
s->hcyl = 0x2c; |
|
2642 |
s->lcyl = 0xf4; |
|
2643 |
} |
|
2644 |
s->status = READY_STAT | SEEK_STAT; |
|
2645 |
ide_set_irq(s); |
|
2646 |
break; |
|
2647 |
case SMART_READ_THRESH: |
|
2648 |
memset(s->io_buffer, 0, 0x200); |
|
2649 |
s->io_buffer[0] = 0x01; /* smart struct version */ |
|
2650 |
for (n=0; n<30; n++) { |
|
2651 |
if (smart_attributes[n][0] == 0) |
|
2652 |
break; |
|
2653 |
s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; |
|
2654 |
s->io_buffer[2+1+(n*12)] = smart_attributes[n][4]; |
|
2655 |
} |
|
2656 |
for (n=0; n<511; n++) /* checksum */ |
|
2657 |
s->io_buffer[511] += s->io_buffer[n]; |
|
2658 |
s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
|
2659 |
s->status = READY_STAT | SEEK_STAT; |
|
2660 |
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); |
|
2661 |
ide_set_irq(s); |
|
2662 |
break; |
|
2663 |
case SMART_READ_DATA: |
|
2664 |
memset(s->io_buffer, 0, 0x200); |
|
2665 |
s->io_buffer[0] = 0x01; /* smart struct version */ |
|
2666 |
for (n=0; n<30; n++) { |
|
2667 |
if (smart_attributes[n][0] == 0) |
|
2668 |
break; |
|
2669 |
s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; |
|
2670 |
s->io_buffer[2+1+(n*12)] = smart_attributes[n][1]; |
|
2671 |
s->io_buffer[2+3+(n*12)] = smart_attributes[n][2]; |
|
2672 |
s->io_buffer[2+4+(n*12)] = smart_attributes[n][3]; |
|
2673 |
} |
|
2674 |
s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00); |
|
2675 |
if (s->smart_selftest_count == 0) { |
|
2676 |
s->io_buffer[363] = 0; |
|
2677 |
} else { |
|
2678 |
s->io_buffer[363] = |
|
2679 |
s->smart_selftest_data[3 + |
|
2680 |
(s->smart_selftest_count - 1) * |
|
2681 |
24]; |
|
2682 |
} |
|
2683 |
s->io_buffer[364] = 0x20; |
|
2684 |
s->io_buffer[365] = 0x01; |
|
2685 |
/* offline data collection capacity: execute + self-test*/ |
|
2686 |
s->io_buffer[367] = (1<<4 | 1<<3 | 1); |
|
2687 |
s->io_buffer[368] = 0x03; /* smart capability (1) */ |
|
2688 |
s->io_buffer[369] = 0x00; /* smart capability (2) */ |
|
2689 |
s->io_buffer[370] = 0x01; /* error logging supported */ |
|
2690 |
s->io_buffer[372] = 0x02; /* minutes for poll short test */ |
|
2691 |
s->io_buffer[373] = 0x36; /* minutes for poll ext test */ |
|
2692 |
s->io_buffer[374] = 0x01; /* minutes for poll conveyance */ |
|
2693 |
|
|
2694 |
for (n=0; n<511; n++) |
|
2695 |
s->io_buffer[511] += s->io_buffer[n]; |
|
2696 |
s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
|
2697 |
s->status = READY_STAT | SEEK_STAT; |
|
2698 |
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); |
|
2699 |
ide_set_irq(s); |
|
2700 |
break; |
|
2701 |
case SMART_READ_LOG: |
|
2702 |
switch (s->sector) { |
|
2703 |
case 0x01: /* summary smart error log */ |
|
2704 |
memset(s->io_buffer, 0, 0x200); |
|
2705 |
s->io_buffer[0] = 0x01; |
|
2706 |
s->io_buffer[1] = 0x00; /* no error entries */ |
|
2707 |
s->io_buffer[452] = s->smart_errors & 0xff; |
|
2708 |
s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8; |
|
2709 |
|
|
2710 |
for (n=0; n<511; n++) |
|
2711 |
s->io_buffer[511] += s->io_buffer[n]; |
|
2712 |
s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
|
2713 |
break; |
|
2714 |
case 0x06: /* smart self test log */ |
|
2715 |
memset(s->io_buffer, 0, 0x200); |
|
2716 |
s->io_buffer[0] = 0x01; |
|
2717 |
if (s->smart_selftest_count == 0) { |
|
2718 |
s->io_buffer[508] = 0; |
|
2719 |
} else { |
|
2720 |
s->io_buffer[508] = s->smart_selftest_count; |
|
2721 |
for (n=2; n<506; n++) |
|
2722 |
s->io_buffer[n] = s->smart_selftest_data[n]; |
|
2723 |
} |
|
2724 |
for (n=0; n<511; n++) |
|
2725 |
s->io_buffer[511] += s->io_buffer[n]; |
|
2726 |
s->io_buffer[511] = 0x100 - s->io_buffer[511]; |
|
2727 |
break; |
|
2728 |
default: |
|
2729 |
goto abort_cmd; |
|
2730 |
} |
|
2731 |
s->status = READY_STAT | SEEK_STAT; |
|
2732 |
ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); |
|
2733 |
ide_set_irq(s); |
|
2734 |
break; |
|
2735 |
case SMART_EXECUTE_OFFLINE: |
|
2736 |
switch (s->sector) { |
|
2737 |
case 0: /* off-line routine */ |
|
2738 |
case 1: /* short self test */ |
|
2739 |
case 2: /* extended self test */ |
|
2740 |
s->smart_selftest_count++; |
|
2741 |
if(s->smart_selftest_count > 21) |
|
2742 |
s->smart_selftest_count = 0; |
|
2743 |
n = 2 + (s->smart_selftest_count - 1) * 24; |
|
2744 |
s->smart_selftest_data[n] = s->sector; |
|
2745 |
s->smart_selftest_data[n+1] = 0x00; /* OK and finished */ |
|
2746 |
s->smart_selftest_data[n+2] = 0x34; /* hour count lsb */ |
|
2747 |
s->smart_selftest_data[n+3] = 0x12; /* hour count msb */ |
|
2748 |
s->status = READY_STAT | SEEK_STAT; |
|
2749 |
ide_set_irq(s); |
|
2750 |
break; |
|
2751 |
default: |
|
2752 |
goto abort_cmd; |
|
2753 |
} |
|
2754 |
break; |
|
2755 |
default: |
|
2756 |
goto abort_cmd; |
|
2757 |
} |
|
2758 |
break; |
|
2570 | 2759 |
default: |
2571 | 2760 |
abort_cmd: |
2572 | 2761 |
ide_abort_command(s); |
... | ... | |
2828 | 3017 |
s->heads = heads; |
2829 | 3018 |
s->sectors = secs; |
2830 | 3019 |
s->nb_sectors = nb_sectors; |
2831 |
|
|
3020 |
/* The SMART values should be preserved across power cycles |
|
3021 |
but they aren't. */ |
|
3022 |
s->smart_enabled = 1; |
|
3023 |
s->smart_autosave = 1; |
|
3024 |
s->smart_errors = 0; |
|
3025 |
s->smart_selftest_count = 0; |
|
3026 |
s->smart_selftest_data = qemu_blockalign(s->bs, 512); |
|
2832 | 3027 |
if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { |
2833 | 3028 |
s->is_cdrom = 1; |
2834 | 3029 |
bdrv_set_change_cb(s->bs, cdrom_change_cb, s); |
Also available in: Unified diff