1*e4b86885SCheng Sean Ye /* 2*e4b86885SCheng Sean Ye * CDDL HEADER START 3*e4b86885SCheng Sean Ye * 4*e4b86885SCheng Sean Ye * The contents of this file are subject to the terms of the 5*e4b86885SCheng Sean Ye * Common Development and Distribution License (the "License"). 6*e4b86885SCheng Sean Ye * You may not use this file except in compliance with the License. 7*e4b86885SCheng Sean Ye * 8*e4b86885SCheng Sean Ye * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*e4b86885SCheng Sean Ye * or http://www.opensolaris.org/os/licensing. 10*e4b86885SCheng Sean Ye * See the License for the specific language governing permissions 11*e4b86885SCheng Sean Ye * and limitations under the License. 12*e4b86885SCheng Sean Ye * 13*e4b86885SCheng Sean Ye * When distributing Covered Code, include this CDDL HEADER in each 14*e4b86885SCheng Sean Ye * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*e4b86885SCheng Sean Ye * If applicable, add the following below this CDDL HEADER, with the 16*e4b86885SCheng Sean Ye * fields enclosed by brackets "[]" replaced with your own identifying 17*e4b86885SCheng Sean Ye * information: Portions Copyright [yyyy] [name of copyright owner] 18*e4b86885SCheng Sean Ye * 19*e4b86885SCheng Sean Ye * CDDL HEADER END 20*e4b86885SCheng Sean Ye */ 21*e4b86885SCheng Sean Ye /* 22*e4b86885SCheng Sean Ye * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*e4b86885SCheng Sean Ye * Use is subject to license terms. 24*e4b86885SCheng Sean Ye */ 25*e4b86885SCheng Sean Ye 26*e4b86885SCheng Sean Ye #include <sys/stat.h> 27*e4b86885SCheng Sean Ye #include <sys/types.h> 28*e4b86885SCheng Sean Ye #include <sys/time.h> 29*e4b86885SCheng Sean Ye #include <sys/systm.h> 30*e4b86885SCheng Sean Ye 31*e4b86885SCheng Sean Ye #include <sys/fm/protocol.h> 32*e4b86885SCheng Sean Ye #include <sys/devfm.h> 33*e4b86885SCheng Sean Ye 34*e4b86885SCheng Sean Ye extern int cpu_get_mem_addr(char *, char *, uint64_t, uint64_t *); 35*e4b86885SCheng Sean Ye 36*e4b86885SCheng Sean Ye int 37*e4b86885SCheng Sean Ye fm_get_paddr(nvlist_t *nvl, uint64_t *paddr) 38*e4b86885SCheng Sean Ye { 39*e4b86885SCheng Sean Ye uint8_t version; 40*e4b86885SCheng Sean Ye uint64_t pa; 41*e4b86885SCheng Sean Ye char *scheme; 42*e4b86885SCheng Sean Ye int err; 43*e4b86885SCheng Sean Ye uint64_t offset; 44*e4b86885SCheng Sean Ye char *unum; 45*e4b86885SCheng Sean Ye char **serids; 46*e4b86885SCheng Sean Ye uint_t nserids; 47*e4b86885SCheng Sean Ye 48*e4b86885SCheng Sean Ye /* Verify FMRI scheme name and version number */ 49*e4b86885SCheng Sean Ye if ((nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) || 50*e4b86885SCheng Sean Ye (strcmp(scheme, FM_FMRI_SCHEME_MEM) != 0) || 51*e4b86885SCheng Sean Ye (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0) || 52*e4b86885SCheng Sean Ye version > FM_MEM_SCHEME_VERSION) { 53*e4b86885SCheng Sean Ye return (EINVAL); 54*e4b86885SCheng Sean Ye } 55*e4b86885SCheng Sean Ye 56*e4b86885SCheng Sean Ye /* 57*e4b86885SCheng Sean Ye * There are two ways a physical address can be obtained from a mem 58*e4b86885SCheng Sean Ye * scheme FMRI. One way is to use the "offset" and "serial" 59*e4b86885SCheng Sean Ye * members, if they are present, together with the "unum" member to 60*e4b86885SCheng Sean Ye * calculate a physical address. This is the preferred way since 61*e4b86885SCheng Sean Ye * it is independent of possible changes to the programming of 62*e4b86885SCheng Sean Ye * underlying hardware registers that may change the physical address. 63*e4b86885SCheng Sean Ye * If the "offset" member is not present, then the address is 64*e4b86885SCheng Sean Ye * retrieved from the "physaddr" member. 65*e4b86885SCheng Sean Ye */ 66*e4b86885SCheng Sean Ye if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0) { 67*e4b86885SCheng Sean Ye if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) != 68*e4b86885SCheng Sean Ye 0) { 69*e4b86885SCheng Sean Ye return (EINVAL); 70*e4b86885SCheng Sean Ye } 71*e4b86885SCheng Sean Ye } else if (nvlist_lookup_string(nvl, FM_FMRI_MEM_UNUM, &unum) != 0 || 72*e4b86885SCheng Sean Ye nvlist_lookup_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, &serids, 73*e4b86885SCheng Sean Ye &nserids) != 0) { 74*e4b86885SCheng Sean Ye return (EINVAL); 75*e4b86885SCheng Sean Ye } else { 76*e4b86885SCheng Sean Ye err = cpu_get_mem_addr(unum, serids[0], offset, &pa); 77*e4b86885SCheng Sean Ye if (err != 0) { 78*e4b86885SCheng Sean Ye if (err == ENOTSUP) { 79*e4b86885SCheng Sean Ye /* Fall back to physaddr */ 80*e4b86885SCheng Sean Ye if (nvlist_lookup_uint64(nvl, 81*e4b86885SCheng Sean Ye FM_FMRI_MEM_PHYSADDR, &pa) != 0) 82*e4b86885SCheng Sean Ye return (EINVAL); 83*e4b86885SCheng Sean Ye } else 84*e4b86885SCheng Sean Ye return (err); 85*e4b86885SCheng Sean Ye } 86*e4b86885SCheng Sean Ye } 87*e4b86885SCheng Sean Ye 88*e4b86885SCheng Sean Ye *paddr = pa; 89*e4b86885SCheng Sean Ye return (0); 90*e4b86885SCheng Sean Ye } 91