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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Create bay topology node from SMBIOS Type 136 structure, call the disk 29 * enumerator to enumerate a SATA direct attached disk. 30 */ 31 32 #include <sys/types.h> 33 #include <strings.h> 34 #include <fm/topo_mod.h> 35 #include <fm/topo_hc.h> 36 #include <sys/systeminfo.h> 37 #include <sys/smbios_impl.h> 38 #include <x86pi_impl.h> 39 40 #define DEVICES "/devices" 41 #define HBA_DRV_NAME "ahci" 42 43 #define BDF(b, df) ((uint16_t)((((uint16_t)(b) << 8) & 0xFF00) | \ 44 ((uint16_t)(df) & 0x00FF))); 45 46 static const topo_pgroup_info_t io_pgroup = { 47 TOPO_PGROUP_IO, 48 TOPO_STABILITY_PRIVATE, 49 TOPO_STABILITY_PRIVATE, 50 1 51 }; 52 53 static const topo_pgroup_info_t binding_pgroup = { 54 TOPO_PGROUP_BINDING, 55 TOPO_STABILITY_PRIVATE, 56 TOPO_STABILITY_PRIVATE, 57 1 58 }; 59 60 /* 61 * Return PCI Bus/Dev/Func 62 */ 63 int 64 bay_bdf(topo_mod_t *mod, smbios_hdl_t *shp, smbios_port_ext_t *epp, 65 uint16_t *bdf) 66 { 67 int devt; 68 id_t dev_id; 69 uint8_t bus, dev_funct; 70 71 char *f = "bay_bdf"; 72 73 /* 74 * Depending on device type, BDF comes from either slot (type-9) or 75 * on-board (type-41) SMBIOS structure. 76 */ 77 devt = epp->smbporte_dtype; 78 dev_id = epp->smbporte_devhdl; 79 80 if (devt == SMB_TYPE_SLOT) { 81 smbios_slot_t slot; 82 (void) smbios_info_slot(shp, dev_id, &slot); 83 bus = slot.smbl_bus; 84 dev_funct = slot.smbl_df; 85 } else if (devt == SMB_TYPE_OBDEVEXT) { 86 smbios_obdev_ext_t ob; 87 (void) smbios_info_obdevs_ext(shp, dev_id, &ob); 88 bus = ob.smboe_bus; 89 dev_funct = ob.smboe_df; 90 } else { 91 topo_mod_dprintf(mod, "%s: unknown device type: %d\n", 92 f, devt); 93 return (-1); 94 } 95 topo_mod_dprintf(mod, "%s: %s: bus(0x%02x) dev/func(0x%02x)\n", f, 96 devt == SMB_TYPE_SLOT ? "slot" : "ob dev", bus, dev_funct); 97 98 *bdf = BDF(bus, dev_funct); 99 100 return (0); 101 } 102 103 /* 104 * Decorate topo node with pgroups. 105 */ 106 int 107 bay_pgroups(topo_mod_t *mod, tnode_t *tnp, di_node_t *dnp, di_node_t *sibp, 108 char *minor_name) 109 { 110 int rv, err; 111 char *ap_path, *oc_path; 112 113 char *f = "bay_pgoups"; 114 115 /* 116 * Create "io" pgroup and attachment point path. 117 */ 118 rv = topo_pgroup_create(tnp, &io_pgroup, &err); 119 if (rv != 0) { 120 topo_mod_dprintf(mod, 121 "%s: failed to create \"io\" pgroup: %s\n", 122 f, topo_strerror(err)); 123 (void) topo_mod_seterrno(mod, err); 124 return (err); 125 } 126 127 ap_path = topo_mod_alloc(mod, MAXPATHLEN); 128 if (ap_path == NULL) { 129 topo_mod_dprintf(mod, "%s: ap_path alloc failed\n"); 130 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 131 } 132 (void) snprintf(ap_path, MAXPATHLEN, "%s%s:%s", DEVICES, 133 di_devfs_path(*dnp), minor_name); 134 topo_mod_dprintf(mod, "%s: ap_path(%s)\n", f, ap_path); 135 136 /* add ap-path */ 137 rv = topo_prop_set_string(tnp, TOPO_PGROUP_IO, TOPO_IO_AP_PATH, 138 TOPO_PROP_IMMUTABLE, ap_path, &err); 139 if (rv != 0) { 140 topo_mod_dprintf(mod, "%s: failed to set ap-path: %s\n", 141 f, topo_strerror(err)); 142 topo_mod_free(mod, ap_path, MAXPATHLEN); 143 (void) topo_mod_seterrno(mod, err); 144 return (err); 145 } 146 topo_mod_free(mod, ap_path, MAXPATHLEN); 147 148 /* 149 * Create "binding" pgroup and occupant path. 150 */ 151 rv = topo_pgroup_create(tnp, &binding_pgroup, &err); 152 if (rv != 0) { 153 topo_mod_dprintf(mod, 154 "%s: failed to create \"io\" pgroup: %s\n", 155 f, topo_strerror(err)); 156 (void) topo_mod_seterrno(mod, err); 157 return (err); 158 } 159 160 oc_path = di_devfs_path(*sibp); 161 if (oc_path == NULL) { 162 topo_mod_dprintf(mod, "%s: no occupant path\n", f); 163 return (-1); 164 } 165 topo_mod_dprintf(mod, "%s: oc_path(%s)\n", f, oc_path); 166 167 /* add ocupant-path */ 168 rv = topo_prop_set_string(tnp, TOPO_PGROUP_BINDING, 169 TOPO_BINDING_OCCUPANT, TOPO_PROP_IMMUTABLE, oc_path, 170 &err); 171 if (rv != 0) { 172 topo_mod_dprintf(mod, "%s: failed to set ap-path: %s\n", 173 f, topo_strerror(err)); 174 di_devfs_path_free(oc_path); 175 (void) topo_mod_seterrno(mod, err); 176 return (err); 177 } 178 di_devfs_path_free(oc_path); 179 180 return (0); 181 } 182 183 int 184 bay_update_tnode(topo_mod_t *mod, tnode_t *tnodep, uint16_t bdf, int phy) 185 { 186 int rv; 187 int minor_cnt = 0; 188 char *minor_name = NULL; 189 di_node_t devtree, dnode, sib; 190 di_minor_t minor = DI_MINOR_NIL; 191 192 char *f = "bay_update_tnode"; 193 194 /* 195 * Find HBA device node from BDF. 196 */ 197 devtree = topo_mod_devinfo(mod); 198 if (devtree == DI_NODE_NIL) { 199 topo_mod_dprintf(mod, "%s: failed to get dev tree\n", f); 200 return (-1); 201 } 202 for (dnode = di_drv_first_node(HBA_DRV_NAME, devtree); 203 dnode != DI_NODE_NIL; 204 dnode = di_drv_next_node(dnode)) { 205 if (bdf == x86pi_bdf(mod, dnode)) { 206 /* 207 * Match child node from PHY. 208 */ 209 sib = di_child_node(dnode); 210 while (sib != DI_NODE_NIL) { 211 if (phy == x86pi_phy(mod, sib)) 212 break; 213 sib = di_sibling_node(sib); 214 } 215 break; 216 } 217 } 218 if (dnode == DI_NODE_NIL) { 219 topo_mod_dprintf(mod, "%s: no HBA di_node\n", f); 220 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 221 } 222 223 /* 224 * HBA attachment point minor node name. 225 */ 226 while ((minor = di_minor_next(dnode, minor)) != DI_MINOR_NIL) { 227 if (strncmp(DDI_NT_SATA_ATTACHMENT_POINT, 228 di_minor_nodetype(minor), 229 strlen(DDI_NT_SATA_ATTACHMENT_POINT)) == 0) { 230 if (phy == minor_cnt++) { 231 minor_name = di_minor_name(minor); 232 topo_mod_dprintf(mod, 233 "%s: phy(%d) minor name(%s)\n", 234 f, phy, minor_name); 235 break; 236 } 237 } 238 } 239 240 rv = bay_pgroups(mod, tnodep, &dnode, &sib, minor_name); 241 if (rv != 0) { 242 topo_mod_dprintf(mod, "%s: failed to add pgroups\n", f); 243 return (-1); 244 } 245 246 247 return (0); 248 } 249 250 /* 251 * x86pi_gen_bay: 252 * create "bay" node 253 * call "disk" enum passing in "bay" node 254 */ 255 int 256 x86pi_gen_bay(topo_mod_t *mod, tnode_t *t_parent, smbios_hdl_t *shp, 257 smbios_port_ext_t *eport, int instance) 258 { 259 int rv; 260 int min = 0, max = 0; 261 id_t port_id; 262 uint16_t bdf; 263 smbios_port_t smb_port; 264 x86pi_hcfmri_t hcfmri = {0}; 265 tnode_t *tn_bay; 266 267 char *f = "x86pi_gen_disk"; 268 269 /* 270 * Label comes from the port (type-8) SMBIOS structure. 271 */ 272 port_id = eport->smbporte_port; 273 274 rv = smbios_info_port(shp, port_id, &smb_port); 275 if (rv != 0) { 276 topo_mod_dprintf(mod, 277 "%s: failed to get port %d SMBIOS struct\n", 278 f, port_id); 279 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 280 } 281 282 /* 283 * Fill in hcfmri info. 284 */ 285 hcfmri.hc_name = BAY; 286 hcfmri.instance = instance; 287 hcfmri.location = x86pi_cleanup_smbios_str(mod, smb_port.smbo_eref, 0); 288 289 /* 290 * Create "bay" node. 291 */ 292 rv = x86pi_enum_generic(mod, &hcfmri, t_parent, t_parent, &tn_bay, 0); 293 if (rv != 0) { 294 topo_mod_dprintf(mod, 295 "%s: failed to create %s topo node: %d\n", 296 f, BAY, instance); 297 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 298 } 299 300 /* free up location string */ 301 if (hcfmri.location != NULL) { 302 topo_mod_strfree(mod, (char *)hcfmri.location); 303 } 304 305 /* 306 * Determine the bay BDF. 307 */ 308 rv = bay_bdf(mod, shp, eport, &bdf); 309 if (rv != 0) { 310 topo_mod_dprintf(mod, "%s: failed to get BDF\n", f); 311 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 312 } 313 topo_mod_dprintf(mod, "%s: BDF(0x%04x)\n", f, bdf); 314 315 /* 316 * Decorate bay topo node. 317 */ 318 rv = bay_update_tnode(mod, tn_bay, bdf, eport->smbporte_phy); 319 if (rv != 0) { 320 topo_mod_dprintf(mod, "%s: failed to decorate bay node\n", f); 321 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 322 } 323 324 /* 325 * Call disk enum passing in decorated bay topo node. 326 */ 327 if (topo_mod_load(mod, DISK, TOPO_VERSION) == NULL) { 328 topo_mod_dprintf(mod, "%s: Failed to load %s module: %s\n", 329 f, DISK, topo_strerror(topo_mod_errno(mod))); 330 return (topo_mod_errno(mod)); 331 } 332 333 rv = topo_node_range_create(mod, tn_bay, DISK, min, max); 334 if (rv != 0) { 335 topo_mod_dprintf(mod, "%s: failed to create range: %s\n", f, 336 topo_strerror(topo_mod_errno(mod))); 337 return (topo_mod_errno(mod)); 338 } 339 340 rv = topo_mod_enumerate(mod, tn_bay, DISK, DISK, min, max, NULL); 341 if (rv != 0) { 342 topo_mod_dprintf(mod, "%s: %s enumeration failed: %s\n", f, 343 DISK, topo_strerror(topo_mod_errno(mod))); 344 return (topo_mod_errno(mod)); 345 } 346 347 topo_mod_dprintf(mod, "%s: done.\n", f); 348 349 return (0); 350 } 351