1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source.  A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright (c) 2017, Joyent, Inc.
14 */
15
16#include <sys/fm/protocol.h>
17#include <fm/topo_mod.h>
18#include <fm/topo_list.h>
19#include <fm/topo_method.h>
20
21/*
22 * Common routines to create transceiver entries in the topology tree.
23 */
24
25static const topo_pgroup_info_t transceiver_pgroup = {
26	TOPO_PGROUP_TRANSCEIVER,
27	TOPO_STABILITY_PRIVATE,
28	TOPO_STABILITY_PRIVATE,
29	1
30};
31
32static const topo_pgroup_info_t sff_transceiver_pgroup = {
33	TOPO_PGROUP_SFF_TRANSCEIVER,
34	TOPO_STABILITY_PRIVATE,
35	TOPO_STABILITY_PRIVATE,
36	1
37};
38
39int
40transceiver_range_create(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
41    topo_instance_t max)
42{
43	return (topo_node_range_create(mod, pnode, TRANSCEIVER, min, max));
44}
45
46static tnode_t *
47transceiver_create_common(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
48    const char *type, boolean_t usable, const char *part, const char *rev,
49    const char *serial)
50{
51	int err;
52	tnode_t *tn = NULL;
53	nvlist_t *fmri = NULL, *auth = NULL;
54
55	if (type == NULL) {
56		topo_mod_dprintf(mod, "transceiver_create_common missing type "
57		    "argument");
58		goto error;
59	}
60
61	if ((auth = topo_mod_auth(mod, pnode)) == NULL) {
62		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s\n",
63		    topo_mod_errmsg(mod));
64		goto error;
65	}
66
67	if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION,
68	    TRANSCEIVER, inst, NULL, auth, part, rev, serial)) == NULL) {
69		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s\n",
70		    topo_mod_errmsg(mod));
71		goto error;
72	}
73
74	if ((tn = topo_node_bind(mod, pnode, TRANSCEIVER, inst, fmri)) ==
75	    NULL) {
76		topo_mod_dprintf(mod, "topo_node_bind() failed: %s\n",
77		    topo_mod_errmsg(mod));
78		goto error;
79	}
80
81	/*
82	 * The FRU for a transceiver is always itself.
83	 */
84	if (topo_node_fru_set(tn, fmri, 0, &err) != 0) {
85		topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s\n",
86		    topo_strerror(err));
87		goto error;
88	}
89
90	if (topo_pgroup_create(tn, &transceiver_pgroup, &err) != 0) {
91		topo_mod_dprintf(mod, "failed to create property group %s: "
92		    "%s\n", TOPO_PGROUP_TRANSCEIVER, topo_strerror(err));
93		goto error;
94	}
95
96	if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER,
97	    TOPO_PROP_TRANSCEIVER_TYPE, TOPO_PROP_IMMUTABLE, type,
98	    &err) != 0) {
99		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
100		    TOPO_PROP_TRANSCEIVER_TYPE, topo_strerror(err));
101		goto error;
102	}
103
104	if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER,
105	    TOPO_PROP_TRANSCEIVER_USABLE, TOPO_PROP_IMMUTABLE,
106	    usable ? "true" : "false", &err) != 0) {
107		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
108		    TOPO_PROP_TRANSCEIVER_USABLE, topo_strerror(err));
109		goto error;
110	}
111
112	nvlist_free(fmri);
113	nvlist_free(auth);
114	return (tn);
115
116error:
117	topo_node_unbind(tn);
118	nvlist_free(fmri);
119	nvlist_free(auth);
120	return (NULL);
121}
122
123int
124transceiver_create_sff(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
125    boolean_t useable, const char *vendor, const char *part, const char *rev,
126    const char *serial, tnode_t **nodep)
127{
128	int err;
129	tnode_t *tn = NULL;
130
131	if ((tn = transceiver_create_common(mod, pnode, inst,
132	    TOPO_PROP_PORT_TYPE_SFF, useable, part, rev, serial)) == NULL) {
133		return (-1);
134	}
135
136	/*
137	 * Always create the SFF property group, even if we can't fill in any
138	 * properties.
139	 */
140	if (topo_pgroup_create(tn, &sff_transceiver_pgroup, &err) != 0) {
141		topo_mod_dprintf(mod, "failed to create property group %s: "
142		    "%s\n", TOPO_PGROUP_SFF_TRANSCEIVER, topo_strerror(err));
143		goto error;
144	}
145
146	if (vendor != NULL && topo_prop_set_string(tn,
147	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_VENDOR,
148	    TOPO_PROP_IMMUTABLE, vendor, &err) != 0) {
149		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
150		    TOPO_PORT_SFF_TRANSCEIVER_VENDOR, topo_strerror(err));
151		goto error;
152	}
153
154	if (part != NULL && topo_prop_set_string(tn,
155	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_PN,
156	    TOPO_PROP_IMMUTABLE, part, &err) != 0) {
157		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
158		    TOPO_PORT_SFF_TRANSCEIVER_PN, topo_strerror(err));
159		goto error;
160	}
161
162	if (rev != NULL && topo_prop_set_string(tn,
163	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_REV,
164	    TOPO_PROP_IMMUTABLE, rev, &err) != 0) {
165		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
166		    TOPO_PORT_SFF_TRANSCEIVER_REV, topo_strerror(err));
167		goto error;
168	}
169
170	if (serial != NULL && topo_prop_set_string(tn,
171	    TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_SN,
172	    TOPO_PROP_IMMUTABLE, serial, &err) != 0) {
173		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
174		    TOPO_PORT_SFF_TRANSCEIVER_SN, topo_strerror(err));
175		goto error;
176	}
177
178	if (nodep != NULL)
179		*nodep = tn;
180	return (0);
181
182error:
183	topo_node_unbind(tn);
184	return (-1);
185}
186