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) 2019, 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 #include <topo_port.h>
22 
23 /*
24  * Common routines to create port entries in the topology tree.
25  */
26 
27 static const topo_pgroup_info_t port_pgroup = {
28 	TOPO_PGROUP_PORT,
29 	TOPO_STABILITY_PRIVATE,
30 	TOPO_STABILITY_PRIVATE,
31 	1
32 };
33 
34 static const topo_method_t port_methods[] = {
35 	{ TOPO_METH_OCCUPIED, TOPO_METH_OCCUPIED_DESC,
36 	    TOPO_METH_OCCUPIED_VERSION, TOPO_STABILITY_INTERNAL,
37 	    topo_mod_hc_occupied },
38 	{ NULL }
39 };
40 
41 int
port_range_create(topo_mod_t * mod,tnode_t * pnode,topo_instance_t min,topo_instance_t max)42 port_range_create(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
43     topo_instance_t max)
44 {
45 	return (topo_node_range_create(mod, pnode, PORT, min, max));
46 }
47 
48 /*
49  * Create a port node, specifying the type of port it is. This will create the
50  * common port property group and populate it. The caller will need to populate
51  * the port-specific property group as needed.
52  */
53 static tnode_t *
port_create_common(topo_mod_t * mod,tnode_t * pnode,topo_instance_t inst,const char * type)54 port_create_common(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
55     const char *type)
56 {
57 	int err;
58 	tnode_t *tn = NULL;
59 	nvlist_t *fmri = NULL, *auth = NULL, *presource = NULL;
60 
61 	if (type == NULL) {
62 		topo_mod_dprintf(mod, "port_create_common missing type "
63 		    "argument\n");
64 		goto error;
65 	}
66 
67 	if ((auth = topo_mod_auth(mod, pnode)) == NULL) {
68 		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s\n",
69 		    topo_mod_errmsg(mod));
70 		goto error;
71 	}
72 
73 	if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, PORT,
74 	    inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
75 		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s\n",
76 		    topo_mod_errmsg(mod));
77 		goto error;
78 	}
79 
80 	if ((tn = topo_node_bind(mod, pnode, PORT, inst, fmri)) == NULL) {
81 		topo_mod_dprintf(mod, "topo_node_bind() failed: %s\n",
82 		    topo_mod_errmsg(mod));
83 		goto error;
84 	}
85 
86 	/*
87 	 * The FRU is always set to the FMRI of the parent device for a port.
88 	 */
89 	if (topo_node_resource(pnode, &presource, &err) != 0) {
90 		topo_mod_dprintf(mod, "topo_node_resource() failed: %s\n",
91 		    topo_strerror(err));
92 		goto error;
93 	}
94 
95 	if (topo_node_fru_set(tn, presource, 0, &err) != 0) {
96 		topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s\n",
97 		    topo_strerror(err));
98 		goto error;
99 	}
100 
101 	if (topo_pgroup_create(tn, &port_pgroup, &err) != 0) {
102 		topo_mod_dprintf(mod, "failed to create property group %s: "
103 		    "%s\n", TOPO_PGROUP_PORT, topo_strerror(err));
104 		goto error;
105 	}
106 
107 	if (topo_prop_set_string(tn, TOPO_PGROUP_PORT, TOPO_PROP_PORT_TYPE,
108 	    TOPO_PROP_IMMUTABLE, type, &err) != 0) {
109 		topo_mod_dprintf(mod, "failed to set %s property: %s\n",
110 		    TOPO_PROP_PORT_TYPE, topo_strerror(err));
111 		goto error;
112 	}
113 
114 	if (topo_method_register(mod, tn, port_methods) != 0) {
115 		topo_mod_dprintf(mod, "topo_method_register() failed on "
116 		    "%s=%" PRIu64 ": %s", PORT, inst, topo_mod_errmsg(mod));
117 		/* errno set */
118 		goto error;
119 	}
120 
121 	nvlist_free(fmri);
122 	nvlist_free(auth);
123 	nvlist_free(presource);
124 	return (tn);
125 error:
126 	topo_node_unbind(tn);
127 	nvlist_free(fmri);
128 	nvlist_free(auth);
129 	nvlist_free(presource);
130 	return (NULL);
131 }
132 
133 int
port_create_sff(topo_mod_t * mod,tnode_t * pnode,topo_instance_t inst,tnode_t ** nodep)134 port_create_sff(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
135     tnode_t **nodep)
136 {
137 	tnode_t *tn;
138 
139 	tn = port_create_common(mod, pnode, inst, TOPO_PROP_PORT_TYPE_SFF);
140 	if (tn == NULL)
141 		return (-1);
142 	*nodep = tn;
143 	return (0);
144 }
145 
146 int
port_create_usb(topo_mod_t * mod,tnode_t * pnode,topo_instance_t inst,tnode_t ** nodep)147 port_create_usb(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
148     tnode_t **nodep)
149 {
150 	tnode_t *tn;
151 
152 	tn = port_create_common(mod, pnode, inst, TOPO_PROP_PORT_TYPE_USB);
153 	if (tn == NULL)
154 		return (-1);
155 	*nodep = tn;
156 	return (0);
157 }
158 
159 int
port_create_unknown(topo_mod_t * mod,tnode_t * pnode,topo_instance_t inst,tnode_t ** nodep)160 port_create_unknown(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
161     tnode_t **nodep)
162 {
163 	tnode_t *tn;
164 
165 	tn = port_create_common(mod, pnode, inst, TOPO_PROP_PORT_TYPE_UNKNOWN);
166 	if (tn == NULL)
167 		return (-1);
168 	*nodep = tn;
169 	return (0);
170 }
171