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 
25 static const topo_pgroup_info_t transceiver_pgroup = {
26 	TOPO_PGROUP_TRANSCEIVER,
27 	TOPO_STABILITY_PRIVATE,
28 	TOPO_STABILITY_PRIVATE,
29 	1
30 };
31 
32 static 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 
39 int
transceiver_range_create(topo_mod_t * mod,tnode_t * pnode,topo_instance_t min,topo_instance_t max)40 transceiver_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 
46 static tnode_t *
transceiver_create_common(topo_mod_t * mod,tnode_t * pnode,topo_instance_t inst,const char * type,boolean_t usable,const char * part,const char * rev,const char * serial)47 transceiver_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 
116 error:
117 	topo_node_unbind(tn);
118 	nvlist_free(fmri);
119 	nvlist_free(auth);
120 	return (NULL);
121 }
122 
123 int
transceiver_create_sff(topo_mod_t * mod,tnode_t * pnode,topo_instance_t inst,boolean_t useable,const char * vendor,const char * part,const char * rev,const char * serial,tnode_t ** nodep)124 transceiver_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 
182 error:
183 	topo_node_unbind(tn);
184 	return (-1);
185 }
186