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
main(int argc,char ** argv)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
online_device(char * path)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
offline_device(char * path)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
getstate_device(char * path)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
getnameinst(char * path,int * instance,char * name,int namelen)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
walk_callback(di_node_t node,void * arg)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
getpath(char * path,int instance,char * name,int pathlen)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