]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/pc98/pc98/pc98_machdep.c
cdn-patch: offer option to mount /etc/keys before attaching geli devices
[FreeBSD/FreeBSD.git] / sys / pc98 / pc98 / pc98_machdep.c
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
50 static  int     ad_geom_method = AD_GEOM_ADJUST_COMPATIDE;
51
52 SYSCTL_INT(_machdep, OID_AUTO, ad_geom_method, CTLFLAG_RWTUN, &ad_geom_method, 0,
53     "IDE disk geometry conversion method");
54
55 /*
56  * Initialize DMA controller
57  */
58 void
59 pc98_init_dmac(void)
60 {
61         outb(0x439, (inb(0x439) & 0xfb));       /* DMA Accsess Control over 1MB */
62         outb(0x29, (0x0c | 0));                         /* Bank Mode Reg. 16M mode */
63         outb(0x29, (0x0c | 1));                         /* Bank Mode Reg. 16M mode */
64         outb(0x29, (0x0c | 2));                         /* Bank Mode Reg. 16M mode */
65         outb(0x29, (0x0c | 3));                         /* Bank Mode Reg. 16M mode */
66         outb(0x11, 0x50);
67 }
68
69 #ifdef EPSON_MEMWIN
70 /*
71  * Disconnect phisical memory in 15-16MB region.
72  *
73  * EPSON PC-486GR, P, SR, SE, HX, HG and HA only.  Other system support
74  * this feature with software DIP switch.
75  */
76 static void
77 init_epson_memwin(void)
78 {
79         /* Disable 15MB-16MB caching. */
80         switch (epson_machine_id) {
81         case EPSON_PC486_HX:
82         case EPSON_PC486_HG:
83         case EPSON_PC486_HA:
84                 /* Cache control start. */
85                 outb(0x43f, 0x42);
86                 outw(0xc40, 0x0033);
87
88                 /* Disable 0xF00000-0xFFFFFF. */
89                 outb(0xc48, 0x49);
90                 outb(0xc4c, 0x00);
91                 outb(0xc48, 0x48);
92                 outb(0xc4c, 0xf0);
93                 outb(0xc48, 0x4d);
94                 outb(0xc4c, 0x00);
95                 outb(0xc48, 0x4c);
96                 outb(0xc4c, 0xff);
97                 outb(0xc48, 0x4f);
98                 outb(0xc4c, 0x00);
99
100                 /* Cache control end. */
101                 outb(0x43f, 0x40);
102                 break;
103
104         case EPSON_PC486_GR:
105         case EPSON_PC486_P:
106         case EPSON_PC486_GR_SUPER:
107         case EPSON_PC486_GR_PLUS:
108         case EPSON_PC486_SE:
109         case EPSON_PC486_SR:
110                 /* Disable 0xF00000-0xFFFFFF. */
111                 outb(0x43f, 0x42);
112                 outb(0x467, 0xe0);
113                 outb(0x567, 0xd8);
114
115                 outb(0x43f, 0x40);
116                 outb(0x467, 0xe0);
117                 outb(0x567, 0xe0);
118                 break;
119         }
120
121         /* Disable 15MB-16MB RAM and enable memory window. */
122         outb(0x43b, inb(0x43b) & 0xfd); /* Clear bit1. */
123 }
124 #endif
125
126 /*
127  * Get physical memory size
128  */
129 unsigned int
130 pc98_getmemsize(unsigned int *base, unsigned int *ext)
131 {
132         unsigned int under16, over16;
133
134         /* available conventional memory size */
135         *base = ((PC98_SYSTEM_PARAMETER(0x501) & 7) + 1) * 128;
136
137         /* available protected memory size under 16MB */
138         under16 = PC98_SYSTEM_PARAMETER(0x401) * 128 + 1024;
139 #ifdef EPSON_MEMWIN
140         if (pc98_machine_type & M_EPSON_PC98) {
141                 if (under16 > (15 * 1024))
142                         /* chop under16 memory to 15MB */
143                         under16 = 15 * 1024;
144                 init_epson_memwin();
145         }
146 #endif
147
148         /* available protected memory size over 16MB / 1MB */
149         over16  = PC98_SYSTEM_PARAMETER(0x594);
150         over16 += PC98_SYSTEM_PARAMETER(0x595) * 256;
151
152         if (over16 > 0)
153                 *ext = (16 + over16) * 1024 - 1024;
154         else
155                 *ext = under16 - 1024;
156
157         return (under16);
158 }
159
160 /*
161  * Read a geometry information of SCSI HDD from BIOS work area.
162  *
163  * XXX - Before reading BIOS work area, we should check whether
164  * host adapter support it.
165  */
166 int
167 scsi_da_bios_params(struct ccb_calc_geometry *ccg)
168 {
169         u_char *tmp;
170         int     target;
171
172         target = ccg->ccb_h.target_id;
173         tmp = (u_char *)&PC98_SYSTEM_PARAMETER(0x460 + target*4);
174         if ((PC98_SYSTEM_PARAMETER(0x482) & ((1 << target)&0xff)) != 0) {
175                 ccg->secs_per_track = *tmp;
176                 ccg->cylinders = ((*(tmp+3)<<8)|*(tmp+2))&0xfff;
177 #if 0
178                 switch (*(tmp + 3) & 0x30) {
179                 case 0x00:
180                         disk_parms->secsiz = 256;
181                         printf("Warning!: not supported.\n");
182                         break;
183                 case 0x10:
184                         disk_parms->secsiz = 512;
185                         break;
186                 case 0x20:
187                         disk_parms->secsiz = 1024;
188                         break;
189                 default:
190                         disk_parms->secsiz = 512;
191                         printf("Warning!: not supported. But force to 512\n");
192                         break;
193                 }
194 #endif
195                 if (*(tmp+3) & 0x40) {
196                         ccg->cylinders += (*(tmp+1)&0xf0)<<8;
197                         ccg->heads = *(tmp+1)&0x0f;
198                 } else {
199                         ccg->heads = *(tmp+1);
200                 }
201                 return (1);
202         }
203
204         return (0);
205 }
206
207 /*
208  * Adjust the geometry of the IDE HDD.
209  */
210
211 /* IDE BIOS compatible mode. */
212 static  void
213 pc98_ata_disk_geom_adjust_idebios(struct disk *disk)
214 {
215
216         if (disk->d_mediasize < MEDIASIZE_4_3G) {
217                 disk->d_fwsectors = 17;
218                 disk->d_fwheads = 8;
219         } else if (disk->d_mediasize < MEDIASIZE_29_5G) {
220                 disk->d_fwsectors = 63;
221                 if (disk->d_fwheads != 15)      /* Allow 15H63S. */
222                         disk->d_fwheads = 16;
223         } else if (disk->d_mediasize < MEDIASIZE_31_5G) {
224                 disk->d_fwsectors = 63;
225                 disk->d_fwheads = 16;
226         } else if (disk->d_mediasize < MEDIASIZE_127G) {
227                 disk->d_fwsectors = 255;
228                 disk->d_fwheads = 16;
229         } else {
230                 /* XXX */
231                 disk->d_fwsectors = 255;
232                 disk->d_fwheads = 255;
233         }
234 }
235
236 /* SCSI BIOS compatible mode. */
237 static  void
238 pc98_ata_disk_geom_adjust_scsibios(struct disk *disk)
239 {
240
241         if (disk->d_mediasize < MEDIASIZE_8G) {
242                 disk->d_fwsectors = 32;
243                 disk->d_fwheads = 8;
244         } else if (disk->d_mediasize < MEDIASIZE_32G) {
245                 disk->d_fwsectors = 128;
246                 disk->d_fwheads = 8;
247         } else if (disk->d_mediasize < MEDIASIZE_60G) {
248                 /* Compatible with IFC-USP 1.2. */
249                 disk->d_fwsectors = 128;
250                 disk->d_fwheads = 15;
251         } else if (disk->d_mediasize < MEDIASIZE_120G) {
252                 disk->d_fwsectors = 255;
253                 disk->d_fwheads = 15;
254         } else {
255                 /* XXX */
256                 disk->d_fwsectors = 255;
257                 disk->d_fwheads = 255;
258         }
259 }
260
261 /* Compatible with the revision 1.28. */
262 static  void
263 pc98_ata_disk_geom_adjust_cyl16bit(struct disk *disk)
264 {
265         off_t totsec = disk->d_mediasize / disk->d_sectorsize;
266         off_t cyl = totsec / disk->d_fwsectors / disk->d_fwheads;
267
268         /*
269          * It is impossible to have more than 65535 cylinders, so if
270          * we have more then try to adjust.  This is lame, but it is
271          * only POC.
272          */
273         if (cyl > 65355) {
274                 if (totsec < 17*8*65535) {
275                         disk->d_fwsectors = 17;
276                         disk->d_fwheads = 8;
277                 } else if (totsec < 63*16*65535) {
278                         disk->d_fwsectors = 63;
279                         disk->d_fwheads = 16;
280                 } else if (totsec < 255*16*65535) {
281                         disk->d_fwsectors = 255;
282                         disk->d_fwheads = 16;
283                 } else {
284                         disk->d_fwsectors = 255;
285                         disk->d_fwheads = 255;
286                 }
287         }
288 }
289
290 void
291 pc98_ata_disk_firmware_geom_adjust(struct disk *disk)
292 {
293         u_int   oldsectors, oldheads;
294
295         oldsectors = disk->d_fwsectors;
296         oldheads = disk->d_fwheads;
297
298         switch (ad_geom_method) {
299         case AD_GEOM_ADJUST_COMPATIDE:
300                 pc98_ata_disk_geom_adjust_idebios(disk);
301                 break;
302         case AD_GEOM_ADJUST_COMPATSCSI:
303                 pc98_ata_disk_geom_adjust_scsibios(disk);
304                 break;
305         case AD_GEOM_ADJUST_COMPATCYL16:
306                 pc98_ata_disk_geom_adjust_cyl16bit(disk);
307                 break;
308         default:
309                 /* Do nothing. */
310                 break;
311         }
312
313         if (bootverbose &&
314             (oldsectors != disk->d_fwsectors || oldheads != disk->d_fwheads))
315                 printf(
316                     "%s%d: geometry adjusted from [%dH/%dS] to [%dH/%dS]\n",
317                     disk->d_name, disk->d_unit,
318                     oldheads, oldsectors,
319                     disk->d_fwheads, disk->d_fwsectors);
320 }