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