1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/cmn_err.h>
29 #include <sys/conf.h>
30 #include <sys/ddi_impldefs.h>
31 #include <sys/autoconf.h>
32 #include <sys/systm.h>
33 #include <sys/modctl.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/sunndi.h>
37 #include <sys/ndi_impldefs.h>
38 #include <sys/promif.h>
39 #include <sys/stat.h>
40 #include <sys/kmem.h>
41 #include <sys/promif.h>
42 #include <sys/conf.h>
43 #include <sys/obpdefs.h>
44 #include <sys/cpuvar.h>
45 #include <vm/seg_kmem.h>
46 #include <sys/prom_plat.h>
47 #include <sys/machsystm.h>
48 #include <sys/note.h>
49 #include <sys/memlist.h>
50 #include <sys/ssm.h>
51
52 #include <sys/sbd_ioctl.h>
53 #include <sys/sbd.h>
54 #include <sys/sbdp_priv.h>
55 #include <sys/sbdp_mem.h>
56 #include <sys/sbdp_error.h>
57 #include <sys/serengeti.h>
58
59 #include <sys/sgsbbc.h> /* To get fn_t type definition */
60
61 /*
62 * Config information
63 */
64 #ifdef DEBUG
65 uint_t sbdp_debug = 0x0;
66 #endif /* DEBUG */
67
68 /*
69 * Enable or disable dr
70 */
71 int sbdp_dr_available = 1;
72
73 /* name properties for some Serengeti device nodes */
74 #define CMP_DEVNAME "cmp"
75 #define MEM_DEVNAME "memory"
76 #define CPU_DEVNAME "cpu"
77 #define IO_PCI_DEVNAME "pci"
78 #define IO_SGHSC_DEVNAME "sghsc"
79 #define IO_WCI_DEVNAME "wci"
80
81 static sbd_devattr_t sbdp_devattr[] = {
82 { CMP_DEVNAME, "cmp", SBD_COMP_CMP },
83 { MEM_DEVNAME, "memory-controller", SBD_COMP_MEM },
84 { CPU_DEVNAME, "cpu", SBD_COMP_CPU },
85 { IO_PCI_DEVNAME, "pci", SBD_COMP_IO },
86 { IO_SGHSC_DEVNAME, "sghsc", SBD_COMP_IO },
87 { IO_WCI_DEVNAME, "wci", SBD_COMP_IO },
88 /* last item must be blank */
89 { NULL, NULL, SBD_COMP_UNKNOWN }
90 };
91
92 /*
93 * In the case of a busy mbox, if a status cmd comes in we return a cached
94 * copy. This cache is a link list of wnodes that contains bd structs with
95 * the appropriate info. When a new wnode is created a whole entry is added
96 * to the list.
97 */
98 sbdp_wnode_t *first_node = NULL; /* first wnode. Entry to the link list */
99 int cur_num_wnodes = 0; /* how many nodes are currently running */
100
101 /* Macros to access fields in the previous array */
102 #define SBDP_CT(i) sbdp_devattr[i].s_dnodetype
103 #define SBDP_DEVNAME(i) sbdp_devattr[(i)].s_devname
104 #define SBDP_OTYPE(i) sbdp_devattr[(i)].s_obp_type
105
106 /*
107 * Prototypes
108 */
109 sbdp_wnode_t *sbdp_get_wnodep(int);
110
111 /*
112 * Module linkage information for the kernel.
113 */
114
115 static struct modlmisc modlmisc = {
116 &mod_miscops,
117 "Serengeti sbdp",
118 };
119
120 static struct modlinkage modlinkage = {
121 MODREV_1,
122 (void *)&modlmisc,
123 NULL
124 };
125
126 /*
127 * VA area used during CPU shutdown.
128 */
129 caddr_t sbdp_shutdown_va;
130
131 /*
132 * Mutex to protect our inventory
133 */
134 kmutex_t sbdp_wnode_mutex;
135
136 int
_init(void)137 _init(void)
138 {
139 int e;
140
141 e = mod_install(&modlinkage);
142 if (e != 0)
143 return (e);
144
145 sbdp_shutdown_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
146 ASSERT(sbdp_shutdown_va != NULL);
147 sbdp_valp = (uint64_t *)vmem_alloc(static_alloc_arena,
148 sizeof (uint64_t), VM_SLEEP);
149
150 mutex_init(&sbdp_wnode_mutex, NULL, MUTEX_DRIVER, NULL);
151 return (e);
152 }
153
154 int
_fini(void)155 _fini(void)
156 {
157 int e;
158
159 /*
160 * Remove the module.
161 */
162 e = mod_remove(&modlinkage);
163 if (e != 0)
164 return (e);
165
166 vmem_free(heap_arena, sbdp_shutdown_va, PAGESIZE);
167 sbdp_shutdown_va = NULL;
168 vmem_free(static_alloc_arena, (void *)sbdp_valp, sizeof (uint64_t));
169 sbdp_valp = NULL;
170
171 mutex_destroy(&sbdp_wnode_mutex);
172 return (e);
173 }
174
175 int
_info(struct modinfo * modinfop)176 _info(struct modinfo *modinfop)
177 {
178 return (mod_info(&modlinkage, modinfop));
179 }
180
181 int
sbdp_get_bd_and_wnode_num(pnode_t nodeid,int * bd,int * wnode)182 sbdp_get_bd_and_wnode_num(pnode_t nodeid, int *bd, int *wnode)
183 {
184 int portid;
185 static fn_t f = "sbdp_get_bd_and_wnode_num";
186 extern int get_portid(pnode_t node, pnode_t *cmpp);
187
188 SBDP_DBG_FUNC("%s\n", f);
189
190 if (sbdp_is_node_bad(nodeid))
191 return (-1);
192
193 if ((portid = get_portid(nodeid, NULL)) == -1)
194 return (-1);
195
196 /*
197 * decode the board number
198 */
199 *bd = SG_PORTID_TO_BOARD_NUM(portid);
200 *wnode = SG_PORTID_TO_NODEID(portid);
201
202 return (0);
203 }
204
205 int
sbdp_get_board_num(sbdp_handle_t * hp,dev_info_t * dip)206 sbdp_get_board_num(sbdp_handle_t *hp, dev_info_t *dip)
207 {
208 _NOTE(ARGUNUSED(hp))
209
210 pnode_t nodeid;
211 int bd, wnode;
212 static fn_t f = "sbdp_get_board_num";
213
214 SBDP_DBG_FUNC("%s\n", f);
215
216 if (dip == NULL)
217 return (-1);
218
219 nodeid = ddi_get_nodeid(dip);
220
221 /*
222 * Portid has encoded the nodeid and the agent id. The top
223 * 4 bits are correspond to the wcnodeid and the lower 5 are the
224 * agent id.
225 * Each agent id represents a physical location hence we can
226 * obtain the board number
227 */
228 if (sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) < 0)
229 return (-1);
230
231 return (bd);
232 }
233
234
235 sbd_devattr_t *
sbdp_get_devattr(void)236 sbdp_get_devattr(void)
237 {
238 return (&sbdp_devattr[0]);
239 }
240
241 int
sbdp_portid_to_cpu_unit(int cmp,int core)242 sbdp_portid_to_cpu_unit(int cmp, int core)
243 {
244 return (SG_PORTID_TO_CPU_UNIT(cmp, core));
245 }
246
247 int
sbdp_get_unit_num(sbdp_handle_t * hp,dev_info_t * dip)248 sbdp_get_unit_num(sbdp_handle_t *hp, dev_info_t *dip)
249 {
250 int unit = -1;
251 int portid;
252 processorid_t cpuid;
253 sbd_comp_type_t type;
254 char dev_type[OBP_MAXPROPNAME];
255 int i;
256 pnode_t nodeid;
257 static fn_t f = "sbdp_get_unit_num";
258
259 SBDP_DBG_FUNC("%s\n", f);
260
261 if (dip == NULL)
262 return (-1);
263
264 nodeid = ddi_get_nodeid(dip);
265
266 if (sbdp_is_node_bad(nodeid))
267 return (-1);
268
269 if (prom_getprop(nodeid, "device_type", (caddr_t)dev_type) < 0) {
270 SBDP_DBG_MISC("%s: couldn't get device_type\n", f);
271 return (-1);
272 }
273
274 for (i = 0; SBDP_CT(i) != SBD_COMP_UNKNOWN; i++) {
275 if (strcmp(dev_type, SBDP_OTYPE(i)) != 0)
276 continue;
277 type = SBDP_CT(i);
278 }
279
280 switch (type) {
281 case SBD_COMP_CPU:
282 if ((cpuid = sbdp_get_cpuid(hp, dip)) != -1) {
283 unit = SG_CPUID_TO_CPU_UNIT(cpuid);
284 }
285 break;
286 case SBD_COMP_MEM:
287 unit = 0;
288 break;
289 case SBD_COMP_IO: {
290 regspace_t regs[3];
291 int len = 0;
292
293 /*
294 * Check to see if this is a cpci node
295 * cpci nodes are assign unit nums of 5 for now
296 * So they don't conflict with the pci unit nums
297 */
298
299 if (strcmp(dev_type, "sghsc") == 0) {
300 SBDP_DBG_MISC("it is a sghsc\n");
301 return (4);
302 }
303
304 if (prom_getprop(nodeid, "portid", (caddr_t)&portid) <= 0) {
305 SBDP_DBG_MISC("%s: couldn't get portid\n", f);
306 return (-1);
307 }
308
309 len = prom_getproplen(nodeid, "reg");
310 if (len <= 0) {
311 SBDP_DBG_MISC("%s: couldn't get length\n", f);
312 return (-1);
313 }
314
315 if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0) {
316 SBDP_DBG_MISC("%s: couldn't get registers\n", f);
317 return (-1);
318 }
319
320 if ((portid % 2) != 0)
321 if ((regs[0].regspec_addr_lo & 0x700000) ==
322 0x700000)
323 unit = 0;
324 else
325 unit = 1;
326 else
327 if ((regs[0].regspec_addr_lo & 0x700000) ==
328 0x700000)
329 unit = 2;
330 else
331 unit = 3;
332
333 SBDP_DBG_MISC("unit is %d\n", unit);
334 break;
335 }
336 default:
337 break;
338
339 }
340
341 return (unit);
342 }
343
344 struct sbdp_mem_dip {
345 sbdp_bd_t *bdp;
346 dev_info_t *dip;
347 };
348
349 static int
sbdp_get_mem_dip(pnode_t node,void * arg,uint_t flags)350 sbdp_get_mem_dip(pnode_t node, void *arg, uint_t flags)
351 {
352 _NOTE(ARGUNUSED(flags))
353
354 struct sbdp_mem_dip *smdp = (struct sbdp_mem_dip *)arg;
355 mem_op_t mem = {0};
356
357 if (node == OBP_NONODE || node == OBP_BADNODE)
358 return (DDI_FAILURE);
359
360 mem.nodes = smdp->bdp->nodes;
361 mem.board = smdp->bdp->bd;
362 mem.nmem = smdp->bdp->nnum;
363
364 (void) sbdp_is_mem(node, &mem);
365
366 /*
367 * We need to find the dip only for the first nodeid
368 */
369 if (smdp->bdp->nnum == 0 && mem.nmem == 1) {
370 ASSERT(smdp->dip == NULL);
371 smdp->dip = e_ddi_nodeid_to_dip(node);
372 }
373
374 smdp->bdp->nnum = mem.nmem;
375
376 return (DDI_SUCCESS);
377 }
378
379
380 /*
381 * Update the board info. Required after a copy rename
382 */
383 void
sbdp_update_bd_info(sbdp_bd_t * bdp)384 sbdp_update_bd_info(sbdp_bd_t *bdp)
385 {
386 attach_pkt_t apkt, *apktp = &apkt;
387 struct sbdp_mem_dip smd = {0};
388 static fn_t f = "sbdp_update_bd_info";
389
390 SBDP_DBG_FUNC("%s\n", f);
391
392 if (bdp == NULL) {
393 return;
394 }
395 /*
396 * Grab the lock
397 */
398 mutex_enter(&bdp->bd_mutex);
399
400 /*
401 * we get the top nodes here. This will have a side effect of
402 * updating the present bit for cpus
403 */
404 apktp->node = bdp->wnode;
405 apktp->board = bdp->bd;
406 apktp->num_of_nodes = 0;
407 apktp->flags = 0;
408 sbdp_walk_prom_tree(prom_rootnode(), sbdp_select_top_nodes,
409 (void *) apktp);
410
411 /*
412 * We need to clear nnum since we are looking again for the
413 * nodes
414 */
415 bdp->nnum = 0;
416 smd.bdp = bdp;
417
418 /*
419 * If a dip is found by sbdp_get_mem_dip(), it will be
420 * returned held
421 */
422 sbdp_walk_prom_tree(prom_rootnode(), sbdp_get_mem_dip, &smd);
423 if (smd.dip != NULL) {
424 sbdp_handle_t *hp;
425
426 hp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP);
427 hp->h_board = bdp->bd;
428 hp->h_wnode = bdp->wnode;
429 hp->h_err = kmem_zalloc(sizeof (*hp->h_err), KM_SLEEP);
430 if (bdp->ml != NULL) {
431 (void) sbdp_del_memlist(hp, bdp->ml);
432 }
433 bdp->ml = sbdp_get_memlist(hp, (dev_info_t *)NULL);
434 /*
435 * if the board doesn't have banks initialize them,
436 * otherwise we assume they have been updated if
437 * necessary
438 */
439 if (bdp->banks == NULL) {
440 sbdp_init_bd_banks(bdp);
441 }
442 #ifdef DEBUG
443 sbdp_print_bd_banks(bdp);
444 #endif
445
446 if (sbdphw_get_base_physaddr(hp, smd.dip, &bdp->bpa))
447 bdp->bpa = -1;
448 ddi_release_devi(smd.dip);
449 kmem_free(hp->h_err, sizeof (*hp->h_err));
450 kmem_free(hp, sizeof (sbdp_handle_t));
451 }
452 mutex_exit(&bdp->bd_mutex);
453 }
454
455 /*
456 * Initialize the board struct. This remains cached. We update it
457 * every time we have a successful show_board and after a copy-rename
458 */
459 void
sbdp_bd_init(sbdp_bd_t * bdp,int bd,int wnode)460 sbdp_bd_init(sbdp_bd_t *bdp, int bd, int wnode)
461 {
462 static fn_t f = "sbdp_bd_init";
463
464 SBDP_DBG_FUNC("%s\n", f);
465
466 bdp->bd = bd;
467 bdp->wnode = wnode;
468
469 SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
470
471 bdp->cpus_present = 0;
472
473 sbdp_update_bd_info(bdp);
474
475 mutex_init(&bdp->bd_mutex, NULL, MUTEX_DRIVER, NULL);
476 bdp->bd_sc = (show_board_t *)kmem_zalloc(sizeof (show_board_t),
477 KM_SLEEP);
478 bdp->valid_cp = -1;
479 }
480
481 /*
482 * This entry is going away. Clean up
483 */
484 void
sbdp_bd_fini(sbdp_bd_t * bdp)485 sbdp_bd_fini(sbdp_bd_t *bdp)
486 {
487 static fn_t f = "sbdp_bd_fini";
488
489 SBDP_DBG_FUNC("%s\n", f);
490
491 sbdp_cleanup_bd(bdp->wnode, bdp->bd);
492 kmem_free(bdp->bd_sc, sizeof (show_board_t));
493 bdp->bd_sc = NULL;
494 mutex_destroy(&bdp->bd_mutex);
495 #ifdef DEBUG
496 sbdp_print_all_segs();
497 #endif
498 }
499
500 /*
501 * A new wnode has arrived. Initialize the struct and create
502 * the board structures.
503 */
504 void
sbdp_wnode_init(sbdp_wnode_t * wnodep,int wnode,int boards)505 sbdp_wnode_init(sbdp_wnode_t *wnodep, int wnode, int boards)
506 {
507 int i;
508 static fn_t f = "sbdp_wnode_init";
509
510 SBDP_DBG_FUNC("%s\n", f);
511
512 wnodep->wnode = wnode;
513 wnodep->nbds = boards;
514 wnodep->bds = kmem_zalloc(sizeof (sbdp_bd_t) * boards, KM_SLEEP);
515 wnodep->next = wnodep->prev = NULL;
516
517 for (i = 0; i < boards; i++)
518 sbdp_bd_init(&wnodep->bds[i], i, wnode);
519 }
520
521 /*
522 * Wnode got DRed out. Clean up all the node stuff including the boards
523 */
524 void
sbdp_wnode_fini(sbdp_wnode_t * wnodep)525 sbdp_wnode_fini(sbdp_wnode_t *wnodep)
526 {
527 int boards;
528 int i;
529 static fn_t f = "sbdp_wnode_fini";
530
531 SBDP_DBG_FUNC("%s\n", f);
532
533 boards = wnodep->nbds;
534
535 for (i = 0; i < boards; i++)
536 sbdp_bd_fini(&wnodep->bds[i]);
537
538 kmem_free(wnodep->bds, sizeof (sbdp_bd_t) * boards);
539 wnodep->next = wnodep->prev = NULL;
540 kmem_free(wnodep, sizeof (sbdp_wnode_t));
541 }
542
543 /*
544 * Add all the necessary fields to this board's struct
545 */
546 void
sbdp_add_new_bd_info(int wnode,int board)547 sbdp_add_new_bd_info(int wnode, int board)
548 {
549 sbdp_wnode_t *cur;
550 static fn_t f = "sbdp_add_new_bd_info";
551
552 SBDP_DBG_FUNC("%s\n", f);
553
554 cur = sbdp_get_wnodep(wnode);
555
556 SBDP_DBG_MISC("adding new board info %d\n", board);
557
558 sbdp_update_bd_info(&cur->bds[board]);
559
560 }
561
562 /*
563 * This board has gone away. Clean the necessary fields
564 */
565 void
sbdp_cleanup_bd(int wnode,int board)566 sbdp_cleanup_bd(int wnode, int board)
567 {
568 sbdp_wnode_t *cur;
569 sbdp_handle_t handle, *hp;
570 sbdp_bd_t *bdp;
571 int i;
572 static fn_t f = "sbdp_cleanup_bd";
573
574 SBDP_DBG_FUNC("%s\n", f);
575
576 cur = sbdp_get_wnodep(wnode);
577
578 SBDP_DBG_MISC("cleaning up bd info for bd %d\n", board);
579 if (cur == NULL) {
580 SBDP_DBG_MISC("cur is null\n");
581 return;
582 }
583
584 bdp = &cur->bds[board];
585
586 /*
587 * Grab the lock
588 */
589 mutex_enter(&bdp->bd_mutex);
590
591 for (i = 0; i < bdp->nnum; i++)
592 bdp->nodes[i] = (pnode_t)0;
593 bdp->nnum = 0;
594
595 sbdp_fini_bd_banks(bdp);
596
597 hp = &handle;
598 hp->h_board = bdp->bd;
599 hp->h_wnode = bdp->wnode;
600 if (bdp->ml) {
601 (void) sbdp_del_memlist(hp, bdp->ml);
602 }
603
604 bdp->ml = NULL;
605
606 bdp->bpa = -1;
607
608 sbdp_cpu_in_reset(wnode, bdp->bd, SBDP_ALL_CPUS, 0);
609
610 bdp->cpus_present = 0;
611
612 mutex_exit(&bdp->bd_mutex);
613 }
614
615 /*
616 * Traverse the list looking for wnode. Return it when found
617 */
618 sbdp_wnode_t *
sbdp_get_wnodep(int wnode)619 sbdp_get_wnodep(int wnode)
620 {
621 sbdp_wnode_t *cur;
622 int i;
623 static fn_t f = "sbdp_get_wnodep";
624
625 SBDP_DBG_FUNC("%s\n", f);
626
627 mutex_enter(&sbdp_wnode_mutex);
628 for (i = 0, cur = first_node; i < cur_num_wnodes; i++,
629 cur = cur->next) {
630 if (cur->wnode == wnode) {
631 mutex_exit(&sbdp_wnode_mutex);
632 return (cur);
633 }
634 }
635 mutex_exit(&sbdp_wnode_mutex);
636
637 return (NULL);
638 }
639
640 /*
641 * Insert this brand new node into our master list. It leaves it all
642 * initialized
643 */
644 void
sbdp_insert_wnode(int wnode,int max_boards)645 sbdp_insert_wnode(int wnode, int max_boards)
646 {
647 sbdp_wnode_t *wnodep;
648 sbdp_wnode_t *cur;
649 static fn_t f = "sbdp_insert_wnode";
650
651 SBDP_DBG_FUNC("%s\n", f);
652
653 wnodep = kmem_zalloc(sizeof (sbdp_wnode_t), KM_SLEEP);
654
655 mutex_enter(&sbdp_wnode_mutex);
656 if (first_node == NULL) {
657 first_node = wnodep;
658 cur_num_wnodes++;
659 } else {
660 cur = first_node + cur_num_wnodes++;
661 cur->next = wnodep;
662 wnodep->prev = cur;
663 }
664 mutex_exit(&sbdp_wnode_mutex);
665 sbdp_wnode_init(wnodep, wnode, max_boards);
666 }
667
668 /*
669 * This node is gone. Remove it from the list and also clean up
670 */
671 void
sbdp_remove_wnode(sbdp_wnode_t * wnodep)672 sbdp_remove_wnode(sbdp_wnode_t *wnodep)
673 {
674 sbdp_wnode_t *cur;
675 static fn_t f = "sbdp_remove_wnode";
676
677 SBDP_DBG_FUNC("%s\n", f);
678
679 if (wnodep != NULL) {
680 sbdp_wnode_fini(wnodep);
681 mutex_enter(&sbdp_wnode_mutex);
682
683 if (first_node == wnodep)
684 first_node = NULL;
685 else {
686 cur = wnodep->prev;
687 if (cur != NULL)
688 cur->next = wnodep->next;
689 if (wnodep->next != NULL)
690 wnodep->next->prev = cur;
691 }
692
693 cur_num_wnodes--;
694 mutex_exit(&sbdp_wnode_mutex);
695 }
696 }
697
698 /*
699 * Entry point from sbd. This is called when a new node is added. We
700 * create an entry in our inventory and initialize all the stuff that will be
701 * needed
702 */
703 int
sbdp_setup_instance(caddr_t arg)704 sbdp_setup_instance(caddr_t arg)
705 {
706 ssm_sbdp_info_t *sbdp_info;
707 int instance;
708 int wnode;
709 int max_boards;
710 static fn_t f = "sbdp_setup_instance";
711
712 SBDP_DBG_FUNC("%s\n", f);
713
714 /*
715 * We get this directly from ssm
716 */
717 sbdp_info = (ssm_sbdp_info_t *)arg;
718
719 instance = sbdp_info->instance;
720 wnode = sbdp_info->wnode;
721 max_boards = plat_max_boards();
722
723 SBDP_DBG_MISC("sbdp_setup_instance: instance %d wnode %d\n", instance,
724 sbdp_info->wnode);
725
726 if (sbdp_get_wnodep(wnode) == NULL) {
727 /*
728 * This node has not been instanstiated
729 * create one
730 */
731 sbdp_insert_wnode(wnode, max_boards);
732 }
733
734 return (DDI_SUCCESS);
735 }
736
737 /*
738 * Entry point from sbd. This is called when a node has been removed (or is
739 * going away. We do all the necessary cleanup
740 */
741 int
sbdp_teardown_instance(caddr_t arg)742 sbdp_teardown_instance(caddr_t arg)
743 {
744 ssm_sbdp_info_t *sbdp_info;
745 int instance;
746 int wnode;
747 sbdp_wnode_t *wnodep;
748 static fn_t f = "sbdp_teardown_instance";
749
750 SBDP_DBG_FUNC("%s\n", f);
751
752 /*
753 * ssm should have set this up
754 */
755 sbdp_info = (ssm_sbdp_info_t *)arg;
756
757 instance = sbdp_info->instance;
758 wnode = sbdp_info->wnode;
759
760 SBDP_DBG_MISC("sbdp_teardown_instance: instance %d wnode %d\n",
761 instance, wnode);
762
763 /*
764 * Find this node and then remove it
765 */
766 if ((wnodep = sbdp_get_wnodep(wnode)) != NULL) {
767 sbdp_remove_wnode(wnodep);
768 }
769 return (DDI_SUCCESS);
770 }
771
772 int
sbdp_disabled_component(sbdp_handle_t * hp)773 sbdp_disabled_component(sbdp_handle_t *hp)
774 {
775 #ifdef lint
776 hp = hp;
777 #endif
778 return (0);
779 }
780
781 /* ARGSUSED */
782 int
sbdp_release_component(sbdp_handle_t * hp,dev_info_t * dip)783 sbdp_release_component(sbdp_handle_t *hp, dev_info_t *dip)
784 {
785 return (0);
786 }
787
788 void
sbdp_set_err(sbd_error_t * ep,int ecode,char * rsc)789 sbdp_set_err(sbd_error_t *ep, int ecode, char *rsc)
790 {
791 static fn_t f = "sbdp_set_err";
792
793 SBDP_DBG_FUNC("%s\n", f);
794 ASSERT(ep != NULL);
795 ep->e_code = ecode;
796
797 if (rsc != NULL) {
798 (void) strcpy((caddr_t)(ep->e_rsc), (caddr_t)rsc);
799 }
800 }
801
802 /*
803 * Serengeti DR passthrus are for debugging purposes only.
804 */
805 static struct {
806 const char *name;
807 int (*handler)(sbdp_handle_t *, void *);
808 } sbdp_passthrus[] = {
809 #ifdef DEBUG
810 { "readmem", sbdp_passthru_readmem },
811 { "prep-script", sbdp_passthru_prep_script },
812 { "test-quiesce", sbdp_passthru_test_quiesce },
813 { "inject-error", sbdp_passthru_inject_error },
814 { "reset-error", sbdp_passthru_reset_error },
815 #endif
816
817 /* the following line must always be last */
818 { NULL, NULL }
819 };
820
821
822 /*ARGSUSED*/
823 int
sbdp_ioctl(sbdp_handle_t * hp,sbdp_ioctl_arg_t * sbdpi)824 sbdp_ioctl(sbdp_handle_t *hp, sbdp_ioctl_arg_t *sbdpi)
825 {
826 #ifdef DEBUG
827 char buf[512];
828 int rv;
829 sbd_ioctl_arg_t *sbdi = (sbd_ioctl_arg_t *)sbdpi->h_iap;
830 int i;
831 static fn_t f = "sbdp_ioctl";
832
833 SBDP_DBG_FUNC("%s\n", f);
834
835 if (sbdi->i_len >= sizeof (buf) ||
836 ddi_copyin(sbdi->i_opts, buf, sbdi->i_len, sbdpi->h_mode)) {
837 sbdp_set_err(hp->h_err, ESBD_FAULT, NULL);
838 return (-1);
839 }
840
841 i = 0;
842 while (sbdp_passthrus[i].name != NULL) {
843 int len;
844
845 len = strlen(sbdp_passthrus[i].name);
846 if (strncmp(sbdp_passthrus[i].name, buf, len) == 0)
847 break;
848 i++;
849 }
850
851 if (sbdp_passthrus[i].name == NULL) {
852 sbdp_set_err(hp->h_err, ESBD_INVAL, NULL);
853 rv = EIO;
854 } else {
855 rv = (*sbdp_passthrus[i].handler)(hp, buf);
856 if (rv != ESBD_NOERROR) {
857 sbdp_set_err(hp->h_err, rv, NULL);
858 rv = EIO;
859 }
860
861 }
862
863 return (rv);
864 #else
865 return (0);
866 #endif
867 }
868
869 /*
870 * Check the dnode we obtained. Need to find a better way to determine
871 * if the node has the correct starting address
872 */
873 int
sbdp_is_node_bad(pnode_t node)874 sbdp_is_node_bad(pnode_t node)
875 {
876 static fn_t f = "sbdp_is_node_bad";
877
878 SBDP_DBG_FUNC("%s\n", f);
879
880 return ((node == OBP_NONODE) || (node == OBP_BADNODE) ||
881 ((node & 0x80000000u) != 0x80000000u));
882 }
883
884 /*
885 * Retrieve the information we have on this board from
886 * the inventory
887 */
888 sbdp_bd_t *
sbdp_get_bd_info(int wnode,int board)889 sbdp_get_bd_info(int wnode, int board)
890 {
891 sbdp_wnode_t *wnodep;
892 sbdp_bd_t *bdp;
893 int max_bds;
894 static fn_t f = "sbdp_get_bd_info";
895
896 SBDP_DBG_FUNC("%s\n", f);
897
898 wnodep = sbdp_get_wnodep(wnode);
899 max_bds = plat_max_boards();
900
901 if ((wnodep == NULL) || ((board < 0) && (board > max_bds))) {
902 return (NULL);
903 }
904
905 bdp = &wnodep->bds[board];
906
907 /*
908 * We might not have the complete bd info. With cheetah we
909 * cannot access the memory decode registers when then cpu is
910 * in reset. If the mem info is incomplete, then we try to gather it
911 * here
912 */
913 sbdp_update_bd_info(bdp);
914
915 return (bdp);
916 }
917
918 /*
919 * There are certain cases where obp marks components as failed
920 * If the status is ok the node won't have any status property. It
921 * is only there if the status is other than ok.
922 */
923 sbd_cond_t
sbdp_get_comp_status(pnode_t nodeid)924 sbdp_get_comp_status(pnode_t nodeid)
925 {
926 char status_buf[OBP_MAXPROPNAME];
927 static const char *status = "status";
928 static const char *failed = "fail";
929 static const char *disabled = "disabled";
930 static fn_t f = "sbdp_get_comp_status";
931
932 SBDP_DBG_FUNC("%s\n", f);
933
934 if (sbdp_is_node_bad(nodeid)) {
935 SBDP_DBG_STATE("node is not ok\n");
936 return (SBD_COND_UNKNOWN);
937 }
938
939 if (prom_getproplen(nodeid, (char *)status) <= 0) {
940 SBDP_DBG_STATE("status is ok\n");
941 return (SBD_COND_OK);
942 }
943
944 if (prom_getprop(nodeid, (char *)status, status_buf) < 0) {
945 SBDP_DBG_STATE("status is unknown\n");
946 return (SBD_COND_UNKNOWN);
947 }
948
949 if (strncmp(status_buf, failed, strlen(failed)) == 0) {
950 SBDP_DBG_STATE("status of failed\n");
951 return (SBD_COND_FAILED);
952 }
953
954 if (strcmp(status_buf, disabled) == 0) {
955 SBDP_DBG_STATE("status of unusable\n");
956 return (SBD_COND_UNUSABLE);
957 }
958
959 return (SBD_COND_OK);
960 }
961
962 void
sbdp_cpu_in_reset(int node,int bd,int unit,int reset)963 sbdp_cpu_in_reset(int node, int bd, int unit, int reset)
964 {
965 sbdp_wnode_t *cur;
966 sbdp_bd_t *bdp;
967 static fn_t f = "sbdp_cpu_in_reset";
968
969 SBDP_DBG_FUNC("%s\n", f);
970
971 if ((unit < -1) || (bd < 0) || (node < 0)) {
972 return;
973 }
974
975 cur = sbdp_get_wnodep(node);
976
977 SBDP_DBG_MISC("marking cpu %d %s for board %d\n", unit,
978 (reset) ? "in reset" : "out of reset", bd);
979
980 if (cur == NULL) {
981 return;
982 }
983
984 bdp = &cur->bds[bd];
985
986 if (unit == SBDP_ALL_CPUS)
987 if (reset == 1)
988 SBDP_SET_ALL_CPUS_IN_RESET(bdp);
989 else
990 SBDP_UNSET_ALL_CPUS_IN_RESET(bdp);
991 else
992 if (reset == 1)
993 SBDP_SET_CPU_IN_RESET(bdp, unit);
994 else
995 SBDP_UNSET_CPU_IN_RESET(bdp, unit);
996 }
997
998 int
sbdp_set_cpu_present(int node,int bd,int unit)999 sbdp_set_cpu_present(int node, int bd, int unit)
1000 {
1001 sbdp_wnode_t *cur;
1002 sbdp_bd_t *bdp;
1003 static fn_t f = "sbdp_set_cpu_present";
1004
1005 SBDP_DBG_FUNC("%s\n", f);
1006
1007 if ((unit < 0) || (bd < 0) || (node < 0)) {
1008 return (-1);
1009 }
1010
1011 cur = sbdp_get_wnodep(node);
1012 if (cur == NULL) {
1013 return (-1);
1014 }
1015
1016 bdp = &cur->bds[bd];
1017
1018 SBDP_SET_CPU_PRESENT(bdp, unit);
1019
1020 return (0);
1021 }
1022
1023 int
sbdp_is_cpu_present(int node,int bd,int unit)1024 sbdp_is_cpu_present(int node, int bd, int unit)
1025 {
1026 sbdp_wnode_t *cur;
1027 sbdp_bd_t *bdp;
1028 static fn_t f = "sbdp_is_cpu_present";
1029
1030 SBDP_DBG_FUNC("%s\n", f);
1031
1032 if ((unit < 0) || (bd < 0) || (node < 0)) {
1033 return (-1);
1034 }
1035
1036 cur = sbdp_get_wnodep(node);
1037 if (cur == NULL) {
1038 return (-1);
1039 }
1040
1041 bdp = &cur->bds[bd];
1042
1043 return (SBDP_IS_CPU_PRESENT(bdp, unit));
1044 }
1045
1046 int
sbdp_is_cpu_in_reset(int node,int bd,int unit)1047 sbdp_is_cpu_in_reset(int node, int bd, int unit)
1048 {
1049 sbdp_wnode_t *cur;
1050 sbdp_bd_t *bdp;
1051 static fn_t f = "sbdp_is_cpu_in_reset";
1052
1053 SBDP_DBG_FUNC("%s\n", f);
1054
1055 if ((unit < 0) || (bd < 0) || (node < 0)) {
1056 return (-1);
1057 }
1058
1059 cur = sbdp_get_wnodep(node);
1060
1061 if (cur == NULL) {
1062 return (-1);
1063 }
1064
1065 bdp = &cur->bds[bd];
1066
1067 return (SBDP_IS_CPU_IN_RESET(bdp, unit));
1068 }
1069
1070 int
sbdp_dr_avail(void)1071 sbdp_dr_avail(void)
1072 {
1073 static fn_t f = "sbdp_dr_avail";
1074
1075 SBDP_DBG_FUNC("%s\n", f);
1076
1077 if (sbdp_dr_available)
1078 if (sg_prom_sb_dr_check() == 0)
1079 return (1);
1080 return (0);
1081 }
1082