17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5749f21d3Swesolows * Common Development and Distribution License (the "License"). 6749f21d3Swesolows * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21749f21d3Swesolows 227c478bd9Sstevel@tonic-gate /* 23*705dd6c2SJakub Jermar * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <mem.h> 287c478bd9Sstevel@tonic-gate #include <fm/fmd_fmri.h> 2970818f58Stsien #include <fm/libtopo.h> 30e4b86885SCheng Sean Ye #include <fm/fmd_agent.h> 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <string.h> 337c478bd9Sstevel@tonic-gate #include <strings.h> 347c478bd9Sstevel@tonic-gate #include <sys/mem.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate mem_t mem; 377c478bd9Sstevel@tonic-gate 38d00f0155Sayznaga static int 397c478bd9Sstevel@tonic-gate mem_fmri_get_unum(nvlist_t *nvl, char **unump) 407c478bd9Sstevel@tonic-gate { 417c478bd9Sstevel@tonic-gate uint8_t version; 427c478bd9Sstevel@tonic-gate char *unum; 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 457c478bd9Sstevel@tonic-gate version > FM_MEM_SCHEME_VERSION || 467c478bd9Sstevel@tonic-gate nvlist_lookup_string(nvl, FM_FMRI_MEM_UNUM, &unum) != 0) 477c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL)); 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate *unump = unum; 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate return (0); 527c478bd9Sstevel@tonic-gate } 537c478bd9Sstevel@tonic-gate 54e4b86885SCheng Sean Ye static int 55e4b86885SCheng Sean Ye page_isretired(nvlist_t *fmri, int *errp) 56e4b86885SCheng Sean Ye { 57e4b86885SCheng Sean Ye fmd_agent_hdl_t *hdl; 58e4b86885SCheng Sean Ye int rc, err; 59e4b86885SCheng Sean Ye 60e4b86885SCheng Sean Ye if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) 61e4b86885SCheng Sean Ye return (-1); 62e4b86885SCheng Sean Ye rc = fmd_agent_page_isretired(hdl, fmri); 63e4b86885SCheng Sean Ye err = fmd_agent_errno(hdl); 64e4b86885SCheng Sean Ye fmd_agent_close(hdl); 65e4b86885SCheng Sean Ye 66e4b86885SCheng Sean Ye if (errp != NULL) 67e4b86885SCheng Sean Ye *errp = err; 68e4b86885SCheng Sean Ye return (rc); 69e4b86885SCheng Sean Ye } 70e4b86885SCheng Sean Ye 717c478bd9Sstevel@tonic-gate ssize_t 727c478bd9Sstevel@tonic-gate fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 737c478bd9Sstevel@tonic-gate { 747aec1d6eScindi char format[64]; 757c478bd9Sstevel@tonic-gate ssize_t size, presz; 767aec1d6eScindi char *rawunum, *preunum, *escunum, *prefix; 777aec1d6eScindi uint64_t val; 787c478bd9Sstevel@tonic-gate int i; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate if (mem_fmri_get_unum(nvl, &rawunum) < 0) 817c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 827c478bd9Sstevel@tonic-gate 837aec1d6eScindi /* 847aec1d6eScindi * If we have a well-formed unum (hc-FMRI), use the string verbatim 857aec1d6eScindi * to form the initial mem:/// components. Otherwise use unum=%s. 867aec1d6eScindi */ 870eb822a1Scindi if (strncmp(rawunum, "hc://", 5) != 0) 887aec1d6eScindi prefix = FM_FMRI_MEM_UNUM "="; 897aec1d6eScindi else 907aec1d6eScindi prefix = ""; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937aec1d6eScindi * If we have a DIMM offset, include it in the string. If we have a PA 947aec1d6eScindi * then use that. Otherwise just format the unum element. 957c478bd9Sstevel@tonic-gate */ 967aec1d6eScindi if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val) == 0) { 977aec1d6eScindi (void) snprintf(format, sizeof (format), 987aec1d6eScindi "%s:///%s%%1$s/%s=%%2$llx", 997aec1d6eScindi FM_FMRI_SCHEME_MEM, prefix, FM_FMRI_MEM_OFFSET); 1007aec1d6eScindi } else if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val) == 0) { 1017aec1d6eScindi (void) snprintf(format, sizeof (format), 1027aec1d6eScindi "%s:///%s%%1$s/%s=%%2$llx", 1037aec1d6eScindi FM_FMRI_SCHEME_MEM, prefix, FM_FMRI_MEM_PHYSADDR); 1047aec1d6eScindi } else { 1057aec1d6eScindi (void) snprintf(format, sizeof (format), 1067aec1d6eScindi "%s:///%s%%1$s", FM_FMRI_SCHEME_MEM, prefix); 1077aec1d6eScindi } 1087aec1d6eScindi 1097aec1d6eScindi /* 1100eb822a1Scindi * If we have a well-formed unum (hc-FMRI), we skip over the 1110eb822a1Scindi * the scheme and authority prefix. 1127aec1d6eScindi * Otherwise, the spaces and colons will be escaped, 1137aec1d6eScindi * rendering the resulting FMRI pretty much unreadable. 1147aec1d6eScindi * We're therefore going to do some escaping of our own first. 1157aec1d6eScindi */ 1160eb822a1Scindi if (strncmp(rawunum, "hc://", 5) == 0) { 1170eb822a1Scindi rawunum += 5; 1180eb822a1Scindi rawunum = strchr(rawunum, '/'); 1190eb822a1Scindi ++rawunum; 1207aec1d6eScindi /* LINTED: variable format specifier */ 1210eb822a1Scindi size = snprintf(buf, buflen, format, rawunum, val); 1227aec1d6eScindi } else { 1237c478bd9Sstevel@tonic-gate preunum = fmd_fmri_strdup(rawunum); 1247c478bd9Sstevel@tonic-gate presz = strlen(preunum) + 1; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate for (i = 0; i < presz - 1; i++) { 1277c478bd9Sstevel@tonic-gate if (preunum[i] == ':' && preunum[i + 1] == ' ') { 1287c478bd9Sstevel@tonic-gate bcopy(preunum + i + 2, preunum + i + 1, 1297c478bd9Sstevel@tonic-gate presz - (i + 2)); 1307c478bd9Sstevel@tonic-gate } else if (preunum[i] == ' ') { 1317c478bd9Sstevel@tonic-gate preunum[i] = ','; 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate escunum = fmd_fmri_strescape(preunum); 1367c478bd9Sstevel@tonic-gate fmd_fmri_free(preunum, presz); 1377c478bd9Sstevel@tonic-gate 1387aec1d6eScindi /* LINTED: variable format specifier */ 1397aec1d6eScindi size = snprintf(buf, buflen, format, escunum, val); 1407c478bd9Sstevel@tonic-gate fmd_fmri_strfree(escunum); 1417aec1d6eScindi } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate return (size); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate int 1477c478bd9Sstevel@tonic-gate fmd_fmri_expand(nvlist_t *nvl) 1487c478bd9Sstevel@tonic-gate { 1497c478bd9Sstevel@tonic-gate char *unum, **serids; 150749f21d3Swesolows uint_t nnvlserids; 151749f21d3Swesolows size_t nserids; 15270818f58Stsien int rc, err = 0; 15370818f58Stsien topo_hdl_t *thp; 1547c478bd9Sstevel@tonic-gate 155822f48a6Skd93003 if ((mem_fmri_get_unum(nvl, &unum) < 0) || (*unum == '\0')) 1567c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL)); 1577c478bd9Sstevel@tonic-gate 15870818f58Stsien /* 15970818f58Stsien * If the mem-scheme topology exports this method expand(), invoke it. 16070818f58Stsien */ 16170818f58Stsien if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 16270818f58Stsien return (fmd_fmri_set_errno(EINVAL)); 16370818f58Stsien rc = topo_fmri_expand(thp, nvl, &err); 16470818f58Stsien fmd_fmri_topo_rele(thp); 16570818f58Stsien if (err != ETOPO_METHOD_NOTSUP) 16670818f58Stsien return (rc); 16770818f58Stsien 1687c478bd9Sstevel@tonic-gate if ((rc = nvlist_lookup_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, 169fbd1c0daSsd77468 &serids, &nnvlserids)) == 0) { /* already have serial #s */ 170fbd1c0daSsd77468 return (0); 171fbd1c0daSsd77468 } else if (rc != ENOENT) 1727c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL)); 1737c478bd9Sstevel@tonic-gate 174d00f0155Sayznaga if (mem_get_serids_by_unum(unum, &serids, &nserids) < 0) { 175d00f0155Sayznaga /* errno is set for us */ 176d00f0155Sayznaga if (errno == ENOTSUP) 177d00f0155Sayznaga return (0); /* nothing to add - no s/n support */ 178d00f0155Sayznaga else 179d00f0155Sayznaga return (-1); 180d00f0155Sayznaga } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate rc = nvlist_add_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, serids, 1837c478bd9Sstevel@tonic-gate nserids); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate mem_strarray_free(serids, nserids); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate if (rc != 0) 1887c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL)); 189fbd1c0daSsd77468 else 1907c478bd9Sstevel@tonic-gate return (0); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1932cb5535aSrobj #ifdef sparc 1947c478bd9Sstevel@tonic-gate static int 1957c478bd9Sstevel@tonic-gate serids_eq(char **serids1, uint_t nserids1, char **serids2, uint_t nserids2) 1967c478bd9Sstevel@tonic-gate { 1977c478bd9Sstevel@tonic-gate int i; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if (nserids1 != nserids2) 2007c478bd9Sstevel@tonic-gate return (0); 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate for (i = 0; i < nserids1; i++) { 2037c478bd9Sstevel@tonic-gate if (strcmp(serids1[i], serids2[i]) != 0) 2047c478bd9Sstevel@tonic-gate return (0); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate return (1); 2087c478bd9Sstevel@tonic-gate } 2092cb5535aSrobj #endif /* sparc */ 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate int 2127c478bd9Sstevel@tonic-gate fmd_fmri_present(nvlist_t *nvl) 2137c478bd9Sstevel@tonic-gate { 2142cb5535aSrobj char *unum = NULL; 21570818f58Stsien int rc, err = 0; 21670818f58Stsien struct topo_hdl *thp; 2172cb5535aSrobj #ifdef sparc 2182cb5535aSrobj char **nvlserids, **serids; 219749f21d3Swesolows uint_t nnvlserids; 220749f21d3Swesolows size_t nserids; 2212cb5535aSrobj #else 2222cb5535aSrobj nvlist_t *unum_nvl; 22325c6ff4bSstephh nvlist_t *nvlcp = NULL; 22425c6ff4bSstephh uint64_t val; 2252cb5535aSrobj #endif /* sparc */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (mem_fmri_get_unum(nvl, &unum) < 0) 2287c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 2297c478bd9Sstevel@tonic-gate 2302cb5535aSrobj #ifdef sparc 23170818f58Stsien /* 23270818f58Stsien * If the mem-scheme topology exports this method present(), invoke it. 23370818f58Stsien */ 23470818f58Stsien if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 23570818f58Stsien return (fmd_fmri_set_errno(EINVAL)); 23670818f58Stsien rc = topo_fmri_present(thp, nvl, &err); 23770818f58Stsien fmd_fmri_topo_rele(thp); 23870818f58Stsien if (err != ETOPO_METHOD_NOTSUP) 23970818f58Stsien return (rc); 24070818f58Stsien 2417c478bd9Sstevel@tonic-gate if (nvlist_lookup_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, &nvlserids, 242d00f0155Sayznaga &nnvlserids) != 0) { 243d00f0155Sayznaga /* 244d00f0155Sayznaga * Some mem scheme FMRIs don't have serial ids because 245d00f0155Sayznaga * either the platform does not support them, or because 246d00f0155Sayznaga * the FMRI was created before support for serial ids was 247d00f0155Sayznaga * introduced. If this is the case, assume it is there. 248d00f0155Sayznaga */ 249d00f0155Sayznaga if (mem.mem_dm == NULL) 250d00f0155Sayznaga return (1); 251d00f0155Sayznaga else 2527c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL)); 253d00f0155Sayznaga } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate if (mem_get_serids_by_unum(unum, &serids, &nserids) < 0) { 256d00f0155Sayznaga if (errno == ENOTSUP) 257d00f0155Sayznaga return (1); /* assume it's there, no s/n support here */ 2587c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * Errors are only signalled to the caller if they're 2617c478bd9Sstevel@tonic-gate * the caller's fault. This isn't - it's a failure on 2627c478bd9Sstevel@tonic-gate * our part to burst or read the serial numbers. We'll 2637c478bd9Sstevel@tonic-gate * whine about it, and tell the caller the named 2647c478bd9Sstevel@tonic-gate * module(s) isn't/aren't there. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate fmd_fmri_warn("failed to retrieve serial number for " 2677c478bd9Sstevel@tonic-gate "unum %s", unum); 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate return (0); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate rc = serids_eq(serids, nserids, nvlserids, nnvlserids); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate mem_strarray_free(serids, nserids); 2752cb5535aSrobj #else 2762cb5535aSrobj /* 2772cb5535aSrobj * On X86 we will invoke the topo is_present method passing in the 2782cb5535aSrobj * unum, which is in hc scheme. The libtopo hc-scheme is_present method 2792cb5535aSrobj * will invoke the node-specific is_present method, which is implemented 2802cb5535aSrobj * by the chip enumerator for rank nodes. The rank node's is_present 2812cb5535aSrobj * method will compare the serial number in the unum with the current 2822cb5535aSrobj * serial to determine if the same DIMM is present. 2832cb5535aSrobj */ 2842cb5535aSrobj if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) { 2852cb5535aSrobj fmd_fmri_warn("failed to get handle to topology"); 2862cb5535aSrobj return (-1); 2872cb5535aSrobj } 2882cb5535aSrobj if (topo_fmri_str2nvl(thp, unum, &unum_nvl, &err) == 0) { 2892cb5535aSrobj rc = topo_fmri_present(thp, unum_nvl, &err); 2902cb5535aSrobj nvlist_free(unum_nvl); 2912cb5535aSrobj } else 2922cb5535aSrobj rc = fmd_fmri_set_errno(EINVAL); 2932cb5535aSrobj fmd_fmri_topo_rele(thp); 2947c478bd9Sstevel@tonic-gate 29525c6ff4bSstephh /* 29625c6ff4bSstephh * Need to check if this is a valid page too. if "isretired" returns 29725c6ff4bSstephh * EINVAL, assume page invalid and return not_present. 29825c6ff4bSstephh */ 29925c6ff4bSstephh if (rc == 1 && nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val) == 30025c6ff4bSstephh 0 && nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val) == 0 && 30125c6ff4bSstephh mem_unum_rewrite(nvl, &nvlcp) == 0 && nvlcp != NULL) { 302e4b86885SCheng Sean Ye int page_err, rval = page_isretired(nvlcp, &page_err); 303e4b86885SCheng Sean Ye if (rval == FMD_AGENT_RETIRE_DONE && page_err == EINVAL) 30425c6ff4bSstephh rc = 0; 30525c6ff4bSstephh nvlist_free(nvlcp); 30625c6ff4bSstephh } 30725c6ff4bSstephh #endif /* sparc */ 30825c6ff4bSstephh return (rc); 30925c6ff4bSstephh } 31025c6ff4bSstephh 31125c6ff4bSstephh int 31225c6ff4bSstephh fmd_fmri_replaced(nvlist_t *nvl) 31325c6ff4bSstephh { 31425c6ff4bSstephh char *unum = NULL; 31525c6ff4bSstephh int rc, err = 0; 31625c6ff4bSstephh struct topo_hdl *thp; 31725c6ff4bSstephh #ifdef sparc 31825c6ff4bSstephh char **nvlserids, **serids; 31925c6ff4bSstephh uint_t nnvlserids; 32025c6ff4bSstephh size_t nserids; 32125c6ff4bSstephh #else 32225c6ff4bSstephh nvlist_t *unum_nvl; 32325c6ff4bSstephh nvlist_t *nvlcp = NULL; 32425c6ff4bSstephh uint64_t val; 32525c6ff4bSstephh #endif /* sparc */ 32625c6ff4bSstephh 32725c6ff4bSstephh if (mem_fmri_get_unum(nvl, &unum) < 0) 32825c6ff4bSstephh return (-1); /* errno is set for us */ 32925c6ff4bSstephh 33025c6ff4bSstephh #ifdef sparc 33125c6ff4bSstephh /* 33225c6ff4bSstephh * If the mem-scheme topology exports this method replaced(), invoke it. 33325c6ff4bSstephh */ 33425c6ff4bSstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 33525c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL)); 33625c6ff4bSstephh rc = topo_fmri_replaced(thp, nvl, &err); 33725c6ff4bSstephh fmd_fmri_topo_rele(thp); 33825c6ff4bSstephh if (err != ETOPO_METHOD_NOTSUP) 33925c6ff4bSstephh return (rc); 34025c6ff4bSstephh 34125c6ff4bSstephh if (nvlist_lookup_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, &nvlserids, 34225c6ff4bSstephh &nnvlserids) != 0) { 34325c6ff4bSstephh /* 34425c6ff4bSstephh * Some mem scheme FMRIs don't have serial ids because 34525c6ff4bSstephh * either the platform does not support them, or because 34625c6ff4bSstephh * the FMRI was created before support for serial ids was 34725c6ff4bSstephh * introduced. If this is the case, assume it is there. 34825c6ff4bSstephh */ 34925c6ff4bSstephh if (mem.mem_dm == NULL) 35025c6ff4bSstephh return (FMD_OBJ_STATE_UNKNOWN); 35125c6ff4bSstephh else 35225c6ff4bSstephh return (fmd_fmri_set_errno(EINVAL)); 35325c6ff4bSstephh } 35425c6ff4bSstephh 35525c6ff4bSstephh if (mem_get_serids_by_unum(unum, &serids, &nserids) < 0) { 35625c6ff4bSstephh if (errno == ENOTSUP) 35725c6ff4bSstephh return (FMD_OBJ_STATE_UNKNOWN); 35825c6ff4bSstephh if (errno != ENOENT) { 35925c6ff4bSstephh /* 36025c6ff4bSstephh * Errors are only signalled to the caller if they're 36125c6ff4bSstephh * the caller's fault. This isn't - it's a failure on 36225c6ff4bSstephh * our part to burst or read the serial numbers. We'll 36325c6ff4bSstephh * whine about it, and tell the caller the named 36425c6ff4bSstephh * module(s) isn't/aren't there. 36525c6ff4bSstephh */ 36625c6ff4bSstephh fmd_fmri_warn("failed to retrieve serial number for " 36725c6ff4bSstephh "unum %s", unum); 36825c6ff4bSstephh } 36925c6ff4bSstephh return (FMD_OBJ_STATE_NOT_PRESENT); 37025c6ff4bSstephh } 37125c6ff4bSstephh 37225c6ff4bSstephh rc = serids_eq(serids, nserids, nvlserids, nnvlserids) ? 37325c6ff4bSstephh FMD_OBJ_STATE_STILL_PRESENT : FMD_OBJ_STATE_REPLACED; 37425c6ff4bSstephh 37525c6ff4bSstephh mem_strarray_free(serids, nserids); 37625c6ff4bSstephh #else 37725c6ff4bSstephh /* 37825c6ff4bSstephh * On X86 we will invoke the topo is_replaced method passing in the 37925c6ff4bSstephh * unum, which is in hc scheme. The libtopo hc-scheme is_replaced 38025c6ff4bSstephh * method will invoke the node-specific is_replaced method, which is 38125c6ff4bSstephh * implemented by the chip enumerator for rank nodes. The rank node's 38225c6ff4bSstephh * is_replaced method will compare the serial number in the unum with 38325c6ff4bSstephh * the current serial to determine if the same DIMM is replaced. 38425c6ff4bSstephh */ 38525c6ff4bSstephh if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) { 38625c6ff4bSstephh fmd_fmri_warn("failed to get handle to topology"); 38725c6ff4bSstephh return (-1); 38825c6ff4bSstephh } 38925c6ff4bSstephh if (topo_fmri_str2nvl(thp, unum, &unum_nvl, &err) == 0) { 39025c6ff4bSstephh rc = topo_fmri_replaced(thp, unum_nvl, &err); 39125c6ff4bSstephh nvlist_free(unum_nvl); 39225c6ff4bSstephh } else 39325c6ff4bSstephh rc = fmd_fmri_set_errno(EINVAL); 39425c6ff4bSstephh fmd_fmri_topo_rele(thp); 39525c6ff4bSstephh 39625c6ff4bSstephh /* 39725c6ff4bSstephh * Need to check if this is a valid page too. if "isretired" returns 39825c6ff4bSstephh * EINVAL, assume page invalid and return not_present. 39925c6ff4bSstephh */ 40025c6ff4bSstephh if ((rc == FMD_OBJ_STATE_STILL_PRESENT || 40125c6ff4bSstephh rc == FMD_OBJ_STATE_UNKNOWN) && 40225c6ff4bSstephh nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val) == 0 && 40325c6ff4bSstephh nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val) == 0 && 40425c6ff4bSstephh mem_unum_rewrite(nvl, &nvlcp) == 0 && nvlcp != NULL) { 405e4b86885SCheng Sean Ye int page_err, rval = page_isretired(nvlcp, &page_err); 406e4b86885SCheng Sean Ye if (rval == FMD_AGENT_RETIRE_DONE && page_err == EINVAL) 40725c6ff4bSstephh rc = FMD_OBJ_STATE_NOT_PRESENT; 40825c6ff4bSstephh nvlist_free(nvlcp); 40925c6ff4bSstephh } 4102cb5535aSrobj #endif /* sparc */ 4117c478bd9Sstevel@tonic-gate return (rc); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate int 4157c478bd9Sstevel@tonic-gate fmd_fmri_contains(nvlist_t *er, nvlist_t *ee) 4167c478bd9Sstevel@tonic-gate { 41770818f58Stsien int rc, err = 0; 41870818f58Stsien struct topo_hdl *thp; 4197c478bd9Sstevel@tonic-gate char *erunum, *eeunum; 4207aec1d6eScindi uint64_t erval = 0, eeval = 0; 4217c478bd9Sstevel@tonic-gate 42270818f58Stsien /* 42370818f58Stsien * If the mem-scheme topology exports this method contains(), invoke it. 42470818f58Stsien */ 42570818f58Stsien if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 42670818f58Stsien return (fmd_fmri_set_errno(EINVAL)); 42770818f58Stsien rc = topo_fmri_contains(thp, er, ee, &err); 42870818f58Stsien fmd_fmri_topo_rele(thp); 42970818f58Stsien if (err != ETOPO_METHOD_NOTSUP) 43070818f58Stsien return (rc); 43170818f58Stsien 4327c478bd9Sstevel@tonic-gate if (mem_fmri_get_unum(er, &erunum) < 0 || 4337c478bd9Sstevel@tonic-gate mem_fmri_get_unum(ee, &eeunum) < 0) 4347c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate if (mem_unum_contains(erunum, eeunum) <= 0) 4377c478bd9Sstevel@tonic-gate return (0); /* can't parse/match, so assume no containment */ 4387c478bd9Sstevel@tonic-gate 4397aec1d6eScindi if (nvlist_lookup_uint64(er, FM_FMRI_MEM_OFFSET, &erval) == 0) { 4407aec1d6eScindi return (nvlist_lookup_uint64(ee, 4417aec1d6eScindi FM_FMRI_MEM_OFFSET, &eeval) == 0 && erval == eeval); 4427aec1d6eScindi } 4437aec1d6eScindi 4447aec1d6eScindi if (nvlist_lookup_uint64(er, FM_FMRI_MEM_PHYSADDR, &erval) == 0) { 4457aec1d6eScindi return (nvlist_lookup_uint64(ee, 4467aec1d6eScindi FM_FMRI_MEM_PHYSADDR, &eeval) == 0 && erval == eeval); 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate return (1); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527aec1d6eScindi /* 4537aec1d6eScindi * We can only make a usable/unusable determination for pages. Mem FMRIs 4547aec1d6eScindi * without page addresses will be reported as usable since Solaris has no 4557aec1d6eScindi * way at present to dynamically disable an entire DIMM or DIMM pair. 4567aec1d6eScindi */ 4577c478bd9Sstevel@tonic-gate int 4587c478bd9Sstevel@tonic-gate fmd_fmri_unusable(nvlist_t *nvl) 4597c478bd9Sstevel@tonic-gate { 460*705dd6c2SJakub Jermar uint64_t val1, val2; 4617c478bd9Sstevel@tonic-gate uint8_t version; 46270818f58Stsien int rc, err1 = 0, err2; 4637aec1d6eScindi nvlist_t *nvlcp = NULL; 4647aec1d6eScindi int retval; 46570818f58Stsien topo_hdl_t *thp; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 4687c478bd9Sstevel@tonic-gate version > FM_MEM_SCHEME_VERSION) 4697c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL)); 4707c478bd9Sstevel@tonic-gate 47170818f58Stsien /* 47270818f58Stsien * If the mem-scheme topology exports this method unusable(), invoke it. 47370818f58Stsien */ 47470818f58Stsien if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) 47570818f58Stsien return (fmd_fmri_set_errno(EINVAL)); 47670818f58Stsien rc = topo_fmri_unusable(thp, nvl, &err1); 47770818f58Stsien fmd_fmri_topo_rele(thp); 47870818f58Stsien if (err1 != ETOPO_METHOD_NOTSUP) 47970818f58Stsien return (rc); 48070818f58Stsien 481*705dd6c2SJakub Jermar err1 = nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &val1); 482*705dd6c2SJakub Jermar err2 = nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &val2); 4837aec1d6eScindi 4847aec1d6eScindi if (err1 == ENOENT && err2 == ENOENT) 4857c478bd9Sstevel@tonic-gate return (0); /* no page, so assume it's still usable */ 4867aec1d6eScindi 4877aec1d6eScindi if ((err1 != 0 && err1 != ENOENT) || (err2 != 0 && err2 != ENOENT)) 4887c478bd9Sstevel@tonic-gate return (fmd_fmri_set_errno(EINVAL)); 4897c478bd9Sstevel@tonic-gate 490*705dd6c2SJakub Jermar if ((rc = mem_unum_rewrite(nvl, &nvlcp)) != 0) 491*705dd6c2SJakub Jermar return (fmd_fmri_set_errno(rc)); 4927aec1d6eScindi 4937aec1d6eScindi /* 4947aec1d6eScindi * Ask the kernel if the page is retired, using either the rewritten 4957aec1d6eScindi * hc FMRI or the original mem FMRI with the specified offset or PA. 4967aec1d6eScindi * Refer to the kernel's page_retire_check() for the error codes. 4977aec1d6eScindi */ 498e4b86885SCheng Sean Ye rc = page_isretired(nvlcp ? nvlcp : nvl, NULL); 4997aec1d6eScindi 500e4b86885SCheng Sean Ye if (rc == FMD_AGENT_RETIRE_FAIL) { 5017aec1d6eScindi /* 5027aec1d6eScindi * The page is not retired and is not scheduled for retirement 5037aec1d6eScindi * (i.e. no request pending and has not seen any errors) 5047aec1d6eScindi */ 5057aec1d6eScindi retval = 0; 506e4b86885SCheng Sean Ye } else if (rc == FMD_AGENT_RETIRE_DONE || 507e4b86885SCheng Sean Ye rc == FMD_AGENT_RETIRE_ASYNC) { 5087c478bd9Sstevel@tonic-gate /* 5097c478bd9Sstevel@tonic-gate * The page has been retired, is in the process of being 5107c478bd9Sstevel@tonic-gate * retired, or doesn't exist. The latter is valid if the page 5117c478bd9Sstevel@tonic-gate * existed in the past but has been DR'd out. 5127c478bd9Sstevel@tonic-gate */ 5137aec1d6eScindi retval = 1; 5147c478bd9Sstevel@tonic-gate } else { 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * Errors are only signalled to the caller if they're the 5177c478bd9Sstevel@tonic-gate * caller's fault. This isn't - it's a failure of the 5187c478bd9Sstevel@tonic-gate * retirement-check code. We'll whine about it and tell 5197c478bd9Sstevel@tonic-gate * the caller the page is unusable. 5207c478bd9Sstevel@tonic-gate */ 5217aec1d6eScindi fmd_fmri_warn("failed to determine page %s=%llx usability: " 5227aec1d6eScindi "rc=%d errno=%d\n", err1 == 0 ? FM_FMRI_MEM_OFFSET : 523*705dd6c2SJakub Jermar FM_FMRI_MEM_PHYSADDR, err1 == 0 ? (u_longlong_t)val1 : 524*705dd6c2SJakub Jermar (u_longlong_t)val2, rc, errno); 5257aec1d6eScindi retval = 1; 5267c478bd9Sstevel@tonic-gate } 5277aec1d6eScindi 5287aec1d6eScindi nvlist_free(nvlcp); 5297aec1d6eScindi 5307aec1d6eScindi return (retval); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate int 5347c478bd9Sstevel@tonic-gate fmd_fmri_init(void) 5357c478bd9Sstevel@tonic-gate { 5367c478bd9Sstevel@tonic-gate return (mem_discover()); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate void 5407c478bd9Sstevel@tonic-gate fmd_fmri_fini(void) 5417c478bd9Sstevel@tonic-gate { 5427aec1d6eScindi mem_dimm_map_t *dm, *em; 543d30c532dStsien mem_bank_map_t *bm, *cm; 544d30c532dStsien mem_grp_t *gm, *hm; 545fbd1c0daSsd77468 mem_seg_map_t *sm, *tm; 5467aec1d6eScindi 5477aec1d6eScindi for (dm = mem.mem_dm; dm != NULL; dm = em) { 5487aec1d6eScindi em = dm->dm_next; 5497aec1d6eScindi fmd_fmri_strfree(dm->dm_label); 550fbd1c0daSsd77468 fmd_fmri_strfree(dm->dm_part); 5517aec1d6eScindi fmd_fmri_strfree(dm->dm_device); 5527aec1d6eScindi fmd_fmri_free(dm, sizeof (mem_dimm_map_t)); 5537aec1d6eScindi } 554d30c532dStsien for (bm = mem.mem_bank; bm != NULL; bm = cm) { 555d30c532dStsien cm = bm->bm_next; 556d30c532dStsien fmd_fmri_free(bm, sizeof (mem_bank_map_t)); 557d30c532dStsien } 558d30c532dStsien for (gm = mem.mem_group; gm != NULL; gm = hm) { 559d30c532dStsien hm = gm->mg_next; 560d30c532dStsien fmd_fmri_free(gm, sizeof (mem_grp_t)); 561d30c532dStsien } 562fbd1c0daSsd77468 for (sm = mem.mem_seg; sm != NULL; sm = tm) { 563fbd1c0daSsd77468 tm = sm->sm_next; 564fbd1c0daSsd77468 fmd_fmri_free(sm, sizeof (mem_seg_map_t)); 565fbd1c0daSsd77468 } 5667c478bd9Sstevel@tonic-gate } 567