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