/*- * Copyright (c) KATO Takenori, 1996, 1997. * * All rights reserved. Unpublished rights reserved under the copyright * laws of Japan. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer as * the first lines of this file unmodified. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_pc98.h" #include #include #include #include #include #include #include #include #include #include #include #include static int ad_geom_method = AD_GEOM_ADJUST_COMPATIDE; TUNABLE_INT("machdep.ad_geom_method", &ad_geom_method); SYSCTL_INT(_machdep, OID_AUTO, ad_geom_method, CTLFLAG_RW, &ad_geom_method, 0, "IDE disk geometry conversion method"); /* * Initialize DMA controller */ void pc98_init_dmac(void) { outb(0x439, (inb(0x439) & 0xfb)); /* DMA Accsess Control over 1MB */ outb(0x29, (0x0c | 0)); /* Bank Mode Reg. 16M mode */ outb(0x29, (0x0c | 1)); /* Bank Mode Reg. 16M mode */ outb(0x29, (0x0c | 2)); /* Bank Mode Reg. 16M mode */ outb(0x29, (0x0c | 3)); /* Bank Mode Reg. 16M mode */ outb(0x11, 0x50); } #ifdef EPSON_MEMWIN /* * Disconnect phisical memory in 15-16MB region. * * EPSON PC-486GR, P, SR, SE, HX, HG and HA only. Other system support * this feature with software DIP switch. */ static void init_epson_memwin(void) { /* Disable 15MB-16MB caching. */ switch (epson_machine_id) { case EPSON_PC486_HX: case EPSON_PC486_HG: case EPSON_PC486_HA: /* Cache control start. */ outb(0x43f, 0x42); outw(0xc40, 0x0033); /* Disable 0xF00000-0xFFFFFF. */ outb(0xc48, 0x49); outb(0xc4c, 0x00); outb(0xc48, 0x48); outb(0xc4c, 0xf0); outb(0xc48, 0x4d); outb(0xc4c, 0x00); outb(0xc48, 0x4c); outb(0xc4c, 0xff); outb(0xc48, 0x4f); outb(0xc4c, 0x00); /* Cache control end. */ outb(0x43f, 0x40); break; case EPSON_PC486_GR: case EPSON_PC486_P: case EPSON_PC486_GR_SUPER: case EPSON_PC486_GR_PLUS: case EPSON_PC486_SE: case EPSON_PC486_SR: /* Disable 0xF00000-0xFFFFFF. */ outb(0x43f, 0x42); outb(0x467, 0xe0); outb(0x567, 0xd8); outb(0x43f, 0x40); outb(0x467, 0xe0); outb(0x567, 0xe0); break; } /* Disable 15MB-16MB RAM and enable memory window. */ outb(0x43b, inb(0x43b) & 0xfd); /* Clear bit1. */ } #endif /* * Get physical memory size */ unsigned int pc98_getmemsize(unsigned int *base, unsigned int *ext) { unsigned int under16, over16; /* available conventional memory size */ *base = ((PC98_SYSTEM_PARAMETER(0x501) & 7) + 1) * 128; /* available protected memory size under 16MB */ under16 = PC98_SYSTEM_PARAMETER(0x401) * 128 + 1024; #ifdef EPSON_MEMWIN if (pc98_machine_type & M_EPSON_PC98) { if (under16 > (15 * 1024)) /* chop under16 memory to 15MB */ under16 = 15 * 1024; init_epson_memwin(); } #endif /* available protected memory size over 16MB / 1MB */ over16 = PC98_SYSTEM_PARAMETER(0x594); over16 += PC98_SYSTEM_PARAMETER(0x595) * 256; if (over16 > 0) *ext = (16 + over16) * 1024 - 1024; else *ext = under16 - 1024; return (under16); } /* * Read a geometry information of SCSI HDD from BIOS work area. * * XXX - Before reading BIOS work area, we should check whether * host adapter support it. */ int scsi_da_bios_params(struct ccb_calc_geometry *ccg) { u_char *tmp; int target; target = ccg->ccb_h.target_id; tmp = (u_char *)&PC98_SYSTEM_PARAMETER(0x460 + target*4); if ((PC98_SYSTEM_PARAMETER(0x482) & ((1 << target)&0xff)) != 0) { ccg->secs_per_track = *tmp; ccg->cylinders = ((*(tmp+3)<<8)|*(tmp+2))&0xfff; #if 0 switch (*(tmp + 3) & 0x30) { case 0x00: disk_parms->secsiz = 256; printf("Warning!: not supported.\n"); break; case 0x10: disk_parms->secsiz = 512; break; case 0x20: disk_parms->secsiz = 1024; break; default: disk_parms->secsiz = 512; printf("Warning!: not supported. But force to 512\n"); break; } #endif if (*(tmp+3) & 0x40) { ccg->cylinders += (*(tmp+1)&0xf0)<<8; ccg->heads = *(tmp+1)&0x0f; } else { ccg->heads = *(tmp+1); } return (1); } return (0); } /* * Adjust the geometry of the IDE HDD. */ /* IDE BIOS compatible mode. */ static void pc98_ata_disk_geom_adjust_idebios(struct disk *disk) { if (disk->d_mediasize < MEDIASIZE_4_3G) { disk->d_fwsectors = 17; disk->d_fwheads = 8; } else if (disk->d_mediasize < MEDIASIZE_29_5G) { disk->d_fwsectors = 63; if (disk->d_fwheads != 15) /* Allow 15H63S. */ disk->d_fwheads = 16; } else if (disk->d_mediasize < MEDIASIZE_31_5G) { disk->d_fwsectors = 63; disk->d_fwheads = 16; } else if (disk->d_mediasize < MEDIASIZE_127G) { disk->d_fwsectors = 255; disk->d_fwheads = 16; } else { /* XXX */ disk->d_fwsectors = 255; disk->d_fwheads = 255; } } /* SCSI BIOS compatible mode. */ static void pc98_ata_disk_geom_adjust_scsibios(struct disk *disk) { if (disk->d_mediasize < MEDIASIZE_8G) { disk->d_fwsectors = 32; disk->d_fwheads = 8; } else if (disk->d_mediasize < MEDIASIZE_32G) { disk->d_fwsectors = 128; disk->d_fwheads = 8; } else if (disk->d_mediasize < MEDIASIZE_60G) { /* Compatible with IFC-USP 1.2. */ disk->d_fwsectors = 128; disk->d_fwheads = 15; } else if (disk->d_mediasize < MEDIASIZE_120G) { disk->d_fwsectors = 255; disk->d_fwheads = 15; } else { /* XXX */ disk->d_fwsectors = 255; disk->d_fwheads = 255; } } /* Compatible with the revision 1.28. */ static void pc98_ata_disk_geom_adjust_cyl16bit(struct disk *disk) { off_t totsec = disk->d_mediasize / disk->d_sectorsize; off_t cyl = totsec / disk->d_fwsectors / disk->d_fwheads; /* * It is impossible to have more than 65535 cylinders, so if * we have more then try to adjust. This is lame, but it is * only POC. */ if (cyl > 65355) { if (totsec < 17*8*65535) { disk->d_fwsectors = 17; disk->d_fwheads = 8; } else if (totsec < 63*16*65535) { disk->d_fwsectors = 63; disk->d_fwheads = 16; } else if (totsec < 255*16*65535) { disk->d_fwsectors = 255; disk->d_fwheads = 16; } else { disk->d_fwsectors = 255; disk->d_fwheads = 255; } } } void pc98_ata_disk_firmware_geom_adjust(struct disk *disk) { u_int oldsectors, oldheads; oldsectors = disk->d_fwsectors; oldheads = disk->d_fwheads; switch (ad_geom_method) { case AD_GEOM_ADJUST_COMPATIDE: pc98_ata_disk_geom_adjust_idebios(disk); break; case AD_GEOM_ADJUST_COMPATSCSI: pc98_ata_disk_geom_adjust_scsibios(disk); break; case AD_GEOM_ADJUST_COMPATCYL16: pc98_ata_disk_geom_adjust_cyl16bit(disk); break; default: /* Do nothing. */ break; } if (bootverbose && (oldsectors != disk->d_fwsectors || oldheads != disk->d_fwheads)) printf( "%s%d: geometry adjusted from [%dH/%dS] to [%dH/%dS]\n", disk->d_name, disk->d_unit, oldheads, oldsectors, disk->d_fwheads, disk->d_fwsectors); }