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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  *
26  * Netract Platform specific functions.
27  *
28  * 	called when :
29  *	machine_type == MTYPE_MONTECARLO
30  */
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /* includes */
34 #include <assert.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <unistd.h>
39 #include <ctype.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <stropts.h>
43 #include <fcntl.h>
44 #include <kvm.h>
45 #include <kstat.h>
46 #include <sys/types.h>
47 #include <sys/utsname.h>
48 #include <sys/openpromio.h>
49 #include <sys/sunddi.h>
50 #include <sys/ddi_impldefs.h>
51 #include <sys/devinfo_impl.h>
52 #include <sys/ioccom.h>
53 #include <sys/systeminfo.h>
54 #include <libintl.h>
55 #include <config_admin.h>
56 #include "pdevinfo.h"
57 #include "display.h"
58 #include "pdevinfo_sun4u.h"
59 #include "display_sun4u.h"
60 #include "libprtdiag.h"
61 #include "libdevinfo.h"
62 
63 /* MC specific header, might just include from MC space */
64 #include "mct_topology.h"
65 #include "envctrl_gen.h"
66 #include "pcf8574_nct.h"
67 #include "netract_gen.h"
68 #include "hscimpl.h"
69 #include "scsbioctl.h"
70 
71 #if !defined(TEXT_DOMAIN)
72 #define	TEXT_DOMAIN			"SYS_TEST"
73 #endif
74 
75 /* globals */
76 #define	MAXNAMESZ			128
77 #define	MAX_NODE_NAME_SZ		32
78 
79 /* this values equates to Max Tree depth for now */
80 #define	MAXIMUM_DEVS			64
81 
82 typedef char device_info_t[MAX_NODE_NAME_SZ];
83 
84 typedef struct {
85 	cfga_list_data_t *ldatap;
86 	int req; /* If set, this list_data was requested by user */
87 } ap_out_t;
88 
89 
90 typedef struct {
91 	uint_t slot_addr;
92 	uint_t slot_stat;
93 	uint_t slot_cond;
94 	device_info_t devs_info[MAXIMUM_DEVS];
95 	uint_t number_devs;
96 } mc_slot_info_t;
97 
98 typedef struct {
99 	mc_slot_info_t mc_slot_info[MC_MAX_SLOTS];
100 } slot_data_t;
101 
102 
103 extern char *progname;
104 extern int print_flag;
105 
106 /* These are used to store all force loads of the drivers */
107 static int ps_fd[MC_MAX_PS];
108 static int oprom_fd;
109 static int slot_index			= 0;
110 static int idx_minuscpu			= 0;
111 static int num_devs			= 0;
112 static int sd_instances[MC_MAX_SLOTS*15];
113 static int gpio_instances[MC_MAX_PS+MC_MAX_FAN];
114 static int sd_count			= 0;
115 static int st_instance;
116 static int gpio_count			= 0;
117 static int slot_table_not_found		= 0;
118 
119 /* default not present */
120 static int alarm_card_present		= 0;
121 static int cpu_ftm_present		= 0;
122 
123 /*
124  * We will store all kstat in globals so that
125  * we can browse thru them later
126  */
127 static	int fail_syssoft_prop		= 0;
128 static  int fail_drv_prop		= 0;
129 di_node_t rootnode;	/* root nexus */
130 slot_data_t mc_slots_data;
131 
132 /* scsb driver kstats */
133 scsb_ks_leddata_t scsb_ks_leddata;
134 scsb_ks_state_t scsb_ks_state;
135 mct_topology_t scsb_ks_topo;
136 
137 /* pcf8574(gpio) driver kstats */
138 envctrl_cpuvoltage_t pcf8574_ks_cpuv;
139 envctrl_pwrsupp_t pcf8574_ks_ps1;
140 envctrl_fantray_t pcf8574_ks_fant1;
141 envctrl_pwrsupp_t pcf8574_ks_ps2;
142 envctrl_fantray_t pcf8574_ks_fant2;
143 
144 /* pcf8591(adc-dac) driver kstats */
145 envctrl_temp_t pcf8591_ks_temp;
146 
147 hsc_slot_table_t hotswap_slot_table[MC_MAX_SLOTS];
148 hsc_prom_slot_table_t prom_slot_table[MC_MAX_SLOTS];
149 
150 static char *hotswap_mode		= NULL;
151 static char *slot_auto_config[MC_MAX_SLOTS];
152 static	int slot_table_size;
153 
154 /*
155  * use this to ascertain what's the system,
156  * default is tonga, we can add more for future variations
157  * 0=tonga, 1=montecarlo
158  * we need also to figure out what the system version is
159  * 0 = 1.5, 1 = 1.0, 0.6 etc.
160  */
161 int montecarlo				= 0;
162 int version_p15_and_p20			= 0;
163 
164 #define	MAX_PRTDIAG_INFO_LENGTH		1024
165 #define	MAX_PRTDIAG_FRUS		22
166 #define	BIT_TEST(X, N)			((X) & (1 << (N)))
167 #define	SLOT1_OK_BIT			0
168 #define	SLOT2_OK_BIT			1
169 #define	SLOT3_OK_BIT			2
170 #define	SLOT4_OK_BIT			3
171 #define	SLOT5_OK_BIT			4
172 #define	SLOT6_OK_BIT			5
173 #define	SLOT7_OK_BIT			6
174 #define	SLOT8_OK_BIT			7
175 #define	PDU1_OK_BIT			SLOT2_OK_BIT
176 #define	PDU2_OK_BIT			SLOT4_OK_BIT
177 #define	FTM_OK_BIT			SLOT5_OK_BIT
178 #define	SCB_OK_BIT			SLOT6_OK_BIT
179 #define	FAN1_OK_BIT			SLOT1_OK_BIT
180 #define	FAN2_OK_BIT			SLOT2_OK_BIT
181 #define	DISK1_OK_BIT			SLOT4_OK_BIT
182 #define	DISK2_OK_BIT			SLOT5_OK_BIT
183 #define	DISK3_OK_BIT			SLOT6_OK_BIT
184 #define	PS1_OK_BIT			SLOT7_OK_BIT
185 #define	PS2_OK_BIT			SLOT8_OK_BIT
186 #define	S_FREE(x)	(((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
187 #define	ENVC_DEBUG_MODE			0x03
188 #define	OPENPROMDEV			"/dev/openprom"
189 #define	I2C_PCF8591_NAME 		"adc-dac"
190 #define	I2C_KSTAT_CPUTEMP 		"adc_temp"
191 #define	SCSB_DEV			"scsb"
192 #define	SDERR				"sderr"
193 #define	STERR				"sterr"
194 #define	OK				"ok"
195 #define	NOK				"Not ok"
196 #define	ON				"on"
197 #define	OFF				"off"
198 #define	BLINK				"blink"
199 #define	NA				"Not Available"
200 #define	UK				"Unknown "
201 #define	YES				"Yes"
202 #define	NO				"No "
203 #define	LO				"low"
204 #define	HI				"high"
205 #define	BLANK				" "
206 #define	SYSSOFT_PROP			"System software"
207 #define	DRV_PROP			"Driver"
208 #define	HSC_PROP_NAME			"hsc-slot-map"
209 #define	HSC_MODE			"hotswap-mode"
210 #define	PCI_ROOT_AP			"pci"
211 #define	PROPS				"Properties:"
212 #define	BOARDTYPE			"Board Type:"
213 #define	DEVS				"Devices:"
214 #define	CPCI_IO				"CompactPCI IO Slot"
215 #define	AC_CARD				"Alarm Card"
216 #define	CPU_FTM				"Front Transition Module"
217 #define	SCTRL_PROM_P06			0x00
218 #define	SCTRL_PROM_P10			0x01
219 #define	SCTRL_PROM_P15			0x02
220 #define	SCTRL_PROM_P20			0x03
221 
222 #define	RMM_NUMBER			3
223 
224 #define	MONTECARLO_PLATFORM		"SUNW,UltraSPARC-IIi-Netract"
225 #define	MAKAHA_PLATFORM			"SUNW,UltraSPARC-IIe-NetraCT-40"
226 
227 /*
228  * The follow table is indexed with the enum's defined by mct_slot_occupant_t
229  * OC_UNKN OC_CPU  OC_AC    OC_BHS OC_FHS OC_HAHS
230  * OC_QFE  OC_FRCH OC_COMBO OC_PMC OC_ATM
231  *
232  * But "scsb" can currently identify only CPU and Alarm Cards by known
233  * slot numbers.
234  */
235 char	*slot_occupants[] = {
236 		CPCI_IO,
237 		"CPU board ",
238 		CPCI_IO,
239 		"Basic HotSwap Board",
240 		"Full HotSwap Board",
241 		"HA Board",
242 		"QFE Board",
243 		"Fresh Choice Board",
244 		"SUN Combo Board",
245 		"PMC Board",
246 		"ATM Board"
247 	};
248 
249 static char	*prtdiag_fru_types[] = {
250 		"I/O        ",	/* 0 */
251 		"CPU        ",
252 		"PSU        ",
253 		"HDD        ",
254 		"FAN        ",
255 		"Alarm Card ",
256 		"SCB        ",
257 		"SSB        ",
258 		"CFTM       ",
259 		"CRTM       ",
260 		"PRTM       ",
261 		"Midplane   "	/* 11 */
262 	};
263 
264 char prtdiag_fru_info[MAX_PRTDIAG_FRUS][MAX_PRTDIAG_INFO_LENGTH];
265 
266 #define	SCB_REG_READ			1
267 #define	SCB_REG_WRITE			2
268 
269 /* Standard Device nodes - hardwired for now */
270 /* will include fan tray later, cpu voltage not impl */
271 static char	*scsb_node = NULL;
272 static char	**ps_node = NULL;
273 static char	*temp_node = NULL;
274 
275 static char	*mc_scsb_node =
276 "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/sysctrl@0,80:scsb";
277 
278 static char	*ot_scsb_node =
279 "/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/sysctrl@0,80:scsb";
280 
281 static char	*mc_ps_node[] = {
282 "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/gpio@0,7c:pwrsuppply",
283 "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/gpio@0,7e:pwrsuppply"
284 };
285 
286 static char	*ot_ps_node[] = {
287 "/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/gpio@0,7c:pwrsuppply",
288 "/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/gpio@0,7e:pwrsuppply"
289 };
290 
291 static char	*mc_temp_node =
292 "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/adc-dac@0,9e:cputemp";
293 
294 /*
295  * these functions will overlay the symbol table of libprtdiag
296  * at runtime (netract systems only)
297  * display functions
298  */
299 int	display(Sys_tree *, Prom_node *, struct system_kstat_data *, int);
300 /* local functions */
301 /*
302  * prom function
303  */
304 static void	gather_diaginfo(int flag);
305 static int	extract_slot_table_from_obp();
306 static int	mc_next(int id);
307 static void	mc_walk(int id);
308 static int	mc_child(int id);
309 static void	mc_dump_node(int id);
310 static int	mc_getpropval(struct openpromio *opp);
311 
312 #ifdef	REDUNDANT_INFO
313 static int	mc_get_cpu_freq(Prom_node *node);
314 static int	mc_get_ecache_size(Prom_node *node);
315 static void	mc_display_cpus(Board_node *board);
316 static void	mc_display_cpu_devices(Sys_tree *tree);
317 #endif	/* REDUNDANT_INFO */
318 
319 static void	netract_disp_prom_version();
320 
321 /*
322  * Since we do not have a system wide kstat for MC/Tg
323  * here we have to do specific kstats to drivers that
324  * post this information - MC/Tg specific drivers
325  * that post kstat here are : scsb, pcf8574(gpio) and pcf8591
326  */
327 static int	analyze_nodes(di_node_t, void*);
328 static void	analyze_pcipci_siblings(di_node_t);
329 static void	display_mc_prtdiag_info();
330 static int	dump_devs(di_node_t, void *);
331 static void	prtdiag_devinfo(void);
332 static void	force_load_drivers();
333 static int	dump_prop_list(char *name,
334 		    di_node_t node, di_prop_t (*nxtprop)());
335 static void	*config_calloc_check(size_t nelem, size_t elsize);
336 static void	explore_slot_occupants();
337 static void	do_scsb_kstat();
338 static void	do_pcf8574_kstat();
339 static void	do_pcf8591_kstat();
340 static void	do_promversion();
341 static int	mc_promopen(int oflag);
342 static int	scsi_disk_status(int disk_number);
343 static void	alarm_card_occupant();
344 static int	scsb_mode(int fd, scsb_op_t sop, uint8_t *new_mode);
345 static int	scsb_ioc_reg_read(int fd, uchar_t index,
346 		    scsb_ioc_rdwr_t *ioc_rd, int num);
347 
348 static int	check_platform();
349 
350 int
351 display(Sys_tree *tree,
352 	    Prom_node *root,
353 	    struct system_kstat_data *kstats,
354 	    int syserrlog)
355 {
356 	int exit_code = 0;   /* init to all OK */
357 	void *value;  /* used for opaque PROM data */
358 	struct mem_total memory_total;  /* Total memory in system */
359 	struct grp_info grps;   /* Info on all groups in system */
360 #ifdef	lint
361 	syserrlog = syserrlog;
362 #endif
363 	sys_clk = -1;  /* System clock freq. (in MHz) */
364 	/*
365 	 * Now display the machine's configuration. We do this if we
366 	 * are not logging or exit_code is set (machine is broke).
367 	 */
368 	if (!logging || exit_code) {
369 		struct utsname uts_buf;
370 
371 		/*
372 		 * Display system banner
373 		 */
374 		(void) uname(&uts_buf);
375 
376 		log_printf(dgettext(TEXT_DOMAIN,
377 			"System Configuration:  Sun Microsystems"
378 			"  %s %s\n"), uts_buf.machine,
379 			get_prop_val(find_prop(root, "banner-name")), 0);
380 
381 		/* display system clock frequency */
382 		value = get_prop_val(find_prop(root, "clock-frequency"));
383 		if (value != NULL) {
384 			sys_clk = ((*((int *)value)) + 500000) / 1000000;
385 			log_printf(dgettext(TEXT_DOMAIN,
386 			    "System clock frequency: "
387 			    "%d MHz\n"), sys_clk, 0);
388 		}
389 
390 		/* Display the Memory Size */
391 		display_memorysize(tree, kstats, &grps, &memory_total);
392 		/* Lets make sure we have all the needed drivers loaded */
393 		/* display Montecarlo/Tonga FRU information */
394 		if (!extract_slot_table_from_obp())
395 			log_printf(dgettext(TEXT_DOMAIN,
396 			    "\r\nslot-table not available\r\n"), 0);
397 		do_scsb_kstat();
398 		force_load_drivers();
399 		gather_diaginfo(print_flag && !logging);
400 		/* figure out if ac is present */
401 		alarm_card_occupant();
402 		/* platform specific display mod */
403 		display_mc_prtdiag_info();
404 		di_fini(rootnode);
405 		netract_disp_prom_version();
406 	}  /* if (!logging || exit_code) */
407 
408 	return (exit_code);
409 
410 }	/* display(....) */
411 
412 static int
413 check_platform()
414 {
415 	char	si_platform[SYS_NMLN];
416 
417 	/*
418 	 * Check for the platform: Montecarlo or Makaha/CP2040 based
419 	 */
420 	if (sysinfo(SI_PLATFORM, si_platform, sizeof (si_platform)) == -1) {
421 		return (-1);
422 	}
423 
424 	if ((strncmp(si_platform, MONTECARLO_PLATFORM,
425 				strlen(MONTECARLO_PLATFORM))) == 0) {
426 		scsb_node = mc_scsb_node;
427 		ps_node = mc_ps_node;
428 		temp_node = mc_temp_node;
429 	} else if ((strncmp(si_platform, MAKAHA_PLATFORM,
430 				strlen(MAKAHA_PLATFORM))) == 0) {
431 		scsb_node = ot_scsb_node;
432 		ps_node = ot_ps_node;
433 		temp_node = NULL;
434 	} else {
435 		return (-1);
436 	}
437 
438 	return (0);
439 }
440 
441 void
442 force_load_drivers()
443 {
444 	int	i;
445 
446 	if (NULL == scsb_node || NULL == ps_node) {
447 		if (check_platform() == -1) {
448 			return;
449 		}
450 	}
451 
452 	/* check scb/ssb presence */
453 	if (scsb_ks_state.scb_present || scsb_ks_state.ssb_present) {
454 		if (open(scsb_node, O_RDONLY) < 0)
455 			log_printf(dgettext(TEXT_DOMAIN,
456 			    "\nscsb open FAILED!"), 0);
457 	}
458 
459 	/* check the num of PS we have */
460 	for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) {
461 		if (scsb_ks_topo.mct_ps[i].fru_status == FRU_PRESENT) {
462 			if ((ps_fd[i] = open(ps_node[i], O_RDONLY)) < 0)
463 				log_printf(dgettext(TEXT_DOMAIN,
464 				    "\npowersupply%d open failed"),
465 				    i, 0);
466 		}
467 	} /* for */
468 
469 	/* open the cpu temp driver */
470 	if (temp_node) {
471 		if (open(temp_node, O_RDONLY) < 0)
472 			log_printf(dgettext(TEXT_DOMAIN,
473 						"\ncputemp open FAILED!"), 0);
474 	}
475 }
476 
477 
478 void
479 explore_slot_occupants()
480 {
481 	char *cp = NULL;
482 	int index;
483 	int ret = CFGA_ERROR;
484 	char *estrp = NULL;
485 	cfga_list_data_t *list_array = NULL;
486 	ap_out_t *out_array = NULL;
487 	int nlist = 0;
488 	char  *prefilt_optp = NULL;
489 	int dyn_exp = 1;
490 	char *plat_opts = NULL;
491 
492 	ret = config_list_ext(0, NULL, &list_array,
493 	    &nlist, plat_opts, prefilt_optp, &estrp,
494 	    dyn_exp ? CFGA_FLAG_LIST_ALL : 0);
495 	if (ret != CFGA_OK) {
496 		log_printf(dgettext(TEXT_DOMAIN,
497 		    "\ncannot explore configuration"), 0);
498 		return;
499 	}
500 	assert(nlist != 0);
501 	out_array = config_calloc_check(nlist, sizeof (*out_array));
502 	if (out_array == NULL) {
503 		ret = CFGA_LIB_ERROR;
504 		goto bail;
505 	}
506 	/* create a list of output stat data */
507 	for (index = 0; index < nlist; index++) {
508 		out_array[index].ldatap = &list_array[index];
509 		out_array[index].req = 0;
510 	}
511 
512 	for (index = 0; index < nlist; index++) {
513 		if ((cp = strstr(out_array[index].ldatap->ap_phys_id,
514 		    "cpci_slot")) != NULL) {
515 			mc_slots_data.mc_slot_info[idx_minuscpu].slot_stat
516 			    = out_array[index].ldatap->ap_o_state;
517 			mc_slots_data.mc_slot_info[idx_minuscpu].slot_cond
518 			    = out_array[index].ldatap->ap_cond;
519 			idx_minuscpu++;
520 		}
521 	}
522 bail:
523 	S_FREE(list_array);
524 	S_FREE(out_array);
525 }
526 
527 
528 /*
529  * config_calloc_check - perform allocation, check result and
530  * set error indicator
531  */
532 void *
533 config_calloc_check(
534 	size_t nelem,
535 	size_t elsize)
536 {
537 	void *p;
538 	static char alloc_fail[] =
539 		"%s: memory allocation failed (%d*%d bytes)\n";
540 
541 	p = calloc(nelem, elsize);
542 	if (p == NULL) {
543 		log_printf(dgettext(TEXT_DOMAIN, alloc_fail), nelem, elsize, 0);
544 	}
545 	return (p);
546 }
547 
548 
549 void
550 do_scsb_kstat()
551 {
552 	kstat_ctl_t	*kc;
553 	kstat_t		*ksp_leddata;
554 	kstat_t		*ksp_state;
555 	kstat_t		 *ksp_topo;
556 	scsb_ks_leddata_t *pks_leddata;
557 	scsb_ks_state_t *pks_state;
558 	mct_topology_t  *pks_topo;
559 	int i;
560 
561 #ifdef	DEBUG_TEMP1
562 		int index;
563 #endif
564 	if (!(kc = kstat_open())) {
565 #ifdef	DEBUG_TEMP
566 		log_printf("\nkstat_open failed", 0);
567 #endif
568 		return;
569 	}
570 #ifdef	lint
571 	kc = kc;
572 #endif
573 	/* get kstat on scsb led data */
574 	if ((ksp_leddata = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_LEDDATA))
575 	    == NULL) {
576 #ifdef	DEBUG_TEMP
577 		log_printf("\nkstat_lookup for scsb_leddata failed", 0);
578 #endif
579 		return;
580 	}
581 	if (kstat_read(kc, ksp_leddata, NULL) == -1) {
582 #ifdef	DEBUG_TEMP
583 		log_printf("\nkstat_read for scsb_leddata failed", 0);
584 #endif
585 		return;
586 	}
587 	pks_leddata = (scsb_ks_leddata_t *)ksp_leddata->ks_data;
588 	scsb_ks_leddata = *pks_leddata; /* set the globals for future */
589 #ifdef	DEBUG_LEDS
590 	/* dump the kstat leddata */
591 	printf("\nDumping LED regs: ");
592 	for (i = 0; i < SCSB_LEDDATA_REGISTERS; ++i) {
593 		log_printf("0x%x ", pks_leddata->scb_led_regs[i] & 0xff, 0);
594 	}
595 	log_printf("\n", 0);
596 #endif
597 	/* get kstat on scsb states */
598 	if ((ksp_state = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_STATE))
599 	    == NULL) {
600 #ifdef	DEBUG_TEMP
601 		log_printf("\nkstat_lookup for scsb_state failed", 0);
602 #endif
603 		return;
604 	}
605 	if (kstat_read(kc, ksp_state, NULL) == -1) {
606 #ifdef	DEBUG_TEMP
607 		log_printf("\nkstat_read for scsb_state failed", 0);
608 #endif
609 		return;
610 	}
611 	pks_state = (scsb_ks_state_t *)ksp_state->ks_data;
612 	scsb_ks_state = *pks_state; /* set the global for future */
613 #ifdef	DEBUG_TEMP1
614 	/* dump the kstat state */
615 	log_printf("\tSCB			is%spresent\n",
616 	    pks_state->scb_present ? " " : " not ", 0);
617 	log_printf("\tSSB			is%spresent\n",
618 	    pks_state->ssb_present ? " " : " not ", 0);
619 	log_printf("\tscsb			is%sfrozen\n",
620 	    pks_state->scsb_frozen ? " " : " not ", 0);
621 	log_printf("\tscsb mode:		", 0);
622 	switch (pks_state->scsb_mode) {
623 		case ENVC_DEBUG_MODE:
624 			log_printf("DEBUG MODE\n", 0);
625 			break;
626 		case ENVCTRL_DIAG_MODE:
627 			log_printf("DIAGNOSTIC MODE\n", 0);
628 			break;
629 		case ENVCTRL_NORMAL_MODE:
630 			log_printf("NORMAL MODE\n", 0);
631 			break;
632 	}
633 	log_printf("\tscsb event code:	0x%x\n", pks_state->event_code, 0);
634 #endif	/* DEBUG_TEMP1 */
635 
636 	if ((ksp_topo = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_TOPOLOGY))
637 	    == NULL) {
638 #ifdef	DEBUG_TEMP
639 		log_printf("\nkstat_lookup for scsb_topo failed", 0);
640 #endif
641 		return;
642 	}
643 	if (kstat_read(kc, ksp_topo, NULL) == -1) {
644 #ifdef	DEBUG_TEMP
645 		log_printf("\nkstat_read for scsb_topo failed", 0);
646 #endif
647 		return;
648 	}
649 	pks_topo = (mct_topology_t *)ksp_topo->ks_data;
650 	scsb_ks_topo = *pks_topo; /* set the global for future */
651 	/*
652 	 * we need to set this so that we can get status info
653 	 * for the 2 powersupplies in MC as we need to get
654 	 * kstat from both driver instances for environment
655 	 */
656 	if (pks_topo->mid_plane.fru_id == SCTRL_MPID_HALF)
657 		montecarlo = 1; /* Monte Carlo */
658 	/*
659 	 * HW version 0.6 and 1.0 had different led maps
660 	 * its assumed that HW 2.0 would not change this
661 	 * need to modify if it does
662 	 */
663 	if ((pks_topo->mct_scb[0].fru_version == SCTRL_PROM_P15) ||
664 	    (pks_topo->mct_scb[0].fru_version == SCTRL_PROM_P20)) {
665 		version_p15_and_p20 = 1;
666 	}
667 
668 	/* set flag to note that CFTM is present */
669 	for (i = 0; i < pks_topo->max_units[CFTM]; ++i) {
670 		if (pks_topo->mct_cftm[i].fru_status == FRU_PRESENT)
671 			cpu_ftm_present = 1;
672 	}
673 
674 #ifdef	DEBUG_TEMP1
675 	/*
676 	 * Midplane
677 	 */
678 	log_printf("Midplane type:		", 0);
679 	if (pks_topo->mid_plane.fru_id == SCTRL_MPID_HALF)
680 		log_printf("Netra ct800 server\n", 0);
681 	else
682 		log_printf("Netra ct400 server%s\n",
683 		    pks_topo->mid_plane.fru_id ==
684 		    SCTRL_MPID_QUARTER_NODSK ? ", no disk" : " with disk", 0);
685 	log_printf("Midplane version:	%d\n",
686 	    pks_topo->mid_plane.fru_version, 0);
687 	log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
688 		pks_topo->mct_scb[0].fru_type,
689 		pks_topo->mct_scb[0].fru_unit,
690 		pks_topo->mct_scb[0].fru_id,
691 		pks_topo->mct_scb[0].fru_version, 0);
692 	/*
693 	 * Slots
694 	 */
695 	log_printf("Slots present out of maximum %d\n",
696 	    pks_topo->max_units[SLOT], 0);
697 	for (i = 0; i < pks_topo->max_units[SLOT]; ++i) {
698 		if (pks_topo->mct_slots[i].fru_status != FRU_PRESENT)
699 			continue;
700 		index = (int)pks_topo->mct_slots[i].fru_type;
701 		log_printf("\tSlot %d occupant: %s;",
702 		    pks_topo->mct_slots[i].fru_unit, slot_occupants[index], 0);
703 		log_printf(" ID 0x%x; VER 0x%x ; ",
704 		    pks_topo->mct_slots[i].fru_id,
705 		    pks_topo->mct_slots[i].fru_version, 0);
706 		log_printf(" Slot health %d\n",
707 		    pks_topo->mct_slots[i].fru_health, 0);
708 		/* pks_topo->mct_slots[i].fru_health */
709 	}
710 
711 	/*
712 	 * PDU
713 	 */
714 	log_printf("PDUs present out of maximum %d\n",
715 	    pks_topo->max_units[PDU], 0);
716 	for (i = 0; i < pks_topo->max_units[PDU]; ++i) {
717 		if (pks_topo->mct_pdu[i].fru_status != FRU_PRESENT)
718 			continue;
719 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
720 		    pks_topo->mct_pdu[i].fru_type,
721 		    pks_topo->mct_pdu[i].fru_unit,
722 		    pks_topo->mct_pdu[i].fru_id,
723 		    pks_topo->mct_pdu[i].fru_version, 0);
724 		/* pks_topo->mct_pdu[i].fru_health */
725 	}
726 
727 	/*
728 	 * Power Supplies
729 	 */
730 	log_printf("Power Supplies present out of maximum %d\n",
731 	    pks_topo->max_units[PS], 0);
732 	for (i = 0; i < pks_topo->max_units[PS]; ++i) {
733 		if (pks_topo->mct_ps[i].fru_status != FRU_PRESENT)
734 			continue;
735 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
736 		    pks_topo->mct_ps[i].fru_type,
737 		    pks_topo->mct_ps[i].fru_unit,
738 		    pks_topo->mct_ps[i].fru_id,
739 		    pks_topo->mct_ps[i].fru_version, 0);
740 	}
741 
742 	/*
743 	 * Disks
744 	 */
745 	log_printf("Disks present out of maximum %d\n",
746 	    pks_topo->max_units[DISK], 0);
747 	for (i = 0; i < pks_topo->max_units[DISK]; ++i) {
748 		if (pks_topo->mct_disk[i].fru_status != FRU_PRESENT)
749 			continue;
750 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
751 		    pks_topo->mct_disk[i].fru_type,
752 		    pks_topo->mct_disk[i].fru_unit,
753 		    pks_topo->mct_disk[i].fru_id,
754 		    pks_topo->mct_disk[i].fru_version, 0);
755 	}
756 
757 	/*
758 	 * Fans
759 	 */
760 	log_printf("Fans present out of maximum %d\n",
761 	    pks_topo->max_units[FAN], 0);
762 	for (i = 0; i < pks_topo->max_units[FAN]; ++i) {
763 		if (pks_topo->mct_fan[i].fru_status != FRU_PRESENT)
764 			continue;
765 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
766 		    pks_topo->mct_fan[i].fru_type,
767 		    pks_topo->mct_fan[i].fru_unit,
768 		    pks_topo->mct_fan[i].fru_id,
769 		    pks_topo->mct_fan[i].fru_version, 0);
770 	}
771 
772 	/*
773 	 * SCBs
774 	 */
775 	log_printf("SCBs present out of maximum %d\n",
776 	    pks_topo->max_units[SCB], 0);
777 	for (i = 0; i < pks_topo->max_units[SCB]; ++i) {
778 		if (pks_topo->mct_scb[i].fru_status != FRU_PRESENT)
779 			continue;
780 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
781 		    pks_topo->mct_scb[i].fru_type,
782 		    pks_topo->mct_scb[i].fru_unit,
783 		    pks_topo->mct_scb[i].fru_id,
784 		    pks_topo->mct_scb[i].fru_version, 0);
785 	}
786 
787 	/*
788 	 * SSBs
789 	 */
790 	log_printf("SSBs present out of maximum %d\n",
791 	    pks_topo->max_units[SSB], 0);
792 	for (i = 0; i < pks_topo->max_units[SSB]; ++i) {
793 		if (pks_topo->mct_ssb[i].fru_status != FRU_PRESENT)
794 			continue;
795 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
796 		    pks_topo->mct_ssb[i].fru_type,
797 		    pks_topo->mct_ssb[i].fru_unit,
798 		    pks_topo->mct_ssb[i].fru_id,
799 		    pks_topo->mct_ssb[i].fru_version, 0);
800 	}
801 
802 	/*
803 	 * Alarms Cards
804 	 */
805 	log_printf("Alarm Cards present out of maximum %d\n",
806 	    pks_topo->max_units[ALARM], 0);
807 	for (i = 0; i < pks_topo->max_units[ALARM]; ++i) {
808 		if (pks_topo->mct_alarm[i].fru_status != FRU_PRESENT)
809 			continue;
810 		log_printf("\ttype %d; unit %d; id 0x%x; VER 0x%x\n",
811 		    pks_topo->mct_alarm[i].fru_type,
812 		    pks_topo->mct_alarm[i].fru_unit,
813 		    pks_topo->mct_alarm[i].fru_id,
814 		    pks_topo->mct_alarm[i].fru_version, 0);
815 	}
816 
817 	/*
818 	 * CFTMs
819 	 */
820 	log_printf("CFTMs present out of maximum %d\n",
821 	    pks_topo->max_units[CFTM], 0);
822 	for (i = 0; i < pks_topo->max_units[CFTM]; ++i) {
823 		if (pks_topo->mct_cftm[i].fru_status != FRU_PRESENT)
824 			continue;
825 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
826 		    pks_topo->mct_cftm[i].fru_type,
827 		    pks_topo->mct_cftm[i].fru_unit,
828 		    pks_topo->mct_cftm[i].fru_id,
829 		    pks_topo->mct_cftm[i].fru_version, 0);
830 	}
831 
832 	/*
833 	 * CRTMs
834 	 */
835 	log_printf("CRTMs present out of maximum %d\n",
836 	    pks_topo->max_units[CRTM], 0);
837 	for (i = 0; i < pks_topo->max_units[CRTM]; ++i) {
838 		if (pks_topo->mct_crtm[i].fru_status != FRU_PRESENT)
839 			continue;
840 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
841 		    pks_topo->mct_crtm[i].fru_type,
842 		    pks_topo->mct_crtm[i].fru_unit,
843 		    pks_topo->mct_crtm[i].fru_id,
844 		    pks_topo->mct_crtm[i].fru_version, 0);
845 	}
846 
847 	/*
848 	 * PRTMs
849 	 */
850 	log_printf("PRTMs present out of maximum %d\n",
851 	    pks_topo->max_units[PRTM], 0);
852 	for (i = 0; i < pks_topo->max_units[PRTM]; ++i) {
853 		if (pks_topo->mct_prtm[i].fru_status != FRU_PRESENT)
854 			continue;
855 		log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
856 		    pks_topo->mct_prtm[i].fru_type,
857 		    pks_topo->mct_prtm[i].fru_unit,
858 		    pks_topo->mct_prtm[i].fru_id,
859 		    pks_topo->mct_prtm[i].fru_version, 0);
860 	}
861 #endif	/* DEBUG_TEMP1 */
862 
863 }	/*  do_scsb_kstat(...) */
864 
865 
866 void
867 do_pcf8574_kstat()
868 {
869 	kstat_ctl_t	*kc;
870 	kstat_t		*ksp_ps;
871 	kstat_t		*ksp_fan;
872 	envctrl_pwrsupp_t *pks_ps;
873 	envctrl_fantray_t *pks_fan;
874 	int	i;
875 	char	*kstat_name = NULL;
876 
877 	if (!(kc = kstat_open())) {
878 #ifdef	DEBUG_TEMP
879 		log_printf("\nkstat_open for pcf8574 failed", 0);
880 #endif
881 		return;
882 	}
883 
884 #ifdef	lint
885 	kc = kc;
886 #endif
887 	/* get kstat on gpio powersupply and fan states */
888 	for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) {
889 		if (i == 1) {
890 			kstat_name = I2C_KSTAT_PWRSUPPLY;
891 			strncat(kstat_name, "1", 1);
892 		} else {
893 			kstat_name = I2C_KSTAT_PWRSUPPLY;
894 			strncat(kstat_name, "2", 1);
895 		}
896 		if ((ksp_ps = kstat_lookup(kc, I2C_PCF8574_NAME, 0, kstat_name))
897 			== NULL) {
898 #ifdef	DEBUG_TEMP
899 			log_printf("\nks lookup for pwrsupply%d failed",
900 			    i+1, 0);
901 #endif
902 			return;
903 		}
904 		if (kstat_read(kc, ksp_ps, NULL) == -1) {
905 #ifdef	DEBUG_TEMP
906 			log_printf("\nks read for pwrsupply%d failed", i+1, 0);
907 #endif
908 			return;
909 		}
910 		pks_ps = (envctrl_pwrsupp_t *)ksp_ps->ks_data;
911 		if (i == 1)
912 			pcf8574_ks_ps1 = *pks_ps; /* ps 1 */
913 		else
914 			pcf8574_ks_ps2 = *pks_ps; /* ps 2 */
915 	} /* for */
916 	for (i = 0; i < scsb_ks_topo.max_units[FAN]; ++i) {
917 		if (i == 1) {
918 			kstat_name = I2C_KSTAT_FANTRAY;
919 			strncat(kstat_name, "1", 1);
920 		} else {
921 			kstat_name = I2C_KSTAT_FANTRAY;
922 			strncat(kstat_name, "2", 1);
923 		}
924 		if ((ksp_fan = kstat_lookup(kc, I2C_PCF8574_NAME,
925 		    0, kstat_name)) == NULL) {
926 #ifdef	DEBUG_TEMP
927 			log_printf("\nks lookup for fantray%d failed",
928 			    i+1, 0);
929 #endif
930 			return;
931 		}
932 		if (kstat_read(kc, ksp_fan, NULL) == -1) {
933 #ifdef	DEBUG_TEMP
934 			log_printf("\nks read for fantray%d failed", i+1, 0);
935 #endif
936 			return;
937 		}
938 		pks_fan = (envctrl_fantray_t *)ksp_fan->ks_data;
939 		if (i == 1)
940 			pcf8574_ks_fant1 = *pks_fan; /* fan 1 */
941 		else
942 			pcf8574_ks_fant2 = *pks_fan; /* fan 2 */
943 	} /* for */
944 	kstat_close(kc);
945 
946 }	/*  do_pcf8574_kstat(...) */
947 
948 void
949 do_pcf8591_kstat()
950 {
951 	kstat_ctl_t	*kc;
952 	kstat_t		*ksp_temp;
953 
954 	envctrl_temp_t *pks_temp;
955 
956 	if (!(kc = kstat_open())) {
957 #ifdef	DEBUG_TEMP
958 		log_printf("ks open for pcf8591 failed", 0);
959 #endif
960 		return;
961 	}
962 #ifdef	lint
963 	kc = kc;
964 #endif
965 	/* get kstat on adc driver's CPU temperature data */
966 	if ((ksp_temp = kstat_lookup(kc, I2C_PCF8591_NAME,
967 	    -1, I2C_KSTAT_CPUTEMP))
968 	    == NULL) {
969 #ifdef	DEBUG_TEMP
970 		log_printf("ks lookup for adc_temp failed", 0);
971 #endif
972 		return;
973 	}
974 	if (kstat_read(kc, ksp_temp, NULL) == -1) {
975 #ifdef	DEBUG_TEMP
976 		log_printf("ks read for adc_temp failed", 0);
977 #endif
978 		return;
979 	}
980 	pks_temp = (envctrl_temp_t *)ksp_temp->ks_data;
981 	pcf8591_ks_temp = *pks_temp;
982 	kstat_close(kc);
983 }	/*  do_pcf8591_kstat(.) */
984 
985 
986 void
987 gather_diaginfo(int flag)
988 {
989 	if (flag) {
990 		/* gather system environmental conditions. */
991 		/* obtain kstat info from gpio & temp. driver */
992 		do_pcf8574_kstat();
993 		do_pcf8591_kstat();
994 		explore_slot_occupants();	/* fill in some occupant info */
995 		prtdiag_devinfo();
996 		analyze_pcipci_siblings(rootnode);
997 	}
998 
999 }	/* display_diaginfo(...) */
1000 
1001 void
1002 netract_disp_prom_version()
1003 {
1004 	/* Display Prom revision header */
1005 	log_printf(dgettext(TEXT_DOMAIN, "System Board PROM revision:\n"), 0);
1006 	log_printf("---------------------------\n", 0);
1007 	do_promversion();
1008 
1009 }	/* netract_disp_prom_version(.) */
1010 
1011 
1012 /*
1013  * Get and print the PROM version.
1014  */
1015 void
1016 do_promversion(void)
1017 {
1018 	Oppbuf  oppbuf;
1019 	struct openpromio *opp = &(oppbuf.opp);
1020 
1021 	if (mc_promopen(O_RDONLY))  {
1022 		log_printf(dgettext(TEXT_DOMAIN,
1023 		    "\nCannot open openprom device"), 0);
1024 		return;
1025 	}
1026 
1027 	opp->oprom_size = MAXVALSIZE;
1028 	if (ioctl(oprom_fd, OPROMGETVERSION, opp) < 0) {
1029 		perror("\nOPROMGETVERSION ioctl failed");
1030 		return;
1031 	}
1032 	log_printf("%s\n", opp->oprom_array, 0);
1033 
1034 	if (close(oprom_fd) < 0) {
1035 		log_printf(dgettext(TEXT_DOMAIN,
1036 		    "\nclose error on %s"), OPENPROMDEV, 0);
1037 		return;
1038 	}
1039 }	/* do_promversion() */
1040 
1041 int
1042 mc_promopen(int oflag)
1043 {
1044 	for (;;) {
1045 		if ((oprom_fd = open(OPENPROMDEV, oflag)) < 0) {
1046 			if (errno == EAGAIN) {
1047 				(void) sleep(5);
1048 				continue;
1049 			}
1050 			if (errno == ENXIO)
1051 				return (-1);
1052 			log_printf(dgettext(TEXT_DOMAIN,
1053 			    "\ncannot open %s"), OPENPROMDEV, 0);
1054 			return (1);
1055 		} else
1056 			return (0);
1057 	}
1058 }
1059 
1060 
1061 /*
1062  * This will return -1 for status unknown, 0 for OK, and 1 for failed (scsi
1063  * hard errors)
1064  * swiped from envmon policies
1065  */
1066 int
1067 scsi_disk_status(int disk_number)
1068 {
1069 	kstat_ctl_t    *kc;
1070 	kstat_t		*ksp_disk;
1071 	kstat_named_t  *disk_data;
1072 
1073 	int i;
1074 	int nlist = 0;
1075 	cfga_list_data_t *list_array = NULL;
1076 	char *ap_ids[] = {"c0"};
1077 
1078 	if ((kc = kstat_open()) == NULL) {
1079 		log_printf(dgettext(TEXT_DOMAIN, "\nks open failed"), 0);
1080 		return (-1);
1081 	}
1082 
1083 	if (disk_number == RMM_NUMBER) { /* RMM */
1084 		if (config_list_ext(1, ap_ids, &list_array, &nlist,
1085 			NULL, NULL, NULL, CFGA_FLAG_LIST_ALL) != CFGA_OK) {
1086 			kstat_close(kc);
1087 			return (-1);
1088 		}
1089 		for (i = 0; i < nlist; i++) {
1090 			if (strstr(list_array[i].ap_phys_id, "rmt/0") != NULL) {
1091 				/* Tape drive */
1092 				if (list_array[i].ap_o_state ==
1093 					CFGA_STAT_UNCONFIGURED) {
1094 					kstat_close(kc);
1095 					return (-1);
1096 				}
1097 				if ((ksp_disk = kstat_lookup(kc, STERR,
1098 						st_instance, NULL)) == NULL) {
1099 					kstat_close(kc);
1100 					return (-1);
1101 				}
1102 				break;
1103 			} else if (strstr(list_array[i].ap_phys_id,
1104 						"dsk/c0t6d0") != NULL) {
1105 				/* CD_ROM */
1106 				if (list_array[i].ap_o_state ==
1107 						CFGA_STAT_UNCONFIGURED) {
1108 					kstat_close(kc);
1109 					return (-1);
1110 				}
1111 				if ((ksp_disk = kstat_lookup(kc, SDERR,
1112 					sd_instances[disk_number-1], NULL)) ==
1113 									NULL) {
1114 					kstat_close(kc);
1115 					return (-1);
1116 				}
1117 				break;
1118 			}
1119 		}
1120 	} else { /* Hard disk */
1121 		if ((ksp_disk = kstat_lookup(kc, SDERR,
1122 			sd_instances[disk_number-1], NULL)) == NULL) {
1123 			kstat_close(kc);
1124 			return (-1);
1125 		}
1126 	}
1127 
1128 	if (kstat_read(kc, ksp_disk, NULL) == -1) {
1129 		log_printf(dgettext(TEXT_DOMAIN,
1130 		    "\nks read error for disk%d, drv inst%d"),
1131 		    disk_number, sd_instances[disk_number-1], 0);
1132 		kstat_close(kc);
1133 		return (-1);
1134 	}
1135 	disk_data = KSTAT_NAMED_PTR(ksp_disk);
1136 	/*
1137 	 * if disk_data[].value is >0, we have a problem
1138 	 */
1139 	if (disk_data[1].value.ui32 == 0) {
1140 		kstat_close(kc);
1141 		return (0);
1142 	} else {
1143 		kstat_close(kc);
1144 		return (1);
1145 	}
1146 }
1147 
1148 
1149 void
1150 prtdiag_devinfo(void)
1151 {
1152 	uint_t flag;
1153 	/* lets get everything we can from kernel */
1154 	flag = DINFOSUBTREE|DINFOPROP;
1155 	rootnode = di_init("/", flag);
1156 	if (rootnode == DI_NODE_NIL) {
1157 		log_printf(dgettext(TEXT_DOMAIN,
1158 		    "\nprtdiag_devinfo: di_init() failed"), 0);
1159 		return;
1160 	}
1161 	(void) di_walk_node(rootnode, DI_WALK_CLDFIRST, NULL,
1162 	    dump_devs);
1163 }
1164 
1165 
1166 /*
1167  * gather information about this node, returns appropriate code.
1168  * specific information we seek are driver names, instances
1169  * we will initialize some globals depending on what we find
1170  * from the kernel device tree info and may be private data
1171  * if required
1172  */
1173 /*ARGSUSED1*/
1174 int
1175 dump_devs(di_node_t node, void *arg)
1176 {
1177 	char *driver_name;
1178 
1179 	driver_name = di_driver_name(node);
1180 	/* we will initialize our globals here */
1181 	if ((di_instance(node) >= 0) &&
1182 	    (driver_name != NULL) &&
1183 	    (!(di_state(node) & DI_DRIVER_DETACHED))) {
1184 		if (strcmp(driver_name, "pcf8574") == 0) {
1185 			gpio_instances[gpio_count] = di_instance(node);
1186 			gpio_count++;
1187 		} else if (strcmp(driver_name, "sd") == 0) {
1188 			sd_instances[sd_count] =  di_instance(node);
1189 			sd_count++;
1190 		} else if (strcmp(driver_name, "st") == 0) {
1191 			st_instance = di_instance(node);
1192 		}
1193 	}
1194 
1195 	if (strcmp(di_node_name(node), "pseudo") == 0)
1196 		return (DI_WALK_PRUNECHILD);
1197 	else
1198 		return (DI_WALK_CONTINUE);
1199 }
1200 
1201 
1202 
1203 /*
1204  * Returns 0 if error , 1 otherwise
1205  */
1206 int
1207 dump_prop_list(char *name, di_node_t node, di_prop_t (*nxtprop)())
1208 {
1209 	int prop_len, i, k, max_slots_minus_cpu, n;
1210 	uchar_t *prop_data;
1211 	char	*p;
1212 	char   *temp_s;
1213 	di_prop_t prop, next;
1214 	int ret_value = 0;
1215 
1216 	max_slots_minus_cpu = scsb_ks_topo.max_units[SLOT]-1;
1217 
1218 	if ((next = nxtprop(node, DI_PROP_NIL)) == DI_PROP_NIL)
1219 		return (0);
1220 	while (next != DI_PROP_NIL) {
1221 		int maybe_str = 1, npossible_strs = 0;
1222 		prop = next;
1223 		next = nxtprop(node, prop);
1224 		/*
1225 		 * get prop length and value:
1226 		 * private interface--always success
1227 		 */
1228 		prop_len = di_prop_rawdata(prop, &prop_data);
1229 		if (di_prop_type(prop) == DDI_PROP_UNDEF_IT) {
1230 			continue;
1231 		}
1232 
1233 		if (prop_len == 0)  {
1234 			continue;
1235 		}
1236 		if (prop_data[prop_len - 1] != '\0') {
1237 			maybe_str = 0;
1238 		} else {
1239 			/*
1240 			 * Every character must be a string character or a \0,
1241 			 * and there must not be two \0's in a row.
1242 			 */
1243 			for (i = 0; i < prop_len; i++) {
1244 				if (prop_data[i] == '\0') {
1245 					npossible_strs++;
1246 				} else if (!isascii(prop_data[i]) ||
1247 				    iscntrl(prop_data[i])) {
1248 					maybe_str = 0;
1249 					break;
1250 				}
1251 
1252 				if ((i > 0) && (prop_data[i] == '\0') &&
1253 				    (prop_data[i - 1] == '\0')) {
1254 					maybe_str = 0;
1255 					break;
1256 				}
1257 			}
1258 		}
1259 
1260 		if (maybe_str) {
1261 			p = (char *)prop_data;
1262 			for (i = 0; i < npossible_strs - 1; i++) {
1263 				if ((strcmp(name, SYSSOFT_PROP) == 0) &&
1264 				    (strcmp(di_prop_name(prop),
1265 				    HSC_PROP_NAME) == 0)) {
1266 					temp_s = p;
1267 					temp_s += strlen(temp_s) + 1;
1268 				}
1269 				p += strlen(p) + 1;
1270 			}
1271 
1272 			if ((strcmp(name, SYSSOFT_PROP) == 0) &&
1273 			    (strcmp(di_prop_name(prop), HSC_PROP_NAME) == 0)) {
1274 				temp_s = temp_s - prop_len+2;
1275 				for (k = 0, n = 0; k < prop_len; k++) {
1276 					if (temp_s[k] == 0) {
1277 						n++;
1278 					}
1279 				}
1280 				if (n % 4) {
1281 					log_printf(dgettext(TEXT_DOMAIN,
1282 					    "\nbad slot-table(%d)\n"), n);
1283 					slot_table_not_found = 0;
1284 					return (ret_value);
1285 				}
1286 				slot_table_size = n / 4;
1287 				/*
1288 				 * NOTE : We save slot table info in order
1289 				 */
1290 				for (k = 0; k < slot_table_size; k++) {
1291 					char *nexus, *pcidev, *phys_slotname;
1292 					char *ga;
1293 					/*
1294 					 * Pick off pointer to nexus
1295 					 * path or PROM handle
1296 					 */
1297 					nexus = temp_s;
1298 					while (*temp_s != NULL)
1299 						temp_s++;
1300 					temp_s++;
1301 
1302 					/*
1303 					 * Pick off pointer to the
1304 					 * pci device number
1305 					 */
1306 					pcidev = temp_s;
1307 					while (*temp_s != NULL)
1308 						temp_s++;
1309 					temp_s++;
1310 
1311 					/* Pick off physical slot no */
1312 					phys_slotname = temp_s;
1313 					while (*temp_s != NULL)
1314 						temp_s++;
1315 					temp_s++;
1316 
1317 					/*
1318 					 * Pick off GA bits which
1319 					 * we dont use for now.
1320 					 */
1321 					ga = temp_s;
1322 					while (*temp_s != NULL)
1323 						temp_s++;
1324 					temp_s++;
1325 
1326 					hotswap_slot_table[k].pslotnum
1327 					    = atoi(phys_slotname);
1328 					hotswap_slot_table[k].ga = atoi(ga);
1329 					hotswap_slot_table[k].pci_devno
1330 					    = atoi(pcidev);
1331 					strcpy(hotswap_slot_table[k].nexus,
1332 					    nexus);
1333 				} /* for (k = 0; k < slot_table_size; k++) */
1334 
1335 				ret_value = 1;
1336 			} else /* (strcmp(name, SYSSOFT_PROP) */
1337 				slot_table_not_found = 1;
1338 
1339 			/*
1340 			 * now we want to save off the info
1341 			 * we would use later
1342 			 */
1343 			if ((strcmp(name, DRV_PROP) == 0) &&
1344 			    (strcmp(di_prop_name(prop), HSC_MODE) == 0)) {
1345 				hotswap_mode = p;
1346 				ret_value = 1;
1347 			} else if ((strcmp(name, DRV_PROP) == 0) &&
1348 			    (strcmp(di_prop_name(prop), HSC_MODE) != 0)) {
1349 				/* save it in order in the right index */
1350 				slot_auto_config[max_slots_minus_cpu] = p;
1351 				max_slots_minus_cpu--;
1352 				ret_value = 1;
1353 			}
1354 
1355 		} else {
1356 			for (i = 0; i < prop_len; ++i)  {
1357 #if	0
1358 				unsigned char byte;
1359 				byte = (unsigned char)prop_data[i];
1360 				log_printf("%2.2x", byte, 0);
1361 #endif
1362 			}
1363 		}
1364 	}
1365 	return (ret_value);
1366 }
1367 
1368 
1369 void
1370 display_mc_prtdiag_info()
1371 {
1372 	int i, index;
1373 	int s_index, i1;
1374 	int tg_cpu_index = 0;
1375 	char *mcfru_type, *status, *mc_ok_led, *mc_nok_led;
1376 	char *misc_info, *health, *board_type;
1377 
1378 	log_printf("===============================", 0);
1379 	log_printf(dgettext(TEXT_DOMAIN,
1380 	    " FRU Information ================================\n"), 0);
1381 	log_printf(dgettext(TEXT_DOMAIN,
1382 	    "FRU         FRU    FRU      Green    Amber"), 0);
1383 	log_printf(dgettext(TEXT_DOMAIN, "    Miscellaneous\n"), 0);
1384 	log_printf(dgettext(TEXT_DOMAIN,
1385 	    "Type        Unit#  Present  LED      LED"), 0);
1386 	log_printf(dgettext(TEXT_DOMAIN, "      Information\n"), 0);
1387 
1388 	log_printf("----------  -----  -------  -----    -----", 0);
1389 	log_printf("    ----------------------------------\n", 0);
1390 
1391 	if (scsb_ks_topo.mid_plane.fru_id == SCTRL_MPID_HALF)
1392 		misc_info = "Netra ct800";
1393 	else {
1394 		misc_info = "Netra ct400";
1395 	}
1396 	mcfru_type = prtdiag_fru_types[MIDPLANE];
1397 	switch (scsb_ks_topo.mid_plane.fru_status) {
1398 		case FRU_PRESENT:
1399 			status = YES;
1400 			break;
1401 		case FRU_NOT_PRESENT:
1402 			status = NO;
1403 			break;
1404 		case FRU_NOT_AVAILABLE:
1405 			status = NA; break;
1406 		default:
1407 			status = NA; break;
1408 		}
1409 	mc_ok_led = "   ";
1410 	mc_nok_led = "   ";
1411 
1412 	log_printf(dgettext(TEXT_DOMAIN,
1413 	    "%10s   %-5d  %-7s %-5s    %-5s   %s\n"),
1414 	    mcfru_type, scsb_ks_topo.mid_plane.fru_unit,
1415 	    status, mc_ok_led, mc_nok_led,
1416 	    misc_info, 0);
1417 	log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0);
1418 	log_printf(dgettext(TEXT_DOMAIN, "%49sVersion=%d\n"), BLANK,
1419 	    scsb_ks_topo.mid_plane.fru_version, 0);
1420 	log_printf(dgettext(TEXT_DOMAIN, "%49sMaximum Slots=%d\n"), BLANK,
1421 	    scsb_ks_topo.max_units[SLOT], 0);
1422 
1423 	/* SCB & SSB */
1424 	mcfru_type = prtdiag_fru_types[SCB];
1425 	for (i = 0; i < scsb_ks_topo.max_units[SCB]; ++i) {
1426 		misc_info = "System Controller Board";
1427 		if (version_p15_and_p20) {
1428 			mc_ok_led =
1429 			    BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[1]
1430 			    & 0xff), SCB_OK_BIT) ? BLINK :
1431 			    (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[1]
1432 			    & 0xff), SCB_OK_BIT) ? ON:OFF);
1433 			mc_nok_led =
1434 			    BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[1]
1435 			    & 0xff), SCB_OK_BIT) ? ON:OFF;
1436 		} else {
1437 			/*
1438 			 * support for 1.0 systems -
1439 			 * Hack! - should use tables ?
1440 			 */
1441 			mc_ok_led =
1442 			    (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2]
1443 			    & 0xff), 0) ? ON:OFF);
1444 			mc_nok_led =
1445 			    BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2]
1446 			    & 0xff), 0) ? ON:OFF;
1447 		}
1448 		switch (scsb_ks_topo.mct_scb[i].fru_status) {
1449 			case FRU_PRESENT:
1450 				status = YES;
1451 				break;
1452 			case FRU_NOT_PRESENT:
1453 				status = NO;
1454 				break;
1455 			case FRU_NOT_AVAILABLE:
1456 				status = NA;
1457 				break;
1458 			default:
1459 				status = NA;
1460 				break;
1461 		}
1462 		log_printf(dgettext(TEXT_DOMAIN,
1463 		    "%10s   %-5d  %-7s %-5s    %-5s   %s\n"),
1464 		    mcfru_type, scsb_ks_topo.mct_scb[i].fru_unit,
1465 		    status, mc_ok_led, mc_nok_led, misc_info, 0);
1466 		log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0);
1467 		log_printf(dgettext(TEXT_DOMAIN, "%49sVersion=%d\n"), BLANK,
1468 		    scsb_ks_topo.mct_scb[0].fru_version, 0);
1469 		if (fail_drv_prop == 1)
1470 			log_printf(dgettext(TEXT_DOMAIN,
1471 			    "%49s%s=%s\n"), BLANK, HSC_MODE,
1472 			    hotswap_mode, 0);
1473 	} /* for */
1474 
1475 	mcfru_type = prtdiag_fru_types[SSB];
1476 	for (i = 0; i < scsb_ks_topo.max_units[SSB]; ++i) {
1477 		misc_info = "System Status Panel";
1478 		switch (scsb_ks_topo.mct_ssb[i].fru_status) {
1479 			case FRU_PRESENT:
1480 				status = YES;
1481 				break;
1482 			case FRU_NOT_PRESENT:
1483 				status = NO;
1484 				break;
1485 			case FRU_NOT_AVAILABLE:
1486 				status = NA;
1487 				break;
1488 			default:
1489 				status = NA;
1490 				break;
1491 		}
1492 		log_printf(dgettext(TEXT_DOMAIN,
1493 		    "%10s   %-5d  %-7s %-5s    %-5s   %s\n"),
1494 		    mcfru_type, scsb_ks_topo.mct_ssb[i].fru_unit,
1495 		    status, BLANK, BLANK, misc_info, 0);
1496 	} /* for */
1497 
1498 	/* Slots */
1499 	for (i = 0; i < scsb_ks_topo.max_units[SLOT]; ++i) {
1500 		if (montecarlo) {
1501 			if (scsb_ks_topo.mct_slots[i].fru_unit == 1)
1502 				mcfru_type = prtdiag_fru_types[1];
1503 			else
1504 				mcfru_type = prtdiag_fru_types[SLOT];
1505 			/*
1506 			 * Another way this could have been done is,
1507 			 * to read the sub system id
1508 			 * it is 0x6722 for Alarm Card
1509 			 * but this id is only valid for the new ACs
1510 			 * older ACs still have the same susbsystem
1511 			 * id as most other Sun PCI cards
1512 			 * We cannot completely rely on this.
1513 			 * Also,it turns out that Sun OpenBoot does not
1514 			 * always follow IEEE 1275 std, hence in a few
1515 			 * systems, the "subsystem-id" published by the
1516 			 * PROM could not be found
1517 			 * We know the AC slot# if present on both MC&Tg
1518 			 * Hence we check on both - now we are sure
1519 			 * that we have found an AC
1520 			 */
1521 			if ((scsb_ks_topo.mct_slots[i].fru_unit == 8) &&
1522 			    (alarm_card_present == 1))
1523 				board_type = AC_CARD;
1524 			else
1525 				board_type = UK;
1526 		} else {
1527 			if (scsb_ks_topo.mct_slots[i].fru_unit == 3)
1528 				mcfru_type = prtdiag_fru_types[1];
1529 			else
1530 				mcfru_type = prtdiag_fru_types[SLOT];
1531 			/*
1532 			 * Another way this could have been done is,
1533 			 * to read the sub system id
1534 			 * it is 0x6722 for Alarm Card
1535 			 * but this id is only valid for the new ACs
1536 			 * older ACs still have the same susbsystem
1537 			 * id as most other Sun PCI cards
1538 			 * We cannot completely rely on this.
1539 			 * Also,it turns out that Sun OpenBoot does not
1540 			 * always follow IEEE 1275 std, hence in a few
1541 			 * systems, the "subsystem-id" published by the
1542 			 * PROM could not be found
1543 			 * We know the AC slot# if present on both MC&Tg
1544 			 * Hence we check on both - now we are sure
1545 			 * that we have found an AC
1546 			 */
1547 			if ((scsb_ks_topo.mct_slots[i].fru_unit == 1) &&
1548 			    (alarm_card_present == 1))
1549 				board_type = AC_CARD;
1550 			else
1551 				board_type = UK;
1552 		}
1553 		if (version_p15_and_p20) {
1554 			mc_ok_led =
1555 			    BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[0]
1556 			    & 0xff), i) ? BLINK :
1557 			    (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[0]
1558 			    & 0xff), i) ? ON:OFF);
1559 			mc_nok_led =
1560 			    BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[0]
1561 			    & 0xff), i) ? ON:OFF;
1562 		} else {
1563 			/*
1564 			 * support for 1.0 systems -
1565 			 * Hack! - should use tables ?
1566 			 */
1567 			if (scsb_ks_topo.mct_slots[i].fru_unit == 7) {
1568 				mc_ok_led =
1569 				    BIT_TEST(
1570 				    (scsb_ks_leddata.leds.p10.blink_leds[1]
1571 				    & 0xff), 0) ? BLINK :
1572 				    (BIT_TEST(
1573 				    (scsb_ks_leddata.leds.p10.ok_leds[1]
1574 				    & 0xff), 0) ? ON:OFF);
1575 				mc_nok_led =
1576 				    BIT_TEST(
1577 				    (scsb_ks_leddata.leds.p10.nok_leds[1]
1578 				    & 0xff), 0) ? ON:OFF;
1579 			} else  if (scsb_ks_topo.mct_slots[i].fru_unit == 8) {
1580 				mc_ok_led =
1581 				    BIT_TEST(
1582 				    (scsb_ks_leddata.leds.p10.blink_leds[1]
1583 				    & 0xff), 1) ? BLINK :
1584 				    (BIT_TEST(
1585 				    (scsb_ks_leddata.leds.p10.ok_leds[1]
1586 				    & 0xff), 1) ? ON:OFF);
1587 				mc_nok_led =
1588 				    BIT_TEST(
1589 				    (scsb_ks_leddata.leds.p10.nok_leds[1]
1590 				    & 0xff), 1) ? ON:OFF;
1591 			} else {
1592 				/*
1593 				 * for all other slots offset,
1594 				 * index are the same
1595 				 */
1596 				mc_ok_led =
1597 				    BIT_TEST(
1598 				    (scsb_ks_leddata.leds.p10.blink_leds[0]
1599 				    & 0xff), i) ? BLINK :
1600 				    (BIT_TEST(
1601 				    (scsb_ks_leddata.leds.p10.ok_leds[0]
1602 				    & 0xff), i) ? ON:OFF);
1603 				mc_nok_led =
1604 				    BIT_TEST(
1605 				    (scsb_ks_leddata.leds.p10.nok_leds[0]
1606 				    & 0xff), i) ? ON:OFF;
1607 			}
1608 
1609 		} /* else if (!version_p15_and_p20) */
1610 
1611 		switch (scsb_ks_topo.mct_slots[i].fru_status) {
1612 			case FRU_PRESENT:
1613 				status = YES;
1614 				break;
1615 			case FRU_NOT_PRESENT:
1616 				status = NO;
1617 				break;
1618 			case FRU_NOT_AVAILABLE:
1619 				status = NA;
1620 				break;
1621 			default:
1622 				status = NA;
1623 				break;
1624 		}
1625 
1626 		index = (int)scsb_ks_topo.mct_slots[i].fru_type;
1627 		if (montecarlo) {
1628 			if (scsb_ks_topo.mct_slots[i].fru_unit == 1) {
1629 				/* cpu slot */
1630 				log_printf(dgettext(TEXT_DOMAIN,
1631 				    "%10s   %-5d  %-7s %-5s    "),
1632 				    mcfru_type,
1633 				    scsb_ks_topo.mct_slots[i].fru_unit,
1634 				    status, mc_ok_led, mc_nok_led, 0);
1635 				log_printf(dgettext(TEXT_DOMAIN, "%-5s   %s\n"),
1636 				    mc_nok_led,
1637 				    slot_occupants[index], 0);
1638 				log_printf(dgettext(TEXT_DOMAIN,
1639 				    "%49stemperature(celsius):%d\n"),
1640 				    BLANK,
1641 				    pcf8591_ks_temp.value, 0);
1642 #ifdef	NEVER
1643 				log_printf(dgettext(TEXT_DOMAIN,
1644 				    "%49sminimum temperature:%d\n"),
1645 				    BLANK,
1646 				    pcf8591_ks_temp.min, 0);
1647 				log_printf(dgettext(TEXT_DOMAIN,
1648 				    "%49swarning temp. threshold:%d\n"),
1649 				    BLANK,
1650 				    pcf8591_ks_temp.warning_threshold, 0);
1651 				log_printf(dgettext(TEXT_DOMAIN,
1652 				    "%49sshutdown temp.threshold:%d\n"),
1653 				    BLANK,
1654 				    pcf8591_ks_temp.shutdown_threshold, 0);
1655 #endif	/* NEVER */
1656 			} else if ((scsb_ks_topo.mct_slots[i].fru_unit == 2) &&
1657 			    (cpu_ftm_present == 1)) {
1658 				/* CFTM slot */
1659 				/*
1660 				 * The CFTM can only be present in Slot 2
1661 				 * for Netract-800, for Netract-400 the FTM
1662 				 * is not sitted in a Slot. Hence, this is
1663 				 * another special case and we need to handle
1664 				 * this differently than other slots
1665 				 */
1666 				log_printf(dgettext(TEXT_DOMAIN,
1667 				    "%10s   %-5d  %-7s %-5s    "),
1668 				    mcfru_type,
1669 				    scsb_ks_topo.mct_slots[i].fru_unit,
1670 				    status, mc_ok_led, mc_nok_led, 0);
1671 				log_printf(dgettext(TEXT_DOMAIN, "%-5s   %s\n"),
1672 				    mc_nok_led,
1673 				    CPU_FTM, 0);
1674 			} else {
1675 				if (fail_drv_prop == 1) {
1676 					log_printf(dgettext(TEXT_DOMAIN,
1677 					    "%10s   %-5d  %-7s %-5s    "),
1678 					    mcfru_type,
1679 					    scsb_ks_topo.mct_slots[i].fru_unit,
1680 					    status, mc_ok_led, 0);
1681 					log_printf(dgettext(TEXT_DOMAIN,
1682 					    "%-5s   %s\n"),
1683 					    mc_nok_led,
1684 					    slot_occupants[index], 0);
1685 					log_printf(dgettext(TEXT_DOMAIN,
1686 					    "%46s%s\n"), BLANK,
1687 					    PROPS, 0);
1688 					log_printf(dgettext(TEXT_DOMAIN,
1689 					    "%49sauto-config=%s\n"),
1690 					    BLANK,
1691 					    slot_auto_config[i], 0);
1692 				} else {
1693 				log_printf(dgettext(TEXT_DOMAIN,
1694 				    "%10s   %-5d  %-7s %-5s    "),
1695 				    mcfru_type,
1696 				    scsb_ks_topo.mct_slots[i].fru_unit,
1697 				    status, mc_ok_led, 0);
1698 				log_printf(dgettext(TEXT_DOMAIN, "%-5s   %s\n"),
1699 				    mc_nok_led,
1700 				    slot_occupants[index], 0);
1701 				}
1702 			}
1703 		} else { /* tonga */
1704 			if (scsb_ks_topo.mct_slots[i].fru_unit == 3) {
1705 				/* cpu slot */
1706 				log_printf(dgettext(TEXT_DOMAIN,
1707 				    "%10s   %-5d  %-7s %-5s    "),
1708 				    mcfru_type,
1709 				    scsb_ks_topo.mct_slots[i].fru_unit,
1710 				    status, mc_ok_led, 0);
1711 				log_printf(dgettext(TEXT_DOMAIN, "%-5s   %s\n"),
1712 				    mc_nok_led,
1713 				    slot_occupants[index], 0);
1714 				log_printf(dgettext(TEXT_DOMAIN,
1715 				    "%49stemperature(celsius):%d\n"),
1716 				    BLANK,
1717 				    pcf8591_ks_temp.value, 0);
1718 #ifdef	NEVER
1719 
1720 				log_printf(dgettext(TEXT_DOMAIN,
1721 				    "%49sminimum temperature:%d\n"),
1722 				    BLANK,
1723 				    pcf8591_ks_temp.min, 0);
1724 				log_printf(dgettext(TEXT_DOMAIN,
1725 				    "%49swarning temp. threshold:%d\n"),
1726 				    BLANK,
1727 				    pcf8591_ks_temp.warning_threshold, 0);
1728 				log_printf(dgettext(TEXT_DOMAIN,
1729 				    "%49sshutdown temp. threshold:%d\n"),
1730 				    BLANK,
1731 				    pcf8591_ks_temp.shutdown_threshold, 0);
1732 #endif	/* NEVER */
1733 			} else {
1734 				if (fail_drv_prop == 1) {
1735 					log_printf(dgettext(TEXT_DOMAIN,
1736 					    "%10s   %-5d  %-7s %-5s    "),
1737 					    mcfru_type,
1738 					    scsb_ks_topo.mct_slots[i].fru_unit,
1739 					    status, mc_ok_led, 0);
1740 					log_printf(dgettext(TEXT_DOMAIN,
1741 					    "%-5s   %s\n"),
1742 					    mc_nok_led,
1743 					    slot_occupants[index], 0);
1744 
1745 					log_printf(dgettext(TEXT_DOMAIN,
1746 					    "%46s%s\n"), BLANK, PROPS, 0);
1747 					log_printf(dgettext(TEXT_DOMAIN,
1748 					    "%49sauto-config=%s\n"),
1749 					    BLANK,
1750 					    slot_auto_config[tg_cpu_index+1],
1751 					    0);
1752 					if (scsb_ks_topo.mct_slots[i].fru_unit
1753 					    != 3)
1754 						tg_cpu_index++;
1755 				} else {
1756 				log_printf(dgettext(TEXT_DOMAIN,
1757 				    "%10s   %-5d  %-7s %-5s    "),
1758 				    mcfru_type,
1759 				    scsb_ks_topo.mct_slots[i].fru_unit,
1760 				    status, mc_ok_led, 0);
1761 				log_printf(dgettext(TEXT_DOMAIN, "%-5s   %s\n"),
1762 				    mc_nok_led,
1763 				    slot_occupants[index], 0);
1764 				}
1765 			}
1766 		}
1767 		/* we first match the correct slot numbers */
1768 		for (s_index = 0; s_index < slot_table_size; s_index++) {
1769 			if (slot_table_not_found == 1) {
1770 			/* use prom table */
1771 			if (scsb_ks_topo.mct_slots[i].fru_unit ==
1772 			    prom_slot_table[s_index].pslotnum) {
1773 				/*
1774 				 * search for the addr/pci num
1775 				 * in all slot info structs
1776 				 */
1777 				for (i1 = 0; i1 < slot_index;
1778 				    i1++) {
1779 			if (prom_slot_table[s_index].pci_devno ==
1780 			    mc_slots_data.mc_slot_info[i1].slot_addr) {
1781 					int nd;
1782 					log_printf(dgettext(TEXT_DOMAIN,
1783 					    "%46s%s%s\n"), BLANK,
1784 					    BOARDTYPE, board_type, 0);
1785 					log_printf(dgettext(TEXT_DOMAIN,
1786 					    "%46s%s\n"), BLANK, DEVS, 0);
1787 					log_printf(dgettext(TEXT_DOMAIN,
1788 					    "%49s%s\n"), BLANK,
1789 					    PCI_ROOT_AP, 0);
1790 			for (nd = 0;
1791 			    nd < mc_slots_data.mc_slot_info[i1].number_devs;
1792 				    nd++) {
1793 			log_printf(dgettext(TEXT_DOMAIN, "%52s%s\n"), BLANK,
1794 			    mc_slots_data.mc_slot_info[i1].devs_info[nd],
1795 			    0);
1796 						} /* for */
1797 
1798 					} /* if */
1799 
1800 				} /* for(i1) */
1801 
1802 			} /* if */
1803 
1804 		} else {
1805 			/* use solaris lot table */
1806 			if (fail_syssoft_prop == 1) {
1807 				if (scsb_ks_topo.mct_slots[i].fru_unit ==
1808 				hotswap_slot_table[s_index].pslotnum) {
1809 					/*
1810 					 * search for the addr/pci
1811 					 * num in all slot info structs
1812 					 */
1813 					for (i1 = 0; i1 < slot_index; i1++) {
1814 				if (hotswap_slot_table[s_index].pci_devno ==
1815 				    mc_slots_data.mc_slot_info[i1].slot_addr) {
1816 					int nd;
1817 			for (nd = 0;
1818 			    nd < mc_slots_data.mc_slot_info[i1].number_devs;
1819 			    nd++) {
1820 			log_printf(dgettext(TEXT_DOMAIN, "%49s%s\n"), BLANK,
1821 			    mc_slots_data.mc_slot_info[i1].devs_info[nd],
1822 			    0);
1823 							}
1824 						} /* if */
1825 
1826 					} /* for(i1) */
1827 
1828 				} /* if */
1829 
1830 			} /* (fail_syssoft_prop == 1) */
1831 
1832 			}  /* (slot_table_not_found == 1) */
1833 
1834 		} /* for(s_index) */
1835 
1836 	}	/* for */
1837 	mcfru_type = "PDU";
1838 	misc_info = "Power Distribution Unit";
1839 	for (i = 0; i < scsb_ks_topo.max_units[PDU]; ++i) {
1840 		if (version_p15_and_p20) {
1841 			mc_ok_led =
1842 			    BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[1]
1843 			    & 0xff), PDU1_OK_BIT+i*2) ? BLINK :
1844 			    (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[1]
1845 			    & 0xff), PDU1_OK_BIT+i*2) ? ON:OFF);
1846 			mc_nok_led =
1847 			    BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[1]
1848 			    & 0xff), PDU1_OK_BIT+i*2) ? ON:OFF;
1849 		}
1850 		switch (scsb_ks_topo.mct_pdu[i].fru_status) {
1851 			case FRU_PRESENT:
1852 				status = YES;
1853 				break;
1854 			case FRU_NOT_PRESENT:
1855 				status = NO;
1856 				break;
1857 			case FRU_NOT_AVAILABLE:
1858 				status = NA;
1859 				break;
1860 			default:
1861 				status = NA;
1862 				break;
1863 		}
1864 		if (version_p15_and_p20) {
1865 			log_printf(dgettext(TEXT_DOMAIN,
1866 			    "%-10s    %-5d  %-7s %-5s    %-5s   %s\n"),
1867 			    mcfru_type, scsb_ks_topo.mct_pdu[i].fru_unit,
1868 			    status, mc_ok_led, mc_nok_led, misc_info, 0);
1869 		} else {
1870 			log_printf(dgettext(TEXT_DOMAIN,
1871 			    "%-10s    %-5d  %-7s%18s%s\n"),
1872 			    mcfru_type, scsb_ks_topo.mct_pdu[i].fru_unit,
1873 			    status, BLANK, misc_info, 0);
1874 		}
1875 	} /* for */
1876 
1877 	/* PS */
1878 	mcfru_type = prtdiag_fru_types[PS];
1879 	misc_info = "Power Supply Unit";
1880 	for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) {
1881 		if (version_p15_and_p20) {
1882 			mc_ok_led =
1883 			    BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[2]
1884 			    & 0xff), PS1_OK_BIT+i) ? BLINK :
1885 			    (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2]
1886 			    & 0xff), PS1_OK_BIT+i) ? ON:OFF);
1887 			mc_nok_led =
1888 			    BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2]
1889 			    & 0xff), PS1_OK_BIT+i) ? ON:OFF;
1890 		} else {
1891 			/*
1892 			 * support for 1.0 systems -
1893 			 * Hack! - should use tables ?
1894 			 */
1895 			mc_ok_led =
1896 			    (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2]
1897 			    & 0xff), 1+i) ? ON:OFF);
1898 			mc_nok_led =
1899 			    BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2]
1900 			    & 0xff), 1+i) ? ON:OFF;
1901 		}
1902 		switch (scsb_ks_topo.mct_ps[i].fru_status) {
1903 			case FRU_PRESENT:
1904 				status = YES;
1905 				break;
1906 			case FRU_NOT_PRESENT:
1907 				status = NO;
1908 				break;
1909 			case FRU_NOT_AVAILABLE:
1910 				status = NA;
1911 				break;
1912 			default:
1913 				status = NA;
1914 				break;
1915 		}
1916 		log_printf(dgettext(TEXT_DOMAIN,
1917 		    "%10s   %-5d  %-7s %-5s    %-5s   %s\n"),
1918 		    mcfru_type, scsb_ks_topo.mct_ps[i].fru_unit,
1919 		    status, mc_ok_led, mc_nok_led,
1920 		    misc_info, 0);
1921 		if (scsb_ks_topo.mct_ps[i].fru_status == FRU_PRESENT) {
1922 			if (scsb_ks_topo.mct_ps[i].fru_unit == 1) {
1923 				log_printf(dgettext(TEXT_DOMAIN,
1924 				    "%49scondition:%s\n"), BLANK,
1925 				    ((pcf8574_ks_ps1.ps_ok)? NOK:OK), 0);
1926 				log_printf(dgettext(TEXT_DOMAIN,
1927 				    "%49stemperature:%s\n"), BLANK,
1928 				    ((pcf8574_ks_ps1.temp_ok)? NOK:OK), 0);
1929 				log_printf(dgettext(TEXT_DOMAIN,
1930 				    "%49sps fan:%s\n"), BLANK,
1931 				    ((pcf8574_ks_ps1.psfan_ok)? NOK:OK), 0);
1932 				log_printf(dgettext(TEXT_DOMAIN,
1933 				    "%49ssupply:%s\n"), BLANK,
1934 				    ((pcf8574_ks_ps1.on_state)? OFF:ON), 0);
1935 			} else {
1936 				log_printf(dgettext(TEXT_DOMAIN,
1937 				    "%49scondition:%s\n"), BLANK,
1938 				    ((pcf8574_ks_ps2.ps_ok)? NOK:OK), 0);
1939 				log_printf(dgettext(TEXT_DOMAIN,
1940 				    "%49stemperature:%s\n"), BLANK,
1941 				    ((pcf8574_ks_ps2.temp_ok)? NOK:OK), 0);
1942 				log_printf(dgettext(TEXT_DOMAIN,
1943 				    "%49sps fan:%s\n"), BLANK,
1944 				    ((pcf8574_ks_ps2.psfan_ok)? NOK:OK), 0);
1945 				log_printf(dgettext(TEXT_DOMAIN,
1946 				    "%49ssupply:%s\n"), BLANK,
1947 				    ((pcf8574_ks_ps2.on_state)? OFF:ON), 0);
1948 			} /* if */
1949 		}
1950 
1951 	} /* for */
1952 
1953 	/* Fan tray */
1954 	mcfru_type = prtdiag_fru_types[FAN];
1955 	misc_info = "Fan Tray";
1956 	for (i = 0; i < scsb_ks_topo.max_units[FAN]; ++i) {
1957 		if (version_p15_and_p20) {
1958 			mc_ok_led =
1959 			    BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[2]
1960 			    & 0xff), FAN1_OK_BIT+i) ? BLINK :
1961 			    (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2]
1962 			    & 0xff), FAN1_OK_BIT+i) ? ON:OFF);
1963 			mc_nok_led =
1964 			    BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2]
1965 			    & 0xff), FAN1_OK_BIT+i) ? ON:OFF;
1966 		} else {
1967 			/*
1968 			 * support for 1.0 systems -
1969 			 * Hack! - should use tables ?
1970 			 */
1971 			mc_ok_led =
1972 			    (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[3]
1973 			    & 0xff), 3+i) ? ON:OFF);
1974 			mc_nok_led =
1975 			    BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[3]
1976 			    & 0xff), 3+i) ? ON:OFF;
1977 		}
1978 		switch (scsb_ks_topo.mct_fan[i].fru_status) {
1979 			case FRU_PRESENT:
1980 				status = YES;
1981 				break;
1982 			case FRU_NOT_PRESENT:
1983 				status = NO;
1984 				break;
1985 			case FRU_NOT_AVAILABLE:
1986 				status = NA;
1987 				break;
1988 			default:
1989 				status = NA;
1990 				break;
1991 		}
1992 		log_printf(dgettext(TEXT_DOMAIN,
1993 		    "%10s   %-5d  %-7s %-5s    %-5s   %s\n"),
1994 		    mcfru_type, scsb_ks_topo.mct_fan[i].fru_unit,
1995 		    status, mc_ok_led, mc_nok_led,
1996 		    misc_info, 0);
1997 		if (scsb_ks_topo.mct_fan[i].fru_status == FRU_PRESENT) {
1998 			if (scsb_ks_topo.mct_fan[i].fru_unit == 1) {
1999 				log_printf(dgettext(TEXT_DOMAIN,
2000 				    "%49scondition:%s\n"), BLANK,
2001 				    ((pcf8574_ks_fant1.fan_ok)? OK:NOK), 0);
2002 				log_printf(dgettext(TEXT_DOMAIN,
2003 				    "%49sfan speed:%s\n"), BLANK,
2004 				    ((pcf8574_ks_fant1.fanspeed)? HI:LO), 0);
2005 			} else {
2006 				log_printf(dgettext(TEXT_DOMAIN,
2007 				    "%49scondition:%s\n"), BLANK,
2008 				    ((pcf8574_ks_fant2.fan_ok)? OK:NOK), 0);
2009 				log_printf(dgettext(TEXT_DOMAIN,
2010 				    "%49sfan speed:%s\n"), BLANK,
2011 				    ((pcf8574_ks_fant2.fanspeed)? HI:LO), 0);
2012 			}
2013 		}
2014 
2015 	} /* for */
2016 
2017 	/* DISKS */
2018 	for (i = 0; i < scsb_ks_topo.max_units[DISK]; ++i) {
2019 		if (scsb_ks_topo.mct_disk[i].fru_unit != RMM_NUMBER)
2020 			mcfru_type = prtdiag_fru_types[DISK];
2021 		else
2022 			mcfru_type = "RMM        ";
2023 		switch (scsb_ks_topo.mct_disk[i].fru_status) {
2024 			case FRU_PRESENT:
2025 				status = YES;
2026 				break;
2027 			case FRU_NOT_PRESENT:
2028 				status = NO;
2029 				break;
2030 			case FRU_NOT_AVAILABLE:
2031 				status = NA;
2032 				break;
2033 			default:
2034 				status = NA;
2035 				break;
2036 		}
2037 		if (version_p15_and_p20) {
2038 			mc_ok_led =
2039 			    BIT_TEST((scsb_ks_leddata.scb_led_regs[8]
2040 			    & 0xff), DISK1_OK_BIT+i) ? BLINK :
2041 			    (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2]
2042 			    & 0xff), DISK1_OK_BIT+i) ? ON:OFF);
2043 			mc_nok_led =
2044 			    BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2]
2045 			    & 0xff), DISK1_OK_BIT+i) ? ON:OFF;
2046 		} else {
2047 			/*
2048 			 * support for 1.0 systems -
2049 			 * Hack! - should use tables ?
2050 			 */
2051 			mc_ok_led =
2052 			    (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2]
2053 			    & 0xff), DISK1_OK_BIT+i) ? ON:OFF);
2054 			mc_nok_led =
2055 			    BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2]
2056 			    & 0xff), DISK1_OK_BIT+i) ? ON:OFF;
2057 		}
2058 		/* print everything except condition */
2059 		if (scsb_ks_topo.mct_disk[i].fru_unit != RMM_NUMBER) {
2060 			misc_info = "Hard Disk Drive";
2061 			log_printf(dgettext(TEXT_DOMAIN,
2062 			    "%10s   %-5d  %-7s %-5s    %-5s   %s\n"),
2063 			    mcfru_type, scsb_ks_topo.mct_disk[i].fru_unit-1,
2064 			    status, mc_ok_led, mc_nok_led, misc_info, 0);
2065 		} else {
2066 			misc_info = "Removable Media Module";
2067 			log_printf(dgettext(TEXT_DOMAIN,
2068 			    "%10s   %5s  %-7s %-5s    %-5s   %s\n"),
2069 			    mcfru_type, BLANK,
2070 			    status, mc_ok_led, mc_nok_led, misc_info, 0);
2071 		}
2072 
2073 		/* find out fru health from the SCSI drivers */
2074 		if (scsb_ks_topo.mct_disk[i].fru_status == FRU_PRESENT) {
2075 			switch (
2076 			    scsi_disk_status(
2077 			    scsb_ks_topo.mct_disk[i].fru_unit)) {
2078 				case 0:
2079 					health = OK;
2080 					break;
2081 				case 1:
2082 					health = NOK;
2083 					break;
2084 				case -1:
2085 					health = UK;
2086 					break;
2087 				default:
2088 					health = NA;
2089 					break;
2090 			}
2091 			log_printf(dgettext(TEXT_DOMAIN,
2092 			    "%49scondition:%s\n"), BLANK, health, 0);
2093 		}
2094 
2095 	}	/* for */
2096 
2097 	log_printf(dgettext(TEXT_DOMAIN, "\n"), 0);
2098 
2099 }	/*  display_mc_prtdiag_info() */
2100 
2101 
2102 void
2103 analyze_pcipci_siblings(di_node_t node)
2104 {
2105 	di_node_t lc_node;
2106 	/* we will find all the dev info for slots first */
2107 	lc_node = di_drv_first_node("pci_pci", node);
2108 	lc_node = di_child_node(lc_node);
2109 	/* we are at "pci" node now */
2110 	do  {
2111 		if (di_walk_node(lc_node, DI_WALK_CLDFIRST,
2112 		    NULL, analyze_nodes) != 0) {
2113 			return;
2114 		}
2115 	} while ((lc_node = di_sibling_node(lc_node)) != DI_NODE_NIL);
2116 
2117 	/* now we wll gather info on sysctrl */
2118 	lc_node = di_drv_first_node(SCSB_DEV, node);
2119 	if (lc_node != DI_NODE_NIL)
2120 		analyze_nodes(lc_node, "sysctrl");
2121 }	/* analyze_pcipci_siblings(.) */
2122 
2123 
2124 int
2125 analyze_nodes(di_node_t l_node, void *arg)
2126 {
2127 	char *temp;
2128 	char *name, *pname;
2129 	di_node_t parent;
2130 	/*
2131 	 *  we will figure out whether the parent node is "pci" type
2132 	 *  we will save info only in this case as we only want to
2133 	 * print out the nodes under AP and not others
2134 	 */
2135 	parent = di_parent_node(l_node);
2136 	pname =  di_node_name(parent);
2137 	name = di_node_name(l_node);
2138 	/*
2139 	 * if this is PCI bridge, we know that this is the AP for slots
2140 	 * hence, we will save off the address(to convert to slot mapping)
2141 	 * later, and also we will start saving off slot info struct for
2142 	 * reporting later
2143 	 * we will save the immediate childs of this bridge only
2144 	 */
2145 	if (strcmp(name, "pci") == 0) {
2146 		num_devs = 0;
2147 		if ((temp = di_bus_addr(l_node)) != NULL) {
2148 			mc_slots_data.mc_slot_info[slot_index].slot_addr
2149 			    = (int)strtol(temp, (char **)NULL, 16);
2150 		}
2151 		slot_index++;
2152 	} else {
2153 		if (strcmp(pname, "pci") == 0) {
2154 	if ((mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs])
2155 	    != NULL) {
2156 	(void) strcat(
2157 	    mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs],
2158 	    name);
2159 			} else {
2160 	(void) strcpy(
2161 	    mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs],
2162 	    name);
2163 			} /* if ((mc_slots_data.mc_slot_inf */
2164 
2165 			num_devs++;
2166 			mc_slots_data.mc_slot_info[slot_index-1].number_devs
2167 			    = num_devs;
2168 		} /* if parent is pci */
2169 
2170 	} /* if node is pci */
2171 	if (arg != NULL) {
2172 		if (strcmp((char *)arg, "sysctrl") == 0) {
2173 			if (dump_prop_list("System", l_node,
2174 			    di_prop_sys_next)) {
2175 				(void) dump_prop_list(NULL, l_node,
2176 				    di_prop_global_next);
2177 			} else {
2178 				fail_syssoft_prop =
2179 				    dump_prop_list(SYSSOFT_PROP,
2180 				    l_node, di_prop_global_next);
2181 			}
2182 
2183 			fail_drv_prop =
2184 			    dump_prop_list(DRV_PROP, l_node,
2185 			    di_prop_drv_next);
2186 			/*
2187 			 * (void) dump_prop_list("Hardware",
2188 			 *   l_node, di_prop_hw_next);
2189 			 */
2190 			/*  dump_priv_data(l_node); */
2191 		}
2192 	}
2193 
2194 	return	(0);
2195 
2196 }	/* analyze_nodes(..) */
2197 
2198 
2199 
2200 /*
2201  * To get the slot information,
2202  * The OBP defines the 'slot-table' property. But the OS
2203  * can override it with 'hsc-slot-map' property
2204  * through the .conf file.
2205  * Since the formats are different, 2 different property names
2206  * are chosen.
2207  * The OBP property format is
2208  * <phandle>,<pci-devno>,<phys-slotno>,<ga-bits>
2209  * The OS property format is (ga-bits is not used however)
2210  * <busnexus-path>,<pci-devno>,<phys-slotno>,<ga-bits>
2211  * returns 0 on error, 1 otherwise
2212  */
2213 int
2214 extract_slot_table_from_obp()
2215 {
2216 	if (mc_promopen(O_RDONLY))  {
2217 		log_printf(dgettext(TEXT_DOMAIN,
2218 		    "\ncannot open openprom device"), 0);
2219 		return (0);
2220 	}
2221 
2222 	if (mc_next(0) == 0)
2223 		return (0);
2224 	mc_walk(mc_next(0));
2225 
2226 	if (close(oprom_fd) < 0) {
2227 		log_printf(dgettext(TEXT_DOMAIN,
2228 		    "\nclose error on %s"), OPENPROMDEV, 0);
2229 		return (0);
2230 	}
2231 
2232 	return (1);
2233 
2234 }	/* extract_slot_table_from_obp() */
2235 
2236 
2237 int
2238 mc_next(int id)
2239 {
2240 	Oppbuf  oppbuf;
2241 	struct openpromio *opp = &(oppbuf.opp);
2242 
2243 	bzero(oppbuf.buf, BUFSIZE);
2244 	opp->oprom_size = MAXVALSIZE;
2245 	opp->oprom_node = id;
2246 	if (ioctl(oprom_fd, OPROMNEXT, opp) < 0) {
2247 		log_printf(dgettext(TEXT_DOMAIN, "\nError OPROMNEXT"), 0);
2248 		return (0);
2249 	}
2250 	return (opp->oprom_node);
2251 
2252 }	/* mc_next(.) */
2253 
2254 
2255 void
2256 mc_walk(int id)
2257 {
2258 	int curnode;
2259 	mc_dump_node(id);
2260 	if (curnode = mc_child(id))
2261 		mc_walk(curnode);
2262 	if (curnode = mc_next(id))
2263 		mc_walk(curnode);
2264 }	/*  mc_walk(.) */
2265 
2266 int
2267 mc_child(int id)
2268 {
2269 	Oppbuf  oppbuf;
2270 	struct openpromio *opp = &(oppbuf.opp);
2271 
2272 	bzero(oppbuf.buf, BUFSIZE);
2273 	opp->oprom_size = MAXVALSIZE;
2274 	opp->oprom_node = id;
2275 	if (ioctl(oprom_fd, OPROMCHILD, opp) < 0) {
2276 		perror("\nOPROMCHILD");
2277 		exit(0);
2278 	}
2279 	return (opp->oprom_node);
2280 
2281 }	/* mc_child(.) */
2282 
2283 
2284 /*
2285  * Print all properties and values
2286  */
2287 void
2288 mc_dump_node(int id)
2289 {
2290 	int k;
2291 	Oppbuf  oppbuf;
2292 	hsc_prom_slot_table_t	*hpstp;
2293 	struct openpromio *opp = &(oppbuf.opp);
2294 
2295 	/* get first prop by asking for null string */
2296 	bzero(oppbuf.buf, BUFSIZE);
2297 	for (;;) {
2298 		/*
2299 		 * get next property name
2300 		 */
2301 		opp->oprom_size = MAXNAMESZ;
2302 
2303 		if (ioctl(oprom_fd, OPROMNXTPROP, opp) < 0) {
2304 			perror("\nOPROMNXTPROP");
2305 			return;
2306 		}
2307 		if (opp->oprom_size == 0)
2308 			break;
2309 		if (strcmp(opp->oprom_array, "slot-table") == 0) {
2310 			if (mc_getpropval(opp) || opp->oprom_size
2311 			    == (uint_t)-1) {
2312 				log_printf(dgettext(TEXT_DOMAIN,
2313 				    "\ndata not available"), 0);
2314 				return;
2315 			} else {
2316 				slot_table_size =
2317 				    opp->oprom_size /
2318 				    sizeof (hsc_prom_slot_table_t);
2319 				hpstp =
2320 				    (hsc_prom_slot_table_t *)opp->oprom_array;
2321 				for (k = 0; k < slot_table_size; k++, hpstp++) {
2322 					prom_slot_table[k].pslotnum =
2323 					    hpstp->pslotnum;
2324 					prom_slot_table[k].ga =
2325 					    hpstp->ga;
2326 					prom_slot_table[k].pci_devno =
2327 					    hpstp->pci_devno;
2328 					prom_slot_table[k].phandle =
2329 					    hpstp->phandle;
2330 				} /* for (k = 0; k < slot_table_size; k++) */
2331 
2332 			}
2333 		}
2334 	}
2335 
2336 }	/* mc_dump_node(.) */
2337 
2338 
2339 int
2340 mc_getpropval(struct openpromio *opp)
2341 {
2342 	opp->oprom_size = MAXVALSIZE;
2343 	if (ioctl(oprom_fd, OPROMGETPROP, opp) < 0) {
2344 		log_printf(dgettext(TEXT_DOMAIN, "\nError OPROMGETPROP"), 0);
2345 		return (1);
2346 	}
2347 	return (0);
2348 
2349 }	/* mc_getpropval(.) */
2350 
2351 
2352 
2353 /*
2354  * This function returns nothing.
2355  */
2356 void
2357 alarm_card_occupant()
2358 {
2359 	int		scsb_fd;
2360 	scsb_ioc_rdwr_t	ioc_read;
2361 	uint8_t		new_mode = 0;
2362 	uint8_t		old_mode = 0;
2363 	uchar_t		reg_index;
2364 
2365 	if (NULL == scsb_node) {
2366 		if (check_platform() == -1) {
2367 			return;
2368 		}
2369 	}
2370 
2371 	if (version_p15_and_p20 == 1)
2372 		reg_index = 0xe9;	/* config status reg offset on SCB */
2373 	else
2374 		reg_index = 0xd7;	/* config status reg offset on SCB */
2375 
2376 	if ((scsb_fd = open(scsb_node, O_RDONLY)) < 0)  {
2377 		log_printf(dgettext(TEXT_DOMAIN,
2378 		    "\n%s open failed"), scsb_node, 0);
2379 		return;
2380 	}
2381 
2382 	/* save off the old mode */
2383 	if (scsb_mode(scsb_fd, GET, &old_mode) == 0)
2384 		return;
2385 	/* we put scsb in diag mode to read this specific ioctl */
2386 	new_mode = ENVCTRL_DIAG_MODE;
2387 	if (scsb_mode(scsb_fd, SET, &new_mode) == 0)
2388 		return;
2389 	/* now lets read the config register */
2390 	if (scsb_ioc_reg_read(scsb_fd, reg_index, &ioc_read, 1) == 0)
2391 		return;
2392 	/* restore the original mode */
2393 	if (scsb_mode(scsb_fd, SET, &old_mode) == 0)
2394 		return;
2395 	alarm_card_present = (BIT_TEST(ioc_read.ioc_rbuf[0]&0xff, 0) ? 1:0);
2396 
2397 }	/* alarm_card_occupant() */
2398 
2399 
2400 /*
2401  * This function changes the SCSB mode to the desired one
2402  * 1 on sucess, 0 otherwise
2403  */
2404 int
2405 scsb_mode(int fd, scsb_op_t sop, uint8_t *new_mode)
2406 {
2407 	struct strioctl sioc;
2408 
2409 	if (sop == GET)
2410 		sioc.ic_cmd = ENVC_IOC_GETMODE;
2411 	else
2412 		sioc.ic_cmd = ENVC_IOC_SETMODE;
2413 
2414 	sioc.ic_timout = 0;
2415 	sioc.ic_len = sizeof (uint8_t);
2416 	sioc.ic_dp = (char *)new_mode;
2417 
2418 
2419 	if (ioctl(fd, I_STR, &sioc) == -1) {
2420 		log_printf(dgettext(TEXT_DOMAIN,
2421 		    "\nscsb_mode():scsb ioctl() failed"), 0);
2422 		return (0);
2423 	}
2424 	return (1);
2425 
2426 }	/* scsb_mode(...) */
2427 
2428 
2429 /*
2430  * 1 on success, 0 otherwise
2431  */
2432 int
2433 scsb_ioc_reg_read(int fd, uchar_t index, scsb_ioc_rdwr_t *ioc_rd, int num)
2434 {
2435 	struct strioctl		sioc;
2436 	scsb_ioc_rdwr_t		*rdwrp;
2437 
2438 	rdwrp = ioc_rd;
2439 	sioc.ic_timout = 0;
2440 	sioc.ic_len = sizeof (scsb_ioc_rdwr_t);
2441 	sioc.ic_dp = (char *)rdwrp;
2442 	/* setup read command before ioctl */
2443 	sioc.ic_cmd = SCSBIOC_REG_READ;
2444 	rdwrp->ioc_wlen = 0;
2445 	rdwrp->ioc_rlen = num;
2446 	rdwrp->ioc_regindex = index;
2447 	if (ioctl(fd, I_STR, &sioc) == -1) {
2448 		log_printf(dgettext(TEXT_DOMAIN,
2449 		    "scsb_ioc_reg_read(): scsb ioctl() failed\n"), 0);
2450 		return (0);
2451 	}
2452 	return (1);
2453 
2454 }	/* scsb_ioc_reg_read(....) */
2455