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