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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 #include <sys/time.h> 29 #include <sys/systm.h> 30 31 #include <sys/fm/protocol.h> 32 #include <sys/devfm.h> 33 34 extern int cpu_get_mem_addr(char *, char *, uint64_t, uint64_t *); 35 36 int 37 fm_get_paddr(nvlist_t *nvl, uint64_t *paddr) 38 { 39 uint8_t version; 40 uint64_t pa; 41 char *scheme; 42 int err; 43 uint64_t offset; 44 char *unum; 45 char **serids; 46 uint_t nserids; 47 48 /* Verify FMRI scheme name and version number */ 49 if ((nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) || 50 (strcmp(scheme, FM_FMRI_SCHEME_MEM) != 0) || 51 (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0) || 52 version > FM_MEM_SCHEME_VERSION) { 53 return (EINVAL); 54 } 55 56 /* 57 * There are two ways a physical address can be obtained from a mem 58 * scheme FMRI. One way is to use the "offset" and "serial" 59 * members, if they are present, together with the "unum" member to 60 * calculate a physical address. This is the preferred way since 61 * it is independent of possible changes to the programming of 62 * underlying hardware registers that may change the physical address. 63 * If the "offset" member is not present, then the address is 64 * retrieved from the "physaddr" member. 65 */ 66 if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0) { 67 if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) != 68 0) { 69 return (EINVAL); 70 } 71 } else if (nvlist_lookup_string(nvl, FM_FMRI_MEM_UNUM, &unum) != 0 || 72 nvlist_lookup_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, &serids, 73 &nserids) != 0) { 74 return (EINVAL); 75 } else { 76 err = cpu_get_mem_addr(unum, serids[0], offset, &pa); 77 if (err != 0) { 78 if (err == ENOTSUP) { 79 /* Fall back to physaddr */ 80 if (nvlist_lookup_uint64(nvl, 81 FM_FMRI_MEM_PHYSADDR, &pa) != 0) 82 return (EINVAL); 83 } else 84 return (err); 85 } 86 } 87 88 *paddr = pa; 89 return (0); 90 } 91