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