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