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