1 /* $NetBSD: autoconf.c,v 1.51 1998/02/08 05:02:51 gwr Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Glass and Gordon W. Ross. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Setup the system to run on the current machine. 41 * 42 * Configure() is called at boot time. Available devices are 43 * determined (from possibilities mentioned in ioconf.c), and 44 * the drivers are initialized. 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/conf.h> 50 #include <sys/device.h> 51 52 #include <dev/scsipi/scsi_all.h> 53 #include <dev/scsipi/scsipi_all.h> 54 #include <dev/scsipi/scsiconf.h> 55 56 #include <machine/autoconf.h> 57 #include <machine/mon.h> 58 59 #include <sun3/sun3/machdep.h> 60 61 /* Make sure the config is OK. */ 62 #if (defined(_SUN3_) + defined(_SUN3X_)) != 1 63 #error "Must have exactly one of: SUN3 and SUN3X options" 64 #endif 65 66 /* Want compile-time initialization here. */ 67 int cold = 1; 68 69 /* 70 * Do general device autoconfiguration, 71 * then choose root device (etc.) 72 * Called by machdep.c: cpu_startup() 73 */ 74 void 75 configure() 76 { 77 78 /* General device autoconfiguration. */ 79 if (config_rootfound("mainbus", NULL) == NULL) 80 panic("configure: mainbus not found"); 81 82 /* 83 * Now that device autoconfiguration is finished, 84 * we can safely enable interrupts. 85 */ 86 printf("enabling interrupts\n"); 87 (void)spl0(); 88 cold = 0; 89 } 90 91 /* 92 * bus_scan: 93 * This function is passed to config_search() by the attach function 94 * for each of the "bus" drivers (obctl, obio, obmem, vme, ...). 95 * The purpose of this function is to copy the "locators" into our 96 * confargs structure, so child drivers may use the confargs both 97 * as match parameters and as temporary storage for the defaulted 98 * locator values determined in the child_match and preserved for 99 * the child_attach function. If the bus attach functions just 100 * used config_found, then we would not have an opportunity to 101 * setup the confargs for each child match and attach call. 102 */ 103 int bus_scan(parent, cf, aux) 104 struct device *parent; 105 struct cfdata *cf; 106 void *aux; 107 { 108 struct confargs *ca = aux; 109 cfmatch_t mf; 110 111 #ifdef DIAGNOSTIC 112 if (cf->cf_fstate == FSTATE_STAR) 113 panic("bus_scan: FSTATE_STAR"); 114 #endif 115 116 /* 117 * Copy the locators into our confargs. 118 * Our parent set ca->ca_bustype already. 119 */ 120 ca->ca_paddr = cf->cf_paddr; 121 ca->ca_intpri = cf->cf_intpri; 122 ca->ca_intvec = cf->cf_intvec; 123 124 /* 125 * Note that this allows the match function to save 126 * defaulted locators in the confargs that will be 127 * preserved for the related attach call. 128 * XXX - This is a hack... 129 */ 130 mf = cf->cf_attach->ca_match; 131 if ((*mf)(parent, cf, ca) > 0) { 132 config_attach(parent, cf, ca, bus_print); 133 } 134 return (0); 135 } 136 137 /* 138 * bus_print: 139 * Just print out the final (non-default) locators. 140 * The parent name is non-NULL when there was no match 141 * found by config_found(). 142 */ 143 int 144 bus_print(args, name) 145 void *args; 146 const char *name; 147 { 148 struct confargs *ca = args; 149 150 if (name) 151 printf("%s:", name); 152 153 if (ca->ca_paddr != -1) 154 printf(" addr 0x%x", ca->ca_paddr); 155 if (ca->ca_intpri != -1) 156 printf(" ipl %d", ca->ca_intpri); 157 if (ca->ca_intvec != -1) 158 printf(" vect 0x%x", ca->ca_intvec); 159 160 return(UNCONF); 161 } 162 163 /****************************************************************/ 164 165 /* 166 * Support code to find the boot device. 167 */ 168 169 static struct devnametobdevmaj nam2blk[] = { 170 { "xy", 3 }, 171 { "sd", 7 }, 172 { "xd", 10 }, 173 { "md", 13 }, 174 { "cd", 18 }, 175 { NULL, 0 }, 176 }; 177 178 /* This takes the args: name, ctlr, unit */ 179 typedef struct device * (*findfunc_t) __P((char *, int, int)); 180 181 static struct device * find_dev_byname __P((char *)); 182 static struct device * net_find __P((char *, int, int)); 183 static struct device * scsi_find __P((char *, int, int)); 184 static struct device * xx_find __P((char *, int, int)); 185 186 struct prom_n2f { 187 const char name[4]; 188 findfunc_t func; 189 }; 190 static struct prom_n2f prom_dev_table[] = { 191 { "ie", net_find }, 192 { "le", net_find }, 193 { "sd", scsi_find }, 194 { "xy", xx_find }, 195 { "xd", xx_find }, 196 { "", 0 }, 197 }; 198 199 /* 200 * Choose root and swap devices. 201 */ 202 void 203 cpu_rootconf() 204 { 205 struct bootparam *bp; 206 struct prom_n2f *nf; 207 struct device *boot_device; 208 int boot_partition; 209 char *devname; 210 findfunc_t find; 211 char promname[4]; 212 char partname[4]; 213 214 /* PROM boot parameters. */ 215 bp = *romVectorPtr->bootParam; 216 217 /* 218 * Copy PROM boot device name (two letters) 219 * to a normal, null terminated string. 220 * (No terminating null in bp->devName) 221 */ 222 promname[0] = bp->devName[0]; 223 promname[1] = bp->devName[1]; 224 promname[2] = '\0'; 225 226 /* Default to "unknown" */ 227 boot_device = NULL; 228 boot_partition = 0; 229 devname = "<unknown>"; 230 partname[0] = '\0'; 231 find = NULL; 232 233 /* Do we know anything about the PROM boot device? */ 234 for (nf = prom_dev_table; nf->func; nf++) 235 if (!strcmp(nf->name, promname)) { 236 find = nf->func; 237 break; 238 } 239 if (find) 240 boot_device = (*find)(promname, bp->ctlrNum, bp->unitNum); 241 if (boot_device) { 242 devname = boot_device->dv_xname; 243 if (boot_device->dv_class == DV_DISK) { 244 boot_partition = bp->partNum & 7; 245 partname[0] = 'a' + boot_partition; 246 partname[1] = '\0'; 247 } 248 } 249 250 printf("boot device: %s%s\n", devname, partname); 251 setroot(boot_device, boot_partition, nam2blk); 252 } 253 254 /* 255 * Functions to find devices using PROM boot parameters. 256 */ 257 258 /* 259 * Network device: Just use controller number. 260 */ 261 static struct device * 262 net_find(name, ctlr, unit) 263 char *name; 264 int ctlr, unit; 265 { 266 char tname[16]; 267 268 sprintf(tname, "%s%d", name, ctlr); 269 return (find_dev_byname(tname)); 270 } 271 272 /* 273 * SCSI device: The controller number corresponds to the 274 * scsibus number, and the unit number is (targ*8 + LUN). 275 */ 276 static struct device * 277 scsi_find(name, ctlr, unit) 278 char *name; 279 int ctlr, unit; 280 { 281 struct device *scsibus; 282 struct scsibus_softc *sbsc; 283 struct scsipi_link *sc_link; 284 int target, lun; 285 char tname[16]; 286 287 sprintf(tname, "scsibus%d", ctlr); 288 scsibus = find_dev_byname(tname); 289 if (scsibus == NULL) 290 return (NULL); 291 292 /* Compute SCSI target/LUN from PROM unit. */ 293 target = (unit >> 3) & 7; 294 lun = unit & 7; 295 296 /* Find the device at this target/LUN */ 297 sbsc = (struct scsibus_softc *)scsibus; 298 sc_link = sbsc->sc_link[target][lun]; 299 if (sc_link == NULL) 300 return (NULL); 301 302 return (sc_link->device_softc); 303 } 304 305 /* 306 * Xylogics SMD disk: (xy, xd) 307 * Assume wired-in unit numbers for now... 308 */ 309 static struct device * 310 xx_find(name, ctlr, unit) 311 char *name; 312 int ctlr, unit; 313 { 314 int diskunit; 315 char tname[16]; 316 317 diskunit = (ctlr * 2) + unit; 318 sprintf(tname, "%s%d", name, diskunit); 319 return (find_dev_byname(tname)); 320 } 321 322 /* 323 * Given a device name, find its struct device 324 * XXX - Move this to some common file? 325 */ 326 static struct device * 327 find_dev_byname(name) 328 char *name; 329 { 330 struct device *dv; 331 332 for (dv = alldevs.tqh_first; dv != NULL; 333 dv = dv->dv_list.tqe_next) { 334 if (!strcmp(dv->dv_xname, name)) { 335 return(dv); 336 } 337 } 338 return (NULL); 339 } 340 341 /* 342 * Misc. helpers used by driver match/attach functions. 343 */ 344 345 /* 346 * Read addr with size len (1,2,4) into val. 347 * If this generates a bus error, return -1 348 * 349 * Create a temporary mapping, 350 * Try the access using peek_* 351 * Clean up temp. mapping 352 */ 353 int 354 bus_peek(bustype, pa, sz) 355 int bustype, pa, sz; 356 { 357 caddr_t va; 358 int rv; 359 360 va = bus_tmapin(bustype, pa); 361 switch (sz) { 362 case 1: 363 rv = peek_byte(va); 364 break; 365 case 2: 366 rv = peek_word(va); 367 break; 368 case 4: 369 rv = peek_long(va); 370 break; 371 default: 372 printf(" bus_peek: invalid size=%d\n", sz); 373 rv = -1; 374 } 375 bus_tmapout(va); 376 377 return (rv); 378 } 379 380 /* from hp300: badbaddr() */ 381 int 382 peek_byte(addr) 383 register caddr_t addr; 384 { 385 label_t faultbuf; 386 register int x; 387 388 nofault = &faultbuf; 389 if (setjmp(&faultbuf)) 390 x = -1; 391 else 392 x = *(volatile u_char *)addr; 393 394 nofault = NULL; 395 return(x); 396 } 397 398 int 399 peek_word(addr) 400 register caddr_t addr; 401 { 402 label_t faultbuf; 403 register int x; 404 405 nofault = &faultbuf; 406 if (setjmp(&faultbuf)) 407 x = -1; 408 else 409 x = *(volatile u_short *)addr; 410 411 nofault = NULL; 412 return(x); 413 } 414 415 int 416 peek_long(addr) 417 register caddr_t addr; 418 { 419 label_t faultbuf; 420 register int x; 421 422 nofault = &faultbuf; 423 if (setjmp(&faultbuf)) 424 x = -1; 425 else { 426 x = *(volatile int *)addr; 427 if (x == -1) { 428 printf("peek_long: uh-oh, actually read -1!\n"); 429 x &= 0x7FFFffff; /* XXX */ 430 } 431 } 432 433 nofault = NULL; 434 return(x); 435 } 436