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