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 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2019, Joyent, Inc. 25 */ 26 27 #include <sys/fm/protocol.h> 28 #include <strings.h> 29 #include <fm/topo_mod.h> 30 #include <fm/topo_method.h> 31 #include <sys/scsi/impl/inquiry.h> 32 #include <sys/scsi/impl/scsi_sas.h> 33 #include <sys/scsi/scsi_address.h> 34 #include <did_props.h> 35 36 static const topo_pgroup_info_t storage_pgroup = 37 { TOPO_PGROUP_STORAGE, TOPO_STABILITY_PRIVATE, 38 TOPO_STABILITY_PRIVATE, 1 }; 39 40 static const topo_method_t recep_methods[] = { 41 { TOPO_METH_OCCUPIED, TOPO_METH_OCCUPIED_DESC, 42 TOPO_METH_OCCUPIED_VERSION, TOPO_STABILITY_INTERNAL, 43 topo_mod_hc_occupied }, 44 { NULL } 45 }; 46 47 void 48 pci_di_prop_set(tnode_t *tn, di_node_t din, char *dpnm, char *tpnm) 49 { 50 int err; 51 char *tmpbuf; 52 53 if (di_prop_lookup_strings(DDI_DEV_T_ANY, din, dpnm, &tmpbuf) == 1) 54 (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm, 55 TOPO_PROP_IMMUTABLE, tmpbuf, &err); 56 } 57 58 void 59 pci_pi_prop_set(tnode_t *tn, di_path_t din, char *dpnm, char *tpnm) 60 { 61 int err; 62 char *tmpbuf; 63 64 if (di_path_prop_lookup_strings(din, dpnm, &tmpbuf) == 1) 65 (void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm, 66 TOPO_PROP_IMMUTABLE, tmpbuf, &err); 67 } 68 69 static void 70 pci_scsi_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent, 71 di_node_t cn, int instance, di_path_t pi) 72 { 73 tnode_t *child; 74 nvlist_t *fmri; 75 int e, *val; 76 int64_t *val64; 77 78 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SCSI_DEVICE, 79 instance, NULL, auth, NULL, NULL, NULL); 80 if (fmri == NULL) 81 return; 82 child = topo_node_bind(mod, parent, SCSI_DEVICE, instance, fmri); 83 nvlist_free(fmri); 84 if (child == NULL) 85 return; 86 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0) 87 return; 88 if (pi != NULL) { 89 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT, 90 TOPO_STORAGE_TARGET_PORT); 91 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT, 92 TOPO_STORAGE_ATTACHED_PORT); 93 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT_PM, 94 TOPO_STORAGE_TARGET_PORT_PM); 95 pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT_PM, 96 TOPO_STORAGE_ATTACHED_PORT_PM); 97 if (di_path_prop_lookup_int64s(pi, 98 SCSI_ADDR_PROP_LUN64, &val64) == 1) 99 (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE, 100 TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64, 101 &e); 102 } else { 103 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT, 104 TOPO_STORAGE_TARGET_PORT); 105 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT, 106 TOPO_STORAGE_ATTACHED_PORT); 107 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM, 108 TOPO_STORAGE_TARGET_PORT_PM); 109 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM, 110 TOPO_STORAGE_ATTACHED_PORT_PM); 111 if (di_prop_lookup_int64(DDI_DEV_T_ANY, cn, 112 SCSI_ADDR_PROP_LUN64, &val64) == 1) 113 (void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE, 114 TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64, 115 &e); 116 } 117 pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID); 118 pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID, 119 TOPO_STORAGE_MANUFACTURER); 120 pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL); 121 pci_di_prop_set(child, cn, INQUIRY_REVISION_ID, 122 TOPO_STORAGE_FIRMWARE_REV); 123 if (di_prop_lookup_ints(DDI_DEV_T_ANY, cn, 124 INQUIRY_DEVICE_TYPE, &val) == 1) 125 (void) topo_prop_set_int32(child, TOPO_PGROUP_STORAGE, 126 TOPO_STORAGE_DEVICE_TYPE, TOPO_PROP_IMMUTABLE, *val, &e); 127 } 128 129 static void 130 pci_smp_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent, 131 di_node_t cn, int instance) 132 { 133 tnode_t *child; 134 nvlist_t *fmri; 135 int e; 136 137 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SMP_DEVICE, 138 instance, NULL, auth, NULL, NULL, NULL); 139 if (fmri == NULL) 140 return; 141 child = topo_node_bind(mod, parent, SMP_DEVICE, instance, fmri); 142 nvlist_free(fmri); 143 if (child == NULL) 144 return; 145 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0) 146 return; 147 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT, 148 TOPO_STORAGE_TARGET_PORT); 149 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT, 150 TOPO_STORAGE_ATTACHED_PORT); 151 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM, 152 TOPO_STORAGE_TARGET_PORT_PM); 153 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM, 154 TOPO_STORAGE_ATTACHED_PORT_PM); 155 pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID); 156 pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID, 157 TOPO_STORAGE_MANUFACTURER); 158 pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL); 159 pci_di_prop_set(child, cn, INQUIRY_REVISION_ID, 160 TOPO_STORAGE_FIRMWARE_REV); 161 } 162 163 static tnode_t * 164 pci_iport_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent, 165 di_node_t cn, int instance) 166 { 167 tnode_t *child; 168 nvlist_t *fmri; 169 int e; 170 171 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, IPORT, 172 instance, NULL, auth, NULL, NULL, NULL); 173 if (fmri == NULL) 174 return (NULL); 175 child = topo_node_bind(mod, parent, IPORT, instance, fmri); 176 nvlist_free(fmri); 177 if (child == NULL) 178 return (NULL); 179 if (topo_pgroup_create(child, &storage_pgroup, &e) < 0) 180 return (child); 181 pci_di_prop_set(child, cn, SCSI_ADDR_PROP_INITIATOR_PORT, 182 TOPO_STORAGE_INITIATOR_PORT); 183 (void) topo_prop_set_string(child, TOPO_PGROUP_STORAGE, 184 TOPO_STORAGE_INITIATOR_PORT_PM, TOPO_PROP_IMMUTABLE, 185 di_bus_addr(cn), &e); 186 return (child); 187 } 188 189 void 190 pci_iports_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn, 191 int niports) 192 { 193 di_node_t cn, smp, sd; 194 di_path_t pi; 195 tnode_t *iport; 196 int i, j; 197 nvlist_t *auth; 198 199 if (topo_node_range_create(mod, parent, IPORT, 0, niports) < 0) 200 return; 201 auth = topo_mod_auth(mod, parent); 202 for (i = 0, cn = di_child_node(pn); cn != DI_NODE_NIL; 203 cn = di_sibling_node(cn)) { 204 /* 205 * First create any iport nodes. 206 */ 207 if (strcmp(di_node_name(cn), "iport") != 0) 208 continue; 209 iport = pci_iport_device_create(mod, auth, parent, cn, i++); 210 if (iport == NULL) 211 continue; 212 213 /* 214 * Now create any scsi-device nodes. 215 */ 216 for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL; 217 sd = di_sibling_node(sd)) 218 if (strcmp(di_node_name(sd), "smp") != 0) 219 j++; 220 for (pi = di_path_phci_next_path(cn, DI_PATH_NIL); 221 pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi)) 222 if (di_path_client_node(pi) != NULL && 223 strcmp(di_node_name(di_path_client_node(pi)), 224 "smp") != 0) 225 j++; 226 if (topo_node_range_create(mod, iport, SCSI_DEVICE, 0, j) < 0) 227 continue; 228 for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL; 229 sd = di_sibling_node(sd)) 230 if (strcmp(di_node_name(sd), "smp") != 0) 231 pci_scsi_device_create(mod, auth, iport, sd, 232 j++, NULL); 233 for (pi = di_path_phci_next_path(cn, DI_PATH_NIL); 234 pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi)) 235 if (di_path_client_node(pi) != NULL && 236 strcmp(di_node_name(di_path_client_node(pi)), 237 "smp") != 0) 238 pci_scsi_device_create(mod, auth, iport, 239 di_path_client_node(pi), j++, pi); 240 241 /* 242 * Now create any smp-device nodes. 243 */ 244 for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL; 245 smp = di_sibling_node(smp)) 246 if (strcmp(di_node_name(smp), "smp") == 0) 247 j++; 248 if (topo_node_range_create(mod, iport, SMP_DEVICE, 0, j) < 0) 249 continue; 250 for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL; 251 smp = di_sibling_node(smp)) 252 if (strcmp(di_node_name(smp), "smp") == 0) 253 pci_smp_device_create(mod, auth, iport, smp, 254 j++); 255 } 256 nvlist_free(auth); 257 } 258 259 void 260 pci_receptacle_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pnode) 261 { 262 int err, i, rcnt, lcnt; 263 char *propstrpm, *propstrlabel, *pm, *label; 264 nvlist_t *fmri, *auth; 265 tnode_t *recep; 266 267 rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode, 268 DI_RECEPTACLE_PHYMASK, &propstrpm); 269 if ((lcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode, 270 DI_RECEPTACLE_LABEL, &propstrlabel)) <= 0) { 271 topo_mod_dprintf(mod, 272 "pci_receptacle_instanciate: rececptacle label not " 273 "found for the pci function node.\n"); 274 return; 275 } 276 277 if (rcnt != lcnt) { 278 topo_mod_dprintf(mod, 279 "pci_receptacle_instantiate: rececptacle label count %d " 280 "doesn match with phy mask count %d\n", lcnt, rcnt); 281 } 282 283 label = propstrlabel; 284 pm = propstrpm; 285 auth = topo_mod_auth(mod, parent); 286 for (i = 0; i < rcnt; i++) { 287 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, 288 RECEPTACLE, i, NULL, auth, NULL, NULL, NULL); 289 if (fmri == NULL) { 290 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s", 291 topo_mod_errmsg(mod)); 292 continue; 293 } 294 recep = topo_node_bind(mod, parent, RECEPTACLE, i, fmri); 295 nvlist_free(fmri); 296 if (recep == NULL) { 297 topo_mod_dprintf(mod, "topo_node_bind() failed: %s", 298 topo_mod_errmsg(mod)); 299 continue; 300 } 301 302 if (label) { 303 if (topo_node_label_set(recep, label, &err) < 0) { 304 topo_mod_dprintf(mod, 305 "topo_receptacle_instantiate: " 306 "topo_node_label_set error(%s)\n", 307 topo_strerror(err)); 308 } 309 if (i < lcnt) { 310 label = label + strlen(label) + 1; 311 } else { 312 label = NULL; 313 } 314 } 315 316 if (topo_pgroup_create(recep, &storage_pgroup, &err) < 0) { 317 topo_mod_dprintf(mod, "ses_set_expander_props: " 318 "create storage error %s\n", topo_strerror(err)); 319 continue; 320 } 321 (void) topo_prop_set_string(recep, TOPO_PGROUP_STORAGE, 322 TOPO_STORAGE_SAS_PHY_MASK, 323 TOPO_PROP_IMMUTABLE, pm, &err); 324 325 if (topo_method_register(mod, recep, recep_methods) != 0) { 326 topo_mod_dprintf(mod, "topo_method_register() failed " 327 "on %s=%d: %s", RECEPTACLE, i, 328 topo_mod_errmsg(mod)); 329 /* errno set */ 330 continue; 331 } 332 333 pm = pm + strlen(pm) + 1; 334 } 335 336 nvlist_free(auth); 337 } 338