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