autoconf.c revision 1.63
1/* $NetBSD: autoconf.c,v 1.63 1999/04/01 00:17:46 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1994 Christian E. Hopps 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christian E. Hopps. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/reboot.h> 35#include <sys/conf.h> 36#include <sys/buf.h> 37#include <sys/device.h> 38#include <sys/disklabel.h> 39#include <sys/disk.h> 40#include <machine/cpu.h> 41#include <amiga/amiga/cfdev.h> 42#include <amiga/amiga/device.h> 43#include <amiga/amiga/custom.h> 44 45void findroot __P((struct device **, int *)); 46void mbattach __P((struct device *, struct device *, void *)); 47int mbprint __P((void *, const char *)); 48int mbmatch __P((struct device *, struct cfdata *, void *)); 49 50int cold; /* 1 if still booting */ 51#include <sys/kernel.h> 52 53struct devnametobdevmaj amiga_nam2blk[] = { 54 { "fd", 2 }, 55 { "sd", 4 }, 56 { "cd", 7 }, 57 { "md", 15 }, 58 { NULL, 0 }, 59}; 60u_long boot_partition; 61 62/* 63 * called at boot time, configure all devices on system 64 */ 65void 66configure() 67{ 68 int s; 69#ifdef DEBUG_KERNEL_START 70 int i; 71#endif 72 73 /* 74 * this is the real thing baby (i.e. not console init) 75 */ 76 amiga_realconfig = 1; 77#ifdef DRACO 78 if (is_draco()) { 79 *draco_intena &= ~DRIRQ_GLOBAL; 80 } else 81#endif 82 custom.intena = INTF_INTEN; 83 s = splhigh(); 84 85 if (config_rootfound("mainbus", "mainbus") == NULL) 86 panic("no mainbus found"); 87 88#ifdef DEBUG_KERNEL_START 89 printf("survived autoconf, going to enable interrupts\n"); 90#endif 91 92#ifdef DRACO 93 if (is_draco()) { 94 *draco_intena |= DRIRQ_GLOBAL; 95 /* softints always enabled */ 96 } else 97#endif 98 { 99 custom.intena = INTF_SETCLR | INTF_INTEN; 100 101 /* also enable hardware aided software interrupts */ 102 custom.intena = INTF_SETCLR | INTF_SOFTINT; 103 } 104#ifdef DEBUG_KERNEL_START 105 for (i=splhigh(); i>=s ;i-=0x100) { 106 splx(i); 107 printf("%d...", (i>>8) & 7); 108 } 109 printf("survived interrupt enable\n"); 110#else 111 splx(s); 112#endif 113 cold = 0; 114#ifdef DEBUG_KERNEL_START 115 printf("survived configure...\n"); 116#endif 117} 118 119void 120cpu_rootconf() 121{ 122 struct device *booted_device; 123 int booted_partition; 124 125 findroot(&booted_device, &booted_partition); 126#ifdef DEBUG_KERNEL_START 127 printf("survived findroot()\n"); 128#endif 129 setroot(booted_device, booted_partition, amiga_nam2blk); 130#ifdef DEBUG_KERNEL_START 131 printf("survived setroot()\n"); 132#endif 133} 134 135/*ARGSUSED*/ 136int 137simple_devprint(auxp, pnp) 138 void *auxp; 139 const char *pnp; 140{ 141 return(QUIET); 142} 143 144int 145matchname(fp, sp) 146 char *fp, *sp; 147{ 148 int len; 149 150 len = strlen(fp); 151 if (strlen(sp) != len) 152 return(0); 153 if (bcmp(fp, sp, len) == 0) 154 return(1); 155 return(0); 156} 157 158/* 159 * use config_search to find appropriate device, then call that device 160 * directly with NULL device variable storage. A device can then 161 * always tell the difference betwean the real and console init 162 * by checking for NULL. 163 */ 164int 165amiga_config_found(pcfp, pdp, auxp, pfn) 166 struct cfdata *pcfp; 167 struct device *pdp; 168 void *auxp; 169 cfprint_t pfn; 170{ 171 struct device temp; 172 struct cfdata *cf; 173 174 if (amiga_realconfig) 175 return(config_found(pdp, auxp, pfn) != NULL); 176 177 if (pdp == NULL) 178 pdp = &temp; 179 180 pdp->dv_cfdata = pcfp; 181 if ((cf = config_search((cfmatch_t)NULL, pdp, auxp)) != NULL) { 182 cf->cf_attach->ca_attach(pdp, NULL, auxp); 183 pdp->dv_cfdata = NULL; 184 return(1); 185 } 186 pdp->dv_cfdata = NULL; 187 return(0); 188} 189 190/* 191 * this function needs to get enough configured to do a console 192 * basically this means start attaching the grfxx's that support 193 * the console. Kinda hacky but it works. 194 */ 195void 196config_console() 197{ 198 struct cfdata *cf; 199 200 /* 201 * we need mainbus' cfdata. 202 */ 203 cf = config_rootsearch(NULL, "mainbus", "mainbus"); 204 if (cf == NULL) { 205 panic("no mainbus"); 206 } 207 /* 208 * delay clock calibration. 209 */ 210 amiga_config_found(cf, NULL, "clock", NULL); 211 212 /* 213 * internal grf. 214 */ 215#ifdef DRACO 216 if (!(is_draco())) 217#endif 218 amiga_config_found(cf, NULL, "grfcc", NULL); 219 /* 220 * zbus knows when its not for real and will 221 * only configure the appropriate hardware 222 */ 223 amiga_config_found(cf, NULL, "zbus", NULL); 224} 225 226/* 227 * mainbus driver 228 */ 229struct cfattach mainbus_ca = { 230 sizeof(struct device), mbmatch, mbattach 231}; 232 233int 234mbmatch(pdp, cfp, auxp) 235 struct device *pdp; 236 struct cfdata *cfp; 237 void *auxp; 238{ 239 240 if (cfp->cf_unit > 0) 241 return(0); 242 /* 243 * We are always here 244 */ 245 return(1); 246} 247 248/* 249 * "find" all the things that should be there. 250 */ 251void 252mbattach(pdp, dp, auxp) 253 struct device *pdp, *dp; 254 void *auxp; 255{ 256 printf("\n"); 257 config_found(dp, "clock", simple_devprint); 258 if (is_a3000() || is_a4000()) { 259 config_found(dp, "a34kbbc", simple_devprint); 260 } else 261#ifdef DRACO 262 if (!is_draco()) 263#endif 264 { 265 config_found(dp, "a2kbbc", simple_devprint); 266 } 267#ifdef DRACO 268 if (is_draco()) { 269 config_found(dp, "drbbc", simple_devprint); 270 config_found(dp, "kbd", simple_devprint); 271 config_found(dp, "drsc", simple_devprint); 272 config_found(dp, "drsupio", simple_devprint); 273 } else 274#endif 275 { 276 config_found(dp, "ser", simple_devprint); 277 config_found(dp, "par", simple_devprint); 278 config_found(dp, "kbd", simple_devprint); 279 config_found(dp, "ms", simple_devprint); 280 config_found(dp, "ms", simple_devprint); 281 config_found(dp, "grfcc", simple_devprint); 282 config_found(dp, "fdc", simple_devprint); 283 } 284 if (is_a4000() || is_a1200()) 285 config_found(dp, "idesc", simple_devprint); 286 if (is_a4000()) /* Try to configure A4000T SCSI */ 287 config_found(dp, "afsc", simple_devprint); 288 if (is_a3000()) 289 config_found(dp, "ahsc", simple_devprint); 290#ifdef DRACO 291 if (!is_draco()) 292#endif 293 config_found(dp, "aucc", simple_devprint); 294 295 config_found(dp, "zbus", simple_devprint); 296} 297 298int 299mbprint(auxp, pnp) 300 void *auxp; 301 const char *pnp; 302{ 303 if (pnp) 304 printf("%s at %s", (char *)auxp, pnp); 305 return(UNCONF); 306} 307 308/* 309 * The system will assign the "booted device" indicator (and thus 310 * rootdev if rootspec is wildcarded) to the first partition 'a' 311 * in preference of boot. However, it does walk unit backwards 312 * to remain compatible with the old Amiga method of picking the 313 * last root found. 314 */ 315#include <sys/fcntl.h> /* XXXX and all that uses it */ 316#include <sys/proc.h> /* XXXX and all that uses it */ 317 318#include "fd.h" 319#include "sd.h" 320#include "cd.h" 321 322#if NFD > 0 323extern struct cfdriver fd_cd; 324#endif 325#if NSD > 0 326extern struct cfdriver sd_cd; 327#endif 328#if NCD > 0 329extern struct cfdriver cd_cd; 330#endif 331 332struct cfdriver *genericconf[] = { 333#if NFD > 0 334 &fd_cd, 335#endif 336#if NSD > 0 337 &sd_cd, 338#endif 339#if NCD > 0 340 &cd_cd, 341#endif 342 NULL, 343}; 344 345void 346findroot(devpp, partp) 347 struct device **devpp; 348 int *partp; 349{ 350 struct disk *dkp; 351 struct partition *pp; 352 struct device **devs; 353 int i, maj, unit; 354 355 /* 356 * Default to "not found". 357 */ 358 *devpp = NULL; 359 360 /* always partition 'a' */ 361 *partp = 0; 362 363#if NSD > 0 364 /* 365 * If we have the boot partition offset (boot_partition), try 366 * to locate the device corresponding to that partition. 367 */ 368#ifdef DEBUG_KERNEL_START 369 printf("Boot partition offset is %ld\n", boot_partition); 370#endif 371 if (boot_partition != 0) { 372 struct bdevsw *bdp; 373 int i; 374 375 for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) { 376#ifdef DEBUG_KERNEL_START 377 printf("probing for sd%d\n", unit); 378#endif 379 if (sd_cd.cd_devs[unit] == NULL) 380 continue; 381 382 /* 383 * Find the disk corresponding to the current 384 * device. 385 */ 386 devs = (struct device **)sd_cd.cd_devs; 387 if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL) 388 continue; 389 390 if (dkp->dk_driver == NULL || 391 dkp->dk_driver->d_strategy == NULL) 392 continue; 393 for (bdp = bdevsw; bdp < (bdevsw + nblkdev); bdp++) 394 if (bdp->d_strategy == 395 dkp->dk_driver->d_strategy) 396 break; 397 if (bdp->d_open(MAKEDISKDEV(4, unit, RAW_PART), 398 FREAD | FNONBLOCK, 0, curproc)) 399 continue; 400 bdp->d_close(MAKEDISKDEV(4, unit, RAW_PART), 401 FREAD | FNONBLOCK, 0, curproc); 402 pp = &dkp->dk_label->d_partitions[0]; 403 for (i = 0; i < dkp->dk_label->d_npartitions; 404 i++, pp++) { 405#ifdef DEBUG_KERNEL_START 406 printf("sd%d%c type %d offset %d size %d\n", 407 unit, i+'a', pp->p_fstype, 408 pp->p_offset, pp->p_size); 409#endif 410 if (pp->p_size == 0 || 411 (pp->p_fstype != FS_BSDFFS && 412 pp->p_fstype != FS_SWAP)) 413 continue; 414 if (pp->p_offset == boot_partition) { 415 if (*devpp == NULL) { 416 *devpp = devs[unit]; 417 *partp = i; 418 } else 419 printf("Ambiguous boot device\n"); 420 } 421 } 422 } 423 } 424 if (*devpp != NULL) 425 return; /* we found the boot device */ 426#endif 427 428 for (i = 0; genericconf[i] != NULL; i++) { 429 for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) { 430 if (genericconf[i]->cd_devs[unit] == NULL) 431 continue; 432 433 /* 434 * Find the disk structure corresponding to the 435 * current device. 436 */ 437 devs = (struct device **)genericconf[i]->cd_devs; 438 if ((dkp = disk_find(devs[unit]->dv_xname)) == NULL) 439 continue; 440 441 if (dkp->dk_driver == NULL || 442 dkp->dk_driver->d_strategy == NULL) 443 continue; 444 445 for (maj = 0; maj < nblkdev; maj++) 446 if (bdevsw[maj].d_strategy == 447 dkp->dk_driver->d_strategy) 448 break; 449#ifdef DIAGNOSTIC 450 if (maj >= nblkdev) 451 panic("findroot: impossible"); 452#endif 453 454 /* Open disk; forces read of disklabel. */ 455 if ((*bdevsw[maj].d_open)(MAKEDISKDEV(maj, 456 unit, 0), FREAD|FNONBLOCK, 0, &proc0)) 457 continue; 458 (void)(*bdevsw[maj].d_close)(MAKEDISKDEV(maj, 459 unit, 0), FREAD|FNONBLOCK, 0, &proc0); 460 461 pp = &dkp->dk_label->d_partitions[0]; 462 if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) { 463 *devpp = devs[unit]; 464 *partp = 0; 465 return; 466 } 467 } 468 } 469} 470 471/* 472 * Try to determine, of this machine is an A3000, which has a builtin 473 * realtime clock and scsi controller, so that this hardware is only 474 * included as "configured" if this IS an A3000 475 */ 476 477int a3000_flag = 1; /* patchable */ 478#ifdef A4000 479int a4000_flag = 1; /* patchable - default to A4000 */ 480#else 481int a4000_flag = 0; /* patchable */ 482#endif 483 484int 485is_a3000() 486{ 487 /* this is a dirty kludge.. but how do you do this RIGHT ? :-) */ 488 extern long boot_fphystart; 489 short sc; 490 491 if ((machineid >> 16) == 3000) 492 return (1); /* It's an A3000 */ 493 if (machineid >> 16) 494 return (0); /* It's not an A3000 */ 495 /* Machine type is unknown, so try to guess it */ 496 /* where is fastram on the A4000 ?? */ 497 /* if fastram is below 0x07000000, assume it's not an A3000 */ 498 if (boot_fphystart < 0x07000000) 499 return(0); 500 /* 501 * OK, fastram starts at or above 0x07000000, check specific 502 * machines 503 */ 504 for (sc = 0; sc < ncfdev; sc++) { 505 switch (cfdev[sc].rom.manid) { 506 case 2026: /* Progressive Peripherals, Inc */ 507 switch (cfdev[sc].rom.prodid) { 508 case 0: /* PPI Mercury - A3000 */ 509 case 1: /* PP&S A3000 '040 */ 510 return(1); 511 case 150: /* PPI Zeus - it's an A2000 */ 512 case 105: /* PP&S A2000 '040 */ 513 case 187: /* PP&S A500 '040 */ 514 return(0); 515 } 516 break; 517 518 case 2112: /* IVS */ 519 switch (cfdev[sc].rom.prodid) { 520 case 242: 521 return(0); /* A2000 accelerator? */ 522 } 523 break; 524 } 525 } 526 return (a3000_flag); /* XXX let flag tell now */ 527} 528 529int 530is_a4000() 531{ 532 if ((machineid >> 16) == 4000) 533 return (1); /* It's an A4000 */ 534 if ((machineid >> 16) == 1200) 535 return (0); /* It's an A1200, so not A4000 */ 536#ifdef DRACO 537 if (is_draco()) 538 return (0); 539#endif 540 /* Do I need this any more? */ 541 if ((custom.deniseid & 0xff) == 0xf8) 542 return (1); 543#ifdef DEBUG 544 if (a4000_flag) 545 printf("Denise ID = %04x\n", (unsigned short)custom.deniseid); 546#endif 547 if (machineid >> 16) 548 return (0); /* It's not an A4000 */ 549 return (a4000_flag); /* Machine type not set */ 550} 551 552int 553is_a1200() 554{ 555 if ((machineid >> 16) == 1200) 556 return (1); /* It's an A1200 */ 557 return (0); /* Machine type not set */ 558} 559