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 2005 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 #include <stdarg.h> 30 #include <sys/param.h> 31 #include <errno.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <strings.h> 35 #include <kstat.h> 36 #include <fm/fmd_api.h> 37 #include <sys/fm/protocol.h> 38 #include <sys/async.h> 39 40 #define IOD_STAT_BUMP(name) iod.iod_stats->name.fmds_value.ui64++ 41 42 /* 43 * USII-io-diagnosis: 44 * 45 * This diagnosis engine consumes the Psycho based IO UEs and CEs 46 * which are generated due to DMA Reads or Writes. 47 * 48 * When a UE is received it will generate the appropriate fault 49 * (defect.ultraSPARC-II.memory.nodiag). This is because we do not plan 50 * to currently add greater diagnosis capabilities for USII systems. 51 * 52 * When a CE is received we allow the legacy in kernel SERD do it's job 53 * and we just bump a counter here. The legacy SERD algorithm will print 54 * out a message and retire pages when the SERD threshold is reached. 55 * 56 */ 57 static void iod_recv(fmd_hdl_t *, fmd_event_t *, nvlist_t *, const char *); 58 59 typedef struct iod_stat { 60 fmd_stat_t ue; /* # of UEs received */ 61 fmd_stat_t ce; /* # of CEs received */ 62 } iod_stat_t; 63 64 typedef struct iod { 65 iod_stat_t *iod_stats; /* Module statistics */ 66 } iod_t; 67 68 static const fmd_hdl_ops_t fmd_ops = { 69 iod_recv, /* fmdo_recv */ 70 NULL, /* fmdo_timeout */ 71 NULL, /* fmdo_close */ 72 NULL, /* fmdo_stats */ 73 NULL /* fmdo_gc */ 74 }; 75 76 static const fmd_hdl_info_t fmd_info = { 77 "UltraSPARC-II I/O Diagnosis", IOD_VERSION, &fmd_ops, NULL 78 }; 79 80 static const iod_stat_t iod_stat = { 81 { "ue", FMD_TYPE_UINT64, "number of received IO UEs" }, 82 { "ce", FMD_TYPE_UINT64, "number of received IO CEs" } 83 }; 84 85 iod_t iod; 86 87 /*ARGSUSED*/ 88 static void 89 iod_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) 90 { 91 fmd_case_t *cp; 92 nvlist_t *fault; 93 char flt[] = "defect.ultraSPARC-II.memory.nodiag"; 94 95 if (fmd_nvl_class_match(hdl, nvl, "*ue")) { 96 IOD_STAT_BUMP(ue); 97 cp = fmd_case_open(hdl, NULL); 98 fault = fmd_nvl_create_fault(hdl, flt, 100, NULL, NULL, NULL); 99 fmd_case_add_ereport(hdl, cp, ep); 100 fmd_case_add_suspect(hdl, cp, fault); 101 fmd_case_solve(hdl, cp); 102 } else if (fmd_nvl_class_match(hdl, nvl, "*ce")) { 103 IOD_STAT_BUMP(ce); 104 } 105 } 106 107 int 108 iod_cpu_check_support(void) 109 { 110 kstat_named_t *kn; 111 kstat_ctl_t *kc; 112 kstat_t *ksp; 113 int i; 114 115 if ((kc = kstat_open()) == NULL) 116 return (0); 117 118 for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 119 if (strcmp(ksp->ks_module, "cpu_info") != 0) 120 continue; 121 122 if (kstat_read(kc, ksp, NULL) == -1) { 123 (void) kstat_close(kc); 124 return (0); 125 } 126 127 for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { 128 if (strcmp(kn->name, "implementation") != 0) 129 continue; 130 131 if (strncmp(KSTAT_NAMED_STR_PTR(kn), "UltraSPARC-II", 132 sizeof ("UltraSPARC-II") - 1) == 0 && 133 strncmp(KSTAT_NAMED_STR_PTR(kn), "UltraSPARC-III", 134 sizeof ("UltraSPARC-III") - 1) != 0) { 135 (void) kstat_close(kc); 136 return (1); 137 } 138 } 139 } 140 141 (void) kstat_close(kc); 142 return (0); 143 } 144 145 void 146 _fmd_init(fmd_hdl_t *hdl) 147 { 148 if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) 149 return; /* error in configuration file or fmd_info */ 150 151 if (!iod_cpu_check_support()) { 152 fmd_hdl_debug(hdl, "no supported CPUs found"); 153 fmd_hdl_unregister(hdl); 154 return; 155 } 156 157 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.drue"); 158 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.s-drue"); 159 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.dwue"); 160 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.s-dwue"); 161 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.drce"); 162 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.s-drce"); 163 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.dwce"); 164 fmd_hdl_subscribe(hdl, "ereport.io.psy.ecc.s-dwce"); 165 166 bzero(&iod, sizeof (iod_t)); 167 168 iod.iod_stats = (iod_stat_t *)fmd_stat_create(hdl, FMD_STAT_NOALLOC, 169 sizeof (iod_stat) / sizeof (fmd_stat_t), (fmd_stat_t *)&iod_stat); 170 } 171