File: /usr/src/linux/arch/ia64/sn/io/ml_iograph.c

1     /* $Id$
2      *
3      * This file is subject to the terms and conditions of the GNU General Public
4      * License.  See the file "COPYING" in the main directory of this archive
5      * for more details.
6      *
7      * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
8      * Copyright (C) 2000 by Colin Ngam
9      */
10     
11     #include <linux/types.h>
12     #include <linux/config.h>
13     #include <linux/slab.h>
14     #include <linux/ctype.h>
15     #include <asm/sn/sgi.h>
16     #include <asm/sn/iograph.h>
17     #include <asm/sn/invent.h>
18     #include <asm/sn/hcl.h>
19     #include <asm/sn/hcl_util.h>
20     #include <asm/sn/labelcl.h>
21     #include <asm/sn/xtalk/xbow.h>
22     #include <asm/sn/pci/bridge.h>
23     #include <asm/sn/klconfig.h>
24     #include <asm/sn/eeprom.h>
25     #include <asm/sn/sn_private.h>
26     #include <asm/sn/pci/pcibr.h>
27     #include <asm/sn/xtalk/xtalk.h>
28     #include <asm/sn/xtalk/xswitch.h>
29     #include <asm/sn/xtalk/xwidget.h>
30     #include <asm/sn/xtalk/xtalk_private.h>
31     #include <asm/sn/xtalk/xtalkaddrs.h>
32     
33     extern int maxnodes;
34     
35     /* #define IOGRAPH_DEBUG */
36     #ifdef IOGRAPH_DEBUG
37     #define DBG(x...) printk(x)
38     #else
39     #define DBG(x...)
40     #endif /* IOGRAPH_DEBUG */
41     
42     /* #define PROBE_TEST */
43     
44     /* At most 2 hubs can be connected to an xswitch */
45     #define NUM_XSWITCH_VOLUNTEER 2
46     
47     /*
48      * Track which hubs have volunteered to manage devices hanging off of
49      * a Crosstalk Switch (e.g. xbow).  This structure is allocated,
50      * initialized, and hung off the xswitch vertex early on when the
51      * xswitch vertex is created.
52      */
53     typedef struct xswitch_vol_s {
54     	mutex_t xswitch_volunteer_mutex;
55     	int		xswitch_volunteer_count;
56     	devfs_handle_t	xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
57     } *xswitch_vol_t;
58     
59     void
60     xswitch_vertex_init(devfs_handle_t xswitch)
61     {
62     	xswitch_vol_t xvolinfo;
63     	int rc;
64     
65     	xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
66     	mutex_init(&xvolinfo->xswitch_volunteer_mutex);
67     	xvolinfo->xswitch_volunteer_count = 0;
68     	rc = hwgraph_info_add_LBL(xswitch, 
69     			INFO_LBL_XSWITCH_VOL,
70     			(arbitrary_info_t)xvolinfo);
71     	ASSERT(rc == GRAPH_SUCCESS); rc = rc;
72     }
73     
74     
75     /*
76      * When assignment of hubs to widgets is complete, we no longer need the
77      * xswitch volunteer structure hanging around.  Destroy it.
78      */
79     static void
80     xswitch_volunteer_delete(devfs_handle_t xswitch)
81     {
82     	xswitch_vol_t xvolinfo;
83     	int rc;
84     
85     	rc = hwgraph_info_remove_LBL(xswitch, 
86     				INFO_LBL_XSWITCH_VOL,
87     				(arbitrary_info_t *)&xvolinfo);
88     #ifdef LATER
89     	ASSERT(rc == GRAPH_SUCCESS); rc = rc;
90     #endif
91     
92     	kfree(xvolinfo);
93     }
94     /*
95      * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
96      */
97     /* ARGSUSED */
98     static void
99     volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master)
100     {
101     	xswitch_vol_t xvolinfo = NULL;
102     
103     	(void)hwgraph_info_get_LBL(xswitch, 
104     				INFO_LBL_XSWITCH_VOL, 
105     				(arbitrary_info_t *)&xvolinfo);
106     	if (xvolinfo == NULL) {
107     #ifdef LATER
108     	    if (!is_headless_node_vertex(master)) {
109     #if defined(SUPPORT_PRINTING_V_FORMAT)
110     		PRINT_WARNING("volunteer for widgets: vertex %v has no info label",
111     			xswitch);
112     #else
113     		PRINT_WARNING("volunteer for widgets: vertex 0x%x has no info label",
114     			xswitch);
115     #endif
116     	    }
117     #endif	/* LATER */
118     	    return;
119     	}
120     
121     	mutex_lock(&xvolinfo->xswitch_volunteer_mutex);
122     	ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
123     	xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
124     	xvolinfo->xswitch_volunteer_count++;
125     	mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);
126     }
127     
128     extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
129     
130     /*
131      * Assign all the xwidgets hanging off the specified xswitch to the
132      * Crosstalk masters that have volunteered for xswitch duty.
133      */
134     /* ARGSUSED */
135     static void
136     assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv)
137     {
138     	int curr_volunteer, num_volunteer;
139     	xwidgetnum_t widgetnum;
140     	xswitch_info_t xswitch_info;
141     	xswitch_vol_t xvolinfo = NULL;
142     	nasid_t nasid;
143     	hubinfo_t hubinfo;
144     
145     	hubinfo_get(hubv, &hubinfo);
146     	nasid = hubinfo->h_nasid;
147     	
148     	xswitch_info = xswitch_info_get(xswitch);
149     	ASSERT(xswitch_info != NULL);
150     
151     	(void)hwgraph_info_get_LBL(xswitch, 
152     				INFO_LBL_XSWITCH_VOL, 
153     				(arbitrary_info_t *)&xvolinfo);
154     	if (xvolinfo == NULL) {
155     #ifdef LATER
156     	    if (!is_headless_node_vertex(hubv)) {
157     #if defined(SUPPORT_PRINTING_V_FORMAT)
158     		PRINT_WARNING("assign_widgets_to_volunteers:vertex %v has "
159     			" no info label",
160     			xswitch);
161     #else
162     		PRINT_WARNING("assign_widgets_to_volunteers:vertex 0x%x has "
163     			" no info label",
164     			xswitch);
165     #endif
166     	    }
167     #endif	/* LATER */
168     	    return;
169     	}
170     
171     	num_volunteer = xvolinfo->xswitch_volunteer_count;
172     	ASSERT(num_volunteer > 0);
173     	curr_volunteer = 0;
174     
175     	/* Assign master hub for xswitch itself.  */
176     	if (HUB_WIDGET_ID_MIN > 0) {
177     		hubv = xvolinfo->xswitch_volunteer[0];
178     		xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
179     	}
180     
181     	/*
182     	 * TBD: Use administrative information to alter assignment of
183     	 * widgets to hubs.
184     	 */
185     	for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
186     
187     #ifndef BRINGUP
188     		int i;
189     #endif
190     		/*
191     		 * Ignore disabled/empty ports.
192     		 */
193     		if (!xbow_port_io_enabled(nasid, widgetnum)) 
194     		    continue;
195     
196     		/*
197     		 * If this is the master IO board, assign it to the same 
198     		 * hub that owned it in the prom.
199     		 */
200     		if (is_master_nasid_widget(nasid, widgetnum)) {
201     			int i;
202     
203     			for (i=0; i<num_volunteer; i++) {
204     				hubv = xvolinfo->xswitch_volunteer[i];
205     				hubinfo_get(hubv, &hubinfo);
206     				nasid = hubinfo->h_nasid;
207     				if (nasid == get_console_nasid())
208     					goto do_assignment;
209     			}
210     #ifdef LATER
211     			PRINT_PANIC("Nasid == %d, console nasid == %d",
212     				nasid, get_console_nasid());
213     #endif
214     		}
215     
216     
217     		/*
218     		 * Do a round-robin assignment among the volunteer nodes.
219     		 */
220     		hubv = xvolinfo->xswitch_volunteer[curr_volunteer];
221     		curr_volunteer = (curr_volunteer + 1) % num_volunteer;
222     		/* fall through */
223     
224     do_assignment:
225     		/*
226     		 * At this point, we want to make hubv the master of widgetnum.
227     		 */
228     		xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
229     	}
230     
231     	xswitch_volunteer_delete(xswitch);
232     }
233     
234     /*
235      * Early iograph initialization.  Called by master CPU in mlreset().
236      * Useful for including iograph.o in kernel.o.
237      */
238     void
239     iograph_early_init(void)
240     {
241     /*
242      * Need new way to get this information ..
243      */
244     	cnodeid_t cnode;
245     	nasid_t nasid;
246     	lboard_t *board;
247     
248     	/*
249     	 * Init. the board-to-hwgraph link early, so FRU analyzer
250     	 * doesn't trip on leftover values if we panic early on.
251     	 */
252     	for(cnode = 0; cnode < numnodes; cnode++) {
253     		nasid = COMPACT_TO_NASID_NODEID(cnode);
254     		board = (lboard_t *)KL_CONFIG_INFO(nasid);
255     		DBG("iograph_early_init: Found board 0x%p\n", board);
256     
257     		/* Check out all the board info stored on a node */
258     		while(board) {
259     			board->brd_graph_link = GRAPH_VERTEX_NONE;
260     			board = KLCF_NEXT(board);
261     			DBG("iograph_early_init: Found board 0x%p\n", board);
262     
263     
264     		}
265     	}
266     
267     	hubio_init();
268     }
269     
270     #ifdef LATER
271     /* There is an identical definition of this in os/scheduler/runq.c */
272     #define INIT_COOKIE(cookie) cookie.must_run = 0; cookie.cpu = PDA_RUNANYWHERE
273     /*
274      * These functions absolutely doesn't belong here.  It's  here, though, 
275      * until the scheduler provides a platform-independent version
276      * that works the way it should.  The interface will definitely change, 
277      * too.  Currently used only in this file and by io/cdl.c in order to
278      * bind various I/O threads to a CPU on the proper node.
279      */
280     cpu_cookie_t
281     setnoderun(cnodeid_t cnodeid)
282     {
283     	int i;
284     	cpuid_t cpunum;
285     	cpu_cookie_t cookie;
286     
287     	INIT_COOKIE(cookie);
288     	if (cnodeid == CNODEID_NONE)
289     		return(cookie);
290     
291     	/*
292     	 * Do a setmustrun to one of the CPUs on the specified
293     	 * node.
294     	 */
295     	if ((cpunum = CNODE_TO_CPU_BASE(cnodeid)) == CPU_NONE) {
296     		return(cookie);
297     	}
298     
299     	cpunum += CNODE_NUM_CPUS(cnodeid) - 1;
300     
301     	for (i = 0; i < CNODE_NUM_CPUS(cnodeid); i++, cpunum--) {
302     
303     		if (cpu_enabled(cpunum)) {
304     			cookie = setmustrun(cpunum);
305     			break;
306     		}
307     	}
308     
309     	return(cookie);
310     }
311     
312     void
313     restorenoderun(cpu_cookie_t cookie)
314     {
315     	restoremustrun(cookie);
316     }
317     #endif	/* LATER */
318     
319     #ifdef LINUX_KERNEL_THREADS
320     static struct semaphore io_init_sema;
321     #endif
322     
323     /*
324      * Let boot processor know that we're done initializing our node's IO
325      * and then exit.
326      */
327     /* ARGSUSED */
328     static void
329     io_init_done(cnodeid_t cnodeid,cpu_cookie_t c)
330     {
331     	/* Let boot processor know that we're done. */
332     #ifdef LINUX_KERNEL_THREADS
333     	up(&io_init_sema);
334     #endif
335     #ifdef LATER
336     	/* This is for the setnoderun done when the io_init thread
337     	 * started 
338     	 */
339     	restorenoderun(c);
340     	sthread_exit();
341     #endif
342     }
343     
344     /* 
345      * Probe to see if this hub's xtalk link is active.  If so,
346      * return the Crosstalk Identification of the widget that we talk to.  
347      * This is called before any of the Crosstalk infrastructure for 
348      * this hub is set up.  It's usually called on the node that we're
349      * probing, but not always.
350      *
351      * TBD: Prom code should actually do this work, and pass through 
352      * hwid for our use.
353      */
354     static void
355     early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid)
356     {
357     	hubreg_t llp_csr_reg;
358     	nasid_t nasid;
359     	hubinfo_t hubinfo;
360     
361     	hubinfo_get(hubv, &hubinfo);
362     	nasid = hubinfo->h_nasid;
363     
364     	llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
365     	/* 
366     	 * If link is up, read the widget's part number.
367     	 * A direct connect widget must respond to widgetnum=0.
368     	 */
369     	if (llp_csr_reg & IIO_LLP_CSR_IS_UP) {
370     		/* TBD: Put hub into "indirect" mode */
371     		/*
372     		 * We're able to read from a widget because our hub's 
373     		 * WIDGET_ID was set up earlier.
374     		 */
375     		widgetreg_t widget_id = *(volatile widgetreg_t *)
376     			(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
377     
378     		DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
379     		(volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
380     
381     		hwid->part_num = XWIDGET_PART_NUM(widget_id);
382     		hwid->rev_num = XWIDGET_REV_NUM(widget_id);
383     		hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
384     
385     		/* TBD: link reset */
386     	} else {
387     
388     		hwid->part_num = XWIDGET_PART_NUM_NONE;
389     		hwid->rev_num = XWIDGET_REV_NUM_NONE;
390     		hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
391     	}
392     
393     }
394     
395     /* Add inventory information to the widget vertex 
396      * Right now (module,slot,revision) is being
397      * added as inventory information.
398      */
399     static void
400     xwidget_inventory_add(devfs_handle_t 		widgetv,
401     		      lboard_t 			*board,
402     		      struct xwidget_hwid_s 	hwid)
403     {
404     	if (!board)
405     		return;
406     	/* Donot add inventory information for the baseio
407     	 * on a speedo with an xbox. It has already been
408     	 * taken care of in SN00_vmc.
409     	 * Speedo with xbox's baseio comes in at slot io1 (widget 9)
410     	 */
411     	device_inventory_add(widgetv,INV_IOBD,board->brd_type,
412     			     board->brd_module,
413     			     SLOTNUM_GETSLOT(board->brd_slot),
414     			     hwid.rev_num);
415     }
416     
417     /*
418      * io_xswitch_widget_init
419      *	
420      */
421     
422     /* defined in include/linux/ctype.h  */
423     /* #define toupper(c)	(islower(c) ? (c) - 'a' + 'A' : (c)) */
424     
425     void
426     io_xswitch_widget_init(devfs_handle_t  	xswitchv,
427     		       devfs_handle_t	hubv,
428     		       xwidgetnum_t	widgetnum,
429     		       async_attach_t	aa)
430     {
431     	xswitch_info_t		xswitch_info;
432     	xwidgetnum_t		hub_widgetid;
433     	devfs_handle_t		widgetv;
434     	cnodeid_t		cnode;
435     	widgetreg_t		widget_id;
436     	nasid_t			nasid, peer_nasid;
437     	struct xwidget_hwid_s 	hwid;
438     	hubinfo_t		hubinfo;
439     	/*REFERENCED*/
440     	int			rc;
441     	char			slotname[SLOTNUM_MAXLENGTH];
442     	char 			pathname[128];
443     	char			new_name[64];
444     	moduleid_t		module;
445     	slotid_t		slot;
446     	lboard_t		*board = NULL;
447     	char			buffer[16];
448     	
449     	DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
450     	/*
451     	 * Verify that xswitchv is indeed an attached xswitch.
452     	 */
453     	xswitch_info = xswitch_info_get(xswitchv);
454     	ASSERT(xswitch_info != NULL);
455     
456     	hubinfo_get(hubv, &hubinfo);
457     	nasid = hubinfo->h_nasid;
458     	cnode = NASID_TO_COMPACT_NODEID(nasid);
459     	hub_widgetid = hubinfo->h_widgetid;
460     
461     
462     	/* Who's the other guy on out crossbow (if anyone) */
463     	peer_nasid = NODEPDA(cnode)->xbow_peer;
464     	if (peer_nasid == INVALID_NASID)
465     		/* If I don't have a peer, use myself. */
466     		peer_nasid = nasid;
467     
468     
469     	/* Check my xbow structure and my peer's */
470     	if (!xbow_port_io_enabled(nasid, widgetnum) &&
471     	    !xbow_port_io_enabled(peer_nasid, widgetnum)) {
472     		return;
473     	}
474     
475     	if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
476     		char			name[4];
477     		/*
478     		 * If the current hub is not supposed to be the master 
479     		 * for this widgetnum, then skip this widget.
480     		 */
481     		if (xswitch_info_master_assignment_get(xswitch_info,
482     						       widgetnum) != hubv) {
483     			return;
484     		}
485     
486     		module  = NODEPDA(cnode)->module_id;
487     #ifdef XBRIDGE_REGS_SIM
488     		/* hardwire for now...could do this with something like:
489     		 * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl);
490     		 * xbow_t xbow = soft->base;
491     		 * xbowreg_t xwidget_id = xbow->xb_wid_id;
492     		 * but I don't feel like figuring out vhdl right now..
493     		 * and I know for a fact the answer is 0x2d000049 
494     		 */
495     		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
496     		DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049));
497     		if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) {
498     #else
499     		if (nasid_has_xbridge(nasid)) {
500     #endif /* XBRIDGE_REGS_SIM */
501     			board = find_lboard_module_class(
502     				(lboard_t *)KL_CONFIG_INFO(nasid),
503     				module,
504     				KLTYPE_IOBRICK);
505     
506     DBG("io_xswitch_widget_init: Board 0x%p\n", board);
507     {
508     		lboard_t dummy;
509     
510     			if (board) {
511     				DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
512     			} else {
513     				DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
514     				board = &dummy;
515     			}
516     				
517     }
518     
519     			/*
520     			 * BRINGUP
521     	 		 * Make sure we really want to say xbrick, pbrick,
522     			 * etc. rather than XIO, graphics, etc.
523     	 		 */
524     
525     #ifdef SUPPORT_PRINTING_M_FORMAT
526     			sprintf(pathname, EDGE_LBL_MODULE "/%M/"
527     				"%cbrick" "/%s/%d",
528     				NODEPDA(cnode)->module_id,
529     				
530     #else
531     			memset(buffer, 0, 16);
532     			format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
533     			sprintf(pathname, EDGE_LBL_MODULE "/%s/"
534     				"%cbrick" "/%s/%d",
535     				buffer,
536     #endif
537     #ifdef BRINGUP
538     
539     				(board->brd_type == KLTYPE_IBRICK) ? 'I' :
540     				(board->brd_type == KLTYPE_PBRICK) ? 'P' :
541     				(board->brd_type == KLTYPE_XBRICK) ? 'X' : '?',
542     #else
543     				toupper(MODULE_GET_BTCHAR(NODEPDA(cnode)->module_id)),
544     #endif /* BRINGUP */
545     				EDGE_LBL_XTALK, widgetnum);
546     		} 
547     		
548     		DBG("io_xswitch_widget_init: path= %s\n", pathname);
549     		rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
550     		
551     		ASSERT(rc == GRAPH_SUCCESS);
552     
553     		/* This is needed to let the user programs to map the
554     		 * module,slot numbers to the corresponding widget numbers
555     		 * on the crossbow.
556     		 */
557     		rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
558     
559     		/* If we are looking at the global master io6
560     		 * then add information about the version of
561     		 * the io6prom as a part of "detailed inventory"
562     		 * information.
563     		 */
564     		if (is_master_baseio(nasid,
565     				     NODEPDA(cnode)->module_id,
566     #ifdef BRINGUP
567      				     get_widget_slotnum(0,widgetnum))) {
568     #else
569     	<<< BOMB! >>> Need a new way to get slot numbers on IP35/IP37
570     #endif
571     			extern void klhwg_baseio_inventory_add(devfs_handle_t,
572     							       cnodeid_t);
573     			module 	= NODEPDA(cnode)->module_id;
574     
575     #ifdef XBRIDGE_REGS_SIM
576     			DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
577     			if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) {
578     #else
579     			if (nasid_has_xbridge(nasid)) {
580     #endif /* XBRIDGE_REGS_SIM */
581     				board = find_lboard_module(
582     					(lboard_t *)KL_CONFIG_INFO(nasid),
583     					module);
584     				/*
585     			 	 * BRINGUP
586     				 * Change iobrick to correct i/o brick
587     				 */
588     #ifdef SUPPORT_PRINTING_M_FORMAT
589     				sprintf(pathname, EDGE_LBL_MODULE "/%M/"
590     #else
591     				sprintf(pathname, EDGE_LBL_MODULE "/%x/"
592     #endif
593     					"iobrick" "/%s/%d",
594     					NODEPDA(cnode)->module_id,
595     					EDGE_LBL_XTALK, widgetnum);
596     			} else {
597     #ifdef BRINGUP
598     				slot = get_widget_slotnum(0, widgetnum);
599     #else
600     	<<< BOMB! Need a new way to get slot numbers on IP35/IP37
601     #endif
602     				board = get_board_name(nasid, module, slot,
603     								new_name);
604     				/*
605     			 	 * Create the vertex for the widget, 
606     				 * using the decimal 
607     			 	 * widgetnum as the name of the primary edge.
608     			 	 */
609     #ifdef SUPPORT_PRINTING_M_FORMAT
610     				sprintf(pathname, EDGE_LBL_MODULE "/%M/"
611                                                     EDGE_LBL_SLOT "/%s/%s",
612                                             NODEPDA(cnode)->module_id,
613                                             slotname, new_name);
614     #else
615     				memset(buffer, 0, 16);
616     				format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
617     				sprintf(pathname, EDGE_LBL_MODULE "/%s/"
618     					  	EDGE_LBL_SLOT "/%s/%s",
619     					buffer,
620     					slotname, new_name);
621     #endif
622     			}
623     
624     			rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
625     			DBG("io_xswitch_widget_init: (2) path= %s\n", pathname);
626     		        /*
627     		         * This is a weird ass code needed for error injection
628     		         * purposes.
629     		         */
630     		        rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
631     			
632     			klhwg_baseio_inventory_add(widgetv,cnode);
633     		}
634     		sprintf(name, "%d", widgetnum);
635     		DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
636     		rc = hwgraph_edge_add(xswitchv, widgetv, name);
637     		
638     		/*
639     		 * crosstalk switch code tracks which
640     		 * widget is attached to each link.
641     		 */
642     		xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
643     		
644     		/*
645     		 * Peek at the widget to get its crosstalk part and
646     		 * mfgr numbers, then present it to the generic xtalk
647     		 * bus provider to have its driver attach routine
648     		 * called (or not).
649     		 */
650     #ifdef XBRIDGE_REGS_SIM
651     		widget_id = 0x2d000049;
652     		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n");
653     #else
654     		widget_id = XWIDGET_ID_READ(nasid, widgetnum);
655     #endif /* XBRIDGE_REGS_SIM */
656     		hwid.part_num = XWIDGET_PART_NUM(widget_id);
657     		hwid.rev_num = XWIDGET_REV_NUM(widget_id);
658     		hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
659     		/* Store some inventory information about
660     		 * the xwidget in the hardware graph.
661     		 */
662     		xwidget_inventory_add(widgetv,board,hwid);
663     		
664     		(void)xwidget_register(&hwid, widgetv, widgetnum,
665     				       hubv, hub_widgetid,
666     				       aa);
667     
668     #ifdef	SN0_USE_BTE
669     		bte_bpush_war(cnode, (void *)board);
670     #endif
671     	}
672     
673     }
674     
675     
676     static void
677     io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode)
678     {
679     	xwidgetnum_t		widgetnum;
680     	async_attach_t          aa;
681     
682     	aa = async_attach_new();
683     	
684     	DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
685     
686     	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; 
687     	     widgetnum++) {
688     		io_xswitch_widget_init(xswitchv,
689     				       cnodeid_to_vertex(cnode),
690     				       widgetnum, aa);
691     	}
692     	/* 
693     	 * Wait for parallel attach threads, if any, to complete.
694     	 */
695     	async_attach_waitall(aa);
696     	async_attach_free(aa);
697     }
698     
699     /*
700      * For each PCI bridge connected to the xswitch, add a link from the
701      * board's klconfig info to the bridge's hwgraph vertex.  This lets
702      * the FRU analyzer find the bridge without traversing the hardware
703      * graph and risking hangs.
704      */
705     static void
706     io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid)
707     {
708     	xwidgetnum_t		widgetnum;
709     	char 			pathname[128];
710     	devfs_handle_t		vhdl;
711     	nasid_t			nasid, peer_nasid;
712     	lboard_t		*board;
713     
714     
715     
716     	/* And its connected hub's nasids */
717     	nasid = COMPACT_TO_NASID_NODEID(cnodeid);
718     	peer_nasid = NODEPDA(cnodeid)->xbow_peer;
719     
720     	/* 
721     	 * Look for paths matching "<widgetnum>/pci" under xswitchv.
722     	 * For every widget, init. its lboard's hwgraph link.  If the
723     	 * board has a PCI bridge, point the link to it.
724     	 */
725     	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
726     		 widgetnum++) {
727     		sprintf(pathname, "%d", widgetnum);
728     		if (hwgraph_traverse(xswitchv, pathname, &vhdl) !=
729     		    GRAPH_SUCCESS)
730     			continue;
731     
732     #if defined (CONFIG_SGI_IP35) || defined (CONFIG_IA64_SGI_SN1) || defined (CONFIG_IA64_GENERIC)
733     		board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid),
734     				NODEPDA(cnodeid)->module_id);
735     #else
736     		{
737     		slotid_t	slot;
738     		slot = get_widget_slotnum(xbow_num, widgetnum);
739     		board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid),
740     				    NODEPDA(cnodeid)->module_id, slot);
741     		}
742     #endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */
743     		if (board == NULL && peer_nasid != INVALID_NASID) {
744     			/*
745     			 * Try to find the board on our peer
746     			 */
747     #if defined (CONFIG_SGI_IP35) || defined (CONFIG_IA64_SGI_SN1) || defined (CONFIG_IA64_GENERIC)
748     			board = find_lboard_module(
749     				(lboard_t *)KL_CONFIG_INFO(peer_nasid),
750     				NODEPDA(cnodeid)->module_id);
751     
752     #else
753     			board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(peer_nasid),
754     						    NODEPDA(cnodeid)->module_id, slot);
755     
756     #endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */
757     		}
758     		if (board == NULL) {
759     #if defined(SUPPORT_PRINTING_V_FORMAT)
760     			PRINT_WARNING("Could not find PROM info for vertex %v, "
761     				"FRU analyzer may fail",
762     				vhdl);
763     #else
764     			PRINT_WARNING("Could not find PROM info for vertex 0x%x, "
765     				"FRU analyzer may fail",
766     				vhdl);
767     #endif
768     			return;
769     		}
770     
771     		sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
772     		if (hwgraph_traverse(xswitchv, pathname, &vhdl) == 
773     		    GRAPH_SUCCESS)
774     			board->brd_graph_link = vhdl;
775     		else
776     			board->brd_graph_link = GRAPH_VERTEX_NONE;
777     	}
778     }
779     
780     /*
781      * Initialize all I/O on the specified node.
782      */
783     static void
784     io_init_node(cnodeid_t cnodeid)
785     {
786     	/*REFERENCED*/
787     	devfs_handle_t hubv, switchv, widgetv;
788     	struct xwidget_hwid_s hwid;
789     	hubinfo_t hubinfo;
790     	int is_xswitch;
791     	nodepda_t	*npdap;
792     	struct semaphore *peer_sema = 0;
793     	uint32_t	widget_partnum;
794     	nodepda_router_info_t *npda_rip;
795     	cpu_cookie_t	c = 0;
796     	extern int hubdev_docallouts(devfs_handle_t);
797     
798     #ifdef LATER
799     	/* Try to execute on the node that we're initializing. */
800     	c = setnoderun(cnodeid);
801     #endif
802     	npdap = NODEPDA(cnodeid);
803     
804     	/*
805     	 * Get the "top" vertex for this node's hardware
806     	 * graph; it will carry the per-hub hub-specific
807     	 * data, and act as the crosstalk provider master.
808     	 * It's canonical path is probably something of the
809     	 * form /hw/module/%M/slot/%d/node
810     	 */
811     	hubv = cnodeid_to_vertex(cnodeid);
812     	DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
813     
814     	ASSERT(hubv != GRAPH_VERTEX_NONE);
815     
816     	hubdev_docallouts(hubv);
817     
818     	/*
819     	 * Set up the dependent routers if we have any.
820     	 */
821     	npda_rip = npdap->npda_rip_first;
822     
823     	while(npda_rip) {
824     		/* If the router info has not been initialized
825     		 * then we need to do the router initialization
826     		 */
827     		if (!npda_rip->router_infop) {
828     			router_init(cnodeid,0,npda_rip);
829     		}
830     		npda_rip = npda_rip->router_next;
831     	}
832     
833     	/*
834     	 * Read mfg info on this hub
835     	 */
836     #ifdef LATER
837     	printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n");
838     	HUB_VERTEX_MFG_INFO(hubv);
839     #endif /* LATER */
840     
841     	/* 
842     	 * If nothing connected to this hub's xtalk port, we're done.
843     	 */
844     	early_probe_for_widget(hubv, &hwid);
845     	if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
846     #ifdef PROBE_TEST
847     		if ((cnodeid == 1) || (cnodeid == 2)) {
848     			int index;
849     
850     			for (index = 0; index < 600; index++)
851     				DBG("Interfering with device probing!!!\n");
852     		}
853     #endif
854     		/* io_init_done takes cpu cookie as 2nd argument 
855     		 * to do a restorenoderun for the setnoderun done 
856     		 * at the start of this thread 
857     		 */
858     		
859     		DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
860     		return;
861     		/* NOTREACHED */
862     	}
863     
864     	/* 
865     	 * attach our hub_provider information to hubv,
866     	 * so we can use it as a crosstalk provider "master"
867     	 * vertex.
868     	 */
869     	xtalk_provider_register(hubv, &hub_provider);
870     	xtalk_provider_startup(hubv);
871     
872     	/*
873     	 * Create a vertex to represent the crosstalk bus
874     	 * attached to this hub, and a vertex to be used
875     	 * as the connect point for whatever is out there
876     	 * on the other side of our crosstalk connection.
877     	 *
878     	 * Crosstalk Switch drivers "climb up" from their
879     	 * connection point to try and take over the switch
880     	 * point.
881     	 *
882     	 * Of course, the edges and verticies may already
883     	 * exist, in which case our net effect is just to
884     	 * associate the "xtalk_" driver with the connection
885     	 * point for the device.
886     	 */
887     
888     	(void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
889     
890     	DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
891     
892     	ASSERT(switchv != GRAPH_VERTEX_NONE);
893     
894     	(void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
895     
896     	DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
897     
898     	/*
899     	 * We need to find the widget id and update the basew_id field
900     	 * accordingly. In particular, SN00 has direct connected bridge,
901     	 * and hence widget id is Not 0.
902     	 */
903     
904     	widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
905     
906     	if (widget_partnum == BRIDGE_WIDGET_PART_NUM ||
907     				widget_partnum == XBRIDGE_WIDGET_PART_NUM){
908     		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
909     
910     		DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
911     
912     	} else if (widget_partnum == XBOW_WIDGET_PART_NUM ||
913     				widget_partnum == XXBOW_WIDGET_PART_NUM) {
914     		/* 
915     		 * Xbow control register does not have the widget ID field.
916     		 * So, hard code the widget ID to be zero.
917     		 */
918     		DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
919     		npdap->basew_id = 0;
920     
921     #if defined(BRINGUP)
922     	} else if (widget_partnum == XG_WIDGET_PART_NUM) {
923     		/* 
924     		 * OK, WTF do we do here if we have an XG direct connected to a HUB/Bedrock???
925     		 * So, hard code the widget ID to be zero?
926     		 */
927     		npdap->basew_id = 0;
928     		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
929     #endif
930     	} else { 
931     		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
932     
933     		panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widgt ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, hubv);
934     
935     		/*NOTREACHED*/
936     	}
937     	{
938     		char widname[10];
939     		sprintf(widname, "%x", npdap->basew_id);
940     		(void)hwgraph_path_add(switchv, widname, &widgetv);
941     		DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
942     		ASSERT(widgetv != GRAPH_VERTEX_NONE);
943     	}
944     	
945     	nodepda->basew_xc = widgetv;
946     
947     	is_xswitch = xwidget_hwid_is_xswitch(&hwid);
948     
949     	/* 
950     	 * Try to become the master of the widget.  If this is an xswitch
951     	 * with multiple hubs connected, only one will succeed.  Mastership
952     	 * of an xswitch is used only when touching registers on that xswitch.
953     	 * The slave xwidgets connected to the xswitch can be owned by various
954     	 * masters.
955     	 */
956     	if (device_master_set(widgetv, hubv) == 0) {
957     
958     		/* Only one hub (thread) per Crosstalk device or switch makes
959     		 * it to here.
960     		 */
961     
962     		/* 
963     		 * Initialize whatever xwidget is hanging off our hub.
964     		 * Whatever it is, it's accessible through widgetnum 0.
965     		 */
966     		hubinfo_get(hubv, &hubinfo);
967     
968     		(void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL);
969     
970     		if (!is_xswitch) {
971     			/* io_init_done takes cpu cookie as 2nd argument 
972     			 * to do a restorenoderun for the setnoderun done 
973     			 * at the start of this thread 
974     			 */
975     			io_init_done(cnodeid,c);
976     			/* NOTREACHED */
977     		}
978     
979     		/* 
980     		 * Special handling for Crosstalk Switches (e.g. xbow).
981     		 * We need to do things in roughly the following order:
982     		 *	1) Initialize xswitch hardware (done above)
983     		 *	2) Determine which hubs are available to be widget masters
984     		 *	3) Discover which links are active from the xswitch
985     		 *	4) Assign xwidgets hanging off the xswitch to hubs
986     		 *	5) Initialize all xwidgets on the xswitch
987     		 */
988     
989     		volunteer_for_widgets(switchv, hubv);
990     
991     		/* If there's someone else on this crossbow, recognize him */
992     		if (npdap->xbow_peer != INVALID_NASID) {
993     			nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer));
994     			peer_sema = &peer_npdap->xbow_sema;
995     			volunteer_for_widgets(switchv, peer_npdap->node_vertex);
996     		}
997     
998     		assign_widgets_to_volunteers(switchv, hubv);
999     
1000     		/* Signal that we're done */
1001     		if (peer_sema) {
1002     			mutex_unlock(peer_sema);
1003     		}
1004     		
1005     	}
1006     	else {
1007     	    /* Wait 'til master is done assigning widgets. */
1008     	    mutex_lock(&npdap->xbow_sema);
1009     	}
1010     
1011     #ifdef PROBE_TEST
1012     	if ((cnodeid == 1) || (cnodeid == 2)) {
1013     		int index;
1014     
1015     		for (index = 0; index < 500; index++)
1016     			DBG("Interfering with device probing!!!\n");
1017     	}
1018     #endif
1019     	/* Now both nodes can safely inititialize widgets */
1020     	io_init_xswitch_widgets(switchv, cnodeid);
1021     	io_link_xswitch_widgets(switchv, cnodeid);
1022     
1023     	/* io_init_done takes cpu cookie as 2nd argument 
1024     	 * to do a restorenoderun for the setnoderun done 
1025     	 * at the start of this thread 
1026     	 */
1027     	io_init_done(cnodeid,c);
1028     
1029     	DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
1030     }
1031     
1032     
1033     #define IOINIT_STKSZ	(16 * 1024)
1034     
1035     #define __DEVSTR1 	"/../.master/"
1036     #define __DEVSTR2 	"/target/"
1037     #define __DEVSTR3 	"/lun/0/disk/partition/"
1038     #define	__DEVSTR4	"/../ef"
1039     
1040     #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
1041     /*
1042      * Currently, we need to allow for 5 IBrick slots with 1 FC each
1043      * plus an internal 1394.
1044      *
1045      * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR.
1046      */
1047     #define NUM_BASE_IO_SCSI_CTLR 6
1048     #endif
1049     /*
1050      * This tells ioconfig where it can start numbering scsi controllers.
1051      * Below this base number, platform-specific handles the numbering.
1052      * XXX Irix legacy..controller numbering should be part of devfsd's job
1053      */
1054     int num_base_io_scsi_ctlr = 2; /* used by syssgi */
1055     devfs_handle_t		base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR];
1056     static devfs_handle_t	baseio_enet_vhdl,baseio_console_vhdl;
1057     
1058     /*
1059      * Put the logical controller number information in the 
1060      * scsi controller vertices for each scsi controller that
1061      * is in a "fixed position".
1062      */
1063     static void
1064     scsi_ctlr_nums_add(devfs_handle_t pci_vhdl)
1065     {
1066     	{
1067     		int i;
1068     
1069     		num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR;
1070     
1071     		/* Initialize base_io_scsi_ctlr_vhdl array */
1072     		for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++)
1073     			base_io_scsi_ctlr_vhdl[i] = GRAPH_VERTEX_NONE;
1074     	}
1075     #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
1076     	{
1077     	/*
1078     	 * May want to consider changing the SN0 code, above, to work more like
1079     	 * the way this works.
1080     	 */
1081     	devfs_handle_t base_ibrick_xbridge_vhdl;
1082     	devfs_handle_t base_ibrick_xtalk_widget_vhdl;
1083     	devfs_handle_t scsi_ctlr_vhdl;
1084     	int i;
1085     	graph_error_t rv;
1086     
1087     	/*
1088     	 * This is a table of "well-known" SCSI controllers and their well-known
1089     	 * controller numbers.  The names in the table start from the base IBrick's
1090     	 * Xbridge vertex, so the first component is the xtalk widget number.
1091     	 */
1092     	static struct {
1093     		char	*base_ibrick_scsi_path;
1094     		int	controller_number;
1095     	} hardwired_scsi_controllers[] = {
1096     		{"15/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 0},
1097     		{"15/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 1},
1098     		{"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2},
1099     		{"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3},
1100     		{"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4},
1101     		{"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5},
1102     		{NULL, -1} /* must be last */
1103     	};
1104     
1105     	base_ibrick_xtalk_widget_vhdl = hwgraph_connectpt_get(pci_vhdl);
1106     	ASSERT_ALWAYS(base_ibrick_xtalk_widget_vhdl != GRAPH_VERTEX_NONE);
1107     
1108     	base_ibrick_xbridge_vhdl = hwgraph_connectpt_get(base_ibrick_xtalk_widget_vhdl);
1109     	ASSERT_ALWAYS(base_ibrick_xbridge_vhdl != GRAPH_VERTEX_NONE);
1110     	hwgraph_vertex_unref(base_ibrick_xtalk_widget_vhdl);
1111     
1112     	/*
1113     	 * Iterate through the list of well-known SCSI controllers.
1114     	 * For each controller found, set it's controller number according
1115     	 * to the table.
1116     	 */
1117     	for (i=0; hardwired_scsi_controllers[i].base_ibrick_scsi_path != NULL; i++) {
1118     		rv = hwgraph_path_lookup(base_ibrick_xbridge_vhdl,
1119     			hardwired_scsi_controllers[i].base_ibrick_scsi_path, &scsi_ctlr_vhdl, NULL);
1120     
1121     		if (rv != GRAPH_SUCCESS) /* No SCSI at this path */
1122     			continue;
1123     
1124     		ASSERT(hardwired_scsi_controllers[i].controller_number < NUM_BASE_IO_SCSI_CTLR);
1125     		base_io_scsi_ctlr_vhdl[hardwired_scsi_controllers[i].controller_number] = scsi_ctlr_vhdl;
1126     		device_controller_num_set(scsi_ctlr_vhdl, hardwired_scsi_controllers[i].controller_number);
1127     		hwgraph_vertex_unref(scsi_ctlr_vhdl); /* (even though we're actually keeping a reference) */
1128     	}
1129     
1130     	hwgraph_vertex_unref(base_ibrick_xbridge_vhdl);
1131     	}
1132     #else
1133     #pragma error Bomb!
1134     #endif
1135     }
1136     
1137     
1138     #include <asm/sn/ioerror_handling.h>
1139     extern devfs_handle_t 	ioc3_console_vhdl_get(void);
1140     devfs_handle_t		sys_critical_graph_root = GRAPH_VERTEX_NONE;
1141     
1142     /* Define the system critical vertices and connect them through
1143      * a canonical parent-child relationships for easy traversal
1144      * during io error handling.
1145      */
1146     static void
1147     sys_critical_graph_init(void)
1148     {
1149     	devfs_handle_t		bridge_vhdl,master_node_vhdl;
1150     	devfs_handle_t  		xbow_vhdl = GRAPH_VERTEX_NONE;
1151     	extern devfs_handle_t	hwgraph_root;
1152     	devfs_handle_t		pci_slot_conn;
1153     	int			slot;
1154     	devfs_handle_t		baseio_console_conn;
1155     
1156     	DBG("sys_critical_graph_init: FIXME.\n");
1157     	baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl);
1158     
1159     	if (baseio_console_conn == NULL) {
1160     		return;
1161     	}
1162     
1163     	/* Get the vertex handle for the baseio bridge */
1164     	bridge_vhdl = device_master_get(baseio_console_conn);
1165     
1166     	/* Get the master node of the baseio card */
1167     	master_node_vhdl = cnodeid_to_vertex(
1168     				master_node_get(baseio_console_vhdl));
1169     	
1170     	/* Add the "root->node" part of the system critical graph */
1171     
1172     	sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl);
1173     
1174     	/* Check if we have a crossbow */
1175     	if (hwgraph_traverse(master_node_vhdl,
1176     			     EDGE_LBL_XTALK"/0",
1177     			     &xbow_vhdl) == GRAPH_SUCCESS) {
1178     		/* We have a crossbow.Add "node->xbow" part of the system 
1179     		 * critical graph.
1180     		 */
1181     		sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl);
1182     		
1183     		/* Add "xbow->baseio bridge" of the system critical graph */
1184     		sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl);
1185     
1186     		hwgraph_vertex_unref(xbow_vhdl);
1187     	} else 
1188     		/* We donot have a crossbow. Add "node->baseio_bridge"
1189     		 * part of the system critical graph.
1190     		 */
1191     		sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl);
1192     
1193     	/* Add all the populated PCI slot vertices to the system critical
1194     	 * graph with the bridge vertex as the parent.
1195     	 */
1196     	for (slot = 0 ; slot < 8; slot++) {
1197     		char	slot_edge[10];
1198     
1199     		sprintf(slot_edge,"%d",slot);
1200     		if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn)
1201     		    != GRAPH_SUCCESS)
1202     			continue;
1203     		sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn);
1204     		hwgraph_vertex_unref(pci_slot_conn);
1205     	}
1206     
1207     	hwgraph_vertex_unref(bridge_vhdl);
1208     
1209     	/* Add the "ioc3 pci connection point  -> console ioc3" part 
1210     	 * of the system critical graph
1211     	 */
1212     
1213     	if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) ==
1214     	    GRAPH_SUCCESS) {
1215     		sys_critical_graph_vertex_add(pci_slot_conn, 
1216     					      baseio_console_vhdl);
1217     		hwgraph_vertex_unref(pci_slot_conn);
1218     	}
1219     
1220     	/* Add the "ethernet pci connection point  -> base ethernet" part of 
1221     	 * the system  critical graph
1222     	 */
1223     	if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) ==
1224     	    GRAPH_SUCCESS) {
1225     		sys_critical_graph_vertex_add(pci_slot_conn, 
1226     					      baseio_enet_vhdl);
1227     		hwgraph_vertex_unref(pci_slot_conn);
1228     	}
1229     
1230     	/* Add the "scsi controller pci connection point  -> base scsi 
1231     	 * controller" part of the system critical graph
1232     	 */
1233     	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0],
1234     			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
1235     		sys_critical_graph_vertex_add(pci_slot_conn, 
1236     					      base_io_scsi_ctlr_vhdl[0]);
1237     		hwgraph_vertex_unref(pci_slot_conn);
1238     	}
1239     	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1],
1240     			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
1241     		sys_critical_graph_vertex_add(pci_slot_conn, 
1242     					      base_io_scsi_ctlr_vhdl[1]);
1243     		hwgraph_vertex_unref(pci_slot_conn);
1244     	}
1245     	hwgraph_vertex_unref(baseio_console_conn);
1246     
1247     }
1248     
1249     static void
1250     baseio_ctlr_num_set(void)
1251     {
1252     	char 			name[MAXDEVNAME];
1253     	devfs_handle_t		console_vhdl, pci_vhdl, enet_vhdl;
1254     
1255     
1256     	DBG("baseio_ctlr_num_set; FIXME\n");
1257     	console_vhdl = ioc3_console_vhdl_get();
1258     	if (console_vhdl == GRAPH_VERTEX_NONE)
1259     		return;
1260     	/* Useful for setting up the system critical graph */
1261     	baseio_console_vhdl = console_vhdl;
1262     
1263     	vertex_to_name(console_vhdl,name,MAXDEVNAME);
1264     
1265     	strcat(name,__DEVSTR1);
1266     	pci_vhdl =  hwgraph_path_to_vertex(name);
1267     	scsi_ctlr_nums_add(pci_vhdl);
1268     	/* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex
1269     	 */
1270     	hwgraph_vertex_unref(pci_vhdl);
1271     
1272     	vertex_to_name(console_vhdl, name, MAXDEVNAME);
1273     	strcat(name, __DEVSTR4);
1274     	enet_vhdl = hwgraph_path_to_vertex(name);
1275     
1276     	/* Useful for setting up the system critical graph */
1277     	baseio_enet_vhdl = enet_vhdl;
1278     
1279     	device_controller_num_set(enet_vhdl, 0);
1280     	/* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex
1281     	 */
1282     	hwgraph_vertex_unref(enet_vhdl);
1283     }
1284     /* #endif */
1285     
1286     void
1287     sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list)
1288     {
1289     	/* REFERENCED */
1290     	int rtn_val;
1291     
1292     	/* 
1293     	** sn00 population:		errb	orrb
1294     	**	0- ql			3+?
1295     	**	1- ql			        2
1296     	**	2- ioc3 ethernet	2+?
1297     	**	3- ioc3 secondary	        1
1298     	**	4-                      0
1299     	** 	5- PCI slot
1300     	** 	6- PCI slot
1301     	** 	7- PCI slot
1302     	*/	
1303     	
1304     	/* The following code implements this heuristic for getting 
1305     	 * maximum usage out of the rrbs
1306     	 *
1307     	 * constraints:
1308     	 *  8 bit ql1 needs 1+1
1309     	 *  ql0 or ql5,6,7 wants 1+2
1310     	 *  ethernet wants 2 or more
1311     	 *
1312     	 * rules for even rrbs:
1313     	 *  if nothing in slot 6 
1314     	 *   4 rrbs to 0 and 2  (0xc8889999)
1315     	 *  else 
1316              *   3 2 3 to slots 0 2 6  (0xc8899bbb)
1317     	 *
1318              * rules for odd rrbs
1319     	 *  if nothing in slot 5 or 7  (0xc8889999)
1320     	 *   4 rrbs to 1 and 3
1321     	 *  else if 1 thing in 5 or 7  (0xc8899aaa) or (0xc8899bbb)
1322              *   3 2 3 to slots 1 3 5|7
1323              *  else
1324              *   2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this
1325     	 *           (0xc89aaabb)      may short what it wants therefore the
1326     	 *			       rule should be to plug pci slots in order)
1327     	 */
1328     
1329     
1330     	if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) {
1331     		/* something in slot 6 */
1332     		rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0);
1333     	}
1334     	else {
1335     		rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0);
1336     	}
1337     	if (rtn_val)
1338     		PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
1339     
1340     	if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && 
1341     	    (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) {
1342     		/* soemthing in slot 5 and 7 */
1343     		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0);
1344     	}
1345     	else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) {
1346     		/* soemthing in slot 5 but not 7 */
1347     		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0);
1348     	}
1349     	else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) {
1350     		/* soemthing in slot 7 but not 5 */
1351     		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0);
1352     	}
1353     	else {
1354     		/* nothing in slot 5 or 7 */
1355     		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0);
1356     	}
1357     	if (rtn_val)
1358     		PRINT_WARNING("sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
1359     }
1360     
1361     
1362     /*
1363      * Initialize all I/O devices.  Starting closest to nodes, probe and
1364      * initialize outward.
1365      */
1366     void
1367     init_all_devices(void)
1368     {
1369     	/* Governor on init threads..bump up when safe 
1370     	 * (beware many devfs races) 
1371     	 */
1372     #ifdef LATER
1373     	int io_init_node_threads = 2;	
1374     #endif
1375     	cnodeid_t cnodeid, active;
1376     
1377     #ifdef LINUX_KERNEL_THREADS
1378     	sema_init(&io_init_sema, 0);
1379     #endif
1380     
1381     	active = 0;
1382     	for (cnodeid = 0; cnodeid < maxnodes; cnodeid++) {
1383     #ifdef LINUX_KERNEL_THREADS
1384     		char thread_name[16];
1385     		extern int io_init_pri;
1386     
1387     		/*
1388     		 * Spawn a service thread for each node to initialize all
1389     		 * I/O on that node.  Each thread attempts to bind itself 
1390     		 * to the node whose I/O it's initializing.
1391     		 */
1392     		sprintf(thread_name, "IO_init[%d]", cnodeid);
1393     
1394     		(void)sthread_create(thread_name, 0, IOINIT_STKSZ, 0,
1395     			io_init_pri, KT_PS, (st_func_t *)io_init_node,
1396     			(void *)(long)cnodeid, 0, 0, 0);
1397     #else
1398                     DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
1399                     io_init_node(cnodeid);
1400     
1401     		DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
1402     
1403     #endif /* LINUX_KERNEL_THREADS */
1404     
1405     #ifdef LINUX_KERNEL_THREADS
1406     		/* Limit how many nodes go at once, to not overload hwgraph */
1407     		/* TBD: Should timeout */
1408     		DBG("started thread for cnode %d\n", cnodeid);
1409     		active++;
1410     		if (io_init_node_threads && 
1411     			active >= io_init_node_threads) {
1412     			down(&io_init_sema);
1413     			active--;
1414     		}
1415     #endif /* LINUX_KERNEL_THREADS */
1416     	}
1417     
1418     #ifdef LINUX_KERNEL_THREADS
1419     	/* Wait until all IO_init threads are done */
1420     
1421     	while (active > 0) {
1422     #ifdef AA_DEBUG
1423     	    DBG("waiting, %d still active\n", active);
1424     #endif
1425     	    down(&io_init_sema);
1426     	    active--;
1427     	}
1428     
1429     #endif /* LINUX_KERNEL_THREADS */
1430     
1431     	for (cnodeid = 0; cnodeid < maxnodes; cnodeid++)
1432     		/*
1433     	 	 * Update information generated by IO init.
1434     		 */
1435     		update_node_information(cnodeid);
1436     
1437     	baseio_ctlr_num_set();
1438     	/* Setup the system critical graph (which is a subgraph of the
1439     	 * main hwgraph). This information is useful during io error
1440     	 * handling.
1441     	 */
1442     	sys_critical_graph_init();
1443     
1444     #if HWG_PRINT
1445     	hwgraph_print();
1446     #endif
1447     
1448     }
1449     
1450     #define toint(x) ((int)(x) - (int)('0'))
1451     
1452     void
1453     devnamefromarcs(char *devnm)
1454     {
1455     	int 			val;
1456     	char 			tmpnm[MAXDEVNAME];
1457     	char 			*tmp1, *tmp2;
1458     	
1459     	val = strncmp(devnm, "dks", 3);
1460     	if (val != 0) 
1461     		return;
1462     	tmp1 = devnm + 3;
1463     	if (!isdigit(*tmp1))
1464     		return;
1465     
1466     	val = 0;
1467     	while (isdigit(*tmp1)) {
1468     		val = 10*val+toint(*tmp1);
1469     		tmp1++;
1470     	}
1471     
1472     	if(*tmp1 != 'd')
1473     		return;
1474     	else
1475     		tmp1++;
1476     
1477     	if ((val < 0) || (val >= NUM_BASE_IO_SCSI_CTLR)) {
1478     		int i;
1479     		int viable_found = 0;
1480     
1481     		DBG("Only controller numbers 0..%d  are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
1482     		DBG("prom \"root\" variables of the form dksXdXsX.\n");
1483     		DBG("To use another disk you must use the full hardware graph path\n\n");
1484     		DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
1485     		for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
1486     			if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
1487     				DBG("%d ", i);
1488     				viable_found=1;
1489     			}
1490     		}
1491     		if (viable_found)
1492     			DBG("\n");
1493     		else
1494     			DBG("none found!\n");
1495     
1496     #ifdef LATER
1497     		if (kdebug)
1498     			debug("ring");
1499     #endif
1500     		DELAY(15000000);
1501     		//prom_reboot();
1502     		panic("FIXME: devnamefromarcs: should call prom_reboot here.\n");
1503     		/* NOTREACHED */
1504     	}
1505     		
1506     	ASSERT(base_io_scsi_ctlr_vhdl[val] != GRAPH_VERTEX_NONE);
1507     	vertex_to_name(base_io_scsi_ctlr_vhdl[val],
1508     		       tmpnm,
1509     		       MAXDEVNAME);
1510     	tmp2 = 	tmpnm + strlen(tmpnm);
1511     	strcpy(tmp2, __DEVSTR2);
1512     	tmp2 += strlen(__DEVSTR2);
1513     	while (*tmp1 != 's') {
1514     		if((*tmp2++ = *tmp1++) == '\0')
1515     			return;
1516     	}	
1517     	tmp1++;
1518     	strcpy(tmp2, __DEVSTR3);
1519     	tmp2 += strlen(__DEVSTR3);
1520     	while ( (*tmp2++ = *tmp1++) )
1521     		;
1522     	tmp2--;
1523     	*tmp2++ = '/';
1524     	strcpy(tmp2, EDGE_LBL_BLOCK);
1525     	strcpy(devnm,tmpnm);
1526     }
1527     
1528     static
1529     struct io_brick_map_s io_brick_tab[] = {
1530     
1531     /* Ibrick widget number to PCI bus number map */
1532       {
1533             'I',                                    /* Ibrick type    */ 
1534         /*  PCI Bus #                                  Widget #       */
1535          {  0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
1536             0,                                      /* 0x8            */
1537             0,                                      /* 0x9            */
1538             0, 0,                                   /* 0xa - 0xb      */
1539             0,                                      /* 0xc            */
1540             0,                                      /* 0xd            */
1541             2,                                      /* 0xe            */
1542             1                                       /* 0xf            */
1543          }
1544       },
1545     
1546     /* Pbrick widget number to PCI bus number map */
1547       {
1548             'P',                                    /* Pbrick type    */ 
1549         /*  PCI Bus #                                  Widget #       */
1550          {  0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
1551             2,                                      /* 0x8            */
1552             1,                                      /* 0x9            */
1553             0, 0,                                   /* 0xa - 0xb      */
1554             5,                                      /* 0xc            */
1555             6,                                      /* 0xd            */
1556             4,                                      /* 0xe            */
1557             3                                       /* 0xf            */
1558          }
1559       },
1560     
1561     /* Xbrick widget to XIO slot map */
1562       {
1563             'X',                                    /* Xbrick type    */ 
1564         /*  XIO Slot #                                 Widget #       */
1565          {  0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
1566             1,                                      /* 0x8            */
1567             2,                                      /* 0x9            */
1568             0, 0,                                   /* 0xa - 0xb      */
1569             3,                                      /* 0xc            */
1570             4,                                      /* 0xd            */
1571             0,                                      /* 0xe            */
1572             0                                       /* 0xf            */
1573          }
1574       }
1575     };
1576     
1577     /*
1578      * Use the brick's type to map a widget number to a meaningful int
1579      */
1580     int
1581     io_brick_map_widget(char brick_type, int widget_num)
1582     {
1583             int num_bricks, i;
1584     
1585             /* Calculate number of bricks in table */
1586             num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
1587     
1588             /* Look for brick prefix in table */
1589             for (i = 0; i < num_bricks; i++) {
1590                    if (brick_type == io_brick_tab[i].ibm_type)
1591                            return(io_brick_tab[i].ibm_map_wid[widget_num]);
1592             }
1593     
1594             return 0;
1595     
1596     }
1597     
1598     /*
1599      * Use the device's vertex to map the device's widget to a meaningful int
1600      */
1601     int
1602     io_path_map_widget(devfs_handle_t vertex)
1603     {
1604             char hw_path_name[MAXDEVNAME];
1605             char *wp, *bp, *sp = NULL;
1606             int  widget_num;
1607     	long atoi(char *);
1608     	int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
1609     
1610     
1611             /* Get the full path name of the vertex */
1612             if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name,
1613                                                          MAXDEVNAME))
1614                     return 0;
1615     
1616             /* Find the widget number in the path name */
1617             wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/");
1618             if (wp == NULL)
1619                     return 0;
1620             widget_num = atoi(wp+7);
1621             if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F)
1622                     return 0;
1623     
1624             /* Find "brick" in the path name */
1625             bp = strstr(hw_path_name, "brick");
1626             if (bp == NULL)
1627                     return 0;
1628     
1629             /* Find preceding slash */
1630             sp = bp;
1631             while (sp > hw_path_name) {
1632                     sp--;
1633                     if (*sp == '/')
1634                             break;
1635             }
1636     
1637             /* Invalid if no preceding slash */
1638             if (!sp)
1639                     return 0;
1640     
1641             /* Bump slash pointer to "brick" prefix */
1642             sp++;
1643             /*
1644              * Verify "brick" prefix length;  valid exaples:
1645              * 'I' from "/Ibrick"
1646              * 'P' from "/Pbrick"
1647              * 'X' from "/Xbrick"
1648              */
1649              if ((bp - sp) != 1)
1650                     return 0;
1651     
1652             return (io_brick_map_widget(*sp, widget_num));
1653     
1654     }
1655