/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * * Netract Platform specific functions. * * called when : * machine_type == MTYPE_MONTECARLO */ /* includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pdevinfo.h" #include "display.h" #include "pdevinfo_sun4u.h" #include "display_sun4u.h" #include "libprtdiag.h" #include "libdevinfo.h" /* MC specific header, might just include from MC space */ #include "mct_topology.h" #include "envctrl_gen.h" #include "pcf8574_nct.h" #include "netract_gen.h" #include "hscimpl.h" #include "scsbioctl.h" #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* globals */ #define MAXNAMESZ 128 #define MAX_NODE_NAME_SZ 32 /* this values equates to Max Tree depth for now */ #define MAXIMUM_DEVS 64 typedef char device_info_t[MAX_NODE_NAME_SZ]; typedef struct { cfga_list_data_t *ldatap; int req; /* If set, this list_data was requested by user */ } ap_out_t; typedef struct { uint_t slot_addr; uint_t slot_stat; uint_t slot_cond; device_info_t devs_info[MAXIMUM_DEVS]; uint_t number_devs; } mc_slot_info_t; typedef struct { mc_slot_info_t mc_slot_info[MC_MAX_SLOTS]; } slot_data_t; extern char *progname; extern int print_flag; /* These are used to store all force loads of the drivers */ static int ps_fd[MC_MAX_PS]; static int oprom_fd; static int slot_index = 0; static int idx_minuscpu = 0; static int num_devs = 0; static int sd_instances[MC_MAX_SLOTS*15]; static int gpio_instances[MC_MAX_PS+MC_MAX_FAN]; static int sd_count = 0; static int st_instance; static int gpio_count = 0; static int slot_table_not_found = 0; /* default not present */ static int alarm_card_present = 0; static int cpu_ftm_present = 0; /* * We will store all kstat in globals so that * we can browse thru them later */ static int fail_syssoft_prop = 0; static int fail_drv_prop = 0; di_node_t rootnode; /* root nexus */ slot_data_t mc_slots_data; /* scsb driver kstats */ scsb_ks_leddata_t scsb_ks_leddata; scsb_ks_state_t scsb_ks_state; mct_topology_t scsb_ks_topo; /* pcf8574(gpio) driver kstats */ envctrl_cpuvoltage_t pcf8574_ks_cpuv; envctrl_pwrsupp_t pcf8574_ks_ps1; envctrl_fantray_t pcf8574_ks_fant1; envctrl_pwrsupp_t pcf8574_ks_ps2; envctrl_fantray_t pcf8574_ks_fant2; /* pcf8591(adc-dac) driver kstats */ envctrl_temp_t pcf8591_ks_temp; hsc_slot_table_t hotswap_slot_table[MC_MAX_SLOTS]; hsc_prom_slot_table_t prom_slot_table[MC_MAX_SLOTS]; static char *hotswap_mode = NULL; static char *slot_auto_config[MC_MAX_SLOTS]; static int slot_table_size; /* * use this to ascertain what's the system, * default is tonga, we can add more for future variations * 0=tonga, 1=montecarlo * we need also to figure out what the system version is * 0 = 1.5, 1 = 1.0, 0.6 etc. */ int montecarlo = 0; int version_p15_and_p20 = 0; #define MAX_PRTDIAG_INFO_LENGTH 1024 #define MAX_PRTDIAG_FRUS 22 #define BIT_TEST(X, N) ((X) & (1 << (N))) #define SLOT1_OK_BIT 0 #define SLOT2_OK_BIT 1 #define SLOT3_OK_BIT 2 #define SLOT4_OK_BIT 3 #define SLOT5_OK_BIT 4 #define SLOT6_OK_BIT 5 #define SLOT7_OK_BIT 6 #define SLOT8_OK_BIT 7 #define PDU1_OK_BIT SLOT2_OK_BIT #define PDU2_OK_BIT SLOT4_OK_BIT #define FTM_OK_BIT SLOT5_OK_BIT #define SCB_OK_BIT SLOT6_OK_BIT #define FAN1_OK_BIT SLOT1_OK_BIT #define FAN2_OK_BIT SLOT2_OK_BIT #define DISK1_OK_BIT SLOT4_OK_BIT #define DISK2_OK_BIT SLOT5_OK_BIT #define DISK3_OK_BIT SLOT6_OK_BIT #define PS1_OK_BIT SLOT7_OK_BIT #define PS2_OK_BIT SLOT8_OK_BIT #define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0) #define ENVC_DEBUG_MODE 0x03 #define OPENPROMDEV "/dev/openprom" #define I2C_PCF8591_NAME "adc-dac" #define I2C_KSTAT_CPUTEMP "adc_temp" #define SCSB_DEV "scsb" #define SDERR "sderr" #define STERR "sterr" #define OK "ok" #define NOK "Not ok" #define ON "on" #define OFF "off" #define BLINK "blink" #define NA "Not Available" #define UK "Unknown " #define YES "Yes" #define NO "No " #define LO "low" #define HI "high" #define BLANK " " #define SYSSOFT_PROP "System software" #define DRV_PROP "Driver" #define HSC_PROP_NAME "hsc-slot-map" #define HSC_MODE "hotswap-mode" #define PCI_ROOT_AP "pci" #define PROPS "Properties:" #define BOARDTYPE "Board Type:" #define DEVS "Devices:" #define CPCI_IO "CompactPCI IO Slot" #define AC_CARD "Alarm Card" #define CPU_FTM "Front Transition Module" #define SCTRL_PROM_P06 0x00 #define SCTRL_PROM_P10 0x01 #define SCTRL_PROM_P15 0x02 #define SCTRL_PROM_P20 0x03 #define RMM_NUMBER 3 #define MONTECARLO_PLATFORM "SUNW,UltraSPARC-IIi-Netract" #define MAKAHA_PLATFORM "SUNW,UltraSPARC-IIe-NetraCT-40" /* * The follow table is indexed with the enum's defined by mct_slot_occupant_t * OC_UNKN OC_CPU OC_AC OC_BHS OC_FHS OC_HAHS * OC_QFE OC_FRCH OC_COMBO OC_PMC OC_ATM * * But "scsb" can currently identify only CPU and Alarm Cards by known * slot numbers. */ char *slot_occupants[] = { CPCI_IO, "CPU board ", CPCI_IO, "Basic HotSwap Board", "Full HotSwap Board", "HA Board", "QFE Board", "Fresh Choice Board", "SUN Combo Board", "PMC Board", "ATM Board" }; static char *prtdiag_fru_types[] = { "I/O ", /* 0 */ "CPU ", "PSU ", "HDD ", "FAN ", "Alarm Card ", "SCB ", "SSB ", "CFTM ", "CRTM ", "PRTM ", "Midplane " /* 11 */ }; char prtdiag_fru_info[MAX_PRTDIAG_FRUS][MAX_PRTDIAG_INFO_LENGTH]; #define SCB_REG_READ 1 #define SCB_REG_WRITE 2 /* Standard Device nodes - hardwired for now */ /* will include fan tray later, cpu voltage not impl */ static char *scsb_node = NULL; static char **ps_node = NULL; static char *temp_node = NULL; static char *mc_scsb_node = "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/sysctrl@0,80:scsb"; static char *ot_scsb_node = "/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/sysctrl@0,80:scsb"; static char *mc_ps_node[] = { "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/gpio@0,7c:pwrsuppply", "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/gpio@0,7e:pwrsuppply" }; static char *ot_ps_node[] = { "/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/gpio@0,7c:pwrsuppply", "/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/gpio@0,7e:pwrsuppply" }; static char *mc_temp_node = "/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/adc-dac@0,9e:cputemp"; /* * these functions will overlay the symbol table of libprtdiag * at runtime (netract systems only) * display functions */ int display(Sys_tree *, Prom_node *, struct system_kstat_data *, int); /* local functions */ /* * prom function */ static void gather_diaginfo(int flag); static int extract_slot_table_from_obp(); static int mc_next(int id); static void mc_walk(int id); static int mc_child(int id); static void mc_dump_node(int id); static int mc_getpropval(struct openpromio *opp); #ifdef REDUNDANT_INFO static int mc_get_cpu_freq(Prom_node *node); static int mc_get_ecache_size(Prom_node *node); static void mc_display_cpus(Board_node *board); static void mc_display_cpu_devices(Sys_tree *tree); #endif /* REDUNDANT_INFO */ static void netract_disp_prom_version(); /* * Since we do not have a system wide kstat for MC/Tg * here we have to do specific kstats to drivers that * post this information - MC/Tg specific drivers * that post kstat here are : scsb, pcf8574(gpio) and pcf8591 */ static int analyze_nodes(di_node_t, void*); static void analyze_pcipci_siblings(di_node_t); static void display_mc_prtdiag_info(); static int dump_devs(di_node_t, void *); static void prtdiag_devinfo(void); static void force_load_drivers(); static int dump_prop_list(char *name, di_node_t node, di_prop_t (*nxtprop)()); static void *config_calloc_check(size_t nelem, size_t elsize); static void explore_slot_occupants(); static void do_scsb_kstat(); static void do_pcf8574_kstat(); static void do_pcf8591_kstat(); static void do_promversion(); static int mc_promopen(int oflag); static int scsi_disk_status(int disk_number); static void alarm_card_occupant(); static int scsb_mode(int fd, scsb_op_t sop, uint8_t *new_mode); static int scsb_ioc_reg_read(int fd, uchar_t index, scsb_ioc_rdwr_t *ioc_rd, int num); static int check_platform(); int display(Sys_tree *tree, Prom_node *root, struct system_kstat_data *kstats, int syserrlog) { int exit_code = 0; /* init to all OK */ void *value; /* used for opaque PROM data */ struct mem_total memory_total; /* Total memory in system */ struct grp_info grps; /* Info on all groups in system */ #ifdef lint syserrlog = syserrlog; #endif sys_clk = -1; /* System clock freq. (in MHz) */ /* * Now display the machine's configuration. We do this if we * are not logging or exit_code is set (machine is broke). */ if (!logging || exit_code) { struct utsname uts_buf; /* * Display system banner */ (void) uname(&uts_buf); log_printf(dgettext(TEXT_DOMAIN, "System Configuration: Oracle Corporation" " %s %s\n"), uts_buf.machine, get_prop_val(find_prop(root, "banner-name")), 0); /* display system clock frequency */ value = get_prop_val(find_prop(root, "clock-frequency")); if (value != NULL) { sys_clk = ((*((int *)value)) + 500000) / 1000000; log_printf(dgettext(TEXT_DOMAIN, "System clock frequency: " "%d MHz\n"), sys_clk, 0); } /* Display the Memory Size */ display_memorysize(tree, kstats, &grps, &memory_total); /* Lets make sure we have all the needed drivers loaded */ /* display Montecarlo/Tonga FRU information */ if (!extract_slot_table_from_obp()) log_printf(dgettext(TEXT_DOMAIN, "\r\nslot-table not available\r\n"), 0); do_scsb_kstat(); force_load_drivers(); gather_diaginfo(print_flag && !logging); /* figure out if ac is present */ alarm_card_occupant(); /* platform specific display mod */ display_mc_prtdiag_info(); di_fini(rootnode); netract_disp_prom_version(); } /* if (!logging || exit_code) */ return (exit_code); } /* display(....) */ static int check_platform() { char si_platform[SYS_NMLN]; /* * Check for the platform: Montecarlo or Makaha/CP2040 based */ if (sysinfo(SI_PLATFORM, si_platform, sizeof (si_platform)) == -1) { return (-1); } if ((strncmp(si_platform, MONTECARLO_PLATFORM, strlen(MONTECARLO_PLATFORM))) == 0) { scsb_node = mc_scsb_node; ps_node = mc_ps_node; temp_node = mc_temp_node; } else if ((strncmp(si_platform, MAKAHA_PLATFORM, strlen(MAKAHA_PLATFORM))) == 0) { scsb_node = ot_scsb_node; ps_node = ot_ps_node; temp_node = NULL; } else { return (-1); } return (0); } void force_load_drivers() { int i; if (NULL == scsb_node || NULL == ps_node) { if (check_platform() == -1) { return; } } /* check scb/ssb presence */ if (scsb_ks_state.scb_present || scsb_ks_state.ssb_present) { if (open(scsb_node, O_RDONLY) < 0) log_printf(dgettext(TEXT_DOMAIN, "\nscsb open FAILED!"), 0); } /* check the num of PS we have */ for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) { if (scsb_ks_topo.mct_ps[i].fru_status == FRU_PRESENT) { if ((ps_fd[i] = open(ps_node[i], O_RDONLY)) < 0) log_printf(dgettext(TEXT_DOMAIN, "\npowersupply%d open failed"), i, 0); } } /* for */ /* open the cpu temp driver */ if (temp_node) { if (open(temp_node, O_RDONLY) < 0) log_printf(dgettext(TEXT_DOMAIN, "\ncputemp open FAILED!"), 0); } } void explore_slot_occupants() { char *cp = NULL; int index; int ret = CFGA_ERROR; char *estrp = NULL; cfga_list_data_t *list_array = NULL; ap_out_t *out_array = NULL; int nlist = 0; char *prefilt_optp = NULL; int dyn_exp = 1; char *plat_opts = NULL; ret = config_list_ext(0, NULL, &list_array, &nlist, plat_opts, prefilt_optp, &estrp, dyn_exp ? CFGA_FLAG_LIST_ALL : 0); if (ret != CFGA_OK) { log_printf(dgettext(TEXT_DOMAIN, "\ncannot explore configuration"), 0); return; } assert(nlist != 0); out_array = config_calloc_check(nlist, sizeof (*out_array)); if (out_array == NULL) { ret = CFGA_LIB_ERROR; goto bail; } /* create a list of output stat data */ for (index = 0; index < nlist; index++) { out_array[index].ldatap = &list_array[index]; out_array[index].req = 0; } for (index = 0; index < nlist; index++) { if ((cp = strstr(out_array[index].ldatap->ap_phys_id, "cpci_slot")) != NULL) { mc_slots_data.mc_slot_info[idx_minuscpu].slot_stat = out_array[index].ldatap->ap_o_state; mc_slots_data.mc_slot_info[idx_minuscpu].slot_cond = out_array[index].ldatap->ap_cond; idx_minuscpu++; } } bail: S_FREE(list_array); S_FREE(out_array); } /* * config_calloc_check - perform allocation, check result and * set error indicator */ void * config_calloc_check( size_t nelem, size_t elsize) { void *p; static char alloc_fail[] = "%s: memory allocation failed (%d*%d bytes)\n"; p = calloc(nelem, elsize); if (p == NULL) { log_printf(dgettext(TEXT_DOMAIN, alloc_fail), nelem, elsize, 0); } return (p); } void do_scsb_kstat() { kstat_ctl_t *kc; kstat_t *ksp_leddata; kstat_t *ksp_state; kstat_t *ksp_topo; scsb_ks_leddata_t *pks_leddata; scsb_ks_state_t *pks_state; mct_topology_t *pks_topo; int i; #ifdef DEBUG_TEMP1 int index; #endif if (!(kc = kstat_open())) { #ifdef DEBUG_TEMP log_printf("\nkstat_open failed", 0); #endif return; } #ifdef lint kc = kc; #endif /* get kstat on scsb led data */ if ((ksp_leddata = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_LEDDATA)) == NULL) { #ifdef DEBUG_TEMP log_printf("\nkstat_lookup for scsb_leddata failed", 0); #endif return; } if (kstat_read(kc, ksp_leddata, NULL) == -1) { #ifdef DEBUG_TEMP log_printf("\nkstat_read for scsb_leddata failed", 0); #endif return; } pks_leddata = (scsb_ks_leddata_t *)ksp_leddata->ks_data; scsb_ks_leddata = *pks_leddata; /* set the globals for future */ #ifdef DEBUG_LEDS /* dump the kstat leddata */ printf("\nDumping LED regs: "); for (i = 0; i < SCSB_LEDDATA_REGISTERS; ++i) { log_printf("0x%x ", pks_leddata->scb_led_regs[i] & 0xff, 0); } log_printf("\n", 0); #endif /* get kstat on scsb states */ if ((ksp_state = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_STATE)) == NULL) { #ifdef DEBUG_TEMP log_printf("\nkstat_lookup for scsb_state failed", 0); #endif return; } if (kstat_read(kc, ksp_state, NULL) == -1) { #ifdef DEBUG_TEMP log_printf("\nkstat_read for scsb_state failed", 0); #endif return; } pks_state = (scsb_ks_state_t *)ksp_state->ks_data; scsb_ks_state = *pks_state; /* set the global for future */ #ifdef DEBUG_TEMP1 /* dump the kstat state */ log_printf("\tSCB is%spresent\n", pks_state->scb_present ? " " : " not ", 0); log_printf("\tSSB is%spresent\n", pks_state->ssb_present ? " " : " not ", 0); log_printf("\tscsb is%sfrozen\n", pks_state->scsb_frozen ? " " : " not ", 0); log_printf("\tscsb mode: ", 0); switch (pks_state->scsb_mode) { case ENVC_DEBUG_MODE: log_printf("DEBUG MODE\n", 0); break; case ENVCTRL_DIAG_MODE: log_printf("DIAGNOSTIC MODE\n", 0); break; case ENVCTRL_NORMAL_MODE: log_printf("NORMAL MODE\n", 0); break; } log_printf("\tscsb event code: 0x%x\n", pks_state->event_code, 0); #endif /* DEBUG_TEMP1 */ if ((ksp_topo = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_TOPOLOGY)) == NULL) { #ifdef DEBUG_TEMP log_printf("\nkstat_lookup for scsb_topo failed", 0); #endif return; } if (kstat_read(kc, ksp_topo, NULL) == -1) { #ifdef DEBUG_TEMP log_printf("\nkstat_read for scsb_topo failed", 0); #endif return; } pks_topo = (mct_topology_t *)ksp_topo->ks_data; scsb_ks_topo = *pks_topo; /* set the global for future */ /* * we need to set this so that we can get status info * for the 2 powersupplies in MC as we need to get * kstat from both driver instances for environment */ if (pks_topo->mid_plane.fru_id == SCTRL_MPID_HALF) montecarlo = 1; /* Monte Carlo */ /* * HW version 0.6 and 1.0 had different led maps * its assumed that HW 2.0 would not change this * need to modify if it does */ if ((pks_topo->mct_scb[0].fru_version == SCTRL_PROM_P15) || (pks_topo->mct_scb[0].fru_version == SCTRL_PROM_P20)) { version_p15_and_p20 = 1; } /* set flag to note that CFTM is present */ for (i = 0; i < pks_topo->max_units[CFTM]; ++i) { if (pks_topo->mct_cftm[i].fru_status == FRU_PRESENT) cpu_ftm_present = 1; } #ifdef DEBUG_TEMP1 /* * Midplane */ log_printf("Midplane type: ", 0); if (pks_topo->mid_plane.fru_id == SCTRL_MPID_HALF) log_printf("Netra ct800 server\n", 0); else log_printf("Netra ct400 server%s\n", pks_topo->mid_plane.fru_id == SCTRL_MPID_QUARTER_NODSK ? ", no disk" : " with disk", 0); log_printf("Midplane version: %d\n", pks_topo->mid_plane.fru_version, 0); log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_scb[0].fru_type, pks_topo->mct_scb[0].fru_unit, pks_topo->mct_scb[0].fru_id, pks_topo->mct_scb[0].fru_version, 0); /* * Slots */ log_printf("Slots present out of maximum %d\n", pks_topo->max_units[SLOT], 0); for (i = 0; i < pks_topo->max_units[SLOT]; ++i) { if (pks_topo->mct_slots[i].fru_status != FRU_PRESENT) continue; index = (int)pks_topo->mct_slots[i].fru_type; log_printf("\tSlot %d occupant: %s;", pks_topo->mct_slots[i].fru_unit, slot_occupants[index], 0); log_printf(" ID 0x%x; VER 0x%x ; ", pks_topo->mct_slots[i].fru_id, pks_topo->mct_slots[i].fru_version, 0); log_printf(" Slot health %d\n", pks_topo->mct_slots[i].fru_health, 0); /* pks_topo->mct_slots[i].fru_health */ } /* * PDU */ log_printf("PDUs present out of maximum %d\n", pks_topo->max_units[PDU], 0); for (i = 0; i < pks_topo->max_units[PDU]; ++i) { if (pks_topo->mct_pdu[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_pdu[i].fru_type, pks_topo->mct_pdu[i].fru_unit, pks_topo->mct_pdu[i].fru_id, pks_topo->mct_pdu[i].fru_version, 0); /* pks_topo->mct_pdu[i].fru_health */ } /* * Power Supplies */ log_printf("Power Supplies present out of maximum %d\n", pks_topo->max_units[PS], 0); for (i = 0; i < pks_topo->max_units[PS]; ++i) { if (pks_topo->mct_ps[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_ps[i].fru_type, pks_topo->mct_ps[i].fru_unit, pks_topo->mct_ps[i].fru_id, pks_topo->mct_ps[i].fru_version, 0); } /* * Disks */ log_printf("Disks present out of maximum %d\n", pks_topo->max_units[DISK], 0); for (i = 0; i < pks_topo->max_units[DISK]; ++i) { if (pks_topo->mct_disk[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_disk[i].fru_type, pks_topo->mct_disk[i].fru_unit, pks_topo->mct_disk[i].fru_id, pks_topo->mct_disk[i].fru_version, 0); } /* * Fans */ log_printf("Fans present out of maximum %d\n", pks_topo->max_units[FAN], 0); for (i = 0; i < pks_topo->max_units[FAN]; ++i) { if (pks_topo->mct_fan[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_fan[i].fru_type, pks_topo->mct_fan[i].fru_unit, pks_topo->mct_fan[i].fru_id, pks_topo->mct_fan[i].fru_version, 0); } /* * SCBs */ log_printf("SCBs present out of maximum %d\n", pks_topo->max_units[SCB], 0); for (i = 0; i < pks_topo->max_units[SCB]; ++i) { if (pks_topo->mct_scb[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_scb[i].fru_type, pks_topo->mct_scb[i].fru_unit, pks_topo->mct_scb[i].fru_id, pks_topo->mct_scb[i].fru_version, 0); } /* * SSBs */ log_printf("SSBs present out of maximum %d\n", pks_topo->max_units[SSB], 0); for (i = 0; i < pks_topo->max_units[SSB]; ++i) { if (pks_topo->mct_ssb[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_ssb[i].fru_type, pks_topo->mct_ssb[i].fru_unit, pks_topo->mct_ssb[i].fru_id, pks_topo->mct_ssb[i].fru_version, 0); } /* * Alarms Cards */ log_printf("Alarm Cards present out of maximum %d\n", pks_topo->max_units[ALARM], 0); for (i = 0; i < pks_topo->max_units[ALARM]; ++i) { if (pks_topo->mct_alarm[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d; unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_alarm[i].fru_type, pks_topo->mct_alarm[i].fru_unit, pks_topo->mct_alarm[i].fru_id, pks_topo->mct_alarm[i].fru_version, 0); } /* * CFTMs */ log_printf("CFTMs present out of maximum %d\n", pks_topo->max_units[CFTM], 0); for (i = 0; i < pks_topo->max_units[CFTM]; ++i) { if (pks_topo->mct_cftm[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_cftm[i].fru_type, pks_topo->mct_cftm[i].fru_unit, pks_topo->mct_cftm[i].fru_id, pks_topo->mct_cftm[i].fru_version, 0); } /* * CRTMs */ log_printf("CRTMs present out of maximum %d\n", pks_topo->max_units[CRTM], 0); for (i = 0; i < pks_topo->max_units[CRTM]; ++i) { if (pks_topo->mct_crtm[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_crtm[i].fru_type, pks_topo->mct_crtm[i].fru_unit, pks_topo->mct_crtm[i].fru_id, pks_topo->mct_crtm[i].fru_version, 0); } /* * PRTMs */ log_printf("PRTMs present out of maximum %d\n", pks_topo->max_units[PRTM], 0); for (i = 0; i < pks_topo->max_units[PRTM]; ++i) { if (pks_topo->mct_prtm[i].fru_status != FRU_PRESENT) continue; log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n", pks_topo->mct_prtm[i].fru_type, pks_topo->mct_prtm[i].fru_unit, pks_topo->mct_prtm[i].fru_id, pks_topo->mct_prtm[i].fru_version, 0); } #endif /* DEBUG_TEMP1 */ } /* do_scsb_kstat(...) */ void do_pcf8574_kstat() { kstat_ctl_t *kc; kstat_t *ksp_ps; kstat_t *ksp_fan; envctrl_pwrsupp_t *pks_ps; envctrl_fantray_t *pks_fan; int i; char *kstat_name = NULL; if (!(kc = kstat_open())) { #ifdef DEBUG_TEMP log_printf("\nkstat_open for pcf8574 failed", 0); #endif return; } #ifdef lint kc = kc; #endif /* get kstat on gpio powersupply and fan states */ for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) { if (i == 1) { kstat_name = I2C_KSTAT_PWRSUPPLY; strncat(kstat_name, "1", 1); } else { kstat_name = I2C_KSTAT_PWRSUPPLY; strncat(kstat_name, "2", 1); } if ((ksp_ps = kstat_lookup(kc, I2C_PCF8574_NAME, 0, kstat_name)) == NULL) { #ifdef DEBUG_TEMP log_printf("\nks lookup for pwrsupply%d failed", i+1, 0); #endif return; } if (kstat_read(kc, ksp_ps, NULL) == -1) { #ifdef DEBUG_TEMP log_printf("\nks read for pwrsupply%d failed", i+1, 0); #endif return; } pks_ps = (envctrl_pwrsupp_t *)ksp_ps->ks_data; if (i == 1) pcf8574_ks_ps1 = *pks_ps; /* ps 1 */ else pcf8574_ks_ps2 = *pks_ps; /* ps 2 */ } /* for */ for (i = 0; i < scsb_ks_topo.max_units[FAN]; ++i) { if (i == 1) { kstat_name = I2C_KSTAT_FANTRAY; strncat(kstat_name, "1", 1); } else { kstat_name = I2C_KSTAT_FANTRAY; strncat(kstat_name, "2", 1); } if ((ksp_fan = kstat_lookup(kc, I2C_PCF8574_NAME, 0, kstat_name)) == NULL) { #ifdef DEBUG_TEMP log_printf("\nks lookup for fantray%d failed", i+1, 0); #endif return; } if (kstat_read(kc, ksp_fan, NULL) == -1) { #ifdef DEBUG_TEMP log_printf("\nks read for fantray%d failed", i+1, 0); #endif return; } pks_fan = (envctrl_fantray_t *)ksp_fan->ks_data; if (i == 1) pcf8574_ks_fant1 = *pks_fan; /* fan 1 */ else pcf8574_ks_fant2 = *pks_fan; /* fan 2 */ } /* for */ kstat_close(kc); } /* do_pcf8574_kstat(...) */ void do_pcf8591_kstat() { kstat_ctl_t *kc; kstat_t *ksp_temp; envctrl_temp_t *pks_temp; if (!(kc = kstat_open())) { #ifdef DEBUG_TEMP log_printf("ks open for pcf8591 failed", 0); #endif return; } #ifdef lint kc = kc; #endif /* get kstat on adc driver's CPU temperature data */ if ((ksp_temp = kstat_lookup(kc, I2C_PCF8591_NAME, -1, I2C_KSTAT_CPUTEMP)) == NULL) { #ifdef DEBUG_TEMP log_printf("ks lookup for adc_temp failed", 0); #endif return; } if (kstat_read(kc, ksp_temp, NULL) == -1) { #ifdef DEBUG_TEMP log_printf("ks read for adc_temp failed", 0); #endif return; } pks_temp = (envctrl_temp_t *)ksp_temp->ks_data; pcf8591_ks_temp = *pks_temp; kstat_close(kc); } /* do_pcf8591_kstat(.) */ void gather_diaginfo(int flag) { if (flag) { /* gather system environmental conditions. */ /* obtain kstat info from gpio & temp. driver */ do_pcf8574_kstat(); do_pcf8591_kstat(); explore_slot_occupants(); /* fill in some occupant info */ prtdiag_devinfo(); analyze_pcipci_siblings(rootnode); } } /* display_diaginfo(...) */ void netract_disp_prom_version() { /* Display Prom revision header */ log_printf(dgettext(TEXT_DOMAIN, "System Board PROM revision:\n"), 0); log_printf("---------------------------\n", 0); do_promversion(); } /* netract_disp_prom_version(.) */ /* * Get and print the PROM version. */ void do_promversion(void) { Oppbuf oppbuf; struct openpromio *opp = &(oppbuf.opp); if (mc_promopen(O_RDONLY)) { log_printf(dgettext(TEXT_DOMAIN, "\nCannot open openprom device"), 0); return; } opp->oprom_size = MAXVALSIZE; if (ioctl(oprom_fd, OPROMGETVERSION, opp) < 0) { perror("\nOPROMGETVERSION ioctl failed"); return; } log_printf("%s\n", opp->oprom_array, 0); if (close(oprom_fd) < 0) { log_printf(dgettext(TEXT_DOMAIN, "\nclose error on %s"), OPENPROMDEV, 0); return; } } /* do_promversion() */ int mc_promopen(int oflag) { for (;;) { if ((oprom_fd = open(OPENPROMDEV, oflag)) < 0) { if (errno == EAGAIN) { (void) sleep(5); continue; } if (errno == ENXIO) return (-1); log_printf(dgettext(TEXT_DOMAIN, "\ncannot open %s"), OPENPROMDEV, 0); return (1); } else return (0); } } /* * This will return -1 for status unknown, 0 for OK, and 1 for failed (scsi * hard errors) * swiped from envmon policies */ int scsi_disk_status(int disk_number) { kstat_ctl_t *kc; kstat_t *ksp_disk; kstat_named_t *disk_data; int i; int nlist = 0; cfga_list_data_t *list_array = NULL; char *ap_ids[] = {"c0"}; if ((kc = kstat_open()) == NULL) { log_printf(dgettext(TEXT_DOMAIN, "\nks open failed"), 0); return (-1); } if (disk_number == RMM_NUMBER) { /* RMM */ if (config_list_ext(1, ap_ids, &list_array, &nlist, NULL, NULL, NULL, CFGA_FLAG_LIST_ALL) != CFGA_OK) { kstat_close(kc); return (-1); } for (i = 0; i < nlist; i++) { if (strstr(list_array[i].ap_phys_id, "rmt/0") != NULL) { /* Tape drive */ if (list_array[i].ap_o_state == CFGA_STAT_UNCONFIGURED) { kstat_close(kc); return (-1); } if ((ksp_disk = kstat_lookup(kc, STERR, st_instance, NULL)) == NULL) { kstat_close(kc); return (-1); } break; } else if (strstr(list_array[i].ap_phys_id, "dsk/c0t6d0") != NULL) { /* CD_ROM */ if (list_array[i].ap_o_state == CFGA_STAT_UNCONFIGURED) { kstat_close(kc); return (-1); } if ((ksp_disk = kstat_lookup(kc, SDERR, sd_instances[disk_number-1], NULL)) == NULL) { kstat_close(kc); return (-1); } break; } } } else { /* Hard disk */ if ((ksp_disk = kstat_lookup(kc, SDERR, sd_instances[disk_number-1], NULL)) == NULL) { kstat_close(kc); return (-1); } } if (kstat_read(kc, ksp_disk, NULL) == -1) { log_printf(dgettext(TEXT_DOMAIN, "\nks read error for disk%d, drv inst%d"), disk_number, sd_instances[disk_number-1], 0); kstat_close(kc); return (-1); } disk_data = KSTAT_NAMED_PTR(ksp_disk); /* * if disk_data[].value is >0, we have a problem */ if (disk_data[1].value.ui32 == 0) { kstat_close(kc); return (0); } else { kstat_close(kc); return (1); } } void prtdiag_devinfo(void) { uint_t flag; /* lets get everything we can from kernel */ flag = DINFOSUBTREE|DINFOPROP; rootnode = di_init("/", flag); if (rootnode == DI_NODE_NIL) { log_printf(dgettext(TEXT_DOMAIN, "\nprtdiag_devinfo: di_init() failed"), 0); return; } (void) di_walk_node(rootnode, DI_WALK_CLDFIRST, NULL, dump_devs); } /* * gather information about this node, returns appropriate code. * specific information we seek are driver names, instances * we will initialize some globals depending on what we find * from the kernel device tree info and may be private data * if required */ /*ARGSUSED1*/ int dump_devs(di_node_t node, void *arg) { char *driver_name; driver_name = di_driver_name(node); /* we will initialize our globals here */ if ((di_instance(node) >= 0) && (driver_name != NULL) && (!(di_state(node) & DI_DRIVER_DETACHED))) { if (strcmp(driver_name, "pcf8574") == 0) { gpio_instances[gpio_count] = di_instance(node); gpio_count++; } else if (strcmp(driver_name, "sd") == 0) { sd_instances[sd_count] = di_instance(node); sd_count++; } else if (strcmp(driver_name, "st") == 0) { st_instance = di_instance(node); } } if (strcmp(di_node_name(node), "pseudo") == 0) return (DI_WALK_PRUNECHILD); else return (DI_WALK_CONTINUE); } /* * Returns 0 if error , 1 otherwise */ int dump_prop_list(char *name, di_node_t node, di_prop_t (*nxtprop)()) { int prop_len, i, k, max_slots_minus_cpu, n; uchar_t *prop_data; char *p; char *temp_s; di_prop_t prop, next; int ret_value = 0; max_slots_minus_cpu = scsb_ks_topo.max_units[SLOT]-1; if ((next = nxtprop(node, DI_PROP_NIL)) == DI_PROP_NIL) return (0); while (next != DI_PROP_NIL) { int maybe_str = 1, npossible_strs = 0; prop = next; next = nxtprop(node, prop); /* * get prop length and value: * private interface--always success */ prop_len = di_prop_rawdata(prop, &prop_data); if (di_prop_type(prop) == DDI_PROP_UNDEF_IT) { continue; } if (prop_len == 0) { continue; } if (prop_data[prop_len - 1] != '\0') { maybe_str = 0; } else { /* * Every character must be a string character or a \0, * and there must not be two \0's in a row. */ for (i = 0; i < prop_len; i++) { if (prop_data[i] == '\0') { npossible_strs++; } else if (!isascii(prop_data[i]) || iscntrl(prop_data[i])) { maybe_str = 0; break; } if ((i > 0) && (prop_data[i] == '\0') && (prop_data[i - 1] == '\0')) { maybe_str = 0; break; } } } if (maybe_str) { p = (char *)prop_data; for (i = 0; i < npossible_strs - 1; i++) { if ((strcmp(name, SYSSOFT_PROP) == 0) && (strcmp(di_prop_name(prop), HSC_PROP_NAME) == 0)) { temp_s = p; temp_s += strlen(temp_s) + 1; } p += strlen(p) + 1; } if ((strcmp(name, SYSSOFT_PROP) == 0) && (strcmp(di_prop_name(prop), HSC_PROP_NAME) == 0)) { temp_s = temp_s - prop_len+2; for (k = 0, n = 0; k < prop_len; k++) { if (temp_s[k] == 0) { n++; } } if (n % 4) { log_printf(dgettext(TEXT_DOMAIN, "\nbad slot-table(%d)\n"), n); slot_table_not_found = 0; return (ret_value); } slot_table_size = n / 4; /* * NOTE : We save slot table info in order */ for (k = 0; k < slot_table_size; k++) { char *nexus, *pcidev, *phys_slotname; char *ga; /* * Pick off pointer to nexus * path or PROM handle */ nexus = temp_s; while (*temp_s != NULL) temp_s++; temp_s++; /* * Pick off pointer to the * pci device number */ pcidev = temp_s; while (*temp_s != NULL) temp_s++; temp_s++; /* Pick off physical slot no */ phys_slotname = temp_s; while (*temp_s != NULL) temp_s++; temp_s++; /* * Pick off GA bits which * we dont use for now. */ ga = temp_s; while (*temp_s != NULL) temp_s++; temp_s++; hotswap_slot_table[k].pslotnum = atoi(phys_slotname); hotswap_slot_table[k].ga = atoi(ga); hotswap_slot_table[k].pci_devno = atoi(pcidev); strcpy(hotswap_slot_table[k].nexus, nexus); } /* for (k = 0; k < slot_table_size; k++) */ ret_value = 1; } else /* (strcmp(name, SYSSOFT_PROP) */ slot_table_not_found = 1; /* * now we want to save off the info * we would use later */ if ((strcmp(name, DRV_PROP) == 0) && (strcmp(di_prop_name(prop), HSC_MODE) == 0)) { hotswap_mode = p; ret_value = 1; } else if ((strcmp(name, DRV_PROP) == 0) && (strcmp(di_prop_name(prop), HSC_MODE) != 0)) { /* save it in order in the right index */ slot_auto_config[max_slots_minus_cpu] = p; max_slots_minus_cpu--; ret_value = 1; } } else { for (i = 0; i < prop_len; ++i) { #if 0 unsigned char byte; byte = (unsigned char)prop_data[i]; log_printf("%2.2x", byte, 0); #endif } } } return (ret_value); } void display_mc_prtdiag_info() { int i, index; int s_index, i1; int tg_cpu_index = 0; char *mcfru_type, *status, *mc_ok_led, *mc_nok_led; char *misc_info, *health, *board_type; log_printf("===============================", 0); log_printf(dgettext(TEXT_DOMAIN, " FRU Information ================================\n"), 0); log_printf(dgettext(TEXT_DOMAIN, "FRU FRU FRU Green Amber"), 0); log_printf(dgettext(TEXT_DOMAIN, " Miscellaneous\n"), 0); log_printf(dgettext(TEXT_DOMAIN, "Type Unit# Present LED LED"), 0); log_printf(dgettext(TEXT_DOMAIN, " Information\n"), 0); log_printf("---------- ----- ------- ----- -----", 0); log_printf(" ----------------------------------\n", 0); if (scsb_ks_topo.mid_plane.fru_id == SCTRL_MPID_HALF) misc_info = "Netra ct800"; else { misc_info = "Netra ct400"; } mcfru_type = prtdiag_fru_types[MIDPLANE]; switch (scsb_ks_topo.mid_plane.fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } mc_ok_led = " "; mc_nok_led = " "; log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s %-5s %s\n"), mcfru_type, scsb_ks_topo.mid_plane.fru_unit, status, mc_ok_led, mc_nok_led, misc_info, 0); log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0); log_printf(dgettext(TEXT_DOMAIN, "%49sVersion=%d\n"), BLANK, scsb_ks_topo.mid_plane.fru_version, 0); log_printf(dgettext(TEXT_DOMAIN, "%49sMaximum Slots=%d\n"), BLANK, scsb_ks_topo.max_units[SLOT], 0); /* SCB & SSB */ mcfru_type = prtdiag_fru_types[SCB]; for (i = 0; i < scsb_ks_topo.max_units[SCB]; ++i) { misc_info = "System Controller Board"; if (version_p15_and_p20) { mc_ok_led = BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[1] & 0xff), SCB_OK_BIT) ? BLINK : (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[1] & 0xff), SCB_OK_BIT) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[1] & 0xff), SCB_OK_BIT) ? ON:OFF; } else { /* * support for 1.0 systems - * Hack! - should use tables ? */ mc_ok_led = (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2] & 0xff), 0) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2] & 0xff), 0) ? ON:OFF; } switch (scsb_ks_topo.mct_scb[i].fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s %-5s %s\n"), mcfru_type, scsb_ks_topo.mct_scb[i].fru_unit, status, mc_ok_led, mc_nok_led, misc_info, 0); log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0); log_printf(dgettext(TEXT_DOMAIN, "%49sVersion=%d\n"), BLANK, scsb_ks_topo.mct_scb[0].fru_version, 0); if (fail_drv_prop == 1) log_printf(dgettext(TEXT_DOMAIN, "%49s%s=%s\n"), BLANK, HSC_MODE, hotswap_mode, 0); } /* for */ mcfru_type = prtdiag_fru_types[SSB]; for (i = 0; i < scsb_ks_topo.max_units[SSB]; ++i) { misc_info = "System Status Panel"; switch (scsb_ks_topo.mct_ssb[i].fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s %-5s %s\n"), mcfru_type, scsb_ks_topo.mct_ssb[i].fru_unit, status, BLANK, BLANK, misc_info, 0); } /* for */ /* Slots */ for (i = 0; i < scsb_ks_topo.max_units[SLOT]; ++i) { if (montecarlo) { if (scsb_ks_topo.mct_slots[i].fru_unit == 1) mcfru_type = prtdiag_fru_types[1]; else mcfru_type = prtdiag_fru_types[SLOT]; /* * Another way this could have been done is, * to read the sub system id * it is 0x6722 for Alarm Card * but this id is only valid for the new ACs * older ACs still have the same susbsystem * id as most other Sun PCI cards * We cannot completely rely on this. * Also,it turns out that Sun OpenBoot does not * always follow IEEE 1275 std, hence in a few * systems, the "subsystem-id" published by the * PROM could not be found * We know the AC slot# if present on both MC&Tg * Hence we check on both - now we are sure * that we have found an AC */ if ((scsb_ks_topo.mct_slots[i].fru_unit == 8) && (alarm_card_present == 1)) board_type = AC_CARD; else board_type = UK; } else { if (scsb_ks_topo.mct_slots[i].fru_unit == 3) mcfru_type = prtdiag_fru_types[1]; else mcfru_type = prtdiag_fru_types[SLOT]; /* * Another way this could have been done is, * to read the sub system id * it is 0x6722 for Alarm Card * but this id is only valid for the new ACs * older ACs still have the same susbsystem * id as most other Sun PCI cards * We cannot completely rely on this. * Also,it turns out that Sun OpenBoot does not * always follow IEEE 1275 std, hence in a few * systems, the "subsystem-id" published by the * PROM could not be found * We know the AC slot# if present on both MC&Tg * Hence we check on both - now we are sure * that we have found an AC */ if ((scsb_ks_topo.mct_slots[i].fru_unit == 1) && (alarm_card_present == 1)) board_type = AC_CARD; else board_type = UK; } if (version_p15_and_p20) { mc_ok_led = BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[0] & 0xff), i) ? BLINK : (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[0] & 0xff), i) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[0] & 0xff), i) ? ON:OFF; } else { /* * support for 1.0 systems - * Hack! - should use tables ? */ if (scsb_ks_topo.mct_slots[i].fru_unit == 7) { mc_ok_led = BIT_TEST( (scsb_ks_leddata.leds.p10.blink_leds[1] & 0xff), 0) ? BLINK : (BIT_TEST( (scsb_ks_leddata.leds.p10.ok_leds[1] & 0xff), 0) ? ON:OFF); mc_nok_led = BIT_TEST( (scsb_ks_leddata.leds.p10.nok_leds[1] & 0xff), 0) ? ON:OFF; } else if (scsb_ks_topo.mct_slots[i].fru_unit == 8) { mc_ok_led = BIT_TEST( (scsb_ks_leddata.leds.p10.blink_leds[1] & 0xff), 1) ? BLINK : (BIT_TEST( (scsb_ks_leddata.leds.p10.ok_leds[1] & 0xff), 1) ? ON:OFF); mc_nok_led = BIT_TEST( (scsb_ks_leddata.leds.p10.nok_leds[1] & 0xff), 1) ? ON:OFF; } else { /* * for all other slots offset, * index are the same */ mc_ok_led = BIT_TEST( (scsb_ks_leddata.leds.p10.blink_leds[0] & 0xff), i) ? BLINK : (BIT_TEST( (scsb_ks_leddata.leds.p10.ok_leds[0] & 0xff), i) ? ON:OFF); mc_nok_led = BIT_TEST( (scsb_ks_leddata.leds.p10.nok_leds[0] & 0xff), i) ? ON:OFF; } } /* else if (!version_p15_and_p20) */ switch (scsb_ks_topo.mct_slots[i].fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } index = (int)scsb_ks_topo.mct_slots[i].fru_type; if (montecarlo) { if (scsb_ks_topo.mct_slots[i].fru_unit == 1) { /* cpu slot */ log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s "), mcfru_type, scsb_ks_topo.mct_slots[i].fru_unit, status, mc_ok_led, mc_nok_led, 0); log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"), mc_nok_led, slot_occupants[index], 0); log_printf(dgettext(TEXT_DOMAIN, "%49stemperature(celsius):%d\n"), BLANK, pcf8591_ks_temp.value, 0); #ifdef NEVER log_printf(dgettext(TEXT_DOMAIN, "%49sminimum temperature:%d\n"), BLANK, pcf8591_ks_temp.min, 0); log_printf(dgettext(TEXT_DOMAIN, "%49swarning temp. threshold:%d\n"), BLANK, pcf8591_ks_temp.warning_threshold, 0); log_printf(dgettext(TEXT_DOMAIN, "%49sshutdown temp.threshold:%d\n"), BLANK, pcf8591_ks_temp.shutdown_threshold, 0); #endif /* NEVER */ } else if ((scsb_ks_topo.mct_slots[i].fru_unit == 2) && (cpu_ftm_present == 1)) { /* CFTM slot */ /* * The CFTM can only be present in Slot 2 * for Netract-800, for Netract-400 the FTM * is not sitted in a Slot. Hence, this is * another special case and we need to handle * this differently than other slots */ log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s "), mcfru_type, scsb_ks_topo.mct_slots[i].fru_unit, status, mc_ok_led, mc_nok_led, 0); log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"), mc_nok_led, CPU_FTM, 0); } else { if (fail_drv_prop == 1) { log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s "), mcfru_type, scsb_ks_topo.mct_slots[i].fru_unit, status, mc_ok_led, 0); log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"), mc_nok_led, slot_occupants[index], 0); log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0); log_printf(dgettext(TEXT_DOMAIN, "%49sauto-config=%s\n"), BLANK, slot_auto_config[i], 0); } else { log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s "), mcfru_type, scsb_ks_topo.mct_slots[i].fru_unit, status, mc_ok_led, 0); log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"), mc_nok_led, slot_occupants[index], 0); } } } else { /* tonga */ if (scsb_ks_topo.mct_slots[i].fru_unit == 3) { /* cpu slot */ log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s "), mcfru_type, scsb_ks_topo.mct_slots[i].fru_unit, status, mc_ok_led, 0); log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"), mc_nok_led, slot_occupants[index], 0); log_printf(dgettext(TEXT_DOMAIN, "%49stemperature(celsius):%d\n"), BLANK, pcf8591_ks_temp.value, 0); #ifdef NEVER log_printf(dgettext(TEXT_DOMAIN, "%49sminimum temperature:%d\n"), BLANK, pcf8591_ks_temp.min, 0); log_printf(dgettext(TEXT_DOMAIN, "%49swarning temp. threshold:%d\n"), BLANK, pcf8591_ks_temp.warning_threshold, 0); log_printf(dgettext(TEXT_DOMAIN, "%49sshutdown temp. threshold:%d\n"), BLANK, pcf8591_ks_temp.shutdown_threshold, 0); #endif /* NEVER */ } else { if (fail_drv_prop == 1) { log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s "), mcfru_type, scsb_ks_topo.mct_slots[i].fru_unit, status, mc_ok_led, 0); log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"), mc_nok_led, slot_occupants[index], 0); log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0); log_printf(dgettext(TEXT_DOMAIN, "%49sauto-config=%s\n"), BLANK, slot_auto_config[tg_cpu_index+1], 0); if (scsb_ks_topo.mct_slots[i].fru_unit != 3) tg_cpu_index++; } else { log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s "), mcfru_type, scsb_ks_topo.mct_slots[i].fru_unit, status, mc_ok_led, 0); log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"), mc_nok_led, slot_occupants[index], 0); } } } /* we first match the correct slot numbers */ for (s_index = 0; s_index < slot_table_size; s_index++) { if (slot_table_not_found == 1) { /* use prom table */ if (scsb_ks_topo.mct_slots[i].fru_unit == prom_slot_table[s_index].pslotnum) { /* * search for the addr/pci num * in all slot info structs */ for (i1 = 0; i1 < slot_index; i1++) { if (prom_slot_table[s_index].pci_devno == mc_slots_data.mc_slot_info[i1].slot_addr) { int nd; log_printf(dgettext(TEXT_DOMAIN, "%46s%s%s\n"), BLANK, BOARDTYPE, board_type, 0); log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, DEVS, 0); log_printf(dgettext(TEXT_DOMAIN, "%49s%s\n"), BLANK, PCI_ROOT_AP, 0); for (nd = 0; nd < mc_slots_data.mc_slot_info[i1].number_devs; nd++) { log_printf(dgettext(TEXT_DOMAIN, "%52s%s\n"), BLANK, mc_slots_data.mc_slot_info[i1].devs_info[nd], 0); } /* for */ } /* if */ } /* for(i1) */ } /* if */ } else { /* use solaris lot table */ if (fail_syssoft_prop == 1) { if (scsb_ks_topo.mct_slots[i].fru_unit == hotswap_slot_table[s_index].pslotnum) { /* * search for the addr/pci * num in all slot info structs */ for (i1 = 0; i1 < slot_index; i1++) { if (hotswap_slot_table[s_index].pci_devno == mc_slots_data.mc_slot_info[i1].slot_addr) { int nd; for (nd = 0; nd < mc_slots_data.mc_slot_info[i1].number_devs; nd++) { log_printf(dgettext(TEXT_DOMAIN, "%49s%s\n"), BLANK, mc_slots_data.mc_slot_info[i1].devs_info[nd], 0); } } /* if */ } /* for(i1) */ } /* if */ } /* (fail_syssoft_prop == 1) */ } /* (slot_table_not_found == 1) */ } /* for(s_index) */ } /* for */ mcfru_type = "PDU"; misc_info = "Power Distribution Unit"; for (i = 0; i < scsb_ks_topo.max_units[PDU]; ++i) { if (version_p15_and_p20) { mc_ok_led = BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[1] & 0xff), PDU1_OK_BIT+i*2) ? BLINK : (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[1] & 0xff), PDU1_OK_BIT+i*2) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[1] & 0xff), PDU1_OK_BIT+i*2) ? ON:OFF; } switch (scsb_ks_topo.mct_pdu[i].fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } if (version_p15_and_p20) { log_printf(dgettext(TEXT_DOMAIN, "%-10s %-5d %-7s %-5s %-5s %s\n"), mcfru_type, scsb_ks_topo.mct_pdu[i].fru_unit, status, mc_ok_led, mc_nok_led, misc_info, 0); } else { log_printf(dgettext(TEXT_DOMAIN, "%-10s %-5d %-7s%18s%s\n"), mcfru_type, scsb_ks_topo.mct_pdu[i].fru_unit, status, BLANK, misc_info, 0); } } /* for */ /* PS */ mcfru_type = prtdiag_fru_types[PS]; misc_info = "Power Supply Unit"; for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) { if (version_p15_and_p20) { mc_ok_led = BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[2] & 0xff), PS1_OK_BIT+i) ? BLINK : (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2] & 0xff), PS1_OK_BIT+i) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2] & 0xff), PS1_OK_BIT+i) ? ON:OFF; } else { /* * support for 1.0 systems - * Hack! - should use tables ? */ mc_ok_led = (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2] & 0xff), 1+i) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2] & 0xff), 1+i) ? ON:OFF; } switch (scsb_ks_topo.mct_ps[i].fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s %-5s %s\n"), mcfru_type, scsb_ks_topo.mct_ps[i].fru_unit, status, mc_ok_led, mc_nok_led, misc_info, 0); if (scsb_ks_topo.mct_ps[i].fru_status == FRU_PRESENT) { if (scsb_ks_topo.mct_ps[i].fru_unit == 1) { log_printf(dgettext(TEXT_DOMAIN, "%49scondition:%s\n"), BLANK, ((pcf8574_ks_ps1.ps_ok)? NOK:OK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49stemperature:%s\n"), BLANK, ((pcf8574_ks_ps1.temp_ok)? NOK:OK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49sps fan:%s\n"), BLANK, ((pcf8574_ks_ps1.psfan_ok)? NOK:OK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49ssupply:%s\n"), BLANK, ((pcf8574_ks_ps1.on_state)? OFF:ON), 0); } else { log_printf(dgettext(TEXT_DOMAIN, "%49scondition:%s\n"), BLANK, ((pcf8574_ks_ps2.ps_ok)? NOK:OK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49stemperature:%s\n"), BLANK, ((pcf8574_ks_ps2.temp_ok)? NOK:OK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49sps fan:%s\n"), BLANK, ((pcf8574_ks_ps2.psfan_ok)? NOK:OK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49ssupply:%s\n"), BLANK, ((pcf8574_ks_ps2.on_state)? OFF:ON), 0); } /* if */ } } /* for */ /* Fan tray */ mcfru_type = prtdiag_fru_types[FAN]; misc_info = "Fan Tray"; for (i = 0; i < scsb_ks_topo.max_units[FAN]; ++i) { if (version_p15_and_p20) { mc_ok_led = BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[2] & 0xff), FAN1_OK_BIT+i) ? BLINK : (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2] & 0xff), FAN1_OK_BIT+i) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2] & 0xff), FAN1_OK_BIT+i) ? ON:OFF; } else { /* * support for 1.0 systems - * Hack! - should use tables ? */ mc_ok_led = (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[3] & 0xff), 3+i) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[3] & 0xff), 3+i) ? ON:OFF; } switch (scsb_ks_topo.mct_fan[i].fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s %-5s %s\n"), mcfru_type, scsb_ks_topo.mct_fan[i].fru_unit, status, mc_ok_led, mc_nok_led, misc_info, 0); if (scsb_ks_topo.mct_fan[i].fru_status == FRU_PRESENT) { if (scsb_ks_topo.mct_fan[i].fru_unit == 1) { log_printf(dgettext(TEXT_DOMAIN, "%49scondition:%s\n"), BLANK, ((pcf8574_ks_fant1.fan_ok)? OK:NOK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49sfan speed:%s\n"), BLANK, ((pcf8574_ks_fant1.fanspeed)? HI:LO), 0); } else { log_printf(dgettext(TEXT_DOMAIN, "%49scondition:%s\n"), BLANK, ((pcf8574_ks_fant2.fan_ok)? OK:NOK), 0); log_printf(dgettext(TEXT_DOMAIN, "%49sfan speed:%s\n"), BLANK, ((pcf8574_ks_fant2.fanspeed)? HI:LO), 0); } } } /* for */ /* DISKS */ for (i = 0; i < scsb_ks_topo.max_units[DISK]; ++i) { if (scsb_ks_topo.mct_disk[i].fru_unit != RMM_NUMBER) mcfru_type = prtdiag_fru_types[DISK]; else mcfru_type = "RMM "; switch (scsb_ks_topo.mct_disk[i].fru_status) { case FRU_PRESENT: status = YES; break; case FRU_NOT_PRESENT: status = NO; break; case FRU_NOT_AVAILABLE: status = NA; break; default: status = NA; break; } if (version_p15_and_p20) { mc_ok_led = BIT_TEST((scsb_ks_leddata.scb_led_regs[8] & 0xff), DISK1_OK_BIT+i) ? BLINK : (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2] & 0xff), DISK1_OK_BIT+i) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2] & 0xff), DISK1_OK_BIT+i) ? ON:OFF; } else { /* * support for 1.0 systems - * Hack! - should use tables ? */ mc_ok_led = (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2] & 0xff), DISK1_OK_BIT+i) ? ON:OFF); mc_nok_led = BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2] & 0xff), DISK1_OK_BIT+i) ? ON:OFF; } /* print everything except condition */ if (scsb_ks_topo.mct_disk[i].fru_unit != RMM_NUMBER) { misc_info = "Hard Disk Drive"; log_printf(dgettext(TEXT_DOMAIN, "%10s %-5d %-7s %-5s %-5s %s\n"), mcfru_type, scsb_ks_topo.mct_disk[i].fru_unit-1, status, mc_ok_led, mc_nok_led, misc_info, 0); } else { misc_info = "Removable Media Module"; log_printf(dgettext(TEXT_DOMAIN, "%10s %5s %-7s %-5s %-5s %s\n"), mcfru_type, BLANK, status, mc_ok_led, mc_nok_led, misc_info, 0); } /* find out fru health from the SCSI drivers */ if (scsb_ks_topo.mct_disk[i].fru_status == FRU_PRESENT) { switch ( scsi_disk_status( scsb_ks_topo.mct_disk[i].fru_unit)) { case 0: health = OK; break; case 1: health = NOK; break; case -1: health = UK; break; default: health = NA; break; } log_printf(dgettext(TEXT_DOMAIN, "%49scondition:%s\n"), BLANK, health, 0); } } /* for */ log_printf(dgettext(TEXT_DOMAIN, "\n"), 0); } /* display_mc_prtdiag_info() */ void analyze_pcipci_siblings(di_node_t node) { di_node_t lc_node; /* we will find all the dev info for slots first */ lc_node = di_drv_first_node("pci_pci", node); lc_node = di_child_node(lc_node); /* we are at "pci" node now */ do { if (di_walk_node(lc_node, DI_WALK_CLDFIRST, NULL, analyze_nodes) != 0) { return; } } while ((lc_node = di_sibling_node(lc_node)) != DI_NODE_NIL); /* now we wll gather info on sysctrl */ lc_node = di_drv_first_node(SCSB_DEV, node); if (lc_node != DI_NODE_NIL) analyze_nodes(lc_node, "sysctrl"); } /* analyze_pcipci_siblings(.) */ int analyze_nodes(di_node_t l_node, void *arg) { char *temp; char *name, *pname; di_node_t parent; /* * we will figure out whether the parent node is "pci" type * we will save info only in this case as we only want to * print out the nodes under AP and not others */ parent = di_parent_node(l_node); pname = di_node_name(parent); name = di_node_name(l_node); /* * if this is PCI bridge, we know that this is the AP for slots * hence, we will save off the address(to convert to slot mapping) * later, and also we will start saving off slot info struct for * reporting later * we will save the immediate childs of this bridge only */ if (strcmp(name, "pci") == 0) { num_devs = 0; if ((temp = di_bus_addr(l_node)) != NULL) { mc_slots_data.mc_slot_info[slot_index].slot_addr = (int)strtol(temp, (char **)NULL, 16); } slot_index++; } else { if (strcmp(pname, "pci") == 0) { if ((mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs]) != NULL) { (void) strcat( mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs], name); } else { (void) strcpy( mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs], name); } /* if ((mc_slots_data.mc_slot_inf */ num_devs++; mc_slots_data.mc_slot_info[slot_index-1].number_devs = num_devs; } /* if parent is pci */ } /* if node is pci */ if (arg != NULL) { if (strcmp((char *)arg, "sysctrl") == 0) { if (dump_prop_list("System", l_node, di_prop_sys_next)) { (void) dump_prop_list(NULL, l_node, di_prop_global_next); } else { fail_syssoft_prop = dump_prop_list(SYSSOFT_PROP, l_node, di_prop_global_next); } fail_drv_prop = dump_prop_list(DRV_PROP, l_node, di_prop_drv_next); /* * (void) dump_prop_list("Hardware", * l_node, di_prop_hw_next); */ /* dump_priv_data(l_node); */ } } return (0); } /* analyze_nodes(..) */ /* * To get the slot information, * The OBP defines the 'slot-table' property. But the OS * can override it with 'hsc-slot-map' property * through the .conf file. * Since the formats are different, 2 different property names * are chosen. * The OBP property format is * ,,, * The OS property format is (ga-bits is not used however) * ,,, * returns 0 on error, 1 otherwise */ int extract_slot_table_from_obp() { if (mc_promopen(O_RDONLY)) { log_printf(dgettext(TEXT_DOMAIN, "\ncannot open openprom device"), 0); return (0); } if (mc_next(0) == 0) return (0); mc_walk(mc_next(0)); if (close(oprom_fd) < 0) { log_printf(dgettext(TEXT_DOMAIN, "\nclose error on %s"), OPENPROMDEV, 0); return (0); } return (1); } /* extract_slot_table_from_obp() */ int mc_next(int id) { Oppbuf oppbuf; struct openpromio *opp = &(oppbuf.opp); bzero(oppbuf.buf, BUFSIZE); opp->oprom_size = MAXVALSIZE; opp->oprom_node = id; if (ioctl(oprom_fd, OPROMNEXT, opp) < 0) { log_printf(dgettext(TEXT_DOMAIN, "\nError OPROMNEXT"), 0); return (0); } return (opp->oprom_node); } /* mc_next(.) */ void mc_walk(int id) { int curnode; mc_dump_node(id); if (curnode = mc_child(id)) mc_walk(curnode); if (curnode = mc_next(id)) mc_walk(curnode); } /* mc_walk(.) */ int mc_child(int id) { Oppbuf oppbuf; struct openpromio *opp = &(oppbuf.opp); bzero(oppbuf.buf, BUFSIZE); opp->oprom_size = MAXVALSIZE; opp->oprom_node = id; if (ioctl(oprom_fd, OPROMCHILD, opp) < 0) { perror("\nOPROMCHILD"); exit(0); } return (opp->oprom_node); } /* mc_child(.) */ /* * Print all properties and values */ void mc_dump_node(int id) { int k; Oppbuf oppbuf; hsc_prom_slot_table_t *hpstp; struct openpromio *opp = &(oppbuf.opp); /* get first prop by asking for null string */ bzero(oppbuf.buf, BUFSIZE); for (;;) { /* * get next property name */ opp->oprom_size = MAXNAMESZ; if (ioctl(oprom_fd, OPROMNXTPROP, opp) < 0) { perror("\nOPROMNXTPROP"); return; } if (opp->oprom_size == 0) break; if (strcmp(opp->oprom_array, "slot-table") == 0) { if (mc_getpropval(opp) || opp->oprom_size == (uint_t)-1) { log_printf(dgettext(TEXT_DOMAIN, "\ndata not available"), 0); return; } else { slot_table_size = opp->oprom_size / sizeof (hsc_prom_slot_table_t); hpstp = (hsc_prom_slot_table_t *)opp->oprom_array; for (k = 0; k < slot_table_size; k++, hpstp++) { prom_slot_table[k].pslotnum = hpstp->pslotnum; prom_slot_table[k].ga = hpstp->ga; prom_slot_table[k].pci_devno = hpstp->pci_devno; prom_slot_table[k].phandle = hpstp->phandle; } /* for (k = 0; k < slot_table_size; k++) */ } } } } /* mc_dump_node(.) */ int mc_getpropval(struct openpromio *opp) { opp->oprom_size = MAXVALSIZE; if (ioctl(oprom_fd, OPROMGETPROP, opp) < 0) { log_printf(dgettext(TEXT_DOMAIN, "\nError OPROMGETPROP"), 0); return (1); } return (0); } /* mc_getpropval(.) */ /* * This function returns nothing. */ void alarm_card_occupant() { int scsb_fd; scsb_ioc_rdwr_t ioc_read; uint8_t new_mode = 0; uint8_t old_mode = 0; uchar_t reg_index; if (NULL == scsb_node) { if (check_platform() == -1) { return; } } if (version_p15_and_p20 == 1) reg_index = 0xe9; /* config status reg offset on SCB */ else reg_index = 0xd7; /* config status reg offset on SCB */ if ((scsb_fd = open(scsb_node, O_RDONLY)) < 0) { log_printf(dgettext(TEXT_DOMAIN, "\n%s open failed"), scsb_node, 0); return; } /* save off the old mode */ if (scsb_mode(scsb_fd, GET, &old_mode) == 0) return; /* we put scsb in diag mode to read this specific ioctl */ new_mode = ENVCTRL_DIAG_MODE; if (scsb_mode(scsb_fd, SET, &new_mode) == 0) return; /* now lets read the config register */ if (scsb_ioc_reg_read(scsb_fd, reg_index, &ioc_read, 1) == 0) return; /* restore the original mode */ if (scsb_mode(scsb_fd, SET, &old_mode) == 0) return; alarm_card_present = (BIT_TEST(ioc_read.ioc_rbuf[0]&0xff, 0) ? 1:0); } /* alarm_card_occupant() */ /* * This function changes the SCSB mode to the desired one * 1 on sucess, 0 otherwise */ int scsb_mode(int fd, scsb_op_t sop, uint8_t *new_mode) { struct strioctl sioc; if (sop == GET) sioc.ic_cmd = ENVC_IOC_GETMODE; else sioc.ic_cmd = ENVC_IOC_SETMODE; sioc.ic_timout = 0; sioc.ic_len = sizeof (uint8_t); sioc.ic_dp = (char *)new_mode; if (ioctl(fd, I_STR, &sioc) == -1) { log_printf(dgettext(TEXT_DOMAIN, "\nscsb_mode():scsb ioctl() failed"), 0); return (0); } return (1); } /* scsb_mode(...) */ /* * 1 on success, 0 otherwise */ int scsb_ioc_reg_read(int fd, uchar_t index, scsb_ioc_rdwr_t *ioc_rd, int num) { struct strioctl sioc; scsb_ioc_rdwr_t *rdwrp; rdwrp = ioc_rd; sioc.ic_timout = 0; sioc.ic_len = sizeof (scsb_ioc_rdwr_t); sioc.ic_dp = (char *)rdwrp; /* setup read command before ioctl */ sioc.ic_cmd = SCSBIOC_REG_READ; rdwrp->ioc_wlen = 0; rdwrp->ioc_rlen = num; rdwrp->ioc_regindex = index; if (ioctl(fd, I_STR, &sioc) == -1) { log_printf(dgettext(TEXT_DOMAIN, "scsb_ioc_reg_read(): scsb ioctl() failed\n"), 0); return (0); } return (1); } /* scsb_ioc_reg_read(....) */