Commit f3d54fc4948b5525cc15e2a082f0cec8610ec5b4
1 parent
357c692c
Abstract out geometry detection code from IDE for reuse
Virtio will want to use the geometry detection code. It doesn't belong in ide.c anyway. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5797 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
123 additions
and
106 deletions
block.c
@@ -739,6 +739,122 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) | @@ -739,6 +739,122 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) | ||
739 | *nb_sectors_ptr = length; | 739 | *nb_sectors_ptr = length; |
740 | } | 740 | } |
741 | 741 | ||
742 | +struct partition { | ||
743 | + uint8_t boot_ind; /* 0x80 - active */ | ||
744 | + uint8_t head; /* starting head */ | ||
745 | + uint8_t sector; /* starting sector */ | ||
746 | + uint8_t cyl; /* starting cylinder */ | ||
747 | + uint8_t sys_ind; /* What partition type */ | ||
748 | + uint8_t end_head; /* end head */ | ||
749 | + uint8_t end_sector; /* end sector */ | ||
750 | + uint8_t end_cyl; /* end cylinder */ | ||
751 | + uint32_t start_sect; /* starting sector counting from 0 */ | ||
752 | + uint32_t nr_sects; /* nr of sectors in partition */ | ||
753 | +} __attribute__((packed)); | ||
754 | + | ||
755 | +/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ | ||
756 | +static int guess_disk_lchs(BlockDriverState *bs, | ||
757 | + int *pcylinders, int *pheads, int *psectors) | ||
758 | +{ | ||
759 | + uint8_t buf[512]; | ||
760 | + int ret, i, heads, sectors, cylinders; | ||
761 | + struct partition *p; | ||
762 | + uint32_t nr_sects; | ||
763 | + int64_t nb_sectors; | ||
764 | + | ||
765 | + bdrv_get_geometry(bs, &nb_sectors); | ||
766 | + | ||
767 | + ret = bdrv_read(bs, 0, buf, 1); | ||
768 | + if (ret < 0) | ||
769 | + return -1; | ||
770 | + /* test msdos magic */ | ||
771 | + if (buf[510] != 0x55 || buf[511] != 0xaa) | ||
772 | + return -1; | ||
773 | + for(i = 0; i < 4; i++) { | ||
774 | + p = ((struct partition *)(buf + 0x1be)) + i; | ||
775 | + nr_sects = le32_to_cpu(p->nr_sects); | ||
776 | + if (nr_sects && p->end_head) { | ||
777 | + /* We make the assumption that the partition terminates on | ||
778 | + a cylinder boundary */ | ||
779 | + heads = p->end_head + 1; | ||
780 | + sectors = p->end_sector & 63; | ||
781 | + if (sectors == 0) | ||
782 | + continue; | ||
783 | + cylinders = nb_sectors / (heads * sectors); | ||
784 | + if (cylinders < 1 || cylinders > 16383) | ||
785 | + continue; | ||
786 | + *pheads = heads; | ||
787 | + *psectors = sectors; | ||
788 | + *pcylinders = cylinders; | ||
789 | +#if 0 | ||
790 | + printf("guessed geometry: LCHS=%d %d %d\n", | ||
791 | + cylinders, heads, sectors); | ||
792 | +#endif | ||
793 | + return 0; | ||
794 | + } | ||
795 | + } | ||
796 | + return -1; | ||
797 | +} | ||
798 | + | ||
799 | +void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs) | ||
800 | +{ | ||
801 | + int translation, lba_detected = 0; | ||
802 | + int cylinders, heads, secs; | ||
803 | + int64_t nb_sectors; | ||
804 | + | ||
805 | + /* if a geometry hint is available, use it */ | ||
806 | + bdrv_get_geometry(bs, &nb_sectors); | ||
807 | + bdrv_get_geometry_hint(bs, &cylinders, &heads, &secs); | ||
808 | + translation = bdrv_get_translation_hint(bs); | ||
809 | + if (cylinders != 0) { | ||
810 | + *pcyls = cylinders; | ||
811 | + *pheads = heads; | ||
812 | + *psecs = secs; | ||
813 | + } else { | ||
814 | + if (guess_disk_lchs(bs, &cylinders, &heads, &secs) == 0) { | ||
815 | + if (heads > 16) { | ||
816 | + /* if heads > 16, it means that a BIOS LBA | ||
817 | + translation was active, so the default | ||
818 | + hardware geometry is OK */ | ||
819 | + lba_detected = 1; | ||
820 | + goto default_geometry; | ||
821 | + } else { | ||
822 | + *pcyls = cylinders; | ||
823 | + *pheads = heads; | ||
824 | + *psecs = secs; | ||
825 | + /* disable any translation to be in sync with | ||
826 | + the logical geometry */ | ||
827 | + if (translation == BIOS_ATA_TRANSLATION_AUTO) { | ||
828 | + bdrv_set_translation_hint(bs, | ||
829 | + BIOS_ATA_TRANSLATION_NONE); | ||
830 | + } | ||
831 | + } | ||
832 | + } else { | ||
833 | + default_geometry: | ||
834 | + /* if no geometry, use a standard physical disk geometry */ | ||
835 | + cylinders = nb_sectors / (16 * 63); | ||
836 | + | ||
837 | + if (cylinders > 16383) | ||
838 | + cylinders = 16383; | ||
839 | + else if (cylinders < 2) | ||
840 | + cylinders = 2; | ||
841 | + *pcyls = cylinders; | ||
842 | + *pheads = 16; | ||
843 | + *psecs = 63; | ||
844 | + if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) { | ||
845 | + if ((*pcyls * *pheads) <= 131072) { | ||
846 | + bdrv_set_translation_hint(bs, | ||
847 | + BIOS_ATA_TRANSLATION_LARGE); | ||
848 | + } else { | ||
849 | + bdrv_set_translation_hint(bs, | ||
850 | + BIOS_ATA_TRANSLATION_LBA); | ||
851 | + } | ||
852 | + } | ||
853 | + } | ||
854 | + bdrv_set_geometry_hint(bs, *pcyls, *pheads, *psecs); | ||
855 | + } | ||
856 | +} | ||
857 | + | ||
742 | void bdrv_set_geometry_hint(BlockDriverState *bs, | 858 | void bdrv_set_geometry_hint(BlockDriverState *bs, |
743 | int cyls, int heads, int secs) | 859 | int cyls, int heads, int secs) |
744 | { | 860 | { |
block.h
@@ -78,6 +78,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, | @@ -78,6 +78,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, | ||
78 | int bdrv_truncate(BlockDriverState *bs, int64_t offset); | 78 | int bdrv_truncate(BlockDriverState *bs, int64_t offset); |
79 | int64_t bdrv_getlength(BlockDriverState *bs); | 79 | int64_t bdrv_getlength(BlockDriverState *bs); |
80 | void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | 80 | void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); |
81 | +void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs); | ||
81 | int bdrv_commit(BlockDriverState *bs); | 82 | int bdrv_commit(BlockDriverState *bs); |
82 | /* async block I/O */ | 83 | /* async block I/O */ |
83 | typedef struct BlockDriverAIOCB BlockDriverAIOCB; | 84 | typedef struct BlockDriverAIOCB BlockDriverAIOCB; |
hw/ide.c
@@ -2676,69 +2676,13 @@ static void ide_reset(IDEState *s) | @@ -2676,69 +2676,13 @@ static void ide_reset(IDEState *s) | ||
2676 | s->media_changed = 0; | 2676 | s->media_changed = 0; |
2677 | } | 2677 | } |
2678 | 2678 | ||
2679 | -struct partition { | ||
2680 | - uint8_t boot_ind; /* 0x80 - active */ | ||
2681 | - uint8_t head; /* starting head */ | ||
2682 | - uint8_t sector; /* starting sector */ | ||
2683 | - uint8_t cyl; /* starting cylinder */ | ||
2684 | - uint8_t sys_ind; /* What partition type */ | ||
2685 | - uint8_t end_head; /* end head */ | ||
2686 | - uint8_t end_sector; /* end sector */ | ||
2687 | - uint8_t end_cyl; /* end cylinder */ | ||
2688 | - uint32_t start_sect; /* starting sector counting from 0 */ | ||
2689 | - uint32_t nr_sects; /* nr of sectors in partition */ | ||
2690 | -} __attribute__((packed)); | ||
2691 | - | ||
2692 | -/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ | ||
2693 | -static int guess_disk_lchs(IDEState *s, | ||
2694 | - int *pcylinders, int *pheads, int *psectors) | ||
2695 | -{ | ||
2696 | - uint8_t *buf = s->io_buffer; | ||
2697 | - int ret, i, heads, sectors, cylinders; | ||
2698 | - struct partition *p; | ||
2699 | - uint32_t nr_sects; | ||
2700 | - | ||
2701 | - ret = bdrv_read(s->bs, 0, buf, 1); | ||
2702 | - if (ret < 0) { | ||
2703 | - return -1; | ||
2704 | - } | ||
2705 | - /* test msdos magic */ | ||
2706 | - if (buf[510] != 0x55 || buf[511] != 0xaa) { | ||
2707 | - return -1; | ||
2708 | - } | ||
2709 | - for(i = 0; i < 4; i++) { | ||
2710 | - p = ((struct partition *)(buf + 0x1be)) + i; | ||
2711 | - nr_sects = le32_to_cpu(p->nr_sects); | ||
2712 | - if (nr_sects && p->end_head) { | ||
2713 | - /* We make the assumption that the partition terminates on | ||
2714 | - a cylinder boundary */ | ||
2715 | - heads = p->end_head + 1; | ||
2716 | - sectors = p->end_sector & 63; | ||
2717 | - if (sectors == 0) | ||
2718 | - continue; | ||
2719 | - cylinders = s->nb_sectors / (heads * sectors); | ||
2720 | - if (cylinders < 1 || cylinders > 16383) | ||
2721 | - continue; | ||
2722 | - *pheads = heads; | ||
2723 | - *psectors = sectors; | ||
2724 | - *pcylinders = cylinders; | ||
2725 | -#if 0 | ||
2726 | - printf("guessed geometry: LCHS=%d %d %d\n", | ||
2727 | - cylinders, heads, sectors); | ||
2728 | -#endif | ||
2729 | - return 0; | ||
2730 | - } | ||
2731 | - } | ||
2732 | - return -1; | ||
2733 | -} | ||
2734 | - | ||
2735 | static void ide_init2(IDEState *ide_state, | 2679 | static void ide_init2(IDEState *ide_state, |
2736 | BlockDriverState *hd0, BlockDriverState *hd1, | 2680 | BlockDriverState *hd0, BlockDriverState *hd1, |
2737 | qemu_irq irq) | 2681 | qemu_irq irq) |
2738 | { | 2682 | { |
2739 | IDEState *s; | 2683 | IDEState *s; |
2740 | static int drive_serial = 1; | 2684 | static int drive_serial = 1; |
2741 | - int i, cylinders, heads, secs, translation, lba_detected = 0; | 2685 | + int i, cylinders, heads, secs; |
2742 | uint64_t nb_sectors; | 2686 | uint64_t nb_sectors; |
2743 | 2687 | ||
2744 | for(i = 0; i < 2; i++) { | 2688 | for(i = 0; i < 2; i++) { |
@@ -2750,56 +2694,12 @@ static void ide_init2(IDEState *ide_state, | @@ -2750,56 +2694,12 @@ static void ide_init2(IDEState *ide_state, | ||
2750 | s->bs = hd1; | 2694 | s->bs = hd1; |
2751 | if (s->bs) { | 2695 | if (s->bs) { |
2752 | bdrv_get_geometry(s->bs, &nb_sectors); | 2696 | bdrv_get_geometry(s->bs, &nb_sectors); |
2697 | + bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); | ||
2698 | + s->cylinders = cylinders; | ||
2699 | + s->heads = heads; | ||
2700 | + s->sectors = secs; | ||
2753 | s->nb_sectors = nb_sectors; | 2701 | s->nb_sectors = nb_sectors; |
2754 | - /* if a geometry hint is available, use it */ | ||
2755 | - bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); | ||
2756 | - translation = bdrv_get_translation_hint(s->bs); | ||
2757 | - if (cylinders != 0) { | ||
2758 | - s->cylinders = cylinders; | ||
2759 | - s->heads = heads; | ||
2760 | - s->sectors = secs; | ||
2761 | - } else { | ||
2762 | - if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) { | ||
2763 | - if (heads > 16) { | ||
2764 | - /* if heads > 16, it means that a BIOS LBA | ||
2765 | - translation was active, so the default | ||
2766 | - hardware geometry is OK */ | ||
2767 | - lba_detected = 1; | ||
2768 | - goto default_geometry; | ||
2769 | - } else { | ||
2770 | - s->cylinders = cylinders; | ||
2771 | - s->heads = heads; | ||
2772 | - s->sectors = secs; | ||
2773 | - /* disable any translation to be in sync with | ||
2774 | - the logical geometry */ | ||
2775 | - if (translation == BIOS_ATA_TRANSLATION_AUTO) { | ||
2776 | - bdrv_set_translation_hint(s->bs, | ||
2777 | - BIOS_ATA_TRANSLATION_NONE); | ||
2778 | - } | ||
2779 | - } | ||
2780 | - } else { | ||
2781 | - default_geometry: | ||
2782 | - /* if no geometry, use a standard physical disk geometry */ | ||
2783 | - cylinders = nb_sectors / (16 * 63); | ||
2784 | - if (cylinders > 16383) | ||
2785 | - cylinders = 16383; | ||
2786 | - else if (cylinders < 2) | ||
2787 | - cylinders = 2; | ||
2788 | - s->cylinders = cylinders; | ||
2789 | - s->heads = 16; | ||
2790 | - s->sectors = 63; | ||
2791 | - if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) { | ||
2792 | - if ((s->cylinders * s->heads) <= 131072) { | ||
2793 | - bdrv_set_translation_hint(s->bs, | ||
2794 | - BIOS_ATA_TRANSLATION_LARGE); | ||
2795 | - } else { | ||
2796 | - bdrv_set_translation_hint(s->bs, | ||
2797 | - BIOS_ATA_TRANSLATION_LBA); | ||
2798 | - } | ||
2799 | - } | ||
2800 | - } | ||
2801 | - bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors); | ||
2802 | - } | 2702 | + |
2803 | if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { | 2703 | if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { |
2804 | s->is_cdrom = 1; | 2704 | s->is_cdrom = 1; |
2805 | bdrv_set_change_cb(s->bs, cdrom_change_cb, s); | 2705 | bdrv_set_change_cb(s->bs, cdrom_change_cb, s); |