1 /* $NetBSD: autoconf.c,v 1.73 2007/12/05 12:31:28 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.73 2007/12/05 12:31:28 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 sys/kern/subr_autoconf.c: configure() 78 */ 79 void 80 cpu_configure(void) 81 { 82 83 /* General device autoconfiguration. */ 84 if (config_rootfound("mainbus", NULL) == NULL) 85 panic("%s: mainbus not found", __func__); 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_ia() 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 108 bus_scan(struct device *parent, struct cfdata *cf, const int *ldesc, void *aux) 109 { 110 struct confargs *ca = aux; 111 112 #ifdef DIAGNOSTIC 113 if (cf->cf_fstate == FSTATE_STAR) 114 panic("%s: FSTATE_STAR", __func__); 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 if (config_match(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(void *args, const char *name) 145 { 146 struct confargs *ca = args; 147 148 if (name) 149 aprint_normal("%s:", name); 150 151 if (ca->ca_paddr != -1) 152 aprint_normal(" addr 0x%lx", ca->ca_paddr); 153 if (ca->ca_intpri != -1) 154 aprint_normal(" ipl %d", ca->ca_intpri); 155 if (ca->ca_intvec != -1) 156 aprint_normal(" vect 0x%x", ca->ca_intvec); 157 158 return UNCONF; 159 } 160 161 /****************************************************************/ 162 163 /* This takes the args: name, ctlr, unit */ 164 typedef struct device * (*findfunc_t)(char *, int, int); 165 166 static struct device * find_dev_byname(char *); 167 static struct device * net_find (char *, int, int); 168 #if NSCSIBUS > 0 169 static struct device * scsi_find(char *, int, int); 170 #endif 171 static struct device * xx_find (char *, int, int); 172 173 struct prom_n2f { 174 const char name[4]; 175 findfunc_t func; 176 }; 177 static struct prom_n2f prom_dev_table[] = { 178 { "ie", net_find }, 179 { "le", net_find }, 180 #if NSCSIBUS > 0 181 { "sd", scsi_find }, 182 #endif 183 { "xy", xx_find }, 184 { "xd", xx_find }, 185 { "", 0 }, 186 }; 187 188 /* 189 * Choose root and swap devices. 190 */ 191 void 192 cpu_rootconf(void) 193 { 194 struct bootparam *bp; 195 struct prom_n2f *nf; 196 struct device *boot_device; 197 int boot_partition; 198 const char *devname; 199 findfunc_t find; 200 char promname[4]; 201 char partname[4]; 202 203 /* PROM boot parameters. */ 204 bp = *romVectorPtr->bootParam; 205 206 /* 207 * Copy PROM boot device name (two letters) 208 * to a normal, null terminated string. 209 * (No terminating null in bp->devName) 210 */ 211 promname[0] = bp->devName[0]; 212 promname[1] = bp->devName[1]; 213 promname[2] = '\0'; 214 215 /* Default to "unknown" */ 216 boot_device = NULL; 217 boot_partition = 0; 218 devname = "<unknown>"; 219 partname[0] = '\0'; 220 find = NULL; 221 222 /* Do we know anything about the PROM boot device? */ 223 for (nf = prom_dev_table; nf->func; nf++) 224 if (!strcmp(nf->name, promname)) { 225 find = nf->func; 226 break; 227 } 228 if (find) 229 boot_device = (*find)(promname, bp->ctlrNum, bp->unitNum); 230 if (boot_device) { 231 devname = boot_device->dv_xname; 232 if (device_class(boot_device) == DV_DISK) { 233 boot_partition = bp->partNum & 7; 234 partname[0] = 'a' + boot_partition; 235 partname[1] = '\0'; 236 } 237 } 238 239 printf("boot device: %s%s\n", devname, partname); 240 setroot(boot_device, boot_partition); 241 } 242 243 /* 244 * Functions to find devices using PROM boot parameters. 245 */ 246 247 /* 248 * Network device: Just use controller number. 249 */ 250 static struct device * 251 net_find(char *name, int ctlr, int unit) 252 { 253 char tname[16]; 254 255 sprintf(tname, "%s%d", name, ctlr); 256 return find_dev_byname(tname); 257 } 258 259 #if NSCSIBUS > 0 260 /* 261 * SCSI device: The controller number corresponds to the 262 * scsibus number, and the unit number is (targ*8 + LUN). 263 */ 264 static struct device * 265 scsi_find(char *name, int ctlr, int unit) 266 { 267 struct device *scsibus; 268 struct scsibus_softc *sbsc; 269 struct scsipi_periph *periph; 270 int target, lun; 271 char tname[16]; 272 273 sprintf(tname, "scsibus%d", ctlr); 274 scsibus = find_dev_byname(tname); 275 if (scsibus == NULL) 276 return NULL; 277 278 /* Compute SCSI target/LUN from PROM unit. */ 279 target = (unit >> 3) & 7; 280 lun = unit & 7; 281 282 /* Find the device at this target/LUN */ 283 sbsc = (struct scsibus_softc *)scsibus; 284 periph = scsipi_lookup_periph(sbsc->sc_channel, target, lun); 285 if (periph == NULL) 286 return NULL; 287 288 return periph->periph_dev; 289 } 290 #endif /* NSCSIBUS > 0 */ 291 292 /* 293 * Xylogics SMD disk: (xy, xd) 294 * Assume wired-in unit numbers for now... 295 */ 296 static struct device * 297 xx_find(char *name, int ctlr, int unit) 298 { 299 int diskunit; 300 char tname[16]; 301 302 diskunit = (ctlr * 2) + unit; 303 sprintf(tname, "%s%d", name, diskunit); 304 return find_dev_byname(tname); 305 } 306 307 /* 308 * Given a device name, find its struct device 309 * XXX - Move this to some common file? 310 */ 311 static struct device * 312 find_dev_byname(char *name) 313 { 314 struct device *dv; 315 316 for (dv = TAILQ_FIRST(&alldevs); dv != NULL; 317 dv = TAILQ_NEXT(dv, dv_list)) { 318 if (!strcmp(dv->dv_xname, name)) { 319 return dv; 320 } 321 } 322 return NULL; 323 } 324 325 /* 326 * Misc. helpers used by driver match/attach functions. 327 */ 328 329 /* 330 * Read addr with size len (1,2,4) into val. 331 * If this generates a bus error, return -1 332 * 333 * Create a temporary mapping, 334 * Try the access using peek_* 335 * Clean up temp. mapping 336 */ 337 int 338 bus_peek(int bustype, int pa, int sz) 339 { 340 void *va; 341 int rv; 342 343 va = bus_tmapin(bustype, pa); 344 switch (sz) { 345 case 1: 346 rv = peek_byte(va); 347 break; 348 case 2: 349 rv = peek_word(va); 350 break; 351 case 4: 352 rv = peek_long(va); 353 break; 354 default: 355 printf(" %s: invalid size=%d\n", __func__, sz); 356 rv = -1; 357 } 358 bus_tmapout(va); 359 360 return rv; 361 } 362 363 /* from hp300: badbaddr() */ 364 int 365 peek_byte(void *addr) 366 { 367 label_t faultbuf; 368 int x; 369 370 nofault = &faultbuf; 371 if (setjmp(&faultbuf)) 372 x = -1; 373 else 374 x = *(volatile u_char *)addr; 375 376 nofault = NULL; 377 return x; 378 } 379 380 int 381 peek_word(void *addr) 382 { 383 label_t faultbuf; 384 int x; 385 386 nofault = &faultbuf; 387 if (setjmp(&faultbuf)) 388 x = -1; 389 else 390 x = *(volatile u_short *)addr; 391 392 nofault = NULL; 393 return x; 394 } 395 396 int 397 peek_long(void *addr) 398 { 399 label_t faultbuf; 400 int x; 401 402 nofault = &faultbuf; 403 if (setjmp(&faultbuf)) 404 x = -1; 405 else { 406 x = *(volatile int *)addr; 407 if (x == -1) { 408 printf("%s: uh-oh, actually read -1!\n", __func__); 409 x &= 0x7FFFffff; /* XXX */ 410 } 411 } 412 413 nofault = NULL; 414 return x; 415 } 416