xref: /illumos-gate/usr/src/cmd/th_tools/th_manage.c (revision 3e1bd7a2aaeb6188caef90679b98088cfef1edc6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <libdevice.h>
37 #include <libdevinfo.h>
38 #define	_KERNEL
39 #include <sys/dditypes.h>
40 #include <sys/devctl.h>
41 #include <sys/bofi.h>
42 
43 static int online_device(char *path);
44 static int offline_device(char *path);
45 static int getstate_device(char *path);
46 static int getnameinst(char *path, int *instance, char *name, int namelen);
47 static int getpath(char *path, int instance, char *name, int pathlen);
48 
49 static char buffer[50*1024];
50 
51 #define	CMD_TABLE_SIZE 11
52 #define	BOFI_ONLINE 0
53 #define	BOFI_OFFLINE 1
54 #define	BOFI_GETSTATE 2
55 #define	BOFI_GETPATH 3
56 
57 static struct {
58 	char *string;
59 	int val;
60 	int devctl_val;
61 } cmd_table[] = {
62 	{"online", -1, BOFI_ONLINE},
63 	{"offline", -1, BOFI_OFFLINE},
64 	{"getstate", -1, BOFI_GETSTATE},
65 	{"getpath", -1, BOFI_GETPATH},
66 	{"broadcast", BOFI_BROADCAST, -1},
67 	{"clear_acc_chk", BOFI_CLEAR_ACC_CHK, -1},
68 	{"clear_errors", BOFI_CLEAR_ERRORS, -1},
69 	{"clear_errdefs", BOFI_CLEAR_ERRDEFS, -1},
70 	{"start", BOFI_START, -1},
71 	{"stop", BOFI_STOP, -1},
72 	{"get_handles", BOFI_GET_HANDLES, -1}
73 };
74 
75 int
76 main(int argc, char **argv)
77 {
78 	struct bofi_errctl errctl;
79 	struct bofi_get_handles get_handles;
80 	int command = -1;
81 	int devctl_command = -1;
82 	int i;
83 	int fd;
84 
85 	char buf[MAXPATHLEN];
86 	char path[MAXPATHLEN];
87 
88 	if (argc == 3) {
89 		(void) strncpy(path, argv[1], MAXPATHLEN);
90 
91 		for (i = 0; i < CMD_TABLE_SIZE; i++) {
92 			if (strcmp(argv[2], cmd_table[i].string) == NULL) {
93 				command = cmd_table[i].val;
94 				devctl_command = cmd_table[i].devctl_val;
95 			}
96 		}
97 		switch (devctl_command) {
98 		case BOFI_ONLINE:
99 		case BOFI_OFFLINE:
100 		case BOFI_GETPATH:
101 		case BOFI_GETSTATE:
102 			break;
103 		default:
104 			if (getnameinst(argv[1], &errctl.instance, buf,
105 			    MAXPATHLEN) == -1) {
106 				(void) fprintf(stderr,
107 				    "th_manage - invalid path\n");
108 				exit(1);
109 			}
110 			(void) strncpy(errctl.name, buf, MAXNAMELEN);
111 			errctl.namesize = strlen(errctl.name);
112 		}
113 	} else if (argc == 4) {
114 		errctl.namesize = strlen(argv[1]);
115 		(void) strncpy(errctl.name, argv[1], MAXNAMELEN);
116 		errctl.instance = atoi(argv[2]);
117 		for (i = 0; i < CMD_TABLE_SIZE; i++) {
118 			if (strcmp(argv[3], cmd_table[i].string) == NULL) {
119 				command = cmd_table[i].val;
120 				devctl_command = cmd_table[i].devctl_val;
121 			}
122 		}
123 		switch (devctl_command) {
124 		case BOFI_ONLINE:
125 		case BOFI_OFFLINE:
126 		case BOFI_GETPATH:
127 		case BOFI_GETSTATE:
128 			(void) strcpy(path, "/devices/");
129 			if (getpath(&path[8], errctl.instance, errctl.name,
130 			    MAXPATHLEN) == -1) {
131 				(void) fprintf(stderr,
132 				    "th_manage - invalid name/instance\n");
133 				exit(1);
134 			}
135 		default:
136 			break;
137 		}
138 	} else {
139 		(void) fprintf(stderr, "usage:\n");
140 		(void) fprintf(stderr,
141 		    "    th_manage name instance state\n");
142 		(void) fprintf(stderr,
143 		    "    th_manage path state\n");
144 		exit(2);
145 	}
146 
147 	if (command == -1) {
148 		/*
149 		 * might have been a devctl command
150 		 */
151 		if (devctl_command == BOFI_ONLINE) {
152 			while (online_device(path) != 0) {
153 				(void) sleep(3);
154 			}
155 			exit(0);
156 		}
157 		if (devctl_command == BOFI_OFFLINE) {
158 			while (offline_device(path) != 0) {
159 				(void) sleep(3);
160 			}
161 			exit(0);
162 		}
163 		if (devctl_command == BOFI_GETSTATE) {
164 			if (getstate_device(path) != 0) {
165 				perror("th_manage - getstate failed");
166 				exit(1);
167 			} else {
168 				exit(0);
169 			}
170 		}
171 		if (devctl_command == BOFI_GETPATH) {
172 			(void) fprintf(stdout, "%s\n", path);
173 			exit(0);
174 		}
175 		(void) fprintf(stderr,
176 		    "th_manage: invalid command\n");
177 		(void) fprintf(stderr,
178 		    "     Command must be one of start, stop, broadcast, "
179 		    "get_handles,\n");
180 		(void) fprintf(stderr,
181 		    "     clear_acc_chk, clear_errors or clear_errdefs\n");
182 		exit(2);
183 	}
184 	fd = open("/devices/pseudo/bofi@0:bofi,ctl", O_RDWR);
185 	if (fd == -1) {
186 		perror("th_manage - open of bofi driver");
187 		exit(2);
188 	}
189 	if (command == BOFI_GET_HANDLES) {
190 		get_handles.namesize = errctl.namesize;
191 		(void) strncpy(get_handles.name, errctl.name, MAXNAMELEN);
192 		get_handles.instance =  errctl.instance;
193 		get_handles.buffer = buffer;
194 		get_handles.count = sizeof (buffer) - 1;
195 		if (ioctl(fd, command, &get_handles) == -1) {
196 			perror("th_manage - setting state failed");
197 			exit(2);
198 		}
199 		buffer[sizeof (buffer) - 1] = '\0';
200 		(void) fprintf(stdout, "%s", buffer);
201 		(void) fflush(stdout);
202 		exit(0);
203 	}
204 	if (errctl.instance == -1) {
205 		struct bofi_get_hdl_info hdli;
206 		struct handle_info *hip, *hp;
207 		int i, j, *instp;
208 
209 		hdli.namesize = errctl.namesize;
210 		(void) strncpy(hdli.name, errctl.name, MAXNAMELEN);
211 		hdli.hdli = 0;
212 		hdli.count = 0;
213 		/*
214 		 * Ask the bofi driver for all handles created by the driver
215 		 * under test.
216 		 */
217 		if (ioctl(fd, BOFI_GET_HANDLE_INFO, &hdli) == -1) {
218 			perror("driver failed to return access handles");
219 			exit(1);
220 		}
221 		if (hdli.count == 0) {
222 			exit(0); /* no handles */
223 		}
224 		if ((hip = memalign(sizeof (void *),
225 		    hdli.count * sizeof (*hip))) == 0) {
226 			perror("out of memory");
227 			exit(1);
228 		}
229 		hdli.hdli = (caddr_t)hip;
230 		if (ioctl(fd, BOFI_GET_HANDLE_INFO, &hdli) == -1) {
231 			perror("couldn't obtain all handles");
232 			exit(1);
233 		}
234 		if ((instp = malloc((hdli.count + 1) * sizeof (*instp))) == 0) {
235 			perror("out of memory");
236 			exit(1);
237 		}
238 		*instp = -1;
239 		for (i = 0, hp = hip; i < hdli.count; hp++, i++) {
240 			for (j = 0; instp[j] != -1; j++)
241 				if (hp->instance == instp[j])
242 					break;
243 			if (instp[j] == -1) {
244 				instp[j] = hp->instance;
245 				instp[j+1] = -1;
246 			}
247 		}
248 		for (i = 0; instp[i] != -1; i++) {
249 			errctl.instance = instp[i];
250 			if (ioctl(fd, command, &errctl) == -1) {
251 				(void) fprintf(stderr,
252 				    "command failed on instance %d : %s\n",
253 				    errctl.instance, strerror(errno));
254 				exit(1);
255 			}
256 		}
257 	} else {
258 		if (ioctl(fd, command, &errctl) == -1) {
259 			perror("th_manage - setting state failed");
260 			exit(1);
261 		}
262 	}
263 	return (0);
264 }
265 
266 
267 /*
268  * These functions provide access to the devctl functions,
269  */
270 static int
271 online_device(char *path)
272 {
273 	devctl_hdl_t	dcp;
274 
275 	if ((dcp = devctl_device_acquire(path, 0)) == NULL) {
276 		return (-1);
277 	}
278 	if ((devctl_device_online(dcp)) == -1) {
279 		devctl_release(dcp);
280 		return (-1);
281 	}
282 	devctl_release(dcp);
283 	return (0);
284 }
285 
286 
287 static int
288 offline_device(char *path)
289 {
290 	devctl_hdl_t	dcp;
291 
292 	if ((dcp = devctl_device_acquire(path, 0)) == NULL) {
293 		return (-1);
294 	}
295 	if ((devctl_device_offline(dcp)) == -1) {
296 		devctl_release(dcp);
297 		return (-1);
298 	}
299 	devctl_release(dcp);
300 	return (0);
301 }
302 
303 static int
304 getstate_device(char *path)
305 {
306 	devctl_hdl_t	dcp;
307 	uint_t		state = 0;
308 
309 	if ((dcp = devctl_device_acquire(path, 0)) == NULL) {
310 		(void) printf("%s unknown unknown\n", path);
311 		return (-1);
312 	}
313 	if ((devctl_device_getstate(dcp, &state)) == -1) {
314 		(void) printf("%s unknown unknown\n", path);
315 		devctl_release(dcp);
316 		return (-1);
317 	}
318 	devctl_release(dcp);
319 	switch (state) {
320 	case DEVICE_DOWN:
321 		(void) printf("%s down not_busy\n", path);
322 		break;
323 	case DEVICE_OFFLINE:
324 		(void) printf("%s offline not_busy\n", path);
325 		break;
326 	case DEVICE_ONLINE:
327 		(void) printf("%s online not_busy\n", path);
328 		break;
329 	case (DEVICE_ONLINE | DEVICE_BUSY):
330 		(void) printf("%s online busy\n", path);
331 		break;
332 	case (DEVICE_DOWN | DEVICE_BUSY):
333 		(void) printf("%s down busy\n", path);
334 		break;
335 	default:
336 		(void) printf("%s unknown unknown\n", path);
337 		break;
338 	}
339 	return (0);
340 }
341 
342 static int
343 getnameinst(char *path, int *instance, char *name, int namelen)
344 {
345 	di_node_t node;
346 	char *driver_name;
347 
348 	if ((node = di_init(&path[8], DINFOSUBTREE)) == DI_NODE_NIL)
349 		return (-1);
350 	if ((driver_name = di_driver_name(node)) == NULL) {
351 		di_fini(node);
352 		return (-1);
353 	}
354 	*instance = di_instance(node);
355 	(void) strncpy(name, driver_name, namelen);
356 	di_fini(node);
357 	return (0);
358 }
359 
360 struct walk_arg {
361 	char *path;
362 	int instance;
363 	char name[MAXPATHLEN];
364 	int found;
365 	int pathlen;
366 };
367 
368 static int
369 walk_callback(di_node_t node, void *arg)
370 {
371 	struct walk_arg *warg = (struct walk_arg *)arg;
372 	char *driver_name;
373 	char *path;
374 
375 	driver_name = di_driver_name(node);
376 	if (driver_name != NULL) {
377 		if (strcmp(driver_name, warg->name) == 0 &&
378 		    di_instance(node) == warg->instance) {
379 			path = di_devfs_path(node);
380 			if (path != NULL) {
381 				warg->found = 1;
382 				(void) strncpy(warg->path, path, warg->pathlen);
383 			}
384 			return (DI_WALK_TERMINATE);
385 		}
386 	}
387 	return (DI_WALK_CONTINUE);
388 }
389 
390 static int
391 getpath(char *path, int instance, char *name, int pathlen)
392 {
393 	di_node_t node;
394 	struct walk_arg warg;
395 
396 	warg.instance = instance;
397 	(void) strncpy(warg.name, name, MAXPATHLEN);
398 	warg.path = path;
399 	warg.pathlen = pathlen;
400 	warg.found = 0;
401 	if ((node = di_init("/", DINFOSUBTREE)) == DI_NODE_NIL)
402 		return (-1);
403 	if (di_walk_node(node, DI_WALK_CLDFIRST, &warg, walk_callback) == -1) {
404 		di_fini(node);
405 		return (-1);
406 	}
407 	if (warg.found == 0) {
408 		di_fini(node);
409 		return (-1);
410 	}
411 	di_fini(node);
412 	return (0);
413 }
414