1/*
2 * Mach Operating System
3 * Copyright (c) 1990 Carnegie-Mellon University
4 * Copyright (c) 1989 Carnegie-Mellon University
5 * Copyright (c) 1988 Carnegie-Mellon University
6 * Copyright (c) 1987 Carnegie-Mellon University
7 * All rights reserved.  The CMU software License Agreement specifies
8 * the terms and conditions for use and redistribution.
9 */
10
11/*
12 * Copyright (c) 1988 Regents of the University of California.
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms are permitted
16 * provided that the above copyright notice and this paragraph are
17 * duplicated in all such forms and that any documentation,
18 * advertising materials, and other materials related to such
19 * distribution and use acknowledge that the software was developed
20 * by the University of California, Berkeley.  The name of the
21 * University may not be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 *
27 *	@(#)config.y	5.8 (Berkeley) 6/18/88
28 */
29
30%union {
31	char	*str;
32	int	val;
33	struct	file_list *file;
34	struct	idlst *lst;
35}
36
37%token	ADDRMOD
38%token	AND
39%token	ANY
40%token	ARGS
41%token	AT
42%token	BIN
43%token	BUILDDIR
44%token	COMMA
45%token	CONFIG
46%token	CONFIGDIR
47%token	CONTROLLER
48%token	CPU
49%token	CSR
50%token	DEVICE
51%token	DISK
52%token	DRIVE
53%token	DST
54%token	DUMPS
55%token	EQUALS
56%token	FLAGS
57%token	IDENT
58%token	INIT
59%token	MACHINE
60%token	MAJOR
61%token	MASTER
62%token	MAXUSERS
63%token	MAXDSIZ
64%token	MBA
65%token	MBII
66%token	MINOR
67%token	MINUS
68%token	NEXUS
69%token	OBJECTDIR
70%token	ON
71%token	OPTIONS
72%token	MAKEOPTIONS
73%token	PRIORITY
74%token	PROFILE
75%token	PSEUDO_DEVICE
76%token	ROOT
77%token	SEMICOLON
78%token	SIZE
79%token	SLAVE
80%token	SOURCEDIR
81%token	SWAP
82%token	TIMEZONE
83%token	TRACE
84%token	UBA
85%token	VECTOR
86%token	VME
87%token  VME16D16
88%token  VME24D16
89%token  VME32D16
90%token  VME16D32
91%token  VME24D32
92%token  VME32D32
93
94/* following 3 are unique to CMU */
95%token	LUN
96%token	SLOT
97%token	TAPE
98
99%token	<str>	ID
100%token	<val>	NUMBER
101%token	<val>	FPNUMBER
102
103%type	<str>	Save_id
104%type	<str>	Opt_value
105%type	<str>	Dev
106%type	<lst>	Id_list
107%type	<val>	optional_size
108%type	<str>	device_name
109%type	<val>	major_minor
110%type	<val>	arg_device_spec
111%type	<val>	root_device_spec
112%type	<val>	dump_device_spec
113%type	<file>	swap_device_spec
114%type	<val>	Value
115
116%{
117
118#include "config.h"
119#include <ctype.h>
120#include <stdio.h>
121
122struct	device cur;
123struct	device *curp = 0;
124char	*temp_id;
125char	*val_id;
126/* char	*malloc(); */
127
128int yylex(void);
129
130int finddev(dev_t dev);
131int alreadychecked(dev_t dev, dev_t list[], dev_t *last);
132void deverror(const char *systemname, const char *devtype);
133void mkconf(char *sysname);
134struct file_list *newswap(void);
135void mkswap(struct file_list *syslist, struct file_list *fl, int size);
136struct device *huhcon(const char *dev);
137void check_nexus(struct device *dev, int num);
138void check_slot(struct device *dev, int num);
139void checksystemspec(struct file_list *fl);
140void verifysystemspecs(void);
141dev_t *verifyswap(struct file_list *fl, dev_t checked[], dev_t *pchecked);
142struct device *dconnect(const char *dev, int num);
143
144%}
145%%
146Configuration:
147	Many_specs
148		{ verifysystemspecs(); }
149		;
150
151Many_specs:
152	Many_specs Spec
153		|
154	/* lambda */
155		;
156
157Spec:
158	Device_spec SEMICOLON
159	      { newdev(&cur); } |
160	Config_spec SEMICOLON
161		|
162	TRACE SEMICOLON
163	      { do_trace = !do_trace; } |
164	SEMICOLON
165		|
166	error SEMICOLON
167		;
168
169Config_spec:
170	MACHINE Save_id
171	    {
172		if (!strcmp($2, "vax")) {
173			machine = MACHINE_VAX;
174			machinename = "vax";
175		} else if (!strcmp($2, "sun")) {
176			/* default to Sun 3 */
177			machine = MACHINE_SUN3;
178			machinename = "sun3";
179		} else if (!strcmp($2, "sun2")) {
180			machine = MACHINE_SUN2;
181			machinename = "sun2";
182		} else if (!strcmp($2, "sun3")) {
183			machine = MACHINE_SUN3;
184			machinename = "sun3";
185		} else if (!strcmp($2, "sun4")) {
186			machine = MACHINE_SUN4;
187			machinename = "sun4";
188		} else if (!strcmp($2, "romp")) {
189			machine = MACHINE_ROMP;
190			machinename = "romp";
191		} else if (!strcmp($2, "ca")) {
192			machine = MACHINE_ROMP;
193			machinename = "ca";
194		} else if (!strcmp($2, "mmax")) {
195			machine = MACHINE_MMAX;
196			machinename = "mmax";
197		} else if (!strcmp($2, "sqt")) {
198			machine = MACHINE_SQT;
199			machinename = "sqt";
200		} else if (!strcmp($2, "i")) {
201			machine = MACHINE_I386;
202			machinename = "i386";
203		} else if (!strcmp($2, "i386")) {
204			machine = MACHINE_I386;
205			machinename = "i386";
206		} else if (!strcmp($2, "ix")) {
207			machine = MACHINE_IX;
208			machinename = "ix";
209		} else if (!strcmp($2, "mipsy")) {
210			machine = MACHINE_MIPSY;
211			machinename = "mipsy";
212		} else if (!strcmp($2, "mips")) {
213			machine = MACHINE_MIPS;
214			machinename = "mips";
215		} else if (!strcmp($2, "i860")) {
216			machine = MACHINE_I860;
217			machinename = "i860";
218		} else if (!strcmp($2, "m68k")) {
219			machine = MACHINE_M68K;
220			machinename = "m68k";
221		} else if (!strcmp($2, "m88k")) {
222			machine = MACHINE_M88K;
223			machinename = "m88k";
224		} else if (!strcmp($2, "m98k")) {
225			machine = MACHINE_M98K;
226			machinename = "m98k";
227		} else if (!strcmp($2, "hppa")) {
228			machine = MACHINE_HPPA;
229			machinename = "hppa";
230		} else if (!strcmp($2, "sparc")) {
231			machine = MACHINE_SPARC;
232			machinename = "sparc";
233		} else if (!strcmp($2, "ppc")) {
234			machine = MACHINE_PPC;
235			machinename = "ppc";
236		} else if (!strcmp($2, "arm64")) {
237			machine = MACHINE_ARM64;
238			machinename = "arm64";
239		} else if (!strcmp($2, "arm")) {
240			machine = MACHINE_ARM;
241			machinename = "arm";
242		} else if (!strcmp($2, "x86_64")) {
243			machine = MACHINE_X86_64;
244			machinename = "x86_64";
245		} else
246			yyerror("Unknown machine type");
247	      } |
248	CPU Save_id
249	      {
250		struct cputype *cp =
251		    (struct cputype *)malloc(sizeof (struct cputype));
252		cp->cpu_name = ns($2);
253		cp->cpu_next = cputype;
254		cputype = cp;
255		free(temp_id);
256	      } |
257	OPTIONS Opt_list
258		|
259	MAKEOPTIONS Mkopt_list
260		|
261	IDENT ID
262	      { ident = ns($2); }
263		|
264	System_spec
265		|
266	MAXUSERS NUMBER
267	      { maxusers = $2; }
268		|
269	BUILDDIR Save_id
270		{ build_directory = ns($2); }
271		|
272	CONFIGDIR Save_id
273		{ config_directory = ns($2); }
274		|
275	OBJECTDIR Save_id
276		{ object_directory = ns($2); }
277		|
278	SOURCEDIR Save_id
279		{ source_directory = ns($2); }
280		|
281	PROFILE
282		{ profiling++; }
283		;
284
285System_spec:
286	  System_id
287		{ checksystemspec(*confp); }
288	| System_id System_parameter_list
289		{ checksystemspec(*confp); }
290	;
291
292System_id:
293	  CONFIG Save_id
294		{ mkconf($2); }
295	;
296
297System_parameter_list:
298	  System_parameter_list System_parameter
299	| System_parameter
300	;
301
302System_parameter:
303	  swap_spec
304	| root_spec
305	| dump_spec
306	| arg_spec
307	;
308
309swap_spec:
310	  SWAP optional_on swap_device_list
311	;
312
313swap_device_list:
314	  swap_device_list AND swap_device
315	| swap_device
316	;
317
318swap_device:
319	  swap_device_spec optional_size
320	      { mkswap(*confp, $1, $2); }
321	;
322
323swap_device_spec:
324	  device_name
325		{
326			struct file_list *fl = newswap();
327
328			if (eq($1, "generic"))
329				fl->f_fn = $1;
330			else {
331				fl->f_swapdev = nametodev($1, 0, 'b');
332				fl->f_fn = devtoname(fl->f_swapdev);
333			}
334			$$ = fl;
335		}
336	| major_minor
337		{
338			struct file_list *fl = newswap();
339
340			fl->f_swapdev = $1;
341			fl->f_fn = devtoname($1);
342			$$ = fl;
343		}
344	;
345
346root_spec:
347	  ROOT optional_on root_device_spec
348		{
349			struct file_list *fl = *confp;
350
351			if (fl && fl->f_rootdev != NODEV)
352				yyerror("extraneous root device specification");
353			else
354				fl->f_rootdev = $3;
355		}
356	;
357
358root_device_spec:
359	  device_name
360		{ $$ = nametodev($1, 0, 'a'); }
361	| major_minor
362	;
363
364dump_spec:
365	  DUMPS optional_on dump_device_spec
366		{
367			struct file_list *fl = *confp;
368
369			if (fl && fl->f_dumpdev != NODEV)
370				yyerror("extraneous dump device specification");
371			else
372				fl->f_dumpdev = $3;
373		}
374
375	;
376
377dump_device_spec:
378	  device_name
379		{ $$ = nametodev($1, 0, 'b'); }
380	| major_minor
381	;
382
383arg_spec:
384	  ARGS optional_on arg_device_spec
385		{
386			struct file_list *fl = *confp;
387
388			if (fl && fl->f_argdev != NODEV)
389				yyerror("extraneous arg device specification");
390			else
391				fl->f_argdev = $3;
392		}
393	;
394
395arg_device_spec:
396	  device_name
397		{ $$ = nametodev($1, 0, 'b'); }
398	| major_minor
399	;
400
401major_minor:
402	  MAJOR NUMBER MINOR NUMBER
403		{ $$ = makedev($2, $4); }
404	;
405
406optional_on:
407	  ON
408	| /* empty */
409	;
410
411optional_size:
412	  SIZE NUMBER
413	      { $$ = $2; }
414	| /* empty */
415	      { $$ = 0; }
416	;
417
418device_name:
419	  Save_id
420		{ $$ = $1; }
421	| Save_id NUMBER
422		{
423			char buf[80];
424
425			(void) sprintf(buf, "%s%d", $1, $2);
426			$$ = ns(buf); free($1);
427		}
428	| Save_id NUMBER ID
429		{
430			char buf[80];
431
432			(void) sprintf(buf, "%s%d%s", $1, $2, $3);
433			$$ = ns(buf); free($1);
434		}
435	;
436
437Opt_list:
438	Opt_list COMMA Option
439		|
440	Option
441		;
442
443Option:
444	Save_id
445	      {
446		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
447		op->op_name = ns($1);
448		op->op_next = (struct opt *) 0;
449		op->op_value = 0;
450		if (opt == (struct opt *) 0)
451			opt = op;
452		else
453			opt_tail->op_next = op;
454		opt_tail = op;
455		free(temp_id);
456	      } |
457	Save_id EQUALS Opt_value
458	      {
459		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
460		op->op_name = ns($1);
461		op->op_next = (struct opt *) 0;
462		op->op_value = ns($3);
463		if (opt == (struct opt *) 0)
464			opt = op;
465		else
466			opt_tail->op_next = op;
467		opt_tail = op;
468		free(temp_id);
469		if (val_id)
470			free(val_id);
471	      } ;
472
473Opt_value:
474	ID
475	      { $$ = val_id = ns($1); } |
476	NUMBER
477	      { char nb[16];
478	          (void) sprintf(nb, "%u", $1);
479	      	  $$ = val_id = ns(nb);
480	      } |
481	/* lambda from MIPS -- WHY */
482	      { $$ = val_id = ns(""); }
483	      ;
484
485Save_id:
486	ID
487	      { $$ = temp_id = ns($1); }
488	;
489
490Mkopt_list:
491	Mkopt_list COMMA Mkoption
492		|
493	Mkoption
494		;
495
496Mkoption:
497	Save_id
498	      {
499		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
500		op->op_name = ns($1);
501		op->op_next =  (struct opt *) 0;
502		op->op_value = 0;
503		mkopt = op;
504		free(temp_id);
505	      } |
506	Save_id EQUALS Opt_value
507	      {
508		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
509		op->op_name = ns($1);
510		op->op_next =  (struct opt *) 0;
511		op->op_value = ns($3);
512		if (mkopt == (struct opt *) 0)
513			mkopt = op;
514		else
515			mkopt_tail->op_next = op;
516		mkopt_tail = op;
517		free(temp_id);
518		if (val_id)
519			free(val_id);
520	      } ;
521
522Dev:
523	UBA
524	      { $$ = ns("uba"); } |
525	MBA
526	      { $$ = ns("mba"); } |
527        VME16D16
528	      {
529		if (machine != MACHINE_SUN2 && machine != MACHINE_SUN3
530		    && machine != MACHINE_SUN4)
531			yyerror("wrong machine type for vme16d16");
532		$$ = ns("vme16d16");
533		} |
534	VME24D16
535	      {
536		if (machine != MACHINE_SUN2 && machine != MACHINE_SUN3
537		    && machine != MACHINE_SUN4)
538			yyerror("wrong machine type for vme24d16");
539			$$ = ns("vme24d16");
540		} |
541	VME32D16
542	      {
543		if (machine != MACHINE_SUN3 && machine != MACHINE_SUN4)
544
545                        yyerror("wrong machine type for vme32d16");
546                $$ = ns("vme32d16");
547                } |
548        VME16D32
549              {
550                if (machine != MACHINE_SUN3  && machine != MACHINE_SUN4)
551                        yyerror("wrong machine type for vme16d32");
552                $$ = ns("vme16d32");
553                } |
554        VME24D32
555              {
556		if (machine != MACHINE_SUN3 && machine != MACHINE_SUN4)
557			yyerror("wrong machine type for vme24d32");
558		$$ = ns("vme24d32");
559		} |
560        VME32D32
561	      {
562		if (machine != MACHINE_SUN3 && machine != MACHINE_SUN4)
563			yyerror("wrong machine type for vme32d32");
564		$$ = ns("vme32d32");
565		} |
566	VME
567	      {
568		if (machine != MACHINE_MIPSY && machine != MACHINE_MIPS)
569			yyerror("wrong machine type for vme");
570			$$ = ns("vme");
571		} |
572	MBII
573	      {
574		if (machine != MACHINE_MIPSY && machine != MACHINE_MIPS)
575			yyerror("wrong machine type for mbii");
576			$$ = ns("mbii");
577		} |
578	ID
579	      { $$ = ns($1); }
580	;
581
582Device_spec:
583	DEVICE Dev_name Dev_info Int_spec
584	      { cur.d_type = DEVICE; } |
585	MASTER Dev_name Dev_info Int_spec
586	      { cur.d_type = MASTER; } |
587	DISK Dev_name Dev_info Int_spec
588	      { cur.d_dk = 1; cur.d_type = DEVICE; } |
589/* TAPE rule is unique to CMU */
590	TAPE Dev_name Dev_info Int_spec
591	      { cur.d_type = DEVICE; } |
592	CONTROLLER Dev_name Dev_info Int_spec
593	      { cur.d_type = CONTROLLER; } |
594	PSEUDO_DEVICE Init_dev Dev
595	      {
596		cur.d_name = $3;
597		cur.d_type = PSEUDO_DEVICE;
598		} |
599	PSEUDO_DEVICE Init_dev Dev NUMBER
600	      {
601		cur.d_name = $3;
602		cur.d_type = PSEUDO_DEVICE;
603		cur.d_slave = $4;
604		} |
605	PSEUDO_DEVICE Init_dev Dev INIT ID
606	      {
607		cur.d_name = $3;
608		cur.d_type = PSEUDO_DEVICE;
609		cur.d_init = ns($5);
610		} |
611	PSEUDO_DEVICE Init_dev Dev NUMBER INIT ID
612	      {
613		cur.d_name = $3;
614		cur.d_type = PSEUDO_DEVICE;
615		cur.d_slave = $4;
616		cur.d_init = ns($6);
617		};
618
619Dev_name:
620	Init_dev Dev NUMBER
621	      {
622		cur.d_name = $2;
623		if (eq($2, "mba"))
624			seen_mba = 1;
625		else if (eq($2, "uba"))
626			seen_uba = 1;
627		else if (eq($2, "mbii"))
628			seen_mbii = 1;
629		else if (eq($2, "vme"))
630			seen_vme = 1;
631		cur.d_unit = $3;
632		};
633
634Init_dev:
635	/* lambda */
636	      { init_dev(&cur); };
637
638Dev_info:
639	Con_info Info_list
640		|
641	/* lambda */
642		;
643
644Con_info:
645	AT Dev NUMBER
646	      {
647		if (eq(cur.d_name, "mba") || eq(cur.d_name, "uba")
648		    || eq(cur.d_name, "mbii") || eq(cur.d_name, "vme")) {
649			(void) sprintf(errbuf,
650			    "%s must be connected to a nexus", cur.d_name);
651			yyerror(errbuf);
652		}
653		cur.d_conn = dconnect($2, $3);
654		if (machine == MACHINE_SQT)
655			dev_param(&cur, "index", cur.d_unit);
656		} |
657/* AT SLOT NUMBER rule is unique to CMU */
658	AT SLOT NUMBER
659	      {
660		check_slot(&cur, $3);
661		cur.d_addr = $3;
662		cur.d_conn = TO_SLOT;
663		 } |
664	AT NEXUS NUMBER
665	      { check_nexus(&cur, $3); cur.d_conn = TO_NEXUS; };
666
667Info_list:
668	Info_list Info
669		|
670	/* lambda */
671		;
672
673Info:
674	CSR NUMBER
675	      {
676		cur.d_addr = $2;
677		if (machine == MACHINE_SQT) {
678			dev_param(&cur, "csr", $2);
679		}
680		} |
681	DRIVE NUMBER
682	      {
683			cur.d_drive = $2;
684			if (machine == MACHINE_SQT) {
685				dev_param(&cur, "drive", $2);
686			}
687		} |
688	SLAVE NUMBER
689	      {
690		if (cur.d_conn != 0 && cur.d_conn != TO_NEXUS &&
691		    cur.d_conn->d_type == MASTER)
692			cur.d_slave = $2;
693		else
694			yyerror("can't specify slave--not to master");
695		} |
696/* MIPS */
697	ADDRMOD NUMBER
698	      { cur.d_addrmod = $2; } |
699/* LUN NUMBER rule is unique to CMU */
700	LUN NUMBER
701	      {
702		if ((cur.d_conn != 0) && (cur.d_conn != TO_SLOT) &&
703			(cur.d_conn->d_type == CONTROLLER)) {
704			cur.d_addr = $2;
705		}
706		else {
707			yyerror("device requires controller card");
708		    }
709		} |
710	FLAGS NUMBER
711	      {
712		cur.d_flags = $2;
713		if (machine == MACHINE_SQT) {
714			dev_param(&cur, "flags", $2);
715		}
716	      } |
717	BIN NUMBER
718	      {
719		 if (machine != MACHINE_SQT)
720			yyerror("bin specification only valid on Sequent Balance");
721		 if ($2 < 1 || $2 > 7)
722			yyerror("bogus bin number");
723		 else {
724			cur.d_bin = $2;
725			dev_param(&cur, "bin", $2);
726		}
727	       } |
728	Dev Value
729	      {
730		if (machine != MACHINE_SQT)
731			yyerror("bad device spec");
732		dev_param(&cur, $1, $2);
733		};
734
735Value:
736	NUMBER
737	      |
738	MINUS NUMBER
739	      { $$ = -($2); }
740	;
741
742Int_spec:
743        Vec_spec
744	      { cur.d_pri = 0; } |
745	PRIORITY NUMBER
746	      { cur.d_pri = $2; } |
747        PRIORITY NUMBER Vec_spec
748	      { cur.d_pri = $2; } |
749        Vec_spec PRIORITY NUMBER
750	      { cur.d_pri = $3; } |
751	/* lambda */
752		;
753
754Vec_spec:
755        VECTOR Id_list
756	      { cur.d_vec = $2; };
757
758
759Id_list:
760	Save_id
761	      {
762		struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
763		a->id = $1; a->id_next = 0; $$ = a;
764		a->id_vec = 0;
765		} |
766	Save_id Id_list
767		{
768		struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
769	        a->id = $1; a->id_next = $2; $$ = a;
770		a->id_vec = 0;
771		} |
772        Save_id NUMBER
773	      {
774		struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
775		a->id_next = 0; a->id = $1; $$ = a;
776		a->id_vec = $2;
777		} |
778        Save_id NUMBER Id_list
779	      {
780		struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
781		a->id_next = $3; a->id = $1; $$ = a;
782		a->id_vec = $2;
783		};
784
785%%
786
787void
788yyerror(const char *s)
789{
790	fprintf(stderr, "config: line %d: %s\n", yyline, s);
791}
792
793/*
794 * return the passed string in a new space
795 */
796char *
797ns(const char *str)
798{
799	register char *cp;
800
801	cp = malloc((unsigned)(strlen(str)+1));
802	(void) strcpy(cp, str);
803	return (cp);
804}
805
806/*
807 * add a device to the list of devices
808 */
809void
810newdev(struct device *dp)
811{
812	register struct device *np;
813
814	np = (struct device *) malloc(sizeof *np);
815	*np = *dp;
816	if (curp == 0)
817		dtab = np;
818	else
819		curp->d_next = np;
820	curp = np;
821	curp->d_next = 0;
822}
823
824/*
825 * note that a configuration should be made
826 */
827void
828mkconf(char *sysname)
829{
830	register struct file_list *fl, **flp;
831
832	fl = (struct file_list *) malloc(sizeof *fl);
833	fl->f_type = SYSTEMSPEC;
834	fl->f_needs = sysname;
835	fl->f_rootdev = NODEV;
836	fl->f_argdev = NODEV;
837	fl->f_dumpdev = NODEV;
838	fl->f_fn = 0;
839	fl->f_next = 0;
840	for (flp = confp; *flp; flp = &(*flp)->f_next)
841		;
842	*flp = fl;
843	confp = flp;
844}
845
846struct file_list *
847newswap(void)
848{
849	struct file_list *fl = (struct file_list *)malloc(sizeof (*fl));
850
851	fl->f_type = SWAPSPEC;
852	fl->f_next = 0;
853	fl->f_swapdev = NODEV;
854	fl->f_swapsize = 0;
855	fl->f_needs = 0;
856	fl->f_fn = 0;
857	return (fl);
858}
859
860/*
861 * Add a swap device to the system's configuration
862 */
863void
864mkswap(struct file_list *syslist, struct file_list *fl, int size)
865{
866	register struct file_list **flp;
867
868	if (syslist == 0 || syslist->f_type != SYSTEMSPEC) {
869		yyerror("\"swap\" spec precedes \"config\" specification");
870		return;
871	}
872	if (size < 0) {
873		yyerror("illegal swap partition size");
874		return;
875	}
876	/*
877	 * Append swap description to the end of the list.
878	 */
879	flp = &syslist->f_next;
880	for (; *flp && (*flp)->f_type == SWAPSPEC; flp = &(*flp)->f_next)
881		;
882	fl->f_next = *flp;
883	*flp = fl;
884	fl->f_swapsize = size;
885	/*
886	 * If first swap device for this system,
887	 * set up f_fn field to insure swap
888	 * files are created with unique names.
889	 */
890	if (syslist->f_fn)
891		return;
892	if (eq(fl->f_fn, "generic"))
893		syslist->f_fn = ns(fl->f_fn);
894	else
895		syslist->f_fn = ns(syslist->f_needs);
896}
897
898/*
899 * find the pointer to connect to the given device and number.
900 * returns 0 if no such device and prints an error message
901 */
902struct device *
903dconnect(const char *dev, int num)
904{
905	register struct device *dp;
906
907	if (num == QUES)
908		return (huhcon(dev));
909	for (dp = dtab; dp != 0; dp = dp->d_next) {
910		if ((num != dp->d_unit) || !eq(dev, dp->d_name))
911			continue;
912		if (dp->d_type != CONTROLLER && dp->d_type != MASTER) {
913			(void) sprintf(errbuf,
914			    "%s connected to non-controller", dev);
915			yyerror(errbuf);
916			return (0);
917		}
918		return (dp);
919	}
920	(void) sprintf(errbuf, "%s %d not defined", dev, num);
921	yyerror(errbuf);
922	return (0);
923}
924
925/*
926 * connect to an unspecific thing
927 */
928struct device *
929huhcon(const char *dev)
930{
931	register struct device *dp, *dcp;
932	struct device rdev;	/* only used if dp is NULL */
933	int oldtype;
934
935	memset(&rdev, 0, sizeof rdev);
936
937	/*
938	 * First make certain that there are some of these to wildcard on
939	 */
940	for (dp = dtab; dp != 0; dp = dp->d_next)
941		if (eq(dp->d_name, dev))
942			break;
943	if (dp == 0) {
944		(void) sprintf(errbuf, "no %s's to wildcard", dev);
945		yyerror(errbuf);
946		return (0);
947	}
948	oldtype = dp->d_type;
949	dcp = dp->d_conn;
950	/*
951	 * Now see if there is already a wildcard entry for this device
952	 * (e.g. Search for a "uba ?")
953	 */
954	for (; dp != 0; dp = dp->d_next)
955		if (eq(dev, dp->d_name) && dp->d_unit == -1)
956			break;
957	/*
958	 * If there isn't, make one because everything needs to be connected
959	 * to something.
960	 */
961	if (dp == 0) {
962		dp = &rdev;
963		init_dev(dp);
964		dp->d_unit = QUES;
965		dp->d_name = ns(dev);
966		dp->d_type = oldtype;
967		newdev(dp);
968		dp = curp;
969		/*
970		 * Connect it to the same thing that other similar things are
971		 * connected to, but make sure it is a wildcard unit
972		 * (e.g. up connected to sc ?, here we make connect sc? to a
973		 * uba?).  If other things like this are on the NEXUS or
974		 * if they aren't connected to anything, then make the same
975		 * connection, else call ourself to connect to another
976		 * unspecific device.
977		 */
978		if (dcp == TO_NEXUS || dcp == 0)
979			dp->d_conn = dcp;
980		else
981			dp->d_conn = dconnect(dcp->d_name, QUES);
982	}
983	return (dp);
984}
985
986void
987init_dev(struct device *dp)
988{
989
990	dp->d_name = "OHNO!!!";
991	dp->d_type = DEVICE;
992	dp->d_conn = 0;
993	dp->d_vec = 0;
994	dp->d_addr = dp->d_pri = dp->d_flags = dp->d_dk = 0;
995	dp->d_slave = dp->d_drive = dp->d_unit = UNKNOWN;
996	if (machine == MACHINE_SUN2 || machine == MACHINE_SUN3
997	    || machine == MACHINE_SUN4){
998		dp->d_addr = UNKNOWN;
999		dp->d_mach = dp->d_bus = 0;
1000	}
1001	if (machine == MACHINE_MIPSY || machine == MACHINE_MIPS){
1002		dp->d_addrmod = 0;
1003	}
1004	dp->d_init = 0;
1005}
1006
1007/*
1008 * make certain that this is a reasonable type of thing to connect to a nexus
1009 */
1010void
1011check_nexus(struct device *dev, int num)
1012{
1013
1014	switch (machine) {
1015
1016	case MACHINE_VAX:
1017		if (!eq(dev->d_name, "uba") && !eq(dev->d_name, "mba"))
1018			yyerror("only uba's and mba's should be connected to the nexus");
1019		if (num != QUES)
1020			yyerror("can't give specific nexus numbers");
1021		break;
1022
1023	case MACHINE_SUN:
1024		if (!eq(dev->d_name, "mb"))
1025			yyerror("only mb's should be connected to the nexus");
1026		break;
1027
1028	case MACHINE_ROMP:
1029		if (!eq(dev->d_name, "iocc"))
1030			yyerror("only iocc's should be connected to the nexus");
1031		break;
1032        case MACHINE_SUN2:
1033		if (!eq(dev->d_name, "virtual") &&
1034		    !eq(dev->d_name, "obmem") &&
1035		    !eq(dev->d_name, "obio") &&
1036		    !eq(dev->d_name, "mbmem") &&
1037		    !eq(dev->d_name, "mbio") &&
1038		    !eq(dev->d_name, "vme16d16") &&
1039		    !eq(dev->d_name, "vme24d16")) {
1040			(void)sprintf(errbuf,
1041			    "unknown bus type `%s' for nexus connection on %s",
1042			    dev->d_name, machinename);
1043			yyerror(errbuf);
1044		}
1045
1046	case MACHINE_MMAX:
1047		yyerror("don't grok 'nexus' on mmax -- try 'slot'.");
1048		break;
1049        case MACHINE_SUN3:
1050        case MACHINE_SUN4:
1051		if (!eq(dev->d_name, "virtual") &&
1052		    !eq(dev->d_name, "obmem") &&
1053		    !eq(dev->d_name, "obio") &&
1054		    !eq(dev->d_name, "mbmem") &&
1055		    !eq(dev->d_name, "mbio") &&
1056		    !eq(dev->d_name, "vme16d16") &&
1057		    !eq(dev->d_name, "vme24d16") &&
1058                    !eq(dev->d_name, "vme32d16") &&
1059		    !eq(dev->d_name, "vme16d32") &&
1060		    !eq(dev->d_name, "vme24d32") &&
1061		    !eq(dev->d_name, "vme32d32")) {
1062			(void)sprintf(errbuf,
1063			    "unknown bus type `%s' for nexus connection on %s",
1064			    dev->d_name, machinename);
1065			yyerror(errbuf);
1066		}
1067		break;
1068	case MACHINE_MIPSY:
1069	case MACHINE_MIPS:
1070		if (!eq(dev->d_name, "vme") && !eq(dev->d_name, "mbii"))
1071			yyerror("only vme's and mbii's should be connected to the nexus");
1072		if (num != QUES)
1073			yyerror("can't give specific nexus numbers");
1074		break;
1075	}
1076}
1077
1078/*
1079 * make certain that this is a reasonable type of thing to connect to a slot
1080 */
1081
1082void
1083check_slot(struct device *dev, int num)
1084{
1085
1086	switch (machine) {
1087
1088	case MACHINE_MMAX:
1089		if (!eq(dev->d_name, "emc"))
1090			yyerror("only emc's plug into backplane slots.");
1091		if (num == QUES)
1092			yyerror("specific slot numbers must be given");
1093		break;
1094
1095	case MACHINE_SQT:
1096		if (!eq(dev->d_name, "mbad") &&
1097		    !eq(dev->d_name, "zdc") &&
1098		    !eq(dev->d_name, "sec")) {
1099			(void)sprintf(errbuf,
1100			    "unknown bus type `%s' for slot on %s",
1101			    dev->d_name, machinename);
1102			yyerror(errbuf);
1103		}
1104		break;
1105
1106	default:
1107		yyerror("don't grok 'slot' for this machine -- try 'nexus'.");
1108		break;
1109	}
1110}
1111
1112/*
1113 * Check system specification and apply defaulting
1114 * rules on root, argument, dump, and swap devices.
1115 */
1116void
1117checksystemspec(struct file_list *fl)
1118{
1119	char buf[BUFSIZ];
1120	register struct file_list *swap;
1121	int generic;
1122
1123	if (fl == 0 || fl->f_type != SYSTEMSPEC) {
1124		yyerror("internal error, bad system specification");
1125		exit(1);
1126	}
1127	swap = fl->f_next;
1128	generic = swap && swap->f_type == SWAPSPEC && eq(swap->f_fn, "generic");
1129	if (fl->f_rootdev == NODEV && !generic) {
1130		yyerror("no root device specified");
1131		exit(1);
1132	}
1133	/*
1134	 * Default swap area to be in 'b' partition of root's
1135	 * device.  If root specified to be other than on 'a'
1136	 * partition, give warning, something probably amiss.
1137	 */
1138	if (swap == 0 || swap->f_type != SWAPSPEC) {
1139		dev_t dev;
1140
1141		swap = newswap();
1142		dev = fl->f_rootdev;
1143		if (minor(dev) & DEV_MASK) {
1144			(void) sprintf(buf,
1145"Warning, swap defaulted to 'b' partition with root on '%c' partition",
1146				(minor(dev) & DEV_MASK) + 'a');
1147			yyerror(buf);
1148		}
1149		swap->f_swapdev =
1150		   makedev(major(dev), (minor(dev) &~ DEV_MASK) | ('b' - 'a'));
1151		swap->f_fn = devtoname(swap->f_swapdev);
1152		mkswap(fl, swap, 0);
1153	}
1154	/*
1155	 * Make sure a generic swap isn't specified, along with
1156	 * other stuff (user must really be confused).
1157	 */
1158	if (generic) {
1159		if (fl->f_rootdev != NODEV)
1160			yyerror("root device specified with generic swap");
1161		if (fl->f_argdev != NODEV)
1162			yyerror("arg device specified with generic swap");
1163		if (fl->f_dumpdev != NODEV)
1164			yyerror("dump device specified with generic swap");
1165		return;
1166	}
1167	/*
1168	 * Default argument device and check for oddball arrangements.
1169	 */
1170	if (fl->f_argdev == NODEV)
1171		fl->f_argdev = swap->f_swapdev;
1172	if (fl->f_argdev != swap->f_swapdev)
1173		yyerror("Warning, arg device different than primary swap");
1174	/*
1175	 * Default dump device and warn if place is not a
1176	 * swap area or the argument device partition.
1177	 */
1178	if (fl->f_dumpdev == NODEV)
1179		fl->f_dumpdev = swap->f_swapdev;
1180	if (fl->f_dumpdev != swap->f_swapdev && fl->f_dumpdev != fl->f_argdev) {
1181		struct file_list *p = swap->f_next;
1182
1183		for (; p && p->f_type == SWAPSPEC; p = p->f_next)
1184			if (fl->f_dumpdev == p->f_swapdev)
1185				return;
1186		(void) sprintf(buf, "Warning, orphaned dump device, %s",
1187			"do you know what you're doing");
1188		yyerror(buf);
1189	}
1190}
1191
1192/*
1193 * Verify all devices specified in the system specification
1194 * are present in the device specifications.
1195 */
1196void
1197verifysystemspecs(void)
1198{
1199	register struct file_list *fl;
1200	dev_t checked[50];
1201	register dev_t *pchecked = checked;
1202
1203	for (fl = conf_list; fl; fl = fl->f_next) {
1204		if (fl->f_type != SYSTEMSPEC)
1205			continue;
1206		if (!finddev(fl->f_rootdev))
1207			deverror(fl->f_needs, "root");
1208		*pchecked++ = fl->f_rootdev;
1209		pchecked = verifyswap(fl->f_next, checked, pchecked);
1210#define	samedev(dev1, dev2) \
1211	((minor(dev1) &~ DEV_MASK) != (minor(dev2) &~ DEV_MASK))
1212		if (!alreadychecked(fl->f_dumpdev, checked, pchecked)) {
1213			if (!finddev(fl->f_dumpdev))
1214				deverror(fl->f_needs, "dump");
1215			*pchecked++ = fl->f_dumpdev;
1216		}
1217		if (!alreadychecked(fl->f_argdev, checked, pchecked)) {
1218			if (!finddev(fl->f_argdev))
1219				deverror(fl->f_needs, "arg");
1220			*pchecked++ = fl->f_argdev;
1221		}
1222	}
1223}
1224
1225/*
1226 * Do as above, but for swap devices.
1227 */
1228dev_t *
1229verifyswap(struct file_list *fl, dev_t checked[], dev_t *pchecked)
1230{
1231
1232	for (;fl && fl->f_type == SWAPSPEC; fl = fl->f_next) {
1233		if (eq(fl->f_fn, "generic"))
1234			continue;
1235		if (alreadychecked(fl->f_swapdev, checked, pchecked))
1236			continue;
1237		if (!finddev(fl->f_swapdev))
1238			fprintf(stderr,
1239			   "config: swap device %s not configured", fl->f_fn);
1240		*pchecked++ = fl->f_swapdev;
1241	}
1242	return (pchecked);
1243}
1244
1245/*
1246 * Has a device already been checked
1247 * for it's existence in the configuration?
1248 */
1249int
1250alreadychecked(dev_t dev, dev_t list[], dev_t *last)
1251{
1252	register dev_t *p;
1253
1254	for (p = list; p < last; p++)
1255		if (samedev(*p, dev))
1256			return (1);
1257	return (0);
1258}
1259
1260void
1261deverror(const char *systemname, const char *devtype)
1262{
1263
1264	fprintf(stderr, "config: %s: %s device not configured\n",
1265		systemname, devtype);
1266}
1267
1268/*
1269 * Look for the device in the list of
1270 * configured hardware devices.  Must
1271 * take into account stuff wildcarded.
1272 */
1273/*ARGSUSED*/
1274int
1275finddev(dev_t dev)
1276{
1277
1278	/* punt on this right now */
1279	return (1);
1280}
1281