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