diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2008-05-18 01:43:07 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2008-05-18 01:43:07 -0400 |
commit | c143761594e4961c408be4866aa10ce2b64eebe7 (patch) | |
tree | 044eed2fdb71103fe4da63dc2de60e6ced05e845 | |
parent | abc7597692b8c74ca91d86a17c9f2590952323cf (diff) | |
download | seabios-hppa-c143761594e4961c408be4866aa10ce2b64eebe7.zip seabios-hppa-c143761594e4961c408be4866aa10ce2b64eebe7.tar.gz seabios-hppa-c143761594e4961c408be4866aa10ce2b64eebe7.tar.bz2 |
Cleanup ata hard drive detection.
Don't rely on nvram for hd geometry - instead use values autodetected.
Don't outb() to PORT_HD_DATA - was left over from old code.
Reorganize parts of ata_init/ata_detect.
Separate hd geometry translation code to its own functions.
-rw-r--r-- | src/ata.c | 274 |
1 files changed, 134 insertions, 140 deletions
@@ -602,56 +602,69 @@ init_drive_atapi(int driveid) } static void -init_drive_ata(int driveid) +fill_fdpt(int driveid) { - SET_EBDA(ata.devices[driveid].type,ATA_TYPE_ATA); + if (driveid > 1) + return; - // Temporary values to do the transfer - SET_EBDA(ata.devices[driveid].device, ATA_DEVICE_HD); - SET_EBDA(ata.devices[driveid].mode, ATA_MODE_PIO16); + u16 nlc = GET_EBDA(ata.devices[driveid].lchs.cylinders); + u16 nlh = GET_EBDA(ata.devices[driveid].lchs.heads); + u16 nlspt = GET_EBDA(ata.devices[driveid].lchs.spt); - // Now we send a IDENTIFY command to ATA device - u8 buffer[0x0200]; - memset(buffer, 0, sizeof(buffer)); - u16 ret = ata_cmd_data(driveid, ATA_CMD_IDENTIFY_DEVICE - , 1, 1 - , MAKE_FARPTR(GET_SEG(SS), (u32)buffer)); - if (ret) - BX_PANIC("ata-detect: Failed to detect ATA device\n"); + u16 npc = GET_EBDA(ata.devices[driveid].pchs.cylinders); + u16 nph = GET_EBDA(ata.devices[driveid].pchs.heads); + u16 npspt = GET_EBDA(ata.devices[driveid].pchs.spt); - u8 removable = (buffer[0] & 0x80) ? 1 : 0; - u8 mode = buffer[96] ? ATA_MODE_PIO32 : ATA_MODE_PIO16; - u16 blksize = *(u16*)&buffer[10]; + SET_EBDA(fdpt[driveid].precompensation, 0xffff); + SET_EBDA(fdpt[driveid].drive_control_byte, 0xc0 | ((nph > 8) << 3)); + SET_EBDA(fdpt[driveid].landing_zone, npc); + SET_EBDA(fdpt[driveid].cylinders, nlc); + SET_EBDA(fdpt[driveid].heads, nlh); + SET_EBDA(fdpt[driveid].sectors, nlspt); - u16 cylinders = *(u16*)&buffer[1*2]; // word 1 - u16 heads = *(u16*)&buffer[3*2]; // word 3 - u16 spt = *(u16*)&buffer[6*2]; // word 6 + if (nlc == npc && nlh == nph && nlspt == npspt) + // no logical CHS mapping used, just physical CHS + // use Standard Fixed Disk Parameter Table (FDPT) + return; - u64 sectors; - if (*(u16*)&buffer[83*2] & (1 << 10)) // word 83 - lba48 support - sectors = *(u64*)&buffer[100*2]; // word 100-103 - else - sectors = *(u32*)&buffer[60*2]; // word 60 and word 61 + // complies with Phoenix style Translated Fixed Disk Parameter + // Table (FDPT) + SET_EBDA(fdpt[driveid].phys_cylinders, npc); + SET_EBDA(fdpt[driveid].phys_heads, nph); + SET_EBDA(fdpt[driveid].phys_sectors, npspt); + SET_EBDA(fdpt[driveid].a0h_signature, 0xa0); - SET_EBDA(ata.devices[driveid].device,ATA_DEVICE_HD); - SET_EBDA(ata.devices[driveid].removable, removable); - SET_EBDA(ata.devices[driveid].mode, mode); - SET_EBDA(ata.devices[driveid].blksize, blksize); - SET_EBDA(ata.devices[driveid].pchs.heads, heads); - SET_EBDA(ata.devices[driveid].pchs.cylinders, cylinders); - SET_EBDA(ata.devices[driveid].pchs.spt, spt); - SET_EBDA(ata.devices[driveid].sectors, sectors); + // Checksum structure. + u8 *p = MAKE_FARPTR(SEG_EBDA, offsetof(struct extended_bios_data_area_s + , fdpt[driveid])); + u8 sum = checksum(p, FIELD_SIZEOF(struct extended_bios_data_area_s + , fdpt[driveid]) - 1); + SET_EBDA(fdpt[driveid].checksum, -sum); +} +static u8 +get_translation(int driveid) +{ u8 channel = driveid / 2; - u8 slave = driveid % 2; u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2); - u8 shift; - for (shift=driveid%4; shift>0; shift--) - translation >>= 2; + translation >>= 2 * (driveid % 4); translation &= 0x03; + return translation; +} +static void +setup_translation(int driveid) +{ + u8 translation = get_translation(driveid); SET_EBDA(ata.devices[driveid].translation, translation); + u8 channel = driveid / 2; + u8 slave = driveid % 2; + u16 heads = GET_EBDA(ata.devices[driveid].pchs.heads); + u16 cylinders = GET_EBDA(ata.devices[driveid].pchs.cylinders); + u16 spt = GET_EBDA(ata.devices[driveid].pchs.spt); + u64 sectors = GET_EBDA(ata.devices[driveid].sectors); + BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=" , channel, slave, cylinders, heads, spt); switch (translation) { @@ -711,15 +724,62 @@ init_drive_ata(int driveid) SET_EBDA(ata.devices[driveid].lchs.heads, heads); SET_EBDA(ata.devices[driveid].lchs.cylinders, cylinders); SET_EBDA(ata.devices[driveid].lchs.spt, spt); +} + +static void +init_drive_ata(int driveid) +{ + SET_EBDA(ata.devices[driveid].type, ATA_TYPE_ATA); + + // Temporary values to do the transfer + SET_EBDA(ata.devices[driveid].device, ATA_DEVICE_HD); + SET_EBDA(ata.devices[driveid].mode, ATA_MODE_PIO16); + + // Now we send a IDENTIFY command to ATA device + u8 buffer[0x0200]; + memset(buffer, 0, sizeof(buffer)); + u16 ret = ata_cmd_data(driveid, ATA_CMD_IDENTIFY_DEVICE + , 1, 1 + , MAKE_FARPTR(GET_SEG(SS), (u32)buffer)); + if (ret) + BX_PANIC("ata-detect: Failed to detect ATA device\n"); + + u8 removable = (buffer[0] & 0x80) ? 1 : 0; + u8 mode = buffer[96] ? ATA_MODE_PIO32 : ATA_MODE_PIO16; + u16 blksize = *(u16*)&buffer[10]; + + u16 cylinders = *(u16*)&buffer[1*2]; // word 1 + u16 heads = *(u16*)&buffer[3*2]; // word 3 + u16 spt = *(u16*)&buffer[6*2]; // word 6 + + u64 sectors; + if (*(u16*)&buffer[83*2] & (1 << 10)) // word 83 - lba48 support + sectors = *(u64*)&buffer[100*2]; // word 100-103 + else + sectors = *(u32*)&buffer[60*2]; // word 60 and word 61 + + SET_EBDA(ata.devices[driveid].device, ATA_DEVICE_HD); + SET_EBDA(ata.devices[driveid].removable, removable); + SET_EBDA(ata.devices[driveid].mode, mode); + SET_EBDA(ata.devices[driveid].blksize, blksize); + SET_EBDA(ata.devices[driveid].pchs.heads, heads); + SET_EBDA(ata.devices[driveid].pchs.cylinders, cylinders); + SET_EBDA(ata.devices[driveid].pchs.spt, spt); + SET_EBDA(ata.devices[driveid].sectors, sectors); + + // Setup disk geometry translation. + setup_translation(driveid); // fill hdidmap u8 hdcount = GET_EBDA(ata.hdcount); SET_EBDA(ata.idmap[0][hdcount], driveid); SET_EBDA(ata.hdcount, ++hdcount); - u64 sizeinmb = GET_EBDA(ata.devices[driveid].sectors); - sizeinmb >>= 11; + // Fill "fdpt" structure. + fill_fdpt(driveid); + // Report drive info to user. + u64 sizeinmb = GET_EBDA(ata.devices[driveid].sectors) >> 11; report_model(driveid, buffer); u8 version = get_ata_version(buffer); if (sizeinmb < (1 << 16)) @@ -742,34 +802,6 @@ init_drive_unknown(int driveid) static void ata_detect() { -#if CONFIG_MAX_ATA_INTERFACES > 0 - SET_EBDA(ata.channels[0].iface,ATA_IFACE_ISA); - SET_EBDA(ata.channels[0].iobase1,0x1f0); - SET_EBDA(ata.channels[0].iobase2,0x3f0); - SET_EBDA(ata.channels[0].irq,14); -#endif -#if CONFIG_MAX_ATA_INTERFACES > 1 - SET_EBDA(ata.channels[1].iface,ATA_IFACE_ISA); - SET_EBDA(ata.channels[1].iobase1,0x170); - SET_EBDA(ata.channels[1].iobase2,0x370); - SET_EBDA(ata.channels[1].irq,15); -#endif -#if CONFIG_MAX_ATA_INTERFACES > 2 - SET_EBDA(ata.channels[2].iface,ATA_IFACE_ISA); - SET_EBDA(ata.channels[2].iobase1,0x1e8); - SET_EBDA(ata.channels[2].iobase2,0x3e0); - SET_EBDA(ata.channels[2].irq,12); -#endif -#if CONFIG_MAX_ATA_INTERFACES > 3 - SET_EBDA(ata.channels[3].iface,ATA_IFACE_ISA); - SET_EBDA(ata.channels[3].iobase1,0x168); - SET_EBDA(ata.channels[3].iobase2,0x360); - SET_EBDA(ata.channels[3].irq,11); -#endif -#if CONFIG_MAX_ATA_INTERFACES > 4 -#error Please fill the ATA interface informations -#endif - // Device detection int driveid; for(driveid=0; driveid<CONFIG_MAX_ATA_DEVICES; driveid++) { @@ -824,97 +856,59 @@ ata_detect() init_drive_unknown(driveid); } - // Store the device count - SET_BDA(disk_count, GET_EBDA(ata.hdcount)); - printf("\n"); - - // FIXME : should use bios=cmos|auto|disable bits - // FIXME : should know about translation bits - // FIXME : move hard_drive_post here } static void ata_init() { - // hdidmap and cdidmap init. + // hdidmap and cdidmap init. u8 device; for (device=0; device < CONFIG_MAX_ATA_DEVICES; device++) { SET_EBDA(ata.idmap[0][device], CONFIG_MAX_ATA_DEVICES); SET_EBDA(ata.idmap[1][device], CONFIG_MAX_ATA_DEVICES); } + +#if CONFIG_MAX_ATA_INTERFACES > 0 + SET_EBDA(ata.channels[0].iface, ATA_IFACE_ISA); + SET_EBDA(ata.channels[0].iobase1, 0x1f0); + SET_EBDA(ata.channels[0].iobase2, 0x3f0); + SET_EBDA(ata.channels[0].irq, 14); +#endif +#if CONFIG_MAX_ATA_INTERFACES > 1 + SET_EBDA(ata.channels[1].iface, ATA_IFACE_ISA); + SET_EBDA(ata.channels[1].iobase1, 0x170); + SET_EBDA(ata.channels[1].iobase2, 0x370); + SET_EBDA(ata.channels[1].irq, 15); +#endif +#if CONFIG_MAX_ATA_INTERFACES > 2 + SET_EBDA(ata.channels[2].iface, ATA_IFACE_ISA); + SET_EBDA(ata.channels[2].iobase1, 0x1e8); + SET_EBDA(ata.channels[2].iobase2, 0x3e0); + SET_EBDA(ata.channels[2].irq, 12); +#endif +#if CONFIG_MAX_ATA_INTERFACES > 3 + SET_EBDA(ata.channels[3].iface, ATA_IFACE_ISA); + SET_EBDA(ata.channels[3].iobase1, 0x168); + SET_EBDA(ata.channels[3].iobase2, 0x360); + SET_EBDA(ata.channels[3].irq, 11); +#endif +#if CONFIG_MAX_ATA_INTERFACES > 4 +#error Please fill the ATA interface informations +#endif } -static void -fill_hdinfo(int hdnum, u8 typecmos, u8 basecmos) +void +hard_drive_setup() { - u8 type = inb_cmos(typecmos); - if (type != 47) - // XXX - halt + if (!CONFIG_ATA) return; - SET_EBDA(fdpt[hdnum].precompensation, ((inb_cmos(basecmos+4) << 8) - | inb_cmos(basecmos+3))); - SET_EBDA(fdpt[hdnum].drive_control_byte, inb_cmos(basecmos+5)); - SET_EBDA(fdpt[hdnum].landing_zone, ((inb_cmos(basecmos+7) << 8) - | inb_cmos(basecmos+6))); - u16 cyl = (inb_cmos(basecmos+1) << 8) | inb_cmos(basecmos+0); - u8 heads = inb_cmos(basecmos+2); - u8 sectors = inb_cmos(basecmos+8); - if (cyl < 1024) { - // no logical CHS mapping used, just physical CHS - // use Standard Fixed Disk Parameter Table (FDPT) - SET_EBDA(fdpt[hdnum].cylinders, cyl); - SET_EBDA(fdpt[hdnum].heads, heads); - SET_EBDA(fdpt[hdnum].sectors, sectors); - return; - } + ata_init(); + ata_detect(); - // complies with Phoenix style Translated Fixed Disk Parameter - // Table (FDPT) - SET_EBDA(fdpt[hdnum].phys_cylinders, cyl); - SET_EBDA(fdpt[hdnum].phys_heads, heads); - SET_EBDA(fdpt[hdnum].phys_sectors, sectors); - SET_EBDA(fdpt[hdnum].sectors, sectors); - SET_EBDA(fdpt[hdnum].a0h_signature, 0xa0); - if (cyl > 8192) { - cyl >>= 4; - heads <<= 4; - } else if (cyl > 4096) { - cyl >>= 3; - heads <<= 3; - } else if (cyl > 2048) { - cyl >>= 2; - heads <<= 2; - } - SET_EBDA(fdpt[hdnum].cylinders, cyl); - SET_EBDA(fdpt[hdnum].heads, heads); - u8 *p = MAKE_FARPTR(SEG_EBDA, offsetof(struct extended_bios_data_area_s - , fdpt[hdnum])); - u8 sum = checksum(p, FIELD_SIZEOF(struct extended_bios_data_area_s - , fdpt[hdnum]) - 1); - SET_EBDA(fdpt[hdnum].checksum, -sum); -} + // Store the device count + SET_BDA(disk_count, GET_EBDA(ata.hdcount)); -void -hard_drive_setup() -{ - outb(0x0a, PORT_HD_DATA); // 0000 1010 = reserved, disable IRQ 14 - SET_BDA(disk_count, 1); SET_BDA(disk_control_byte, 0xc0); - - // move disk geometry data from CMOS to EBDA disk parameter table(s) - u8 diskinfo = inb_cmos(CMOS_DISK_DATA); - if ((diskinfo & 0xf0) == 0xf0) - // Fill EBDA table for hard disk 0. - fill_hdinfo(0, CMOS_DISK_DRIVE1_TYPE, CMOS_DISK_DRIVE1_CYL); - if ((diskinfo & 0x0f) == 0x0f) - // XXX - bochs halts on any other type - // Fill EBDA table for hard disk 1. - fill_hdinfo(1, CMOS_DISK_DRIVE2_TYPE, CMOS_DISK_DRIVE2_CYL); - - if (CONFIG_ATA) { - ata_init(); - ata_detect(); - } } |