1 /* $NetBSD: autoconf.c,v 1.75 2008/04/28 20:23:38 martin 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Setup the system to run on the current machine. 34 * 35 * Configure() is called at boot time. Available devices are 36 * determined (from possibilities mentioned in ioconf.c), and 37 * the drivers are initialized. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.75 2008/04/28 20:23:38 martin Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/conf.h> 46 #include <sys/device.h> 47 48 #include "scsibus.h" 49 50 #if NSCSIBUS > 0 51 #include <dev/scsipi/scsi_all.h> 52 #include <dev/scsipi/scsipi_all.h> 53 #include <dev/scsipi/scsiconf.h> 54 #endif 55 56 #include <machine/autoconf.h> 57 #include <machine/mon.h> 58 59 #include <sun3/sun3/machdep.h> 60 61 62 /* Make sure the config is OK. */ 63 #if (defined(_SUN3_) + defined(_SUN3X_)) != 1 64 #error "Must have exactly one of: SUN3 and SUN3X options" 65 #endif 66 67 /* 68 * Do general device autoconfiguration, 69 * then choose root device (etc.) 70 * Called by sys/kern/subr_autoconf.c: configure() 71 */ 72 void 73 cpu_configure(void) 74 { 75 76 /* General device autoconfiguration. */ 77 if (config_rootfound("mainbus", NULL) == NULL) 78 panic("%s: mainbus not found", __func__); 79 80 /* 81 * Now that device autoconfiguration is finished, 82 * we can safely enable interrupts. 83 */ 84 printf("enabling interrupts\n"); 85 (void)spl0(); 86 } 87 88 /* 89 * bus_scan: 90 * This function is passed to config_search_ia() by the attach function 91 * for each of the "bus" drivers (obctl, obio, obmem, vme, ...). 92 * The purpose of this function is to copy the "locators" into our 93 * confargs structure, so child drivers may use the confargs both 94 * as match parameters and as temporary storage for the defaulted 95 * locator values determined in the child_match and preserved for 96 * the child_attach function. If the bus attach functions just 97 * used config_found, then we would not have an opportunity to 98 * setup the confargs for each child match and attach call. 99 */ 100 int 101 bus_scan(struct device *parent, struct cfdata *cf, const int *ldesc, void *aux) 102 { 103 struct confargs *ca = aux; 104 105 #ifdef DIAGNOSTIC 106 if (cf->cf_fstate == FSTATE_STAR) 107 panic("%s: FSTATE_STAR", __func__); 108 #endif 109 110 /* 111 * Copy the locators into our confargs. 112 * Our parent set ca->ca_bustype already. 113 */ 114 ca->ca_paddr = cf->cf_paddr; 115 ca->ca_intpri = cf->cf_intpri; 116 ca->ca_intvec = cf->cf_intvec; 117 118 /* 119 * Note that this allows the match function to save 120 * defaulted locators in the confargs that will be 121 * preserved for the related attach call. 122 * XXX - This is a hack... 123 */ 124 if (config_match(parent, cf, ca) > 0) { 125 config_attach(parent, cf, ca, bus_print); 126 } 127 return 0; 128 } 129 130 /* 131 * bus_print: 132 * Just print out the final (non-default) locators. 133 * The parent name is non-NULL when there was no match 134 * found by config_found(). 135 */ 136 int 137 bus_print(void *args, const char *name) 138 { 139 struct confargs *ca = args; 140 141 if (name) 142 aprint_normal("%s:", name); 143 144 if (ca->ca_paddr != -1) 145 aprint_normal(" addr 0x%lx", ca->ca_paddr); 146 if (ca->ca_intpri != -1) 147 aprint_normal(" ipl %d", ca->ca_intpri); 148 if (ca->ca_intvec != -1) 149 aprint_normal(" vect 0x%x", ca->ca_intvec); 150 151 return UNCONF; 152 } 153 154 /****************************************************************/ 155 156 /* This takes the args: name, ctlr, unit */ 157 typedef struct device * (*findfunc_t)(char *, int, int); 158 159 static struct device * net_find (char *, int, int); 160 #if NSCSIBUS > 0 161 static struct device * scsi_find(char *, int, int); 162 #endif 163 static struct device * xx_find (char *, int, int); 164 165 struct prom_n2f { 166 const char name[4]; 167 findfunc_t func; 168 }; 169 static struct prom_n2f prom_dev_table[] = { 170 { "ie", net_find }, 171 { "le", net_find }, 172 #if NSCSIBUS > 0 173 { "sd", scsi_find }, 174 #endif 175 { "xy", xx_find }, 176 { "xd", xx_find }, 177 { "", 0 }, 178 }; 179 180 /* 181 * Choose root and swap devices. 182 */ 183 void 184 cpu_rootconf(void) 185 { 186 struct bootparam *bp; 187 struct prom_n2f *nf; 188 struct device *boot_device; 189 int boot_partition; 190 const char *devname; 191 findfunc_t find; 192 char promname[4]; 193 char partname[4]; 194 195 /* PROM boot parameters. */ 196 bp = *romVectorPtr->bootParam; 197 198 /* 199 * Copy PROM boot device name (two letters) 200 * to a normal, null terminated string. 201 * (No terminating null in bp->devName) 202 */ 203 promname[0] = bp->devName[0]; 204 promname[1] = bp->devName[1]; 205 promname[2] = '\0'; 206 207 /* Default to "unknown" */ 208 boot_device = NULL; 209 boot_partition = 0; 210 devname = "<unknown>"; 211 partname[0] = '\0'; 212 find = NULL; 213 214 /* Do we know anything about the PROM boot device? */ 215 for (nf = prom_dev_table; nf->func; nf++) 216 if (!strcmp(nf->name, promname)) { 217 find = nf->func; 218 break; 219 } 220 if (find) 221 boot_device = (*find)(promname, bp->ctlrNum, bp->unitNum); 222 if (boot_device) { 223 devname = boot_device->dv_xname; 224 if (device_class(boot_device) == DV_DISK) { 225 boot_partition = bp->partNum & 7; 226 partname[0] = 'a' + boot_partition; 227 partname[1] = '\0'; 228 } 229 } 230 231 printf("boot device: %s%s\n", devname, partname); 232 setroot(boot_device, boot_partition); 233 } 234 235 /* 236 * Functions to find devices using PROM boot parameters. 237 */ 238 239 /* 240 * Network device: Just use controller number. 241 */ 242 static struct device * 243 net_find(char *name, int ctlr, int unit) 244 { 245 return device_find_by_driver_unit(name, ctlr); 246 } 247 248 #if NSCSIBUS > 0 249 /* 250 * SCSI device: The controller number corresponds to the 251 * scsibus number, and the unit number is (targ*8 + LUN). 252 */ 253 static struct device * 254 scsi_find(char *name, int ctlr, int unit) 255 { 256 struct device *scsibus; 257 struct scsibus_softc *sbsc; 258 struct scsipi_periph *periph; 259 int target, lun; 260 261 scsibus = device_find_by_driver_unit("scsibus", ctlr); 262 if (scsibus == NULL) 263 return NULL; 264 265 /* Compute SCSI target/LUN from PROM unit. */ 266 target = (unit >> 3) & 7; 267 lun = unit & 7; 268 269 /* Find the device at this target/LUN */ 270 sbsc = device_private(scsibus); 271 periph = scsipi_lookup_periph(sbsc->sc_channel, target, lun); 272 if (periph == NULL) 273 return NULL; 274 275 return periph->periph_dev; 276 } 277 #endif /* NSCSIBUS > 0 */ 278 279 /* 280 * Xylogics SMD disk: (xy, xd) 281 * Assume wired-in unit numbers for now... 282 */ 283 static struct device * 284 xx_find(char *name, int ctlr, int unit) 285 { 286 return device_find_by_driver_unit(name, ctlr * 2 + unit); 287 } 288 289 /* 290 * Misc. helpers used by driver match/attach functions. 291 */ 292 293 /* 294 * Read addr with size len (1,2,4) into val. 295 * If this generates a bus error, return -1 296 * 297 * Create a temporary mapping, 298 * Try the access using peek_* 299 * Clean up temp. mapping 300 */ 301 int 302 bus_peek(int bustype, int pa, int sz) 303 { 304 void *va; 305 int rv; 306 307 va = bus_tmapin(bustype, pa); 308 switch (sz) { 309 case 1: 310 rv = peek_byte(va); 311 break; 312 case 2: 313 rv = peek_word(va); 314 break; 315 case 4: 316 rv = peek_long(va); 317 break; 318 default: 319 printf(" %s: invalid size=%d\n", __func__, sz); 320 rv = -1; 321 } 322 bus_tmapout(va); 323 324 return rv; 325 } 326 327 /* from hp300: badbaddr() */ 328 int 329 peek_byte(void *addr) 330 { 331 label_t faultbuf; 332 int x; 333 334 nofault = &faultbuf; 335 if (setjmp(&faultbuf)) 336 x = -1; 337 else 338 x = *(volatile u_char *)addr; 339 340 nofault = NULL; 341 return x; 342 } 343 344 int 345 peek_word(void *addr) 346 { 347 label_t faultbuf; 348 int x; 349 350 nofault = &faultbuf; 351 if (setjmp(&faultbuf)) 352 x = -1; 353 else 354 x = *(volatile u_short *)addr; 355 356 nofault = NULL; 357 return x; 358 } 359 360 int 361 peek_long(void *addr) 362 { 363 label_t faultbuf; 364 int x; 365 366 nofault = &faultbuf; 367 if (setjmp(&faultbuf)) 368 x = -1; 369 else { 370 x = *(volatile int *)addr; 371 if (x == -1) { 372 printf("%s: uh-oh, actually read -1!\n", __func__); 373 x &= 0x7FFFffff; /* XXX */ 374 } 375 } 376 377 nofault = NULL; 378 return x; 379 } 380