145d3dd9Robert Mustacchi/*
245d3dd9Robert Mustacchi * This file and its contents are supplied under the terms of the
345d3dd9Robert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
445d3dd9Robert Mustacchi * You may only use this file in accordance with the terms of version
545d3dd9Robert Mustacchi * 1.0 of the CDDL.
645d3dd9Robert Mustacchi *
745d3dd9Robert Mustacchi * A full copy of the text of the CDDL should have accompanied this
845d3dd9Robert Mustacchi * source.  A copy of the CDDL is also available via the Internet at
945d3dd9Robert Mustacchi * http://www.illumos.org/license/CDDL.
1045d3dd9Robert Mustacchi */
1145d3dd9Robert Mustacchi
1245d3dd9Robert Mustacchi/*
1345d3dd9Robert Mustacchi * Copyright (c) 2017, Joyent, Inc.
1445d3dd9Robert Mustacchi */
1545d3dd9Robert Mustacchi
1645d3dd9Robert Mustacchi#include <sys/fm/protocol.h>
1745d3dd9Robert Mustacchi#include <fm/topo_mod.h>
1845d3dd9Robert Mustacchi#include <fm/topo_list.h>
1945d3dd9Robert Mustacchi#include <fm/topo_method.h>
2045d3dd9Robert Mustacchi
2145d3dd9Robert Mustacchi/*
2245d3dd9Robert Mustacchi * Common routines to create transceiver entries in the topology tree.
2345d3dd9Robert Mustacchi */
2445d3dd9Robert Mustacchi
2545d3dd9Robert Mustacchistatic const topo_pgroup_info_t transceiver_pgroup = {
2645d3dd9Robert Mustacchi	TOPO_PGROUP_TRANSCEIVER,
2745d3dd9Robert Mustacchi	TOPO_STABILITY_PRIVATE,
2845d3dd9Robert Mustacchi	TOPO_STABILITY_PRIVATE,
2945d3dd9Robert Mustacchi	1
3045d3dd9Robert Mustacchi};
3145d3dd9Robert Mustacchi
3245d3dd9Robert Mustacchistatic const topo_pgroup_info_t sff_transceiver_pgroup = {
3345d3dd9Robert Mustacchi	TOPO_PGROUP_SFF_TRANSCEIVER,
3445d3dd9Robert Mustacchi	TOPO_STABILITY_PRIVATE,
3545d3dd9Robert Mustacchi	TOPO_STABILITY_PRIVATE,
3645d3dd9Robert Mustacchi	1
3745d3dd9Robert Mustacchi};
3845d3dd9Robert Mustacchi
3945d3dd9Robert Mustacchiint
4045d3dd9Robert Mustacchitransceiver_range_create(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
4145d3dd9Robert Mustacchi    topo_instance_t max)
4245d3dd9Robert Mustacchi{
4345d3dd9Robert Mustacchi	return (topo_node_range_create(mod, pnode, TRANSCEIVER, min, max));
4445d3dd9Robert Mustacchi}
4545d3dd9Robert Mustacchi
4645d3dd9Robert Mustacchistatic tnode_t *
4745d3dd9Robert Mustacchitransceiver_create_common(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
4845d3dd9Robert Mustacchi    const char *type, boolean_t usable, const char *part, const char *rev,
4945d3dd9Robert Mustacchi    const char *serial)
5045d3dd9Robert Mustacchi{
5145d3dd9Robert Mustacchi	int err;
5245d3dd9Robert Mustacchi	tnode_t *tn = NULL;
5345d3dd9Robert Mustacchi	nvlist_t *fmri = NULL, *auth = NULL;
5445d3dd9Robert Mustacchi
5545d3dd9Robert Mustacchi	if (type == NULL) {
5645d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "transceiver_create_common missing type "
5745d3dd9Robert Mustacchi		    "argument");
5845d3dd9Robert Mustacchi		goto error;
5945d3dd9Robert Mustacchi	}
6045d3dd9Robert Mustacchi
6145d3dd9Robert Mustacchi	if ((auth = topo_mod_auth(mod, pnode)) == NULL) {
6245d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s\n",
6345d3dd9Robert Mustacchi		    topo_mod_errmsg(mod));
6445d3dd9Robert Mustacchi		goto error;
6545d3dd9Robert Mustacchi	}
6645d3dd9Robert Mustacchi
6745d3dd9Robert Mustacchi	if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION,
6845d3dd9Robert Mustacchi	    TRANSCEIVER, inst, NULL, auth, part, rev, serial)) == NULL) {
6945d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s\n",
7045d3dd9Robert Mustacchi		    topo_mod_errmsg(mod));
7145d3dd9Robert Mustacchi		goto error;
7245d3dd9Robert Mustacchi	}
7345d3dd9Robert Mustacchi
7445d3dd9Robert Mustacchi	if ((tn = topo_node_bind(mod, pnode, TRANSCEIVER, inst, fmri)) ==
7545d3dd9Robert Mustacchi	    NULL) {
7645d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "topo_node_bind() failed: %s\n",
7745d3dd9Robert Mustacchi		    topo_mod_errmsg(mod));
7845d3dd9Robert Mustacchi		goto error;
7945d3dd9Robert Mustacchi	}
8045d3dd9Robert Mustacchi
8145d3dd9Robert Mustacchi	/*
8245d3dd9Robert Mustacchi	 * The FRU for a transceiver is always itself.
8345d3dd9Robert Mustacchi	 */
8445d3dd9Robert Mustacchi	if (topo_node_fru_set(tn, fmri, 0, &err) != 0) {
8545d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s\n",
8645d3dd9Robert Mustacchi		    topo_strerror(err));
8745d3dd9Robert Mustacchi		goto error;
8845d3dd9Robert Mustacchi	}
8945d3dd9Robert Mustacchi
9045d3dd9Robert Mustacchi	if (topo_pgroup_create(tn, &transceiver_pgroup, &err) != 0) {
9145d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to create property group %s: "
9245d3dd9Robert Mustacchi		    "%s\n", TOPO_PGROUP_TRANSCEIVER, topo_strerror(err));
9345d3dd9Robert Mustacchi		goto error;
9445d3dd9Robert Mustacchi	}
9545d3dd9Robert Mustacchi
9645d3dd9Robert Mustacchi	if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER,
9745d3dd9Robert Mustacchi	    TOPO_PROP_TRANSCEIVER_TYPE, TOPO_PROP_IMMUTABLE, type,
9845d3dd9Robert Mustacchi	    &err) != 0) {
9945d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
10045d3dd9Robert Mustacchi		    TOPO_PROP_TRANSCEIVER_TYPE, topo_strerror(err));
10145d3dd9Robert Mustacchi		goto error;
10245d3dd9Robert Mustacchi	}
10345d3dd9Robert Mustacchi
10445d3dd9Robert Mustacchi	if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER,
10545d3dd9Robert Mustacchi	    TOPO_PROP_TRANSCEIVER_USABLE, TOPO_PROP_IMMUTABLE,
10645d3dd9Robert Mustacchi	    usable ? "true" : "false", &err) != 0) {
10745d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
10845d3dd9Robert Mustacchi		    TOPO_PROP_TRANSCEIVER_USABLE, topo_strerror(err));
10945d3dd9Robert Mustacchi		goto error;
11045d3dd9Robert Mustacchi	}
11145d3dd9Robert Mustacchi
11245d3dd9Robert Mustacchi	nvlist_free(fmri);
11345d3dd9Robert Mustacchi	nvlist_free(auth);
11445d3dd9Robert Mustacchi	return (tn);
11545d3dd9Robert Mustacchi
11645d3dd9Robert Mustacchierror:
11745d3dd9Robert Mustacchi	topo_node_unbind(tn);
11845d3dd9Robert Mustacchi	nvlist_free(fmri);
11945d3dd9Robert Mustacchi	nvlist_free(auth);
12045d3dd9Robert Mustacchi	return (NULL);
12145d3dd9Robert Mustacchi}
12245d3dd9Robert Mustacchi
12345d3dd9Robert Mustacchiint
12445d3dd9Robert Mustacchitransceiver_create_sff(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
12545d3dd9Robert Mustacchi    boolean_t useable, const char *vendor, const char *part, const char *rev,
12645d3dd9Robert Mustacchi    const char *serial, tnode_t **nodep)
12745d3dd9Robert Mustacchi{
12845d3dd9Robert Mustacchi	int err;
12945d3dd9Robert Mustacchi	tnode_t *tn = NULL;
13045d3dd9Robert Mustacchi
13145d3dd9Robert Mustacchi	if ((tn = transceiver_create_common(mod, pnode, inst,
13245d3dd9Robert Mustacchi	    TOPO_PROP_PORT_TYPE_SFF, useable, part, rev, serial)) == NULL) {
13345d3dd9Robert Mustacchi		return (-1);
13445d3dd9Robert Mustacchi	}
13545d3dd9Robert Mustacchi
13645d3dd9Robert Mustacchi	/*
13745d3dd9Robert Mustacchi	 * Always create the SFF property group, even if we can't fill in any
13845d3dd9Robert Mustacchi	 * properties.
13945d3dd9Robert Mustacchi	 */
14045d3dd9Robert Mustacchi	if (topo_pgroup_create(tn, &sff_transceiver_pgroup, &err) != 0) {
14145d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to create property group %s: "
14245d3dd9Robert Mustacchi		    "%s\n", TOPO_PGROUP_SFF_TRANSCEIVER, topo_strerror(err));
14345d3dd9Robert Mustacchi		goto error;
14445d3dd9Robert Mustacchi	}
14545d3dd9Robert Mustacchi
14645d3dd9Robert Mustacchi	if (vendor != NULL && topo_prop_set_string(tn,
14745d3dd9Robert Mustacchi	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_VENDOR,
14845d3dd9Robert Mustacchi	    TOPO_PROP_IMMUTABLE, vendor, &err) != 0) {
14945d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
15045d3dd9Robert Mustacchi		    TOPO_PORT_SFF_TRANSCEIVER_VENDOR, topo_strerror(err));
15145d3dd9Robert Mustacchi		goto error;
15245d3dd9Robert Mustacchi	}
15345d3dd9Robert Mustacchi
15445d3dd9Robert Mustacchi	if (part != NULL && topo_prop_set_string(tn,
15545d3dd9Robert Mustacchi	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_PN,
15645d3dd9Robert Mustacchi	    TOPO_PROP_IMMUTABLE, part, &err) != 0) {
15745d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
15845d3dd9Robert Mustacchi		    TOPO_PORT_SFF_TRANSCEIVER_PN, topo_strerror(err));
15945d3dd9Robert Mustacchi		goto error;
16045d3dd9Robert Mustacchi	}
16145d3dd9Robert Mustacchi
16245d3dd9Robert Mustacchi	if (rev != NULL && topo_prop_set_string(tn,
16345d3dd9Robert Mustacchi	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_REV,
16445d3dd9Robert Mustacchi	    TOPO_PROP_IMMUTABLE, rev, &err) != 0) {
16545d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
16645d3dd9Robert Mustacchi		    TOPO_PORT_SFF_TRANSCEIVER_REV, topo_strerror(err));
16745d3dd9Robert Mustacchi		goto error;
16845d3dd9Robert Mustacchi	}
16945d3dd9Robert Mustacchi
17045d3dd9Robert Mustacchi	if (serial != NULL && topo_prop_set_string(tn,
17145d3dd9Robert Mustacchi	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_SN,
17245d3dd9Robert Mustacchi	    TOPO_PROP_IMMUTABLE, serial, &err) != 0) {
17345d3dd9Robert Mustacchi		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
17445d3dd9Robert Mustacchi		    TOPO_PORT_SFF_TRANSCEIVER_SN, topo_strerror(err));
17545d3dd9Robert Mustacchi		goto error;
17645d3dd9Robert Mustacchi	}
17745d3dd9Robert Mustacchi
17845d3dd9Robert Mustacchi	if (nodep != NULL)
17945d3dd9Robert Mustacchi		*nodep = tn;
18045d3dd9Robert Mustacchi	return (0);
18145d3dd9Robert Mustacchi
18245d3dd9Robert Mustacchierror:
18345d3dd9Robert Mustacchi	topo_node_unbind(tn);
18445d3dd9Robert Mustacchi	return (-1);
18545d3dd9Robert Mustacchi}
186