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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <strings.h> 29 #include <fm/fmd_fmri.h> 30 #include <fm/libtopo.h> 31 #include <fm/topo_mod.h> 32 33 int 34 fmd_fmri_init(void) 35 { 36 return (0); 37 } 38 39 void 40 fmd_fmri_fini(void) 41 { 42 } 43 44 ssize_t 45 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 46 { 47 int err; 48 uint8_t version; 49 ssize_t len; 50 topo_hdl_t *thp; 51 char *str; 52 53 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 54 version > FM_HC_SCHEME_VERSION) 55 return (fmd_fmri_set_errno(EINVAL)); 56 57 thp = fmd_fmri_topology(TOPO_VERSION); 58 if (topo_fmri_nvl2str(thp, nvl, &str, &err) != 0) 59 return (fmd_fmri_set_errno(EINVAL)); 60 61 if (buf != NULL) 62 len = snprintf(buf, buflen, "%s", str); 63 else 64 len = strlen(str); 65 66 topo_hdl_strfree(thp, str); 67 68 return (len); 69 } 70 71 typedef struct hc_walk_arg { 72 void *p; 73 int *resultp; 74 } hc_walk_arg_t; 75 76 static int 77 hc_topo_walk(topo_hdl_t *thp, topo_walk_cb_t fn, void *arg, int *resultp) 78 { 79 int err, rv; 80 topo_walk_t *twp; 81 hc_walk_arg_t hcarg; 82 83 hcarg.p = arg; 84 hcarg.resultp = resultp; 85 86 if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, fn, 87 &hcarg, &err)) == NULL) 88 return (-1); 89 90 rv = (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) 91 ? -1 : 0; 92 93 topo_walk_fini(twp); 94 return (rv); 95 } 96 97 /*ARGSUSED*/ 98 static int 99 hc_topo_present(topo_hdl_t *thp, tnode_t *node, void *arg) 100 { 101 int cmp, err; 102 nvlist_t *out, *asru; 103 hc_walk_arg_t *hcargp = (hc_walk_arg_t *)arg; 104 105 /* 106 * Only care about sata-ports and disks 107 */ 108 if (strcmp(topo_node_name(node), SATA_PORT) != 0 && 109 strcmp(topo_node_name(node), DISK) != 0) 110 return (TOPO_WALK_NEXT); 111 112 if (topo_node_asru(node, &asru, NULL, &err) != 0 || 113 asru == NULL) { 114 return (TOPO_WALK_NEXT); 115 } 116 117 /* 118 * Check if the ASRU of this node matches the ASRU passed in 119 */ 120 cmp = topo_fmri_compare(thp, asru, (nvlist_t *)hcargp->p, &err); 121 122 nvlist_free(asru); 123 124 if (cmp <= 0) 125 return (TOPO_WALK_NEXT); 126 127 /* 128 * Yes, so try to execute the topo-present method. 129 */ 130 if (topo_method_invoke(node, TOPO_METH_PRESENT, 131 TOPO_METH_PRESENT_VERSION, (nvlist_t *)hcargp->p, &out, &err) 132 == 0) { 133 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, 134 (uint32_t *)hcargp->resultp); 135 nvlist_free(out); 136 return (TOPO_WALK_TERMINATE); 137 } else { 138 return (TOPO_WALK_ERR); 139 } 140 141 } 142 143 /* 144 * The SATA disk topology permits an ASRU to be declared as a pseudo-hc 145 * FMRI, something like this: 146 * 147 * hc:///motherboard=0/hostbridge=0/pcibus=0/pcidev=1/pcifn=0/sata-port=1 148 * ASRU: hc:///component=sata0/1 149 * FRU: hc:///component=MB 150 * Label: sata0/1 151 * 152 * This is a hack to support cfgadm attachment point ASRUs without defining 153 * a new scheme. As a result, we need to support an is_present function for 154 * something * that begins with hc:///component=. To do this, we compare the 155 * nvlist provided by the caller against the ASRU property for all possible 156 * topology nodes. 157 * 158 * The SATA phase 2 project will address the lack of a proper FMRI scheme 159 * for cfgadm attachment points. This code may be removed when the SATA 160 * phase 2 FMA work is completed. 161 */ 162 static int 163 hc_sata_hack(nvlist_t *nvl) 164 { 165 int ispresent = 1; 166 topo_hdl_t *thp; 167 168 /* 169 * If there's an error during the topology update, punt by 170 * indicating presence. 171 */ 172 thp = fmd_fmri_topology(TOPO_VERSION); 173 (void) hc_topo_walk(thp, hc_topo_present, nvl, &ispresent); 174 175 return (ispresent); 176 } 177 178 int 179 fmd_fmri_present(nvlist_t *nvl) 180 { 181 int err, present; 182 topo_hdl_t *thp; 183 nvlist_t **hcprs; 184 char *nm; 185 uint_t hcnprs; 186 187 err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); 188 err |= nvlist_lookup_string(hcprs[0], FM_FMRI_HC_NAME, &nm); 189 if (err != 0) 190 return (0); 191 192 if (strcmp(nm, "component") == 0) 193 return (hc_sata_hack(nvl)); 194 195 thp = fmd_fmri_topology(TOPO_VERSION); 196 present = topo_fmri_present(thp, nvl, &err); 197 198 if (err != 0) 199 return (present); 200 else 201 return (1); 202 } 203 204 /* 205 * fmd_fmri_unusable() is called by fmadm to determine if a faulty ASRU 206 * is usable. In general we don't expect to get ASRUs in this scheme, 207 * so it's unlikely this routine will get called. In case it does, 208 * though, we just return false by default, as we have no real way to 209 * find the component or determine the component's usability. 210 */ 211 /*ARGSUSED*/ 212 int 213 fmd_fmri_unusable(nvlist_t *nvl) 214 { 215 return (0); 216 } 217