1 /* $NetBSD: autoconf.c,v 1.61 2003/07/15 03:36:16 lukem 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/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.61 2003/07/15 03:36:16 lukem Exp $"); 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/conf.h> 53 #include <sys/device.h> 54 55 #include "scsibus.h" 56 57 #if NSCSIBUS > 0 58 #include <dev/scsipi/scsi_all.h> 59 #include <dev/scsipi/scsipi_all.h> 60 #include <dev/scsipi/scsiconf.h> 61 #endif 62 63 #include <machine/autoconf.h> 64 #include <machine/mon.h> 65 66 #include <sun3/sun3/machdep.h> 67 68 69 /* Make sure the config is OK. */ 70 #if (defined(_SUN3_) + defined(_SUN3X_)) != 1 71 #error "Must have exactly one of: SUN3 and SUN3X options" 72 #endif 73 74 /* 75 * Do general device autoconfiguration, 76 * then choose root device (etc.) 77 * Called by machdep.c: cpu_startup() 78 */ 79 void 80 cpu_configure() 81 { 82 83 /* General device autoconfiguration. */ 84 if (config_rootfound("mainbus", NULL) == NULL) 85 panic("configure: mainbus not found"); 86 87 /* 88 * Now that device autoconfiguration is finished, 89 * we can safely enable interrupts. 90 */ 91 printf("enabling interrupts\n"); 92 (void)spl0(); 93 } 94 95 /* 96 * bus_scan: 97 * This function is passed to config_search() by the attach function 98 * for each of the "bus" drivers (obctl, obio, obmem, vme, ...). 99 * The purpose of this function is to copy the "locators" into our 100 * confargs structure, so child drivers may use the confargs both 101 * as match parameters and as temporary storage for the defaulted 102 * locator values determined in the child_match and preserved for 103 * the child_attach function. If the bus attach functions just 104 * used config_found, then we would not have an opportunity to 105 * setup the confargs for each child match and attach call. 106 */ 107 int bus_scan(parent, cf, aux) 108 struct device *parent; 109 struct cfdata *cf; 110 void *aux; 111 { 112 struct confargs *ca = aux; 113 114 #ifdef DIAGNOSTIC 115 if (cf->cf_fstate == FSTATE_STAR) 116 panic("bus_scan: FSTATE_STAR"); 117 #endif 118 119 /* 120 * Copy the locators into our confargs. 121 * Our parent set ca->ca_bustype already. 122 */ 123 ca->ca_paddr = cf->cf_paddr; 124 ca->ca_intpri = cf->cf_intpri; 125 ca->ca_intvec = cf->cf_intvec; 126 127 /* 128 * Note that this allows the match function to save 129 * defaulted locators in the confargs that will be 130 * preserved for the related attach call. 131 * XXX - This is a hack... 132 */ 133 if (config_match(parent, cf, ca) > 0) { 134 config_attach(parent, cf, ca, bus_print); 135 } 136 return (0); 137 } 138 139 /* 140 * bus_print: 141 * Just print out the final (non-default) locators. 142 * The parent name is non-NULL when there was no match 143 * found by config_found(). 144 */ 145 int 146 bus_print(args, name) 147 void *args; 148 const char *name; 149 { 150 struct confargs *ca = args; 151 152 if (name) 153 aprint_normal("%s:", name); 154 155 if (ca->ca_paddr != -1) 156 aprint_normal(" addr 0x%x", ca->ca_paddr); 157 if (ca->ca_intpri != -1) 158 aprint_normal(" ipl %d", ca->ca_intpri); 159 if (ca->ca_intvec != -1) 160 aprint_normal(" vect 0x%x", ca->ca_intvec); 161 162 return(UNCONF); 163 } 164 165 /****************************************************************/ 166 167 /* This takes the args: name, ctlr, unit */ 168 typedef struct device * (*findfunc_t) __P((char *, int, int)); 169 170 static struct device * find_dev_byname __P((char *)); 171 static struct device * net_find __P((char *, int, int)); 172 #if NSCSIBUS > 0 173 static struct device * scsi_find __P((char *, int, int)); 174 #endif 175 static struct device * xx_find __P((char *, int, int)); 176 177 struct prom_n2f { 178 const char name[4]; 179 findfunc_t func; 180 }; 181 static struct prom_n2f prom_dev_table[] = { 182 { "ie", net_find }, 183 { "le", net_find }, 184 #if NSCSIBUS > 0 185 { "sd", scsi_find }, 186 #endif 187 { "xy", xx_find }, 188 { "xd", xx_find }, 189 { "", 0 }, 190 }; 191 192 /* 193 * Choose root and swap devices. 194 */ 195 void 196 cpu_rootconf() 197 { 198 struct bootparam *bp; 199 struct prom_n2f *nf; 200 struct device *boot_device; 201 int boot_partition; 202 char *devname; 203 findfunc_t find; 204 char promname[4]; 205 char partname[4]; 206 207 /* PROM boot parameters. */ 208 bp = *romVectorPtr->bootParam; 209 210 /* 211 * Copy PROM boot device name (two letters) 212 * to a normal, null terminated string. 213 * (No terminating null in bp->devName) 214 */ 215 promname[0] = bp->devName[0]; 216 promname[1] = bp->devName[1]; 217 promname[2] = '\0'; 218 219 /* Default to "unknown" */ 220 boot_device = NULL; 221 boot_partition = 0; 222 devname = "<unknown>"; 223 partname[0] = '\0'; 224 find = NULL; 225 226 /* Do we know anything about the PROM boot device? */ 227 for (nf = prom_dev_table; nf->func; nf++) 228 if (!strcmp(nf->name, promname)) { 229 find = nf->func; 230 break; 231 } 232 if (find) 233 boot_device = (*find)(promname, bp->ctlrNum, bp->unitNum); 234 if (boot_device) { 235 devname = boot_device->dv_xname; 236 if (boot_device->dv_class == DV_DISK) { 237 boot_partition = bp->partNum & 7; 238 partname[0] = 'a' + boot_partition; 239 partname[1] = '\0'; 240 } 241 } 242 243 printf("boot device: %s%s\n", devname, partname); 244 setroot(boot_device, boot_partition); 245 } 246 247 /* 248 * Functions to find devices using PROM boot parameters. 249 */ 250 251 /* 252 * Network device: Just use controller number. 253 */ 254 static struct device * 255 net_find(name, ctlr, unit) 256 char *name; 257 int ctlr, unit; 258 { 259 char tname[16]; 260 261 sprintf(tname, "%s%d", name, ctlr); 262 return (find_dev_byname(tname)); 263 } 264 265 #if NSCSIBUS > 0 266 /* 267 * SCSI device: The controller number corresponds to the 268 * scsibus number, and the unit number is (targ*8 + LUN). 269 */ 270 static struct device * 271 scsi_find(name, ctlr, unit) 272 char *name; 273 int ctlr, unit; 274 { 275 struct device *scsibus; 276 struct scsibus_softc *sbsc; 277 struct scsipi_periph *periph; 278 int target, lun; 279 char tname[16]; 280 281 sprintf(tname, "scsibus%d", ctlr); 282 scsibus = find_dev_byname(tname); 283 if (scsibus == NULL) 284 return (NULL); 285 286 /* Compute SCSI target/LUN from PROM unit. */ 287 target = (unit >> 3) & 7; 288 lun = unit & 7; 289 290 /* Find the device at this target/LUN */ 291 sbsc = (struct scsibus_softc *)scsibus; 292 periph = scsipi_lookup_periph(sbsc->sc_channel, target, lun); 293 if (periph == NULL) 294 return (NULL); 295 296 return (periph->periph_dev); 297 } 298 #endif /* NSCSIBUS > 0 */ 299 300 /* 301 * Xylogics SMD disk: (xy, xd) 302 * Assume wired-in unit numbers for now... 303 */ 304 static struct device * 305 xx_find(name, ctlr, unit) 306 char *name; 307 int ctlr, unit; 308 { 309 int diskunit; 310 char tname[16]; 311 312 diskunit = (ctlr * 2) + unit; 313 sprintf(tname, "%s%d", name, diskunit); 314 return (find_dev_byname(tname)); 315 } 316 317 /* 318 * Given a device name, find its struct device 319 * XXX - Move this to some common file? 320 */ 321 static struct device * 322 find_dev_byname(name) 323 char *name; 324 { 325 struct device *dv; 326 327 for (dv = alldevs.tqh_first; dv != NULL; 328 dv = dv->dv_list.tqe_next) { 329 if (!strcmp(dv->dv_xname, name)) { 330 return(dv); 331 } 332 } 333 return (NULL); 334 } 335 336 /* 337 * Misc. helpers used by driver match/attach functions. 338 */ 339 340 /* 341 * Read addr with size len (1,2,4) into val. 342 * If this generates a bus error, return -1 343 * 344 * Create a temporary mapping, 345 * Try the access using peek_* 346 * Clean up temp. mapping 347 */ 348 int 349 bus_peek(bustype, pa, sz) 350 int bustype, pa, sz; 351 { 352 caddr_t va; 353 int rv; 354 355 va = bus_tmapin(bustype, pa); 356 switch (sz) { 357 case 1: 358 rv = peek_byte(va); 359 break; 360 case 2: 361 rv = peek_word(va); 362 break; 363 case 4: 364 rv = peek_long(va); 365 break; 366 default: 367 printf(" bus_peek: invalid size=%d\n", sz); 368 rv = -1; 369 } 370 bus_tmapout(va); 371 372 return (rv); 373 } 374 375 /* from hp300: badbaddr() */ 376 int 377 peek_byte(addr) 378 caddr_t addr; 379 { 380 label_t faultbuf; 381 int x; 382 383 nofault = &faultbuf; 384 if (setjmp(&faultbuf)) 385 x = -1; 386 else 387 x = *(volatile u_char *)addr; 388 389 nofault = NULL; 390 return(x); 391 } 392 393 int 394 peek_word(addr) 395 caddr_t addr; 396 { 397 label_t faultbuf; 398 int x; 399 400 nofault = &faultbuf; 401 if (setjmp(&faultbuf)) 402 x = -1; 403 else 404 x = *(volatile u_short *)addr; 405 406 nofault = NULL; 407 return(x); 408 } 409 410 int 411 peek_long(addr) 412 caddr_t addr; 413 { 414 label_t faultbuf; 415 int x; 416 417 nofault = &faultbuf; 418 if (setjmp(&faultbuf)) 419 x = -1; 420 else { 421 x = *(volatile int *)addr; 422 if (x == -1) { 423 printf("peek_long: uh-oh, actually read -1!\n"); 424 x &= 0x7FFFffff; /* XXX */ 425 } 426 } 427 428 nofault = NULL; 429 return(x); 430 } 431