Home | History | Annotate | Download | only in cpumem-diagnosis
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * OPL platform specific functions for
     31  * CPU/Memory error diagnosis engine.
     32  */
     33 #include <cmd_opl.h>
     34 #include <string.h>
     35 #include <errno.h>
     36 #include <cmd_mem.h>
     37 #include <sys/fm/protocol.h>
     38 #include <sys/int_const.h>
     39 
     40 cmd_list_t *
     41 opl_cpulist_insert(fmd_hdl_t *hdl, uint32_t cpuid, int flt_type)
     42 {
     43 	opl_cpu_t *opl_cpu = NULL;
     44 	cmd_list_t *list_head = NULL;
     45 	uint32_t c, s, sib_cpuid, base_cpuid;
     46 
     47 	switch (flt_type) {
     48 	case IS_STRAND:
     49 		opl_cpu = fmd_hdl_alloc(hdl, sizeof (opl_cpu_t), FMD_SLEEP);
     50 		opl_cpu->oc_cpuid = cpuid;
     51 		cmd_list_append(&opl_cpu_list, opl_cpu);
     52 		list_head = &opl_cpu_list;
     53 		break;
     54 
     55 	case IS_CORE:
     56 		/*
     57 		 * Currently there are only two strands per core.
     58 		 * Xor the least significant bit to get the sibling strand
     59 		 */
     60 		sib_cpuid = cpuid ^ 1;
     61 		for (s = 0; s <= STRAND_UPPER_BOUND; s++) {
     62 			opl_cpu = fmd_hdl_alloc(hdl, sizeof (opl_cpu_t),
     63 			    FMD_SLEEP);
     64 			if (s == 0) {
     65 				opl_cpu->oc_cpuid = cpuid;
     66 				cmd_list_append(&opl_cpu_list, opl_cpu);
     67 				list_head = &opl_cpu_list;
     68 			} else {
     69 				opl_cpu->oc_cpuid = sib_cpuid;
     70 				cmd_list_insert_after(&opl_cpu_list,
     71 				    list_head, opl_cpu);
     72 			}
     73 		}
     74 		break;
     75 
     76 	case IS_CHIP:
     77 		/*
     78 		 * Enumerate all the cpus/strands based on the max # of cores
     79 		 * within a chip and max # of strands within a core.
     80 		 */
     81 		base_cpuid = (cpuid >> CHIPID_SHIFT) << CHIPID_SHIFT;
     82 		for (c = 0; c <= CORE_UPPER_BOUND; c++) {
     83 			for (s = 0; s <= STRAND_UPPER_BOUND; s++) {
     84 				opl_cpu = fmd_hdl_alloc(hdl,
     85 				    sizeof (opl_cpu_t), FMD_SLEEP);
     86 				opl_cpu->oc_cpuid = base_cpuid |
     87 				    c << COREID_SHIFT | s;
     88 				if (c == 0 && s == 0) {
     89 					cmd_list_append(&opl_cpu_list, opl_cpu);
     90 					list_head = &opl_cpu_list;
     91 				} else
     92 					cmd_list_insert_after(&opl_cpu_list,
     93 					    list_head, opl_cpu);
     94 			}
     95 		}
     96 		break;
     97 
     98 	default:
     99 		list_head = NULL;
    100 		break;
    101 	}
    102 
    103 	return (list_head);
    104 }
    105 
    106 void
    107 opl_cpulist_free(fmd_hdl_t *hdl, cmd_list_t *cpu_list)
    108 {
    109 	opl_cpu_t *opl_cpu;
    110 
    111 	fmd_hdl_debug(hdl,
    112 	    "Enter opl_cpulist_free for cpulist %llx\n", cpu_list);
    113 
    114 	while ((opl_cpu = cmd_list_next(cpu_list)) != NULL) {
    115 		cmd_list_delete(cpu_list, opl_cpu);
    116 		fmd_hdl_free(hdl, opl_cpu, sizeof (opl_cpu_t));
    117 	}
    118 }
    119 
    120 /*
    121  * Based on "avg" function of eversholt
    122  */
    123 uint8_t
    124 opl_avg(uint_t sum, uint_t cnt)
    125 {
    126 	unsigned long long s = sum * 10;
    127 
    128 	return ((s / cnt / 10) + (((s / cnt % 10) >= 5) ? 1 : 0));
    129 }
    130 
    131 /*
    132  * This function builds the resource fmri page based on
    133  * the kstat "cpu_fru" of the faulted cpu and cpuid
    134  * using the "hc" scheme.
    135  */
    136 nvlist_t *
    137 opl_cpursrc_create(fmd_hdl_t *hdl, uint32_t cpuid)
    138 {
    139 	nvlist_t *fmri;
    140 	char *frustr, *comp;
    141 	int cmu_num;
    142 
    143 	if ((errno = nvlist_alloc(&fmri, NV_UNIQUE_NAME, 0)) != 0)
    144 		return (NULL);
    145 
    146 	if ((frustr = cmd_cpu_getfrustr_by_id(hdl, cpuid)) == NULL) {
    147 		nvlist_free(fmri);
    148 		return (NULL);
    149 	}
    150 
    151 	/*
    152 	 * get the CMU # from cpu_fru for each model
    153 	 * exit with an error if we can not find one.
    154 	 */
    155 	if (strncmp(frustr, OPL_CPU_FRU_FMRI_DC,
    156 	    sizeof (OPL_CPU_FRU_FMRI_DC) - 1) == 0) {
    157 		comp = frustr + sizeof (OPL_CPU_FRU_FMRI_DC) - 1;
    158 		(void) sscanf(comp, "%2d", &cmu_num);
    159 	} else if (strncmp(frustr, OPL_CPU_FRU_FMRI_FF1,
    160 	    sizeof (OPL_CPU_FRU_FMRI_FF1) - 1) == 0) {
    161 		comp = frustr + sizeof (OPL_CPU_FRU_FMRI_FF1) - 1;
    162 		(void) sscanf(comp, "%d", &cmu_num);
    163 		cmu_num /= 2;
    164 	} else if (strncmp(frustr, OPL_CPU_FRU_FMRI_FF2,
    165 	    sizeof (OPL_CPU_FRU_FMRI_FF2) - 1) == 0) {
    166 		comp = frustr + sizeof (OPL_CPU_FRU_FMRI_FF2) - 1;
    167 		(void) sscanf(comp, "%d", &cmu_num);
    168 		cmu_num /= 2;
    169 	} else if (strncmp(frustr, OPL_CPU_FRU_FMRI_IKKAKU,
    170 	    sizeof (OPL_CPU_FRU_FMRI_IKKAKU) - 1) == 0) {
    171 		cmu_num = 0;
    172 	} else {
    173 		CMD_STAT_BUMP(bad_cpu_asru);
    174 		fmd_hdl_strfree(hdl, frustr);
    175 		nvlist_free(fmri);
    176 		return (NULL);
    177 	}
    178 
    179 	if (cmd_fmri_hc_set(hdl, fmri, FM_HC_SCHEME_VERSION, NULL, NULL,
    180 	    NPAIRS, "chassis", 0, "cmu", cmu_num, "chip",
    181 	    ((cpuid >> CHIPID_SHIFT) & CHIP_OR_CORE_MASK),
    182 	    "core", ((cpuid >> COREID_SHIFT) & CHIP_OR_CORE_MASK),
    183 	    "strand", (cpuid & STRAND_MASK)) != 0) {
    184 		fmd_hdl_strfree(hdl, frustr);
    185 		nvlist_free(fmri);
    186 		return (NULL);
    187 	}
    188 
    189 	fmd_hdl_strfree(hdl, frustr);
    190 	return (fmri);
    191 }
    192 
    193 nvlist_t *
    194 opl_mem_fru_create(fmd_hdl_t *hdl, nvlist_t *nvl)
    195 {
    196 	nvlist_t *fmri;
    197 	char *unum;
    198 	char **serids;
    199 	size_t nserids;
    200 
    201 
    202 	if (nvlist_lookup_string(nvl, FM_FMRI_MEM_UNUM, &unum) != 0)
    203 		return (NULL);
    204 
    205 	fmd_hdl_debug(hdl, "opl_mem_fru_create for mem %s\n", unum);
    206 
    207 	if ((fmri = cmd_mem_fmri_create(unum, NULL, 0)) == NULL)
    208 		return (NULL);
    209 
    210 	if ((nvlist_lookup_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, &serids,
    211 	    &nserids)) == 0) {
    212 		if ((nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
    213 		    serids, nserids)) != 0) {
    214 			nvlist_free(fmri);
    215 			return (NULL);
    216 		}
    217 	}
    218 
    219 	return (fmri);
    220 }
    221