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 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 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 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 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 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 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 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