xref: /illumos-gate/usr/src/cmd/i2cadm/i2cadm_mux.c (revision 32002227574cf0a435dc03de622191ca53724f0a)
1*32002227SRobert Mustacchi /*
2*32002227SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*32002227SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*32002227SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*32002227SRobert Mustacchi  * 1.0 of the CDDL.
6*32002227SRobert Mustacchi  *
7*32002227SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*32002227SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*32002227SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*32002227SRobert Mustacchi  */
11*32002227SRobert Mustacchi 
12*32002227SRobert Mustacchi /*
13*32002227SRobert Mustacchi  * Copyright 2025 Oxide Computer Company
14*32002227SRobert Mustacchi  */
15*32002227SRobert Mustacchi 
16*32002227SRobert Mustacchi /*
17*32002227SRobert Mustacchi  * i2cadm mux related operations.
18*32002227SRobert Mustacchi  */
19*32002227SRobert Mustacchi 
20*32002227SRobert Mustacchi #include <stdarg.h>
21*32002227SRobert Mustacchi #include <string.h>
22*32002227SRobert Mustacchi #include <err.h>
23*32002227SRobert Mustacchi #include <sys/sysmacros.h>
24*32002227SRobert Mustacchi #include <ofmt.h>
25*32002227SRobert Mustacchi 
26*32002227SRobert Mustacchi #include "i2cadm.h"
27*32002227SRobert Mustacchi 
28*32002227SRobert Mustacchi static void
i2cadm_mux_list_usage(FILE * f)29*32002227SRobert Mustacchi i2cadm_mux_list_usage(FILE *f)
30*32002227SRobert Mustacchi {
31*32002227SRobert Mustacchi 	(void) fprintf(f, "\ti2cadm mux list [-H] [-o field,[...] [-p]] "
32*32002227SRobert Mustacchi 	    "[filter]\n");
33*32002227SRobert Mustacchi }
34*32002227SRobert Mustacchi 
35*32002227SRobert Mustacchi static void
i2cadm_mux_list_help(const char * fmt,...)36*32002227SRobert Mustacchi i2cadm_mux_list_help(const char *fmt, ...)
37*32002227SRobert Mustacchi {
38*32002227SRobert Mustacchi 	if (fmt != NULL) {
39*32002227SRobert Mustacchi 		va_list ap;
40*32002227SRobert Mustacchi 
41*32002227SRobert Mustacchi 		va_start(ap, fmt);
42*32002227SRobert Mustacchi 		vwarnx(fmt, ap);
43*32002227SRobert Mustacchi 		va_end(ap);
44*32002227SRobert Mustacchi 	}
45*32002227SRobert Mustacchi 
46*32002227SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  i2cadm mux list [-H] "
47*32002227SRobert Mustacchi 	    "[-o field[,...] [-p]] [filter...]\n\n");
48*32002227SRobert Mustacchi 	(void) fprintf(stderr, "List multiplexors in the system. Each <filter> "
49*32002227SRobert Mustacchi 	    "selects a multiplexor based " "on\nits device's name, device "
50*32002227SRobert Mustacchi 	    "driver, or the mux's name. When multiple filters are\nspecified, "
51*32002227SRobert Mustacchi 	    "they are treated like an OR. It is an error if a filter isn't "
52*32002227SRobert Mustacchi 	    "used.\n\n"
53*32002227SRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
54*32002227SRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
55*32002227SRobert Mustacchi 	    "\t-p\t\tparseable output (requires -o)\n");
56*32002227SRobert Mustacchi 	(void) fprintf(stderr, "\nThe following fields are supported:\n"
57*32002227SRobert Mustacchi 	    "\tdevice\t\tthe name of the device that powers the mux\n"
58*32002227SRobert Mustacchi 	    "\tnports\t\tthe number of ports on the mux\n"
59*32002227SRobert Mustacchi 	    "\tname\t\tthe name of the mux\n"
60*32002227SRobert Mustacchi 	    "\tinstance\tthe instance of the driver for the mux\n"
61*32002227SRobert Mustacchi 	    "\tpath\t\tthe I2C path of the mux\n");
62*32002227SRobert Mustacchi }
63*32002227SRobert Mustacchi 
64*32002227SRobert Mustacchi typedef enum {
65*32002227SRobert Mustacchi 	I2CADM_MUX_LIST_DEVICE,
66*32002227SRobert Mustacchi 	I2CADM_MUX_LIST_NAME,
67*32002227SRobert Mustacchi 	I2CADM_MUX_LIST_NPORTS,
68*32002227SRobert Mustacchi 	I2CADM_MUX_LIST_INSTANCE,
69*32002227SRobert Mustacchi 	I2CADM_MUX_LIST_PATH
70*32002227SRobert Mustacchi } i2cadm_mux_list_otype_t;
71*32002227SRobert Mustacchi 
72*32002227SRobert Mustacchi static boolean_t
i2cadm_mux_list_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)73*32002227SRobert Mustacchi i2cadm_mux_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
74*32002227SRobert Mustacchi {
75*32002227SRobert Mustacchi 	const i2c_mux_disc_t *disc = ofarg->ofmt_cbarg;
76*32002227SRobert Mustacchi 	size_t len;
77*32002227SRobert Mustacchi 	di_node_t dn;
78*32002227SRobert Mustacchi 
79*32002227SRobert Mustacchi 	switch (ofarg->ofmt_id) {
80*32002227SRobert Mustacchi 	case I2CADM_MUX_LIST_DEVICE:
81*32002227SRobert Mustacchi 		dn = di_parent_node(i2c_mux_disc_devi(disc));
82*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "%s", di_node_name(dn));
83*32002227SRobert Mustacchi 		break;
84*32002227SRobert Mustacchi 	case I2CADM_MUX_LIST_NAME:
85*32002227SRobert Mustacchi 		len = strlcpy(buf, i2c_mux_disc_name(disc), buflen);
86*32002227SRobert Mustacchi 		break;
87*32002227SRobert Mustacchi 	case I2CADM_MUX_LIST_NPORTS:
88*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "%u", i2c_mux_disc_nports(disc));
89*32002227SRobert Mustacchi 		break;
90*32002227SRobert Mustacchi 	case I2CADM_MUX_LIST_INSTANCE:
91*32002227SRobert Mustacchi 		/*
92*32002227SRobert Mustacchi 		 * Because a mux exists here, we know our parent instance must
93*32002227SRobert Mustacchi 		 * be active and attached.
94*32002227SRobert Mustacchi 		 */
95*32002227SRobert Mustacchi 		dn = di_parent_node(i2c_mux_disc_devi(disc));
96*32002227SRobert Mustacchi 		len = snprintf(buf, buflen, "%s%d", di_driver_name(dn),
97*32002227SRobert Mustacchi 		    di_instance(dn));
98*32002227SRobert Mustacchi 		break;
99*32002227SRobert Mustacchi 	case I2CADM_MUX_LIST_PATH:
100*32002227SRobert Mustacchi 		len = strlcpy(buf, i2c_mux_disc_path(disc), buflen);
101*32002227SRobert Mustacchi 		break;
102*32002227SRobert Mustacchi 	default:
103*32002227SRobert Mustacchi 		return (B_FALSE);
104*32002227SRobert Mustacchi 	}
105*32002227SRobert Mustacchi 
106*32002227SRobert Mustacchi 	return (len < buflen);
107*32002227SRobert Mustacchi }
108*32002227SRobert Mustacchi 
109*32002227SRobert Mustacchi static const char *i2cadm_mux_list_fields = "device,nports,name,instance,path";
110*32002227SRobert Mustacchi static const ofmt_field_t i2cadm_mux_list_ofmt[] = {
111*32002227SRobert Mustacchi 	{ "DEVICE", 12, I2CADM_MUX_LIST_DEVICE, i2cadm_mux_list_ofmt_cb },
112*32002227SRobert Mustacchi 	{ "NAME", 12, I2CADM_MUX_LIST_NAME, i2cadm_mux_list_ofmt_cb },
113*32002227SRobert Mustacchi 	{ "NPORTS", 12, I2CADM_MUX_LIST_NPORTS, i2cadm_mux_list_ofmt_cb },
114*32002227SRobert Mustacchi 	{ "INSTANCE", 16, I2CADM_MUX_LIST_INSTANCE, i2cadm_mux_list_ofmt_cb },
115*32002227SRobert Mustacchi 	{ "PATH", 40, I2CADM_MUX_LIST_PATH, i2cadm_mux_list_ofmt_cb },
116*32002227SRobert Mustacchi 	{ NULL, 0, 0, NULL }
117*32002227SRobert Mustacchi };
118*32002227SRobert Mustacchi 
119*32002227SRobert Mustacchi static int
i2cadm_mux_list(int argc,char * argv[])120*32002227SRobert Mustacchi i2cadm_mux_list(int argc, char *argv[])
121*32002227SRobert Mustacchi {
122*32002227SRobert Mustacchi 	int c, ret = EXIT_SUCCESS;
123*32002227SRobert Mustacchi 	uint_t flags = 0;
124*32002227SRobert Mustacchi 	boolean_t parse = B_FALSE;
125*32002227SRobert Mustacchi 	const char *fields = NULL;
126*32002227SRobert Mustacchi 	bool *filts = NULL, print = false;
127*32002227SRobert Mustacchi 	ofmt_status_t oferr;
128*32002227SRobert Mustacchi 	ofmt_handle_t ofmt;
129*32002227SRobert Mustacchi 	const i2c_mux_disc_t *disc;
130*32002227SRobert Mustacchi 	i2c_mux_iter_t *iter;
131*32002227SRobert Mustacchi 	i2c_iter_t iret;
132*32002227SRobert Mustacchi 
133*32002227SRobert Mustacchi 	while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
134*32002227SRobert Mustacchi 		switch (c) {
135*32002227SRobert Mustacchi 		case 'H':
136*32002227SRobert Mustacchi 			flags |= OFMT_NOHEADER;
137*32002227SRobert Mustacchi 			break;
138*32002227SRobert Mustacchi 		case 'o':
139*32002227SRobert Mustacchi 			fields = optarg;
140*32002227SRobert Mustacchi 			break;
141*32002227SRobert Mustacchi 		case 'p':
142*32002227SRobert Mustacchi 			parse = B_TRUE;
143*32002227SRobert Mustacchi 			flags |= OFMT_PARSABLE;
144*32002227SRobert Mustacchi 			break;
145*32002227SRobert Mustacchi 		case ':':
146*32002227SRobert Mustacchi 			i2cadm_mux_list_help("option -%c requires an "
147*32002227SRobert Mustacchi 			    "argument", optopt);
148*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
149*32002227SRobert Mustacchi 		case '?':
150*32002227SRobert Mustacchi 			i2cadm_mux_list_help("unknown option: -%c",
151*32002227SRobert Mustacchi 			    optopt);
152*32002227SRobert Mustacchi 			exit(EXIT_USAGE);
153*32002227SRobert Mustacchi 		}
154*32002227SRobert Mustacchi 	}
155*32002227SRobert Mustacchi 
156*32002227SRobert Mustacchi 	if (parse && fields == NULL) {
157*32002227SRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
158*32002227SRobert Mustacchi 	}
159*32002227SRobert Mustacchi 
160*32002227SRobert Mustacchi 	if (!parse) {
161*32002227SRobert Mustacchi 		flags |= OFMT_WRAP;
162*32002227SRobert Mustacchi 	}
163*32002227SRobert Mustacchi 
164*32002227SRobert Mustacchi 	if (fields == NULL) {
165*32002227SRobert Mustacchi 		fields = i2cadm_mux_list_fields;
166*32002227SRobert Mustacchi 	}
167*32002227SRobert Mustacchi 
168*32002227SRobert Mustacchi 	argc -= optind;
169*32002227SRobert Mustacchi 	argv += optind;
170*32002227SRobert Mustacchi 
171*32002227SRobert Mustacchi 	if (argc > 0) {
172*32002227SRobert Mustacchi 		filts = calloc(argc, sizeof (bool));
173*32002227SRobert Mustacchi 		if (filts == NULL) {
174*32002227SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
175*32002227SRobert Mustacchi 			    "filter tracking");
176*32002227SRobert Mustacchi 		}
177*32002227SRobert Mustacchi 	}
178*32002227SRobert Mustacchi 
179*32002227SRobert Mustacchi 	oferr = ofmt_open(fields, i2cadm_mux_list_ofmt, flags, 0, &ofmt);
180*32002227SRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, i2cadm_ofmt_errx, warnx);
181*32002227SRobert Mustacchi 
182*32002227SRobert Mustacchi 
183*32002227SRobert Mustacchi 	if (!i2c_mux_discover_init(i2cadm.i2c_hdl, &iter)) {
184*32002227SRobert Mustacchi 		i2cadm_fatal("failed to in initialize mux walk");
185*32002227SRobert Mustacchi 	}
186*32002227SRobert Mustacchi 
187*32002227SRobert Mustacchi 	while ((iret = i2c_mux_discover_step(iter, &disc)) ==
188*32002227SRobert Mustacchi 	    I2C_ITER_VALID) {
189*32002227SRobert Mustacchi 		if (argc > 0) {
190*32002227SRobert Mustacchi 			const char *name = i2c_mux_disc_name(disc);
191*32002227SRobert Mustacchi 			di_node_t dn = di_parent_node(i2c_mux_disc_devi(disc));
192*32002227SRobert Mustacchi 			const char *drv = di_driver_name(dn);
193*32002227SRobert Mustacchi 			const char *pname = di_node_name(dn);
194*32002227SRobert Mustacchi 			bool match = false;
195*32002227SRobert Mustacchi 
196*32002227SRobert Mustacchi 			for (int i = 0; i < argc; i++) {
197*32002227SRobert Mustacchi 				if (strcmp(argv[i], name) == 0 ||
198*32002227SRobert Mustacchi 				    strcmp(argv[i], drv) == 0 ||
199*32002227SRobert Mustacchi 				    strcmp(argv[i], pname) == 0) {
200*32002227SRobert Mustacchi 					match = true;
201*32002227SRobert Mustacchi 					filts[i] = true;
202*32002227SRobert Mustacchi 				}
203*32002227SRobert Mustacchi 			}
204*32002227SRobert Mustacchi 
205*32002227SRobert Mustacchi 			if (!match) {
206*32002227SRobert Mustacchi 				continue;
207*32002227SRobert Mustacchi 			}
208*32002227SRobert Mustacchi 		}
209*32002227SRobert Mustacchi 
210*32002227SRobert Mustacchi 		ofmt_print(ofmt, (void *)disc);
211*32002227SRobert Mustacchi 		print = true;
212*32002227SRobert Mustacchi 	}
213*32002227SRobert Mustacchi 
214*32002227SRobert Mustacchi 	if (iret == I2C_ITER_ERROR) {
215*32002227SRobert Mustacchi 		i2cadm_warn("failed to iterate muxes");
216*32002227SRobert Mustacchi 		ret = EXIT_FAILURE;
217*32002227SRobert Mustacchi 	}
218*32002227SRobert Mustacchi 
219*32002227SRobert Mustacchi 	for (int i = 0; i < argc; i++) {
220*32002227SRobert Mustacchi 		if (!filts[i]) {
221*32002227SRobert Mustacchi 			warnx("filter '%s' did not match any muxes", argv[i]);
222*32002227SRobert Mustacchi 			ret = EXIT_FAILURE;
223*32002227SRobert Mustacchi 		}
224*32002227SRobert Mustacchi 	}
225*32002227SRobert Mustacchi 
226*32002227SRobert Mustacchi 	if (!print && argc == 0) {
227*32002227SRobert Mustacchi 		warnx("no I2C muxes found");
228*32002227SRobert Mustacchi 		ret = EXIT_FAILURE;
229*32002227SRobert Mustacchi 	}
230*32002227SRobert Mustacchi 
231*32002227SRobert Mustacchi 	free(filts);
232*32002227SRobert Mustacchi 	ofmt_close(ofmt);
233*32002227SRobert Mustacchi 	return (ret);
234*32002227SRobert Mustacchi }
235*32002227SRobert Mustacchi 
236*32002227SRobert Mustacchi static i2cadm_cmdtab_t i2cadm_mux_cmds[] = {
237*32002227SRobert Mustacchi 	{ "list", i2cadm_mux_list, i2cadm_mux_list_usage },
238*32002227SRobert Mustacchi };
239*32002227SRobert Mustacchi 
240*32002227SRobert Mustacchi int
i2cadm_mux(int argc,char * argv[])241*32002227SRobert Mustacchi i2cadm_mux(int argc, char *argv[])
242*32002227SRobert Mustacchi {
243*32002227SRobert Mustacchi 	return (i2cadm_walk_tab(i2cadm_mux_cmds, ARRAY_SIZE(i2cadm_mux_cmds),
244*32002227SRobert Mustacchi 	    argc, argv));
245*32002227SRobert Mustacchi }
246*32002227SRobert Mustacchi 
247*32002227SRobert Mustacchi void
i2cadm_mux_usage(FILE * f)248*32002227SRobert Mustacchi i2cadm_mux_usage(FILE *f)
249*32002227SRobert Mustacchi {
250*32002227SRobert Mustacchi 	i2cadm_walk_usage(i2cadm_mux_cmds, ARRAY_SIZE(i2cadm_mux_cmds), f);
251*32002227SRobert Mustacchi }
252