1 /* $NetBSD: autoconf.c,v 1.69 2006/10/05 14:46:11 tsutsui 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.69 2006/10/05 14:46:11 tsutsui 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(void) 81 { 82 83 /* 84 * Install handlers for our "soft" interrupts. 85 * There might be a better place to do this? 86 */ 87 softintr_init(); 88 89 /* General device autoconfiguration. */ 90 if (config_rootfound("mainbus", NULL) == NULL) 91 panic("configure: mainbus not found"); 92 93 /* 94 * Now that device autoconfiguration is finished, 95 * we can safely enable interrupts. 96 */ 97 printf("enabling interrupts\n"); 98 (void)spl0(); 99 } 100 101 /* 102 * bus_scan: 103 * This function is passed to config_search_ia() by the attach function 104 * for each of the "bus" drivers (obctl, obio, obmem, vme, ...). 105 * The purpose of this function is to copy the "locators" into our 106 * confargs structure, so child drivers may use the confargs both 107 * as match parameters and as temporary storage for the defaulted 108 * locator values determined in the child_match and preserved for 109 * the child_attach function. If the bus attach functions just 110 * used config_found, then we would not have an opportunity to 111 * setup the confargs for each child match and attach call. 112 */ 113 int 114 bus_scan(struct device *parent, struct cfdata *cf, 115 const int *ldesc, void *aux) 116 { 117 struct confargs *ca = aux; 118 119 #ifdef DIAGNOSTIC 120 if (cf->cf_fstate == FSTATE_STAR) 121 panic("bus_scan: FSTATE_STAR"); 122 #endif 123 124 /* 125 * Copy the locators into our confargs. 126 * Our parent set ca->ca_bustype already. 127 */ 128 ca->ca_paddr = cf->cf_paddr; 129 ca->ca_intpri = cf->cf_intpri; 130 ca->ca_intvec = cf->cf_intvec; 131 132 /* 133 * Note that this allows the match function to save 134 * defaulted locators in the confargs that will be 135 * preserved for the related attach call. 136 * XXX - This is a hack... 137 */ 138 if (config_match(parent, cf, ca) > 0) { 139 config_attach(parent, cf, ca, bus_print); 140 } 141 return (0); 142 } 143 144 /* 145 * bus_print: 146 * Just print out the final (non-default) locators. 147 * The parent name is non-NULL when there was no match 148 * found by config_found(). 149 */ 150 int 151 bus_print(void *args, const char *name) 152 { 153 struct confargs *ca = args; 154 155 if (name) 156 aprint_normal("%s:", name); 157 158 if (ca->ca_paddr != -1) 159 aprint_normal(" addr 0x%lx", ca->ca_paddr); 160 if (ca->ca_intpri != -1) 161 aprint_normal(" ipl %d", ca->ca_intpri); 162 if (ca->ca_intvec != -1) 163 aprint_normal(" vect 0x%x", ca->ca_intvec); 164 165 return(UNCONF); 166 } 167 168 /****************************************************************/ 169 170 /* This takes the args: name, ctlr, unit */ 171 typedef struct device * (*findfunc_t)(char *, int, int); 172 173 static struct device * find_dev_byname(char *); 174 static struct device * net_find (char *, int, int); 175 #if NSCSIBUS > 0 176 static struct device * scsi_find(char *, int, int); 177 #endif 178 static struct device * xx_find (char *, int, int); 179 180 struct prom_n2f { 181 const char name[4]; 182 findfunc_t func; 183 }; 184 static struct prom_n2f prom_dev_table[] = { 185 { "ie", net_find }, 186 { "le", net_find }, 187 #if NSCSIBUS > 0 188 { "sd", scsi_find }, 189 #endif 190 { "xy", xx_find }, 191 { "xd", xx_find }, 192 { "", 0 }, 193 }; 194 195 /* 196 * Choose root and swap devices. 197 */ 198 void 199 cpu_rootconf(void) 200 { 201 struct bootparam *bp; 202 struct prom_n2f *nf; 203 struct device *boot_device; 204 int boot_partition; 205 const char *devname; 206 findfunc_t find; 207 char promname[4]; 208 char partname[4]; 209 210 /* PROM boot parameters. */ 211 bp = *romVectorPtr->bootParam; 212 213 /* 214 * Copy PROM boot device name (two letters) 215 * to a normal, null terminated string. 216 * (No terminating null in bp->devName) 217 */ 218 promname[0] = bp->devName[0]; 219 promname[1] = bp->devName[1]; 220 promname[2] = '\0'; 221 222 /* Default to "unknown" */ 223 boot_device = NULL; 224 boot_partition = 0; 225 devname = "<unknown>"; 226 partname[0] = '\0'; 227 find = NULL; 228 229 /* Do we know anything about the PROM boot device? */ 230 for (nf = prom_dev_table; nf->func; nf++) 231 if (!strcmp(nf->name, promname)) { 232 find = nf->func; 233 break; 234 } 235 if (find) 236 boot_device = (*find)(promname, bp->ctlrNum, bp->unitNum); 237 if (boot_device) { 238 devname = boot_device->dv_xname; 239 if (device_class(boot_device) == DV_DISK) { 240 boot_partition = bp->partNum & 7; 241 partname[0] = 'a' + boot_partition; 242 partname[1] = '\0'; 243 } 244 } 245 246 printf("boot device: %s%s\n", devname, partname); 247 setroot(boot_device, boot_partition); 248 } 249 250 /* 251 * Functions to find devices using PROM boot parameters. 252 */ 253 254 /* 255 * Network device: Just use controller number. 256 */ 257 static struct device * 258 net_find(char *name, int ctlr, int unit) 259 { 260 char tname[16]; 261 262 sprintf(tname, "%s%d", name, ctlr); 263 return (find_dev_byname(tname)); 264 } 265 266 #if NSCSIBUS > 0 267 /* 268 * SCSI device: The controller number corresponds to the 269 * scsibus number, and the unit number is (targ*8 + LUN). 270 */ 271 static struct device * 272 scsi_find(char *name, int ctlr, int 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(char *name, int ctlr, int unit) 305 { 306 int diskunit; 307 char tname[16]; 308 309 diskunit = (ctlr * 2) + unit; 310 sprintf(tname, "%s%d", name, diskunit); 311 return (find_dev_byname(tname)); 312 } 313 314 /* 315 * Given a device name, find its struct device 316 * XXX - Move this to some common file? 317 */ 318 static struct device * 319 find_dev_byname(char *name) 320 { 321 struct device *dv; 322 323 for (dv = alldevs.tqh_first; dv != NULL; 324 dv = dv->dv_list.tqe_next) { 325 if (!strcmp(dv->dv_xname, name)) { 326 return(dv); 327 } 328 } 329 return (NULL); 330 } 331 332 /* 333 * Misc. helpers used by driver match/attach functions. 334 */ 335 336 /* 337 * Read addr with size len (1,2,4) into val. 338 * If this generates a bus error, return -1 339 * 340 * Create a temporary mapping, 341 * Try the access using peek_* 342 * Clean up temp. mapping 343 */ 344 int 345 bus_peek(int bustype, int pa, int sz) 346 { 347 caddr_t va; 348 int rv; 349 350 va = bus_tmapin(bustype, pa); 351 switch (sz) { 352 case 1: 353 rv = peek_byte(va); 354 break; 355 case 2: 356 rv = peek_word(va); 357 break; 358 case 4: 359 rv = peek_long(va); 360 break; 361 default: 362 printf(" bus_peek: invalid size=%d\n", sz); 363 rv = -1; 364 } 365 bus_tmapout(va); 366 367 return (rv); 368 } 369 370 /* from hp300: badbaddr() */ 371 int 372 peek_byte(caddr_t addr) 373 { 374 label_t faultbuf; 375 int x; 376 377 nofault = &faultbuf; 378 if (setjmp(&faultbuf)) 379 x = -1; 380 else 381 x = *(volatile u_char *)addr; 382 383 nofault = NULL; 384 return(x); 385 } 386 387 int 388 peek_word(caddr_t addr) 389 { 390 label_t faultbuf; 391 int x; 392 393 nofault = &faultbuf; 394 if (setjmp(&faultbuf)) 395 x = -1; 396 else 397 x = *(volatile u_short *)addr; 398 399 nofault = NULL; 400 return(x); 401 } 402 403 int 404 peek_long(caddr_t addr) 405 { 406 label_t faultbuf; 407 int x; 408 409 nofault = &faultbuf; 410 if (setjmp(&faultbuf)) 411 x = -1; 412 else { 413 x = *(volatile int *)addr; 414 if (x == -1) { 415 printf("peek_long: uh-oh, actually read -1!\n"); 416 x &= 0x7FFFffff; /* XXX */ 417 } 418 } 419 420 nofault = NULL; 421 return(x); 422 } 423