diff options
author | aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-11-25 21:50:24 +0000 |
---|---|---|
committer | aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-11-25 21:50:24 +0000 |
commit | f3d54fc4948b5525cc15e2a082f0cec8610ec5b4 (patch) | |
tree | 39881504adc6380a107acfb038cfb612256bc5a5 /block.c | |
parent | 357c692cca6614ac3583ca39b710a9888a673785 (diff) |
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
Diffstat (limited to 'block.c')
-rw-r--r-- | block.c | 116 |
1 files changed, 116 insertions, 0 deletions
@@ -739,6 +739,122 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) *nb_sectors_ptr = length; } +struct partition { + uint8_t boot_ind; /* 0x80 - active */ + uint8_t head; /* starting head */ + uint8_t sector; /* starting sector */ + uint8_t cyl; /* starting cylinder */ + uint8_t sys_ind; /* What partition type */ + uint8_t end_head; /* end head */ + uint8_t end_sector; /* end sector */ + uint8_t end_cyl; /* end cylinder */ + uint32_t start_sect; /* starting sector counting from 0 */ + uint32_t nr_sects; /* nr of sectors in partition */ +} __attribute__((packed)); + +/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ +static int guess_disk_lchs(BlockDriverState *bs, + int *pcylinders, int *pheads, int *psectors) +{ + uint8_t buf[512]; + int ret, i, heads, sectors, cylinders; + struct partition *p; + uint32_t nr_sects; + int64_t nb_sectors; + + bdrv_get_geometry(bs, &nb_sectors); + + ret = bdrv_read(bs, 0, buf, 1); + if (ret < 0) + return -1; + /* test msdos magic */ + if (buf[510] != 0x55 || buf[511] != 0xaa) + return -1; + for(i = 0; i < 4; i++) { + p = ((struct partition *)(buf + 0x1be)) + i; + nr_sects = le32_to_cpu(p->nr_sects); + if (nr_sects && p->end_head) { + /* We make the assumption that the partition terminates on + a cylinder boundary */ + heads = p->end_head + 1; + sectors = p->end_sector & 63; + if (sectors == 0) + continue; + cylinders = nb_sectors / (heads * sectors); + if (cylinders < 1 || cylinders > 16383) + continue; + *pheads = heads; + *psectors = sectors; + *pcylinders = cylinders; +#if 0 + printf("guessed geometry: LCHS=%d %d %d\n", + cylinders, heads, sectors); +#endif + return 0; + } + } + return -1; +} + +void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs) +{ + int translation, lba_detected = 0; + int cylinders, heads, secs; + int64_t nb_sectors; + + /* if a geometry hint is available, use it */ + bdrv_get_geometry(bs, &nb_sectors); + bdrv_get_geometry_hint(bs, &cylinders, &heads, &secs); + translation = bdrv_get_translation_hint(bs); + if (cylinders != 0) { + *pcyls = cylinders; + *pheads = heads; + *psecs = secs; + } else { + if (guess_disk_lchs(bs, &cylinders, &heads, &secs) == 0) { + if (heads > 16) { + /* if heads > 16, it means that a BIOS LBA + translation was active, so the default + hardware geometry is OK */ + lba_detected = 1; + goto default_geometry; + } else { + *pcyls = cylinders; + *pheads = heads; + *psecs = secs; + /* disable any translation to be in sync with + the logical geometry */ + if (translation == BIOS_ATA_TRANSLATION_AUTO) { + bdrv_set_translation_hint(bs, + BIOS_ATA_TRANSLATION_NONE); + } + } + } else { + default_geometry: + /* if no geometry, use a standard physical disk geometry */ + cylinders = nb_sectors / (16 * 63); + + if (cylinders > 16383) + cylinders = 16383; + else if (cylinders < 2) + cylinders = 2; + *pcyls = cylinders; + *pheads = 16; + *psecs = 63; + if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) { + if ((*pcyls * *pheads) <= 131072) { + bdrv_set_translation_hint(bs, + BIOS_ATA_TRANSLATION_LARGE); + } else { + bdrv_set_translation_hint(bs, + BIOS_ATA_TRANSLATION_LBA); + } + } + } + bdrv_set_geometry_hint(bs, *pcyls, *pheads, *psecs); + } +} + void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs) { |