1/*- 2 * Copyright (c) KATO Takenori, 1996, 1997. 3 * 4 * All rights reserved. Unpublished rights reserved under the copyright 5 * laws of Japan. 6 * 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer as 13 * the first lines of this file unmodified. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34#include "opt_pc98.h" 35 36#include <sys/param.h> 37#include <sys/systm.h> 38 39#include <sys/bio.h> 40#include <sys/bus.h> 41#include <sys/conf.h> 42#include <sys/kernel.h> 43#include <sys/sysctl.h> 44#include <cam/cam.h> 45#include <cam/cam_ccb.h> 46#include <geom/geom_disk.h> 47#include <machine/md_var.h> 48#include <pc98/pc98/pc98_machdep.h> 49 50static int ad_geom_method = AD_GEOM_ADJUST_COMPATIDE; 51 52TUNABLE_INT("machdep.ad_geom_method", &ad_geom_method); 53SYSCTL_INT(_machdep, OID_AUTO, ad_geom_method, CTLFLAG_RW, &ad_geom_method, 0, 54 "IDE disk geometry conversion method"); 55 56/* 57 * Initialize DMA controller 58 */ 59void 60pc98_init_dmac(void) 61{ 62 outb(0x439, (inb(0x439) & 0xfb)); /* DMA Accsess Control over 1MB */ 63 outb(0x29, (0x0c | 0)); /* Bank Mode Reg. 16M mode */ 64 outb(0x29, (0x0c | 1)); /* Bank Mode Reg. 16M mode */ 65 outb(0x29, (0x0c | 2)); /* Bank Mode Reg. 16M mode */ 66 outb(0x29, (0x0c | 3)); /* Bank Mode Reg. 16M mode */ 67 outb(0x11, 0x50); 68} 69 70#ifdef EPSON_MEMWIN 71/* 72 * Disconnect phisical memory in 15-16MB region. 73 * 74 * EPSON PC-486GR, P, SR, SE, HX, HG and HA only. Other system support 75 * this feature with software DIP switch. 76 */ 77static void 78init_epson_memwin(void) 79{ 80 /* Disable 15MB-16MB caching. */ 81 switch (epson_machine_id) { 82 case EPSON_PC486_HX: 83 case EPSON_PC486_HG: 84 case EPSON_PC486_HA: 85 /* Cache control start. */ 86 outb(0x43f, 0x42); 87 outw(0xc40, 0x0033); 88 89 /* Disable 0xF00000-0xFFFFFF. */ 90 outb(0xc48, 0x49); 91 outb(0xc4c, 0x00); 92 outb(0xc48, 0x48); 93 outb(0xc4c, 0xf0); 94 outb(0xc48, 0x4d); 95 outb(0xc4c, 0x00); 96 outb(0xc48, 0x4c); 97 outb(0xc4c, 0xff); 98 outb(0xc48, 0x4f); 99 outb(0xc4c, 0x00); 100 101 /* Cache control end. */ 102 outb(0x43f, 0x40); 103 break; 104 105 case EPSON_PC486_GR: 106 case EPSON_PC486_P: 107 case EPSON_PC486_GR_SUPER: 108 case EPSON_PC486_GR_PLUS: 109 case EPSON_PC486_SE: 110 case EPSON_PC486_SR: 111 /* Disable 0xF00000-0xFFFFFF. */ 112 outb(0x43f, 0x42); 113 outb(0x467, 0xe0); 114 outb(0x567, 0xd8); 115 116 outb(0x43f, 0x40); 117 outb(0x467, 0xe0); 118 outb(0x567, 0xe0); 119 break; 120 } 121 122 /* Disable 15MB-16MB RAM and enable memory window. */ 123 outb(0x43b, inb(0x43b) & 0xfd); /* Clear bit1. */ 124} 125#endif 126 127/* 128 * Get physical memory size 129 */ 130unsigned int 131pc98_getmemsize(unsigned int *base, unsigned int *ext) 132{ 133 unsigned int under16, over16; 134 135 /* available conventional memory size */ 136 *base = ((PC98_SYSTEM_PARAMETER(0x501) & 7) + 1) * 128; 137 138 /* available protected memory size under 16MB */ 139 under16 = PC98_SYSTEM_PARAMETER(0x401) * 128 + 1024; 140#ifdef EPSON_MEMWIN 141 if (pc98_machine_type & M_EPSON_PC98) { 142 if (under16 > (15 * 1024)) 143 /* chop under16 memory to 15MB */ 144 under16 = 15 * 1024; 145 init_epson_memwin(); 146 } 147#endif 148 149 /* available protected memory size over 16MB / 1MB */ 150 over16 = PC98_SYSTEM_PARAMETER(0x594); 151 over16 += PC98_SYSTEM_PARAMETER(0x595) * 256; 152 153 if (over16 > 0) 154 *ext = (16 + over16) * 1024 - 1024; 155 else 156 *ext = under16 - 1024; 157 158 return (under16); 159} 160 161/* 162 * Read a geometry information of SCSI HDD from BIOS work area. 163 * 164 * XXX - Before reading BIOS work area, we should check whether 165 * host adapter support it. 166 */ 167int 168scsi_da_bios_params(struct ccb_calc_geometry *ccg) 169{ 170 u_char *tmp; 171 int target; 172 173 target = ccg->ccb_h.target_id; 174 tmp = (u_char *)&PC98_SYSTEM_PARAMETER(0x460 + target*4); 175 if ((PC98_SYSTEM_PARAMETER(0x482) & ((1 << target)&0xff)) != 0) { 176 ccg->secs_per_track = *tmp; 177 ccg->cylinders = ((*(tmp+3)<<8)|*(tmp+2))&0xfff; 178#if 0 179 switch (*(tmp + 3) & 0x30) { 180 case 0x00: 181 disk_parms->secsiz = 256; 182 printf("Warning!: not supported.\n"); 183 break; 184 case 0x10: 185 disk_parms->secsiz = 512; 186 break; 187 case 0x20: 188 disk_parms->secsiz = 1024; 189 break; 190 default: 191 disk_parms->secsiz = 512; 192 printf("Warning!: not supported. But force to 512\n"); 193 break; 194 } 195#endif 196 if (*(tmp+3) & 0x40) { 197 ccg->cylinders += (*(tmp+1)&0xf0)<<8; 198 ccg->heads = *(tmp+1)&0x0f; 199 } else { 200 ccg->heads = *(tmp+1); 201 } 202 return (1); 203 } 204 205 return (0); 206} 207 208/* 209 * Adjust the geometry of the IDE HDD. 210 */ 211 212/* IDE BIOS compatible mode. */ 213static void 214pc98_ata_disk_geom_adjust_idebios(struct disk *disk) 215{ 216 217 if (disk->d_mediasize < MEDIASIZE_4_3G) { 218 disk->d_fwsectors = 17; 219 disk->d_fwheads = 8; 220 } else if (disk->d_mediasize < MEDIASIZE_29_5G) { 221 disk->d_fwsectors = 63; 222 if (disk->d_fwheads != 15) /* Allow 15H63S. */ 223 disk->d_fwheads = 16; 224 } else if (disk->d_mediasize < MEDIASIZE_31_5G) { 225 disk->d_fwsectors = 63; 226 disk->d_fwheads = 16; 227 } else if (disk->d_mediasize < MEDIASIZE_127G) { 228 disk->d_fwsectors = 255; 229 disk->d_fwheads = 16; 230 } else { 231 /* XXX */ 232 disk->d_fwsectors = 255; 233 disk->d_fwheads = 255; 234 } 235} 236 237/* SCSI BIOS compatible mode. */ 238static void 239pc98_ata_disk_geom_adjust_scsibios(struct disk *disk) 240{ 241 242 if (disk->d_mediasize < MEDIASIZE_8G) { 243 disk->d_fwsectors = 32; 244 disk->d_fwheads = 8; 245 } else if (disk->d_mediasize < MEDIASIZE_32G) { 246 disk->d_fwsectors = 128; 247 disk->d_fwheads = 8; 248 } else if (disk->d_mediasize < MEDIASIZE_60G) { 249 /* Compatible with IFC-USP 1.2. */ 250 disk->d_fwsectors = 128; 251 disk->d_fwheads = 15; 252 } else if (disk->d_mediasize < MEDIASIZE_120G) { 253 disk->d_fwsectors = 255; 254 disk->d_fwheads = 15; 255 } else { 256 /* XXX */ 257 disk->d_fwsectors = 255; 258 disk->d_fwheads = 255; 259 } 260} 261 262/* Compatible with the revision 1.28. */ 263static void 264pc98_ata_disk_geom_adjust_cyl16bit(struct disk *disk) 265{ 266 off_t totsec = disk->d_mediasize / disk->d_sectorsize; 267 off_t cyl = totsec / disk->d_fwsectors / disk->d_fwheads; 268 269 /* 270 * It is impossible to have more than 65535 cylinders, so if 271 * we have more then try to adjust. This is lame, but it is 272 * only POC. 273 */ 274 if (cyl > 65355) { 275 if (totsec < 17*8*65535) { 276 disk->d_fwsectors = 17; 277 disk->d_fwheads = 8; 278 } else if (totsec < 63*16*65535) { 279 disk->d_fwsectors = 63; 280 disk->d_fwheads = 16; 281 } else if (totsec < 255*16*65535) { 282 disk->d_fwsectors = 255; 283 disk->d_fwheads = 16; 284 } else { 285 disk->d_fwsectors = 255; 286 disk->d_fwheads = 255; 287 } 288 } 289} 290 291void 292pc98_ata_disk_firmware_geom_adjust(struct disk *disk) 293{ 294 u_int oldsectors, oldheads; 295 296 oldsectors = disk->d_fwsectors; 297 oldheads = disk->d_fwheads; 298 299 switch (ad_geom_method) { 300 case AD_GEOM_ADJUST_COMPATIDE: 301 pc98_ata_disk_geom_adjust_idebios(disk); 302 break; 303 case AD_GEOM_ADJUST_COMPATSCSI: 304 pc98_ata_disk_geom_adjust_scsibios(disk); 305 break; 306 case AD_GEOM_ADJUST_COMPATCYL16: 307 pc98_ata_disk_geom_adjust_cyl16bit(disk); 308 break; 309 default: 310 /* Do nothing. */ 311 break; 312 } 313 314 if (bootverbose && 315 (oldsectors != disk->d_fwsectors || oldheads != disk->d_fwheads)) 316 printf( 317 "%s%d: geometry adjusted from [%dH/%dS] to [%dH/%dS]\n", 318 disk->d_name, disk->d_unit, 319 oldheads, oldsectors, 320 disk->d_fwheads, disk->d_fwsectors); 321} 322