2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <strings.h>
2N/A#include <devid.h>
2N/A#include <inttypes.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <fcntl.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <fm/topo_mod.h>
2N/A#include <fm/topo_list.h>
2N/A#include <sys/scsi/scsi_address.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <bay_impl.h>
2N/A
2N/Astatic int bay_enum(topo_mod_t *, tnode_t *, const char *,
2N/A topo_instance_t, topo_instance_t, void *, void *);
2N/A
2N/Astatic const topo_modops_t bay_ops =
2N/A { bay_enum, NULL };
2N/A
2N/Astatic const topo_modinfo_t bay_info =
2N/A { BAY, FM_FMRI_SCHEME_HC, BAY_VERSION, &bay_ops };
2N/A
2N/Astatic const topo_method_t bay_fac_methods[] = {
2N/A { TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
2N/A TOPO_STABILITY_INTERNAL, bay_enum_facility },
2N/A { NULL }
2N/A};
2N/A
2N/Astatic const topo_pgroup_info_t io_pgroup = {
2N/A TOPO_PGROUP_IO,
2N/A TOPO_STABILITY_PRIVATE,
2N/A TOPO_STABILITY_PRIVATE,
2N/A 1
2N/A};
2N/A
2N/Astatic const topo_pgroup_info_t binding_pgroup = {
2N/A TOPO_PGROUP_BINDING,
2N/A TOPO_STABILITY_PRIVATE,
2N/A TOPO_STABILITY_PRIVATE,
2N/A 1
2N/A};
2N/A
2N/A/* place to keep bays */
2N/Abay_t bays[MAX_HBAS][MAX_BAYS];
2N/A
2N/A/* place to keep hba nodes */
2N/Adi_node_t hba_nodes[MAX_HBAS];
2N/Aint hba_node_cnt;
2N/A
2N/A/* external chassis count */
2N/Aint ch_ext;
2N/A
2N/A/* internal bay instance count */
2N/Aint bay_icnt;
2N/A
2N/A/* 'generic' bay enumeration flag */
2N/Aboolean_t generic_flag = B_FALSE;
2N/A
2N/A/*
2N/A * Create io and binding pgroups and add ap_path/oc_path to them.
2N/A */
2N/Avoid
2N/Abay_add_pgroups(topo_mod_t *mod, tnode_t *tn, bay_t *bp, char *ap_path,
2N/A char *oc_path)
2N/A{
2N/A int rv;
2N/A int err;
2N/A char *devid = NULL;
2N/A
2N/A char *f = "bay_add_pgroups";
2N/A
2N/A /* create io pgroup */
2N/A rv = topo_pgroup_create(tn, &io_pgroup, &err);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "%s: failed to create io pgroup: %s\n",
2N/A f, topo_strerror(err));
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return;
2N/A }
2N/A
2N/A /* add ap-path to io pgroup */
2N/A if (ap_path != NULL) {
2N/A rv = topo_prop_set_string(tn, TOPO_PGROUP_IO, TOPO_IO_AP_PATH,
2N/A TOPO_PROP_IMMUTABLE, ap_path, &err);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to set ap-path: %s\n",
2N/A f, topo_strerror(err));
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return;
2N/A }
2N/A }
2N/A
2N/A /* create binding pgroup */
2N/A rv = topo_pgroup_create(tn, &binding_pgroup, &err);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to create binding pgroup: %s\n",
2N/A f, topo_strerror(err));
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return;
2N/A }
2N/A
2N/A if (oc_path != NULL) {
2N/A /* add oc-path to binding pgroup */
2N/A rv = topo_prop_set_string(tn, TOPO_PGROUP_BINDING,
2N/A TOPO_BINDING_OCCUPANT_PATH, TOPO_PROP_IMMUTABLE, oc_path,
2N/A &err);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to set oc_path: %s\n",
2N/A f, topo_strerror(err));
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return;
2N/A }
2N/A
2N/A /* since there's an occupant, add devid to the io pgroup */
2N/A devid = get_devid(mod, oc_path, bp);
2N/A if (devid != NULL) {
2N/A rv = topo_prop_set_string(tn, TOPO_PGROUP_IO,
2N/A TOPO_IO_DEVID, TOPO_PROP_IMMUTABLE, devid, &err);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to set devid: %s\n",
2N/A f, topo_strerror(err));
2N/A (void) topo_mod_seterrno(mod, err);
2N/A }
2N/A topo_mod_strfree(mod, devid);
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Generate the attachment-point path bay property.
2N/A */
2N/Avoid
2N/Abay_gen_ap_path(topo_mod_t *mod, bay_t *bp, char **ap_path)
2N/A{
2N/A int rv;
2N/A char *mpxd = NULL;
2N/A char *path = NULL;
2N/A di_minor_t minor = DI_MINOR_NIL;
2N/A di_node_t cnode = DI_NODE_NIL;
2N/A di_path_t pnode = DI_PATH_NIL;
2N/A
2N/A rv = find_child(mod, bp->hba_dnode, &cnode, &pnode, bp->phy);
2N/A if (rv != 0) {
2N/A *ap_path = NULL;
2N/A topo_mod_dprintf(mod, "bay_gen_ap_path: child node NIL.\n");
2N/A return;
2N/A }
2N/A
2N/A if (cnode != DI_NODE_NIL) {
2N/A minor = find_minor_ap(mod, cnode);
2N/A }
2N/A if (minor == DI_MINOR_NIL) {
2N/A /* look in grandchildren (!mpxio) */
2N/A minor = find_minor_ap(mod, bp->hba_dnode);
2N/A if (minor == DI_MINOR_NIL) {
2N/A *ap_path = NULL;
2N/A topo_mod_dprintf(mod,
2N/A "bay_gen_ap_path: minor node NIL.\n");
2N/A return;
2N/A }
2N/A }
2N/A
2N/A /* check MPxIO */
2N/A mpxd = topo_mod_alloc(mod, MAXNAMELEN);
2N/A (void) get_str_prop(bp->hba_dnode, DI_PATH_NIL, "mpxio-disable", mpxd);
2N/A
2N/A /* create attachment-point path */
2N/A if (mpxd != NULL && cmp_str(mpxd, "yes")) {
2N/A path = di_devfs_minor_path(minor);
2N/A } else {
2N/A path = gen_ap(mod, minor);
2N/A }
2N/A
2N/A /* return path */
2N/A *ap_path = topo_mod_strdup(mod, path);
2N/A
2N/A if (mpxd != NULL && cmp_str(mpxd, "yes")) {
2N/A di_devfs_path_free(path);
2N/A } else {
2N/A topo_mod_strfree(mod, path);
2N/A }
2N/A
2N/A topo_mod_free(mod, mpxd, MAXNAMELEN);
2N/A}
2N/A
2N/A/*
2N/A * Generate the occupant path bay property.
2N/A */
2N/Avoid
2N/Abay_gen_oc_path(topo_mod_t *mod, bay_t *bp, char **oc_path)
2N/A{
2N/A int rv;
2N/A char *path = NULL;
2N/A char *mpxd = NULL;
2N/A di_node_t cnode = DI_NODE_NIL;
2N/A di_path_t pnode = DI_PATH_NIL;
2N/A boolean_t path_free = B_FALSE;
2N/A
2N/A /* find the phy matching child node */
2N/A rv = find_child(mod, bp->hba_dnode, &cnode, &pnode, bp->phy);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "bay_gen_oc_path: child node NIL.\n");
2N/A return;
2N/A }
2N/A
2N/A /* check MPxIO */
2N/A mpxd = topo_mod_alloc(mod, MAXNAMELEN);
2N/A (void) get_str_prop(bp->hba_dnode, DI_PATH_NIL, "mpxio-disable", mpxd);
2N/A
2N/A /* create occupant path */
2N/A if (cnode != DI_NODE_NIL && mpxd != NULL && cmp_str(mpxd, "yes")) {
2N/A path = di_devfs_path(di_child_node(cnode));
2N/A path_free = B_TRUE;
2N/A } else {
2N/A path = gen_oc(mod, cnode, pnode);
2N/A }
2N/A
2N/A /* sometimes 'mpxio-disable' just can't be trusted */
2N/A if (path == NULL) {
2N/A if (cnode != DI_NODE_NIL) {
2N/A path = di_devfs_path(cnode);
2N/A path_free = B_TRUE;
2N/A } else if (pnode != DI_PATH_NIL) {
2N/A path = di_path_devfs_path(pnode);
2N/A path_free = B_TRUE;
2N/A }
2N/A }
2N/A
2N/A /* return path */
2N/A if (path != NULL) {
2N/A *oc_path = topo_mod_strdup(mod, path);
2N/A }
2N/A
2N/A if (path_free) {
2N/A di_devfs_path_free(path);
2N/A } else {
2N/A topo_mod_strfree(mod, path);
2N/A }
2N/A
2N/A topo_mod_free(mod, mpxd, MAXNAMELEN);
2N/A}
2N/A
2N/A/*
2N/A * Add properties to the bay node.
2N/A */
2N/Avoid
2N/Abay_decorate(topo_mod_t *mod, tnode_t *tn, bay_t *bp)
2N/A{
2N/A char *ap_path = NULL;
2N/A char *oc_path = NULL;
2N/A
2N/A /* generate attachment-point path */
2N/A bay_gen_ap_path(mod, bp, &ap_path);
2N/A
2N/A /* generate occupant path */
2N/A bay_gen_oc_path(mod, bp, &oc_path);
2N/A
2N/A topo_mod_dprintf(mod,
2N/A "bay_decorate: %s:%d ap_path %s oc_path %s\n",
2N/A bp->hba_nm, bp->phy,
2N/A ap_path != NULL ? ap_path : "NULL",
2N/A oc_path != NULL ? oc_path : "NULL");
2N/A
2N/A /* add ap_path/oc_path to the bay topo node */
2N/A bay_add_pgroups(mod, tn, bp, ap_path, oc_path);
2N/A
2N/A /* set chassis alias */
2N/A if (topo_mod_set_ch_alias(mod, tn, oc_path) != 0) {
2N/A /* no matching devchassis path; try client */
2N/A di_node_t cnode = DI_NODE_NIL;
2N/A di_path_t pn = DI_PATH_NIL;
2N/A int rv, lun;
2N/A char *tgt = NULL;
2N/A if (oc_path != NULL) {
2N/A topo_mod_strfree(mod, oc_path);
2N/A oc_path = NULL;
2N/A }
2N/A
2N/A /* child node matching phy */
2N/A (void) find_child(mod, bp->hba_dnode, &cnode, &pn, bp->phy);
2N/A
2N/A /* 'target-port' prop */
2N/A tgt = topo_mod_alloc(mod, MAXNAMELEN);
2N/A if (tgt == NULL) {
2N/A topo_mod_dprintf(mod,
2N/A "bay_decorate: no memory for target-port\n");
2N/A goto out;
2N/A }
2N/A rv = get_str_prop(cnode, pn, SCSI_ADDR_PROP_TARGET_PORT, tgt);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "bay_decorate: failed to get target-port\n");
2N/A topo_mod_free(mod, tgt, MAXNAMELEN);
2N/A goto out;
2N/A }
2N/A
2N/A /* 'lun' prop */
2N/A lun = get_int_prop(cnode, pn, "lun");
2N/A if (lun < 0 || lun > 255) {
2N/A topo_mod_dprintf(mod,
2N/A "bay_decorate: invalid lun (%d)\n", lun);
2N/A topo_mod_free(mod, tgt, MAXNAMELEN);
2N/A goto out;
2N/A }
2N/A
2N/A oc_path = topo_mod_client_ocpath(mod, cnode, tgt, lun);
2N/A (void) topo_mod_set_ch_alias(mod, tn, oc_path);
2N/A topo_mod_free(mod, tgt, MAXNAMELEN);
2N/A }
2N/Aout:
2N/A /* cleanup */
2N/A if (ap_path != NULL) {
2N/A topo_mod_strfree(mod, ap_path);
2N/A }
2N/A if (oc_path != NULL) {
2N/A topo_mod_strfree(mod, oc_path);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Drive the generation of the bay topo node.
2N/A */
2N/Avoid
2N/Abay_gen_bay(topo_mod_t *mod, tnode_t *pnode, bay_t *bp)
2N/A{
2N/A int rv;
2N/A tnode_t *bay_tn;
2N/A topo_mod_t *dmod;
2N/A
2N/A char *f = "bay_gen_bay";
2N/A
2N/A if (bp == NULL) {
2N/A topo_mod_dprintf(mod, "%s: NULL bay\n", f);
2N/A return;
2N/A }
2N/A
2N/A /* create bay topo node */
2N/A rv = bay_create_tnode(mod, pnode, &bay_tn, bp);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to enumerate %s HBA bay #%d\n",
2N/A f, bp->hba_nm, bp->inst);
2N/A return;
2N/A }
2N/A
2N/A /* set tnode specifics for LED control */
2N/A topo_node_setspecific(bay_tn, (void *)bp);
2N/A
2N/A /* see if HBA supports SGPIO before registering fac methods */
2N/A rv = bay_led_ctl(mod, bay_tn, BAY_PROP_IDENT, 0, BAY_INDICATOR_GET);
2N/A if (rv != -1) {
2N/A /* register bay facility node methods */
2N/A rv = topo_method_register(mod, bay_tn, bay_fac_methods);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to register bay_fac_methods: %s.\n",
2N/A f, topo_mod_errmsg(mod));
2N/A }
2N/A }
2N/A
2N/A /* decorate bay topo node */
2N/A bay_decorate(mod, bay_tn, bp);
2N/A
2N/A /* load the disk module */
2N/A dmod = topo_mod_load(mod, DISK, TOPO_VERSION);
2N/A if (dmod == NULL) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to load disk enum for %s:%d: (%s)\n",
2N/A f, bp->hba_nm, bp->phy,
2N/A topo_strerror(topo_mod_errno(mod)));
2N/A return;
2N/A }
2N/A
2N/A /* call the disk.so enum w/bay topo node as parent */
2N/A rv = topo_node_range_create(mod, bay_tn, DISK, 0, 0);
2N/A if (rv != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to create &s range: %s\n",
2N/A f, BAY, topo_mod_errmsg(mod));
2N/A return;
2N/A }
2N/A
2N/A rv = topo_mod_enumerate(mod, bay_tn, DISK, DISK, 0, 0, NULL);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to enum disk for %s:%d: (%s)\n",
2N/A f, bp->hba_nm, bp->phy,
2N/A topo_strerror(topo_mod_errno(mod)));
2N/A return;
2N/A }
2N/A
2N/A /* create 'target-port-l0ids' property(s) */
2N/A rv = create_l0ids(mod, bay_tn, bp);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to create %s properties for %s:%d: (%s)\n",
2N/A f, TOPO_STORAGE_TARGET_PORT_L0IDS, bp->hba_nm, bp->phy,
2N/A topo_strerror(topo_mod_errno(mod)));
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Abay_xch_auth(topo_mod_t *mod, nvlist_t *auth, char *mfg, char *name,
2N/A char *part, char *serial, char *alias)
2N/A{
2N/A int i, rv;
2N/A struct auths_s {
2N/A const char *name;
2N/A char *val;
2N/A } ch_auths[] = {
2N/A { FM_FMRI_AUTH_V1_CHASSIS_MFG, mfg },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_NM, name },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_PN, part },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_SN, serial },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_ALIAS, alias },
2N/A { NULL, NULL }
2N/A };
2N/A
2N/A for (i = 0; ch_auths[i].name != NULL; i++) {
2N/A rv = nvlist_add_string(auth, ch_auths[i].name, ch_auths[i].val);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "bay_xch_auth: failed to add %s authorty\n",
2N/A ch_auths[i].name);
2N/A return (rv);
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Abay_xch_props(topo_mod_t *mod, tnode_t *tnode, char *mfg, char *name,
2N/A char *part, char *serial, char *alias)
2N/A{
2N/A int i, err = 0;
2N/A struct auths_s {
2N/A const char *name;
2N/A char *val;
2N/A } ch_auths[] = {
2N/A { FM_FMRI_AUTH_V1_CHASSIS_MFG, mfg },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_NM, name },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_PN, part },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_SN, serial },
2N/A { FM_FMRI_AUTH_V1_CHASSIS_ALIAS, alias },
2N/A { NULL, NULL }
2N/A };
2N/A
2N/A for (i = 0; ch_auths[i].name != NULL; i++) {
2N/A if (topo_prop_set_string(tnode, FM_FMRI_AUTHORITY,
2N/A ch_auths[i].name, TOPO_PROP_IMMUTABLE, ch_auths[i].val,
2N/A &err) != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "bay_xch_props: failed to add %s prop: %s\n",
2N/A ch_auths[i].name, topo_strerror(err));
2N/A return (topo_mod_seterrno(mod, err));
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Create an external chassis (e.g. JBOD) topo node. This is different than
2N/A * a bay topo node because it's authority info is different and the resource
2N/A * and FRU fmris should be the same.
2N/A */
2N/Astatic int
2N/Abay_create_xch(topo_mod_t *mod, topo_instance_t instance, tnode_t *pnode,
2N/A tnode_t **tnode, bay_t *bayp)
2N/A{
2N/A int rv;
2N/A int err;
2N/A char *ch_serial = NULL;
2N/A char *ch_label = NULL;
2N/A char *ch_part = "unknown";
2N/A char *ch_name = NULL;
2N/A nvlist_t *fmri = NULL;
2N/A nvlist_t *frufmri = NULL;
2N/A nvlist_t *auth = NULL;
2N/A
2N/A char *f = "bay_create_xch";
2N/A
2N/A ch_serial = topo_mod_strdup(mod, (const char *)bayp->ch_serial);
2N/A ch_label = topo_mod_strdup(mod, (const char *)bayp->ch_label);
2N/A ch_name = topo_mod_strdup(mod, (const char *)bayp->ch_prod);
2N/A
2N/A /* create auth */
2N/A rv = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "%s: failed to alloc auth\n", f);
2N/A goto bad;
2N/A }
2N/A
2N/A /* use external chassis name for manufacturer */
2N/A if (bay_xch_auth(mod, auth, ch_name, ch_name, ch_part, ch_serial,
2N/A ch_label) != 0) {
2N/A goto bad;
2N/A }
2N/A
2N/A /* create fmri */
2N/A fmri = topo_mod_hcfmri(mod, NULL, FM_HC_SCHEME_VERSION,
2N/A EXTERNALCHASSIS, instance, NULL, auth, NULL, NULL, ch_serial);
2N/A if (fmri == NULL) {
2N/A topo_mod_dprintf(mod, "%s: failed to create fmri: %s\n",
2N/A f, topo_strerror(topo_mod_errno(mod)));
2N/A goto bad;
2N/A }
2N/A
2N/A /* bind to parent */
2N/A *tnode = topo_node_bind(mod, pnode, EXTERNALCHASSIS, instance, fmri);
2N/A if (*tnode == NULL) {
2N/A topo_mod_dprintf(mod, "%s: failed to bind node: %s\n",
2N/A f, topo_strerror(topo_mod_errno(mod)));
2N/A goto bad;
2N/A }
2N/A nvlist_free(auth);
2N/A nvlist_free(fmri);
2N/A
2N/A /* set the authority props */
2N/A if (bay_xch_props(mod, *tnode, ch_name, ch_name, ch_part, ch_serial,
2N/A ch_label) != 0) {
2N/A /* errno is set for us */
2N/A return (-1);
2N/A }
2N/A
2N/A /* copy resource fmri and set as FRU fmri */
2N/A rv = topo_node_resource(*tnode, &frufmri, &err);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "%s: failed to get resource: %s\n",
2N/A f, topo_strerror(err));
2N/A return (topo_mod_seterrno(mod, err));
2N/A }
2N/A
2N/A rv = topo_node_fru_set(*tnode, frufmri, 0, &err);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "%s: failed to set FRU fmri: %s\n",
2N/A f, topo_strerror(err));
2N/A nvlist_free(frufmri);
2N/A return (topo_mod_seterrno(mod, err));
2N/A }
2N/A nvlist_free(frufmri);
2N/A
2N/A /* set the label */
2N/A rv = topo_node_label_set(*tnode, ch_label, &err);
2N/A if (rv != 0) {
2N/A (void) topo_mod_seterrno(mod, err);
2N/A topo_mod_dprintf(mod, "%s: failed to set label: %s\n",
2N/A f, topo_strerror(err));
2N/A return (topo_mod_seterrno(mod, err));
2N/A }
2N/A
2N/A /* clean-up */
2N/A topo_mod_strfree(mod, ch_serial);
2N/A topo_mod_strfree(mod, ch_label);
2N/A topo_mod_strfree(mod, ch_name);
2N/A
2N/A return (0);
2N/Abad:
2N/A if (auth != NULL) {
2N/A nvlist_free(auth);
2N/A }
2N/A if (fmri != NULL) {
2N/A nvlist_free(fmri);
2N/A }
2N/A
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Go find direct attached bays (children of the hba).
2N/A */
2N/Astatic void
2N/Abay_direct(topo_mod_t *mod, tnode_t *t_parent, di_node_t hba_dnode,
2N/A int hba_idx, char *conf_file, int max_phys)
2N/A{
2N/A int nbays = 0;
2N/A int i;
2N/A int rv;
2N/A tnode_t *root_tn = t_parent;
2N/A tnode_t *ch_tn;
2N/A tnode_t *exch_tn;
2N/A boolean_t i_ch = B_TRUE;
2N/A
2N/A char *f = "bay_direct";
2N/A
2N/A if (!generic_flag) {
2N/A /* fill in bays from the training mode config file */
2N/A rv = read_config(mod, hba_dnode, conf_file, bays[hba_idx],
2N/A &nbays);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to read config file\n", f);
2N/A return;
2N/A }
2N/A if (nbays == 0) {
2N/A topo_mod_dprintf(mod, "%s: no bays found for %s\n",
2N/A f, di_driver_name(hba_dnode));
2N/A return;
2N/A }
2N/A } else {
2N/A nbays = max_phys;
2N/A }
2N/A
2N/A /*
2N/A * Sanity check at least the first child to make sure the bays are
2N/A * direct attached.
2N/A */
2N/A if (!sas_direct(bays[hba_idx][0].hba_dnode)) {
2N/A topo_mod_dprintf(mod, "%s: %s bays not direct attached\n",
2N/A f, di_driver_name(bays[hba_idx][0].hba_dnode));
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * Each hba connects to either the server internal bays (system
2N/A * chassis) or to an external JBOD type external chassis.
2N/A */
2N/A i_ch = internal_ch(&bays[hba_idx][0]);
2N/A if (!i_ch) {
2N/A /* create an external-chassis */
2N/A rv = topo_node_range_create(mod, t_parent, EXTERNALCHASSIS,
2N/A 0, ch_ext + 1);
2N/A if (rv == 0 || topo_mod_errno(mod) == EMOD_NODE_DUP) {
2N/A rv = bay_create_xch(mod, ch_ext, t_parent, &exch_tn,
2N/A &bays[hba_idx][0]);
2N/A if (rv == 0 && exch_tn != NULL) {
2N/A root_tn = exch_tn;
2N/A ++ch_ext;
2N/A } else {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to create external "
2N/A "chassis topo node %d.\n", f, ch_ext);
2N/A }
2N/A } else {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to create %s range: %s\n",
2N/A f, EXTERNALCHASSIS, topo_mod_errmsg(mod));
2N/A }
2N/A } else {
2N/A /* internal bays go under 'chassis' nodes */
2N/A if (!cmp_str(topo_node_name(t_parent), CHASSIS)) {
2N/A /* lookup 'chassis=0' */
2N/A ch_tn = topo_node_lookup(t_parent, CHASSIS, 0);
2N/A if (ch_tn != NULL) {
2N/A root_tn = ch_tn;
2N/A } else {
2N/A topo_mod_dprintf(mod, "%s: failed to find "
2N/A "chassis=0 tnode. Using %s parent tnode\n",
2N/A f, topo_node_name(root_tn));
2N/A }
2N/A }
2N/A }
2N/A
2N/A topo_mod_dprintf(mod, "%s: HBA %s: %d bays root node(%s)\n",
2N/A f, bays[hba_idx][0].hba_nm, nbays, topo_node_name(root_tn));
2N/A
2N/A /* create the range */
2N/A rv = topo_node_range_create(mod, root_tn, BAY, 0,
2N/A MAX_HBAS * MAX_BAYS);
2N/A if (rv != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to create &s range: %s\n",
2N/A BAY, topo_mod_errmsg(mod));
2N/A return;
2N/A }
2N/A
2N/A /* go through the bays and enumerate */
2N/A for (i = 0; i < nbays; i++) {
2N/A /* set the bay instance */
2N/A bays[hba_idx][i].inst = i_ch ? bay_icnt : i;
2N/A
2N/A bay_gen_bay(mod, root_tn, &bays[hba_idx][i]);
2N/A
2N/A /* internal chassis count */
2N/A if (i_ch) {
2N/A ++bay_icnt;
2N/A }
2N/A }
2N/A}
2N/A
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Abay_enum(topo_mod_t *mod, tnode_t *t_parent, const char *name,
2N/A topo_instance_t min, topo_instance_t max, void *arg, void *priv)
2N/A{
2N/A int i, j;
2N/A int n;
2N/A struct stat st;
2N/A int bay_inst = 0;
2N/A char *conf_fnm = NULL;
2N/A char *prod = NULL;
2N/A char *ch_sn = NULL;
2N/A di_node_t devtree;
2N/A
2N/A char *f = "bay_enum";
2N/A
2N/A /* see who's calling us */
2N/A topo_mod_dprintf(mod, "%s: parent: (%s) topo node\n", f,
2N/A topo_node_name(t_parent));
2N/A
2N/A /*
2N/A * If we're being called with a parent 'bay' node, then the node has
2N/A * been created and we only need to create the facility indicator and
2N/A * sensor nodes for it. Currently only expecting sun4vpi.so.
2N/A */
2N/A if (cmp_str(topo_node_name(t_parent), BAY)) {
2N/A /* register fac methods for existing "bay" topo node */
2N/A if (topo_method_register(mod, t_parent, bay_fac_methods) != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: topo_method_register() failed: %s",
2N/A f, topo_mod_errmsg(mod));
2N/A return (-1);
2N/A }
2N/A return (0);
2N/A }
2N/A
2N/A /*
2N/A * Create topology for direct attached bays and call the disk enum to
2N/A * create topo nodes for disk drive occupants.
2N/A *
2N/A * Look into the devinfo snapshot to see if there are any SAS HBAs
2N/A * with direct attached bays/disks.
2N/A */
2N/A devtree = topo_mod_devinfo(mod);
2N/A if (devtree != DI_NODE_NIL) {
2N/A /* walk the devtree looking for SAS HBA nodes */
2N/A hba_node_cnt = 0;
2N/A (void) di_walk_node(devtree, DI_WALK_CLDFIRST,
2N/A (void *)hba_nodes, gather_sas_hba);
2N/A } else {
2N/A topo_mod_dprintf(mod,
2N/A "%s: failed to get devinfo snapshot.\n", f);
2N/A return (-1);
2N/A }
2N/A if (hba_node_cnt == MAX_HBAS) {
2N/A topo_mod_dprintf(mod, "%s: HBA count: MAX\n", f);
2N/A }
2N/A if (hba_node_cnt == 0) {
2N/A topo_mod_dprintf(mod, "%s: No HBAs found.\n", f);
2N/A return (0);
2N/A }
2N/A
2N/A /* sort HBA devinfo nodes relative to their PICe slot ID */
2N/A if (sort_hba_nodes(mod, t_parent, hba_nodes) != 0) {
2N/A topo_mod_dprintf(mod, "%s: failed to sort HBA di_nodes\n", f);
2N/A }
2N/A
2N/A /* initialize bays */
2N/A for (i = 0; i < MAX_HBAS; i++)
2N/A for (j = 0; j < MAX_BAYS; j++)
2N/A bzero(&bays[i][j], sizeof (bay_t));
2N/A
2N/A /* make some space */
2N/A conf_fnm = topo_mod_alloc(mod, MAXNAMELEN);
2N/A prod = topo_mod_alloc(mod, MAXNAMELEN);
2N/A ch_sn = topo_mod_alloc(mod, MAXNAMELEN);
2N/A if (conf_fnm == NULL || prod == NULL || ch_sn == NULL) {
2N/A topo_mod_dprintf(mod, "%s: No Memory.\n", f);
2N/A (void) topo_mod_seterrno(mod, ENOMEM);
2N/A if (ch_sn != NULL)
2N/A topo_mod_free(mod, ch_sn, MAXNAMELEN);
2N/A if (prod != NULL)
2N/A topo_mod_free(mod, prod, MAXNAMELEN);
2N/A if (conf_fnm != NULL)
2N/A topo_mod_free(mod, conf_fnm, MAXNAMELEN);
2N/A return (-1);
2N/A }
2N/A
2N/A /* get the product name and chassis S/N */
2N/A if (get_prod(mod, t_parent, prod, ch_sn) != 0) {
2N/A topo_mod_dprintf(mod, "%s: failed to get identity info\n", f);
2N/A topo_mod_free(mod, ch_sn, MAXNAMELEN);
2N/A topo_mod_free(mod, prod, MAXNAMELEN);
2N/A topo_mod_free(mod, conf_fnm, MAXNAMELEN);
2N/A return (-1);
2N/A }
2N/A
2N/A /* create the output config file name */
2N/A gen_ofile_name(prod, ch_sn, conf_fnm);
2N/A topo_mod_dprintf(mod, "%s: config file name %s\n", f, conf_fnm);
2N/A
2N/A /* init generic enum flag */
2N/A generic_flag = B_FALSE;
2N/A
2N/A /* make sure the file is present */
2N/A while (stat(conf_fnm, &st) < 0) {
2N/A if (strlen(prod) > 0 && strlen(ch_sn) > 0) {
2N/A /* try only product name */
2N/A *ch_sn = '\0'; /* zero length */
2N/A gen_ofile_name(prod, ch_sn, conf_fnm);
2N/A topo_mod_dprintf(mod,
2N/A "%s: secondary config file name %s\n",
2N/A f, conf_fnm);
2N/A } else if (strlen(prod) > 0) {
2N/A /* try only platform name */
2N/A *prod = '\0';
2N/A gen_ofile_name(prod, ch_sn, conf_fnm);
2N/A topo_mod_dprintf(mod,
2N/A "%s: plat only config file name %s\n",
2N/A f, conf_fnm);
2N/A } else {
2N/A /* no file */
2N/A topo_mod_dprintf(mod, "%s: NO config file, look "
2N/A "for \'sas-das-generic\' boot flag.\n", f);
2N/A
2N/A generic_flag = get_generic(mod, devtree);
2N/A if (!generic_flag) {
2N/A topo_mod_dprintf(mod,
2N/A "%s: NO generic DAS config\n", f);
2N/A topo_mod_free(mod, ch_sn, MAXNAMELEN);
2N/A topo_mod_free(mod, prod, MAXNAMELEN);
2N/A topo_mod_free(mod, conf_fnm, MAXNAMELEN);
2N/A return (0);
2N/A }
2N/A topo_mod_dprintf(mod, "%s: generic DAS config\n", f);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /* set bay instance if not passed in NULL */
2N/A if (priv != NULL) {
2N/A bay_inst = *(int *)priv;
2N/A }
2N/A
2N/A /* enumerate */
2N/A bay_icnt = bay_inst; /* init internal bay count */
2N/A ch_ext = 0; /* init external chassis count */
2N/A for (i = 0; i < hba_node_cnt; i++) {
2N/A /* find and create direct attached bay nodes */
2N/A n = get_num_phys(hba_nodes[i]);
2N/A topo_mod_dprintf(mod, "%s: %s contains max: %d bays\n", f,
2N/A di_driver_name(hba_nodes[i]), n);
2N/A if (n == 0) {
2N/A topo_mod_dprintf(mod, "%s: no bays for %s\n", f,
2N/A di_driver_name(hba_nodes[i]));
2N/A continue;
2N/A }
2N/A
2N/A if (generic_flag) {
2N/A /* no config file and boot flag set */
2N/A char *drv_nm = di_driver_name(hba_nodes[i]);
2N/A for (j = 0; j < n; j++) {
2N/A bay_t *bp = &bays[i][j];
2N/A /* fill generic bays */
2N/A bp->hba_dnode = hba_nodes[i];
2N/A bp->hba_nm = drv_nm != NULL ?
2N/A topo_mod_strdup(mod, drv_nm) :
2N/A topo_mod_strdup(mod, "unknown");
2N/A bp->hba_inst = di_instance(hba_nodes[i]);
2N/A bp->ch_prod = topo_mod_strdup(mod, prod);
2N/A bp->ch_label = topo_mod_strdup(mod, "SYS");
2N/A bp->ch_serial = topo_mod_strdup(mod, ch_sn);
2N/A bp->phy = j;
2N/A bp->label = generic_label(mod, hba_nodes[i],
2N/A t_parent, j);
2N/A }
2N/A }
2N/A
2N/A /* enumerate direct attached sas disks */
2N/A bay_direct(mod, t_parent, hba_nodes[i], i, conf_fnm, n);
2N/A }
2N/A
2N/A /* clean up */
2N/A for (i = 0; i < hba_node_cnt; i++) {
2N/A n = get_num_phys(hba_nodes[i]);
2N/A for (j = 0; j < n; j++) {
2N/A bay_t *bp = &bays[i][j];
2N/A if (bp->hba_nm != NULL) {
2N/A topo_mod_strfree(mod, bp->hba_nm);
2N/A bp->hba_nm = NULL;
2N/A }
2N/A if (bp->ch_prod != NULL) {
2N/A topo_mod_strfree(mod, bp->ch_prod);
2N/A bp->ch_prod = NULL;
2N/A }
2N/A if (bp->ch_label != NULL) {
2N/A topo_mod_strfree(mod, bp->ch_label);
2N/A bp->ch_label = NULL;
2N/A }
2N/A if (bp->ch_serial != NULL) {
2N/A topo_mod_strfree(mod, bp->ch_serial);
2N/A bp->ch_serial = NULL;
2N/A }
2N/A if (bp->label != NULL) {
2N/A topo_mod_strfree(mod, bp->label);
2N/A bp->label = NULL;
2N/A }
2N/A }
2N/A }
2N/A topo_mod_free(mod, ch_sn, MAXNAMELEN);
2N/A topo_mod_free(mod, prod, MAXNAMELEN);
2N/A topo_mod_free(mod, conf_fnm, MAXNAMELEN);
2N/A
2N/A topo_mod_dprintf(mod, "%s: done.\n", f);
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/A_topo_init(topo_mod_t *mod, topo_version_t version)
2N/A{
2N/A int result;
2N/A
2N/A if (getenv("TOPOBAYDEBUG") != NULL) {
2N/A /* Turn on module debugging output */
2N/A topo_mod_setdebug(mod);
2N/A }
2N/A topo_mod_dprintf(mod, "_topo_init: "
2N/A "initializing %s enumerator\n", BAY);
2N/A
2N/A if (version != TOPO_VERSION) {
2N/A (void) topo_mod_seterrno(mod, EMOD_VER_NEW);
2N/A topo_mod_dprintf(mod, "incompatible topo version %d\n",
2N/A version);
2N/A return (-1);
2N/A }
2N/A
2N/A result = topo_mod_register(mod, &bay_info, TOPO_VERSION);
2N/A if (result < 0) {
2N/A topo_mod_dprintf(mod, "_topo_init: "
2N/A "%s registration failed: %s\n",
2N/A BAY, topo_mod_errmsg(mod));
2N/A /* module errno already set */
2N/A return (-1);
2N/A }
2N/A
2N/A topo_mod_dprintf(mod, "_topo_init: "
2N/A "%s enumerator initialized\n", BAY);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/A_topo_fini(topo_mod_t *mod)
2N/A{
2N/A topo_mod_dprintf(mod, "_topo_fini: "
2N/A "%s enumerator uninitialized\n", BAY);
2N/A
2N/A topo_mod_unregister(mod);
2N/A}