1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 0 stevel * Common Development and Distribution License, Version 1.0 only 6 0 stevel * (the "License"). You may not use this file except in compliance 7 0 stevel * with the License. 8 0 stevel * 9 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 0 stevel * or http://www.opensolaris.org/os/licensing. 11 0 stevel * See the License for the specific language governing permissions 12 0 stevel * and limitations under the License. 13 0 stevel * 14 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 15 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 0 stevel * If applicable, add the following below this CDDL HEADER, with the 17 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 18 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 19 0 stevel * 20 0 stevel * CDDL HEADER END 21 0 stevel */ 22 0 stevel /* 23 0 stevel * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <ctype.h> 30 0 stevel #include <stdio.h> 31 0 stevel #include <stdlib.h> 32 0 stevel #include <string.h> 33 0 stevel #include <fcntl.h> 34 0 stevel #include <unistd.h> 35 0 stevel #include <libdevinfo.h> 36 0 stevel #include <errno.h> 37 0 stevel #include <libintl.h> 38 0 stevel #define CFGA_PLUGIN_LIB 39 0 stevel #include <config_admin.h> 40 0 stevel #include "ap.h" 41 0 stevel #include <sys/obpdefs.h> 42 0 stevel #include <sys/processor.h> 43 0 stevel #include <sys/stat.h> 44 0 stevel #include <sys/sbd_ioctl.h> 45 0 stevel #include <sys/int_fmtio.h> 46 0 stevel 47 0 stevel static cfga_err_t 48 0 stevel ap_getncm(apd_t *a, sbd_comp_type_t type, int *ncm) 49 0 stevel { 50 0 stevel sbd_ioctl_arg_t *ctl; 51 0 stevel sbd_getncm_cmd_t *cp; 52 0 stevel 53 0 stevel if (a->fd == -1 || a->ctl == NULL) 54 0 stevel return (CFGA_LIB_ERROR); 55 0 stevel 56 0 stevel ctl = (sbd_ioctl_arg_t *)a->ctl; 57 0 stevel ctl->ic_type = type; 58 0 stevel ctl->ic_name[0] = '\0'; 59 0 stevel ctl->ic_unit = 0; 60 0 stevel ctl->i_len = 0; 61 0 stevel ctl->i_opts = NULL; 62 0 stevel 63 0 stevel DBG("ioctl(%d SBD_CMD_GETNCM, 0x%p)\n", a->fd, (void *)ctl); 64 0 stevel 65 0 stevel if (ioctl(a->fd, SBD_CMD_GETNCM, ctl) == -1) { 66 0 stevel ap_err(a, ERR_CMD_FAIL, CMD_GETNCM); 67 0 stevel return (CFGA_ERROR); 68 0 stevel } 69 0 stevel 70 0 stevel cp = &ctl->i_cmd.cmd_getncm; 71 0 stevel 72 0 stevel DBG("ncm(%d)=%d\n", type, cp->g_ncm); 73 0 stevel 74 0 stevel if (ncm) 75 0 stevel *ncm = cp->g_ncm; 76 0 stevel 77 0 stevel return (CFGA_OK); 78 0 stevel } 79 0 stevel 80 0 stevel cfga_err_t 81 0 stevel ap_stat(apd_t *a, int all) 82 0 stevel { 83 0 stevel int fd; 84 0 stevel int ncm; 85 0 stevel int select; 86 0 stevel int stsize; 87 0 stevel int oflag; 88 0 stevel sbd_stat_cmd_t *sc; 89 0 stevel sbd_ioctl_arg_t *ctl; 90 0 stevel cfga_err_t rc; 91 0 stevel sbd_stat_t *new_stat; 92 0 stevel 93 0 stevel rc = CFGA_LIB_ERROR; 94 0 stevel 95 0 stevel DBG("ap_stat(%s)\n", a->path); 96 0 stevel 97 0 stevel /* Open the file descriptor if not already open */ 98 0 stevel if (a->fd == -1) { 99 0 stevel DBG("open(%s)\n", a->path); 100 0 stevel if (a->statonly != 0) 101 0 stevel oflag = O_RDONLY; 102 0 stevel else 103 0 stevel oflag = O_RDWR; 104 0 stevel if ((fd = open(a->path, oflag, 0)) == -1) { 105 0 stevel ap_err(a, ERR_AP_INVAL); 106 0 stevel return (rc); 107 0 stevel } 108 0 stevel a->fd = fd; 109 0 stevel } else { 110 0 stevel fd = a->fd; 111 0 stevel } 112 0 stevel 113 0 stevel if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) { 114 0 stevel ap_err(a, ERR_CMD_FAIL, CMD_STATUS); 115 0 stevel return (rc); 116 0 stevel } 117 0 stevel 118 0 stevel if (a->tgt == AP_BOARD) { 119 0 stevel /* 120 0 stevel * The status target is the board. If we need to 121 0 stevel * return component data (to support the -a option), 122 0 stevel * get the number of components on the board. 123 0 stevel */ 124 0 stevel select = 0; 125 0 stevel if (all) { 126 0 stevel cfga_err_t r; 127 0 stevel r = ap_getncm(a, SBD_COMP_NONE, &ncm); 128 0 stevel if (r != CFGA_OK) { 129 0 stevel return (r); 130 0 stevel } 131 0 stevel } else { 132 0 stevel ncm = 0; 133 0 stevel } 134 0 stevel } else { 135 0 stevel select = 1; 136 0 stevel ncm = 1; 137 0 stevel } 138 0 stevel 139 0 stevel DBG("ncm=%d\n", ncm); 140 0 stevel 141 0 stevel a->ncm = ncm; 142 0 stevel 143 0 stevel /* 144 0 stevel * The status structure contains space for one component; 145 0 stevel * add the space for the other components if necessary. 146 0 stevel */ 147 0 stevel stsize = sizeof (sbd_stat_t); 148 0 stevel if (ncm > 1) 149 0 stevel stsize += ((ncm - 1) * sizeof (sbd_dev_stat_t)); 150 0 stevel 151 0 stevel if ((new_stat = realloc(a->stat, stsize)) == NULL) { 152 0 stevel ap_err(a, ERR_CMD_FAIL, CMD_STATUS); 153 0 stevel return (rc); 154 0 stevel } 155 0 stevel 156 0 stevel a->stat = new_stat; 157 0 stevel 158 0 stevel 159 0 stevel ctl = (sbd_ioctl_arg_t *)a->ctl; 160 0 stevel ctl->i_len = 0; 161 0 stevel ctl->i_opts = NULL; 162 0 stevel ctl->ic_type = SBD_COMP_NONE; 163 0 stevel if (all) 164 0 stevel ctl->i_flags |= SBD_FLAG_ALLCMP; 165 0 stevel sc = &ctl->i_cmd.cmd_stat; 166 0 stevel sc->s_statp = (caddr_t)a->stat; 167 0 stevel sc->s_nbytes = stsize; 168 0 stevel 169 0 stevel if (select) { 170 0 stevel /* 171 0 stevel * The target is a specific component. Pass its 172 0 stevel * name and unit number to the driver. Set its 173 0 stevel * type to UNKNOWN since the plugin does not know 174 0 stevel * the type of the component specified by the user. 175 0 stevel */ 176 0 stevel ctl->ic_type = SBD_COMP_UNKNOWN; 177 0 stevel ctl->ic_unit = a->cnum; 178 0 stevel strcpy(ctl->ic_name, a->cname); 179 0 stevel } 180 0 stevel 181 0 stevel DBG("ioctl(%d SBD_CMD_STATUS, sc=0x%p sz=%d flags=%d", 182 0 stevel fd, (void *)sc->s_statp, sc->s_nbytes, ctl->i_flags); 183 0 stevel if (select) 184 0 stevel DBG(" cname=<%s> cnum=%d", a->cname, a->cnum); 185 0 stevel DBG(")\n"); 186 0 stevel 187 0 stevel if (ioctl(fd, SBD_CMD_STATUS, ctl) == -1) { 188 0 stevel ap_err(a, ERR_CMD_FAIL, CMD_STATUS); 189 0 stevel rc = CFGA_ERROR; 190 0 stevel } else 191 0 stevel rc = CFGA_OK; 192 0 stevel 193 0 stevel DBG("ap_stat()=%d\n", rc); 194 0 stevel 195 0 stevel return (rc); 196 0 stevel } 197 0 stevel 198 0 stevel /* 199 0 stevel * Convert a component to a target type. 200 0 stevel */ 201 0 stevel static ap_target_t 202 0 stevel ap_cm_tgt(sbd_comp_type_t type) 203 0 stevel { 204 0 stevel ap_target_t c; 205 0 stevel 206 0 stevel switch (type) { 207 0 stevel case SBD_COMP_CPU: 208 0 stevel c = AP_CPU; 209 0 stevel break; 210 0 stevel case SBD_COMP_MEM: 211 0 stevel c = AP_MEM; 212 0 stevel break; 213 0 stevel case SBD_COMP_IO: 214 0 stevel c = AP_IO; 215 0 stevel break; 216 0 stevel case SBD_COMP_CMP: 217 0 stevel c = AP_CMP; 218 0 stevel break; 219 0 stevel default: 220 0 stevel c = AP_NONE; 221 0 stevel break; 222 0 stevel } 223 0 stevel 224 0 stevel return (c); 225 0 stevel } 226 0 stevel 227 0 stevel cfga_err_t 228 0 stevel apd_init(apd_t *a, int all) 229 0 stevel { 230 0 stevel int i; 231 0 stevel char *cn, *dn; 232 0 stevel sbd_stat_t *st; 233 0 stevel sbd_dev_stat_t *dst; 234 0 stevel cfga_err_t rc; 235 0 stevel 236 0 stevel /* 237 0 stevel * Ideally, for board operations (other than status) it is not 238 0 stevel * necessary to issue the STATUS ioctl. The call however allows a 239 0 stevel * final sanity check to ensure that the board number returned 240 0 stevel * by the driver matches the plugin's notion of the board number 241 0 stevel * as extracted from the ap_id. If this check is not desirable, 242 0 stevel * we can change the code to issue the status call only when 243 0 stevel * necessary. Note that for component operations, we need to do 244 0 stevel * the STATUS in order to figure out the component type and 245 0 stevel * validate the command/options accordingly. XXX 246 0 stevel */ 247 0 stevel if ((rc = ap_stat(a, all)) != CFGA_OK) { 248 0 stevel ap_err(a, ERR_AP_INVAL); 249 0 stevel return (rc); 250 0 stevel } 251 0 stevel 252 0 stevel st = (sbd_stat_t *)a->stat; 253 0 stevel 254 0 stevel /* 255 0 stevel * Set the component count to the returned stat count. 256 0 stevel */ 257 0 stevel if (a->ncm > st->s_nstat) { 258 0 stevel 259 0 stevel DBG("ncm=%d nstat=%d (truncated)\n", a->ncm, st->s_nstat); 260 0 stevel 261 0 stevel a->ncm = st->s_nstat; 262 0 stevel } 263 0 stevel 264 0 stevel if (a->tgt == AP_BOARD) { 265 0 stevel 266 0 stevel DBG("tgt=%d\n", a->tgt); 267 0 stevel 268 0 stevel /* 269 0 stevel * Initialize the RCM module here so that it can record 270 0 stevel * the initial state of the capacity information. 271 0 stevel */ 272 0 stevel rc = ap_rcm_init(a); 273 0 stevel 274 0 stevel return (rc); 275 0 stevel } 276 0 stevel 277 0 stevel a->tgt = AP_NONE; 278 0 stevel cn = a->cname; 279 0 stevel 280 0 stevel DBG("cname=<%s> cunit=<%d>\n", a->cname, a->cnum); 281 0 stevel 282 0 stevel for (dst = st->s_stat, i = 0; i < st->s_nstat; i++, dst++) { 283 0 stevel 284 0 stevel DBG("ds_name,ds_unit,ds_type=<%s,%d,%d> ", 285 0 stevel dst->ds_name, dst->ds_unit, dst->ds_type); 286 0 stevel 287 0 stevel if (dst->ds_unit != a->cnum) 288 0 stevel continue; 289 0 stevel 290 0 stevel /* 291 0 stevel * Consider the names matched if they are either 292 0 stevel * both absent or the same. It is conceivable that 293 0 stevel * a NULL component name be considered valid 294 0 stevel * by the driver. 295 0 stevel */ 296 0 stevel dn = dst->ds_name; 297 0 stevel 298 0 stevel if ((dn == NULL && cn == NULL) || 299 0 stevel (dn != NULL && cn != NULL && strcmp(dn, cn) == 0)) { 300 0 stevel a->tgt = ap_cm_tgt(dst->ds_type); 301 0 stevel a->cmstat = (void *)dst; 302 0 stevel 303 0 stevel DBG("found "); 304 0 stevel 305 0 stevel break; 306 0 stevel } 307 0 stevel } 308 0 stevel 309 0 stevel DBG("tgt=%d\n", a->tgt); 310 0 stevel 311 0 stevel if (a->tgt == AP_NONE) { 312 0 stevel ap_err(a, ERR_CM_INVAL, a->cid); 313 0 stevel return (CFGA_INVAL); 314 0 stevel } 315 0 stevel 316 0 stevel /* 317 0 stevel * Initialize the RCM module here so that it can record 318 0 stevel * the initial state of the capacity information. 319 0 stevel */ 320 0 stevel rc = ap_rcm_init(a); 321 0 stevel 322 0 stevel return (rc); 323 0 stevel } 324 0 stevel 325 0 stevel void 326 0 stevel apd_free(apd_t *a) 327 0 stevel { 328 0 stevel if (a == NULL) 329 0 stevel return; 330 0 stevel 331 0 stevel ap_rcm_fini(a); 332 0 stevel 333 0 stevel if (a->fd != -1) 334 0 stevel close(a->fd); 335 0 stevel 336 0 stevel s_free(a->options); 337 0 stevel s_free(a->path); 338 0 stevel s_free(a->drv); 339 0 stevel s_free(a->target); 340 0 stevel s_free(a->cname); 341 0 stevel s_free(a->ctl); 342 0 stevel s_free(a->stat); 343 0 stevel 344 0 stevel free(a); 345 0 stevel } 346 0 stevel 347 0 stevel apd_t * 348 0 stevel apd_alloc(const char *ap_id, cfga_flags_t flags, char **errstring, 349 0 stevel struct cfga_msg *msgp, struct cfga_confirm *confp) 350 0 stevel { 351 0 stevel apd_t *a; 352 0 stevel 353 0 stevel if ((a = calloc(1, sizeof (*a))) == NULL) 354 0 stevel return (NULL); 355 0 stevel 356 0 stevel if (errstring != NULL) 357 0 stevel *errstring = NULL; 358 0 stevel 359 0 stevel a->fd = -1; 360 0 stevel a->errstring = errstring; 361 0 stevel a->msgp = msgp; 362 0 stevel a->confp = confp; 363 0 stevel a->class = "sbd"; 364 0 stevel 365 0 stevel if (flags & CFGA_FLAG_LIST_ALL) 366 0 stevel ap_setopt(a, OPT_LIST_ALL); 367 0 stevel if (flags & CFGA_FLAG_FORCE) 368 0 stevel ap_setopt(a, OPT_FORCE); 369 0 stevel if (flags & CFGA_FLAG_VERBOSE) 370 0 stevel ap_setopt(a, OPT_VERBOSE); 371 0 stevel 372 0 stevel if (ap_id == NULL || ap_parse(a, ap_id) == 0) 373 0 stevel return (a); 374 0 stevel 375 0 stevel apd_free(a); 376 0 stevel return (NULL); 377 0 stevel } 378 0 stevel 379 0 stevel /* 380 0 stevel * The type field is defined to be parsable by cfgadm(1M): It 381 0 stevel * must not contain white space characters. This function 382 0 stevel * converts white space to underscore. 383 0 stevel */ 384 0 stevel 385 0 stevel static void 386 0 stevel parsable_strncpy(char *op, const char *ip, size_t n) 387 0 stevel { 388 0 stevel char c; 389 0 stevel 390 0 stevel while (n-- > 0) { 391 0 stevel c = *ip++; 392 0 stevel if (isspace(c)) 393 0 stevel c = '_'; 394 0 stevel *op++ = c; 395 0 stevel if (c == '\0') 396 0 stevel break; 397 0 stevel } 398 0 stevel } 399 0 stevel 400 0 stevel void 401 0 stevel ap_init(apd_t *a, cfga_list_data_t *ap) 402 0 stevel { 403 0 stevel sbd_stat_t *st; 404 0 stevel 405 0 stevel st = (sbd_stat_t *)a->stat; 406 0 stevel 407 0 stevel DBG("ap_init bd=%d rs=%d os=%d type=<%s>\n", 408 0 stevel a->bnum, st->s_rstate, st->s_ostate, st->s_type); 409 0 stevel 410 0 stevel parsable_strncpy(ap->ap_type, st->s_type, sizeof (ap->ap_type)); 411 0 stevel ap->ap_r_state = (cfga_stat_t)st->s_rstate; 412 0 stevel ap->ap_o_state = (cfga_stat_t)st->s_ostate; 413 0 stevel ap->ap_cond = (cfga_cond_t)st->s_cond; 414 0 stevel ap->ap_busy = (cfga_busy_t)st->s_busy; 415 0 stevel ap->ap_status_time = st->s_time; 416 0 stevel ap_info(a, ap->ap_info, AP_BOARD); 417 0 stevel } 418 0 stevel 419 0 stevel typedef struct { 420 0 stevel int cmd; 421 0 stevel int ioc; 422 0 stevel } ap_ioc_t; 423 0 stevel 424 0 stevel static ap_ioc_t 425 0 stevel ap_iocs[] = { 426 0 stevel {CMD_ASSIGN, SBD_CMD_ASSIGN }, 427 0 stevel {CMD_POWERON, SBD_CMD_POWERON }, 428 0 stevel {CMD_TEST, SBD_CMD_TEST }, 429 0 stevel {CMD_CONNECT, SBD_CMD_CONNECT }, 430 0 stevel {CMD_CONFIGURE, SBD_CMD_CONFIGURE }, 431 0 stevel {CMD_UNCONFIGURE, SBD_CMD_UNCONFIGURE }, 432 0 stevel {CMD_DISCONNECT, SBD_CMD_DISCONNECT }, 433 0 stevel {CMD_POWEROFF, SBD_CMD_POWEROFF }, 434 0 stevel {CMD_STATUS, SBD_CMD_STATUS }, 435 0 stevel {CMD_GETNCM, SBD_CMD_GETNCM }, 436 0 stevel {CMD_UNASSIGN, SBD_CMD_UNASSIGN }, 437 0 stevel {CMD_PASSTHRU, SBD_CMD_PASSTHRU }, 438 0 stevel {CMD_NONE, 0 } 439 0 stevel }; 440 0 stevel 441 0 stevel static int 442 0 stevel ap_ioc(int cmd) 443 0 stevel { 444 0 stevel ap_ioc_t *acp; 445 0 stevel 446 0 stevel DBG("ap_ioc(%d)\n", cmd); 447 0 stevel 448 0 stevel for (acp = ap_iocs; acp->cmd != CMD_NONE; acp++) 449 0 stevel if (acp->cmd == cmd) 450 0 stevel break; 451 0 stevel 452 0 stevel DBG("ap_ioc(%d)=0x%x\n", cmd, acp->ioc); 453 0 stevel 454 0 stevel return (acp->ioc); 455 0 stevel } 456 0 stevel 457 0 stevel cfga_err_t 458 0 stevel ap_suspend_query(apd_t *a, int cmd, int *check) 459 0 stevel { 460 0 stevel int ioc; 461 0 stevel sbd_dev_stat_t *dst; 462 0 stevel 463 0 stevel /* 464 0 stevel * See if the a quiesce operation is required for 465 0 stevel * this command for any of the components. If the 466 0 stevel * command does not map to an ioctl, then there is 467 0 stevel * nothing to do. 468 0 stevel */ 469 0 stevel if ((ioc = ap_ioc(cmd)) == 0) 470 0 stevel return (CFGA_OK); 471 0 stevel else if (a->tgt == AP_BOARD) { 472 0 stevel int i; 473 0 stevel 474 0 stevel dst = ((sbd_stat_t *)a->stat)->s_stat; 475 0 stevel 476 0 stevel /* 477 0 stevel * See if any component requires a 478 0 stevel * OS suspension for this command. 479 0 stevel */ 480 0 stevel for (i = 0; i < a->ncm; i++, dst++) 481 0 stevel if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend)) 482 0 stevel (*check)++; 483 0 stevel } else { 484 0 stevel dst = (sbd_dev_stat_t *)a->cmstat; 485 0 stevel if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend)) 486 0 stevel (*check)++; 487 0 stevel } 488 0 stevel 489 0 stevel return (CFGA_OK); 490 0 stevel } 491 0 stevel 492 0 stevel cfga_err_t 493 0 stevel ap_platopts_check(apd_t *a, int first, int last) 494 0 stevel { 495 0 stevel int c; 496 0 stevel uint_t platopts; 497 0 stevel sbd_stat_t *stat; 498 0 stevel ap_opts_t *opts; 499 0 stevel 500 0 stevel opts = &a->opts; 501 0 stevel stat = (sbd_stat_t *)a->stat; 502 0 stevel platopts = stat->s_platopts; 503 0 stevel 504 0 stevel 505 0 stevel /* 506 0 stevel * If there are no platform options set then there 507 0 stevel * is no need to check this operation 508 0 stevel */ 509 0 stevel if (opts->platform == NULL) 510 0 stevel return (CFGA_OK); 511 0 stevel 512 0 stevel /* 513 0 stevel * Check if any of the steps in the sequence 514 0 stevel * allows for a platform option 515 0 stevel */ 516 0 stevel for (c = first; c <= last; c++) 517 0 stevel /* 518 0 stevel * If the platopt is set it means that the platform does not 519 0 stevel * support options for this cmd 520 0 stevel */ 521 0 stevel if (SBD_CHECK_PLATOPTS(ap_ioc(c), platopts) == 0) { 522 0 stevel return (CFGA_OK); 523 0 stevel } 524 0 stevel 525 0 stevel ap_err(a, ERR_OPT_INVAL, opts->platform); 526 0 stevel 527 0 stevel return (CFGA_INVAL); 528 0 stevel } 529 0 stevel 530 0 stevel cfga_err_t 531 0 stevel ap_ioctl(apd_t *a, int cmd) 532 0 stevel { 533 0 stevel int ioc; 534 0 stevel sbd_ioctl_arg_t *ctl; 535 0 stevel 536 0 stevel if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) { 537 0 stevel ap_err(a, ERR_CMD_FAIL, cmd); 538 0 stevel return (CFGA_LIB_ERROR); 539 0 stevel } 540 0 stevel 541 0 stevel ap_msg(a, MSG_ISSUE, cmd, a->target); 542 0 stevel 543 0 stevel ctl = (sbd_ioctl_arg_t *)a->ctl; 544 0 stevel ctl->i_flags = 0; 545 0 stevel ctl->i_len = 0; 546 0 stevel ctl->i_opts = NULL; 547 0 stevel 548 0 stevel if (ap_getopt(a, OPT_FORCE)) 549 0 stevel ctl->i_flags |= SBD_FLAG_FORCE; 550 0 stevel if (ap_getopt(a, OPT_SUSPEND_OK)) 551 0 stevel ctl->i_flags |= SBD_FLAG_QUIESCE_OKAY; 552 0 stevel 553 0 stevel if (a->tgt == AP_BOARD) 554 0 stevel ctl->ic_type = SBD_COMP_NONE; 555 0 stevel else { 556 0 stevel ctl->ic_type = SBD_COMP_UNKNOWN; 557 0 stevel ctl->ic_unit = a->cnum; 558 0 stevel strcpy(ctl->ic_name, a->cname); 559 0 stevel } 560 0 stevel 561 0 stevel if (!(ioc = ap_ioc(cmd))) { 562 0 stevel ap_err(a, ERR_CMD_FAIL, cmd); 563 0 stevel return (CFGA_LIB_ERROR); 564 0 stevel } 565 0 stevel 566 0 stevel /* 567 0 stevel * If this is a passthru command, pass all of its 568 0 stevel * options; otherwise, pass all options after the 569 0 stevel * platform keyword. 570 0 stevel */ 571 0 stevel if (cmd == CMD_PASSTHRU) 572 0 stevel ctl->i_opts = a->options; 573 0 stevel else { 574 0 stevel /* 575 0 stevel * Only pass the platform option to the cmds that the platform 576 0 stevel * has specified as ok 577 0 stevel */ 578 0 stevel sbd_stat_t *stat; 579 0 stevel 580 0 stevel stat = (sbd_stat_t *)a->stat; 581 0 stevel if (SBD_CHECK_PLATOPTS(ioc, stat->s_platopts) == 0) 582 0 stevel ctl->i_opts = a->opts.platform; 583 0 stevel } 584 0 stevel 585 0 stevel if (ctl->i_opts != NULL) 586 0 stevel ctl->i_len = strlen(ctl->i_opts) + 1; 587 0 stevel 588 0 stevel DBG("i_opts=%s\n", ctl->i_opts ? ctl->i_opts : "NULL"); 589 0 stevel DBG("i_flags=0x%x\n", ctl->i_flags); 590 0 stevel 591 0 stevel if (ap_getopt(a, OPT_SIM)) { 592 0 stevel ap_msg(a, MSG_DONE, cmd, a->target); 593 0 stevel return (CFGA_OK); 594 0 stevel } 595 0 stevel 596 0 stevel if (ioctl(a->fd, ioc, ctl) == -1) { 597 0 stevel ap_err(a, ERR_CMD_FAIL, cmd); 598 0 stevel return (CFGA_ERROR); 599 0 stevel } 600 0 stevel ap_msg(a, MSG_DONE, cmd, a->target); 601 0 stevel 602 0 stevel return (CFGA_OK); 603 0 stevel } 604 0 stevel 605 0 stevel /* 606 0 stevel * Return the error string corresponding to a given error code. 607 0 stevel * String table and error code sets are provided by sbd_etab. This data 608 0 stevel * structure is automatically generated at compile time from the error 609 0 stevel * code and message text information in sbd_ioctl.h. 610 0 stevel */ 611 0 stevel static char * 612 0 stevel mod_estr(int code) 613 0 stevel { 614 0 stevel int i; 615 0 stevel char *s; 616 0 stevel extern sbd_etab_t sbd_etab[]; 617 0 stevel extern int sbd_etab_len; 618 0 stevel 619 0 stevel s = NULL; 620 0 stevel 621 0 stevel for (i = 0; i < sbd_etab_len; i++) { 622 0 stevel sbd_etab_t *eptr = &sbd_etab[i]; 623 0 stevel 624 0 stevel if ((code >= eptr->t_base) && (code <= eptr->t_bnd)) { 625 0 stevel int index; 626 0 stevel char **t_text; 627 0 stevel 628 0 stevel /* 629 0 stevel * Found it. Just extract the string 630 0 stevel */ 631 0 stevel index = code - eptr->t_base; 632 0 stevel t_text = eptr->t_text; 633 0 stevel s = strdup(t_text[index]); 634 0 stevel break; 635 0 stevel } 636 0 stevel } 637 0 stevel 638 0 stevel if (i == sbd_etab_len) { 639 0 stevel char buf[32]; 640 0 stevel 641 0 stevel snprintf(buf, sizeof (buf), "error %d", code); 642 0 stevel s = strdup(buf); 643 0 stevel } 644 0 stevel 645 0 stevel return (s); 646 0 stevel } 647 0 stevel 648 0 stevel char * 649 0 stevel ap_sys_err(apd_t *a, char **rp) 650 0 stevel { 651 0 stevel int code; 652 0 stevel char *p; 653 0 stevel char *rsc; 654 0 stevel 655 0 stevel sbd_ioctl_arg_t *ctl = (sbd_ioctl_arg_t *)a->ctl; 656 0 stevel 657 0 stevel /* 658 0 stevel * The driver sets the errno to EIO if it returns 659 0 stevel * more detailed error info via e_code. In all 660 0 stevel * other cases, use standard error text. 661 0 stevel */ 662 0 stevel if (ctl == NULL || errno != EIO) { 663 0 stevel if ((p = strerror(errno)) != NULL) 664 0 stevel p = strdup(p); 665 0 stevel return (p); 666 0 stevel } 667 0 stevel 668 0 stevel code = ctl->ie_code; 669 0 stevel rsc = ctl->ie_rsc; 670 0 stevel 671 0 stevel if (code) 672 0 stevel p = mod_estr(code); 673 0 stevel else if ((p = strerror(errno)) != NULL) 674 0 stevel p = strdup(p); 675 0 stevel 676 0 stevel if (*rsc != '\0' && rp != NULL) 677 0 stevel *rp = strdup(rsc); 678 0 stevel 679 0 stevel return (p); 680 0 stevel } 681 0 stevel 682 0 stevel /* 683 0 stevel * cfgadm -o err=plugin-err,cmd=name,code=ecode -x errtest ap_id. 684 0 stevel */ 685 0 stevel cfga_err_t 686 0 stevel ap_test_err(apd_t *a, const char *options) 687 0 stevel { 688 0 stevel int err; 689 0 stevel int cmd; 690 0 stevel ap_opts_t *opts; 691 0 stevel sbd_ioctl_arg_t ctl; 692 0 stevel 693 0 stevel opts = &a->opts; 694 0 stevel err = opts->err; 695 0 stevel cmd = CMD_DISCONNECT; 696 0 stevel 697 0 stevel DBG("ap_test_err(%d %d)\n", opts->code, opts->err); 698 0 stevel 699 0 stevel switch (err) { 700 0 stevel case ERR_CMD_INVAL: 701 0 stevel ap_err(a, err, ap_cmd_name(cmd)); 702 0 stevel break; 703 0 stevel case ERR_CMD_NOTSUPP: 704 0 stevel ap_err(a, err, cmd); 705 0 stevel break; 706 0 stevel case ERR_CMD_FAIL: 707 0 stevel errno = EIO; 708 0 stevel ctl.i_err.e_code = opts->code; 709 0 stevel *ctl.i_err.e_rsc = '\0'; 710 0 stevel a->ctl = &ctl; 711 0 stevel ap_err(a, err, cmd); 712 0 stevel a->ctl = NULL; 713 0 stevel break; 714 0 stevel case ERR_OPT_INVAL: 715 0 stevel ap_err(a, err, options); 716 0 stevel break; 717 0 stevel case ERR_OPT_NOVAL: 718 0 stevel ap_err(a, err, options); 719 0 stevel break; 720 0 stevel case ERR_AP_INVAL: 721 0 stevel ap_err(a, err); 722 0 stevel break; 723 0 stevel case ERR_CM_INVAL: 724 0 stevel ap_err(a, err, a->cid); 725 0 stevel break; 726 0 stevel case ERR_TRANS_INVAL: 727 0 stevel ap_err(a, ERR_TRANS_INVAL, cmd); 728 0 stevel break; 729 0 stevel } 730 0 stevel 731 0 stevel return (CFGA_LIB_ERROR); 732 0 stevel } 733 0 stevel 734 0 stevel static char * 735 0 stevel ap_help_topics[] = { 736 0 stevel "\nSbd specific commands/options:\n\n", 737 0 stevel "\tcfgadm [-o parsable] -l ap_id\n", 738 0 stevel "\tcfgadm [-o unassign|nopoweroff] -c disconnect ap_id\n", 739 0 stevel "\tcfgadm -t ap_id\n", 740 0 stevel "\tcfgadm -x assign ap_id\n", 741 0 stevel "\tcfgadm -x unassign ap_id\n", 742 0 stevel "\tcfgadm -x poweron ap_id\n", 743 0 stevel "\tcfgadm -x poweroff ap_id\n", 744 0 stevel NULL 745 0 stevel }; 746 0 stevel 747 0 stevel /*ARGSUSED*/ 748 0 stevel cfga_err_t 749 0 stevel ap_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 750 0 stevel { 751 0 stevel int len; 752 0 stevel char **p; 753 0 stevel char *q; 754 0 stevel 755 0 stevel if (msgp == NULL || msgp->message_routine == NULL) 756 0 stevel return (CFGA_OK); 757 0 stevel 758 0 stevel for (p = ap_help_topics; *p != NULL; p++) { 759 0 stevel if ((len = strlen(*p)) == 0) 760 0 stevel continue; 761 0 stevel if ((q = (char *)calloc(len + 1, 1)) == NULL) 762 0 stevel continue; 763 0 stevel strcpy(q, *p); 764 0 stevel (*msgp->message_routine)(msgp->appdata_ptr, q); 765 0 stevel free(q); 766 0 stevel } 767 0 stevel 768 0 stevel return (CFGA_OK); 769 0 stevel } 770 0 stevel 771 0 stevel static char * 772 0 stevel ap_dev_type(sbd_dev_stat_t *dst) 773 0 stevel { 774 0 stevel char *type; 775 0 stevel 776 0 stevel switch (dst->ds_type) { 777 0 stevel case SBD_COMP_CPU: 778 0 stevel type = "cpu"; 779 0 stevel break; 780 0 stevel case SBD_COMP_MEM: 781 0 stevel type = "memory"; 782 0 stevel break; 783 0 stevel case SBD_COMP_IO: 784 0 stevel type = "io"; 785 0 stevel break; 786 0 stevel case SBD_COMP_CMP: 787 0 stevel type = "cpu"; 788 0 stevel break; 789 0 stevel default: 790 0 stevel type = "other"; 791 0 stevel break; 792 0 stevel } 793 0 stevel 794 0 stevel DBG("ap_dev_type(%d)=%s\n", dst->ds_type, type); 795 0 stevel 796 0 stevel return (type); 797 0 stevel } 798 0 stevel 799 0 stevel static sbd_dev_stat_t * 800 0 stevel ap_cm_stat(apd_t *a, int seq) 801 0 stevel { 802 0 stevel sbd_stat_t *st; 803 0 stevel 804 0 stevel if (seq == CM_DFLT) 805 0 stevel return (a->cmstat); 806 0 stevel 807 0 stevel st = (sbd_stat_t *)a->stat; 808 0 stevel return (st->s_stat + seq); 809 0 stevel } 810 0 stevel 811 0 stevel char * 812 0 stevel ap_cm_devpath(apd_t *a, int seq) 813 0 stevel { 814 0 stevel int len; 815 0 stevel char *path; 816 0 stevel char *devpath; 817 0 stevel sbd_io_stat_t *dst; 818 0 stevel 819 0 stevel 820 0 stevel /* 821 0 stevel * If no component sequence number is provided 822 0 stevel * default to the current target component. 823 0 stevel * Assume an io component so that we can get 824 0 stevel * the path if the component is indeed of type io. 825 0 stevel */ 826 0 stevel if (seq == -1) 827 0 stevel dst = (sbd_io_stat_t *)a->cmstat; 828 0 stevel else { 829 0 stevel sbd_stat_t *st; 830 0 stevel st = (sbd_stat_t *)a->stat; 831 0 stevel dst = (sbd_io_stat_t *)st->s_stat + seq; 832 0 stevel } 833 0 stevel 834 0 stevel if (dst->is_type != SBD_COMP_IO) 835 0 stevel path = NULL; 836 0 stevel else 837 0 stevel path = dst->is_pathname; 838 0 stevel 839 0 stevel if (str_valid(path)) { 840 0 stevel len = strlen(DEVDIR) + strlen(path) + 1; 841 0 stevel 842 0 stevel if ((devpath = calloc(1, len)) == NULL) 843 0 stevel return (NULL); 844 0 stevel 845 0 stevel (void) snprintf(devpath, len, "%s%s", DEVDIR, path); 846 0 stevel } else 847 0 stevel devpath = NULL; 848 0 stevel 849 0 stevel DBG("ap_cm_path(%d)=%s\n", seq, devpath ? devpath : ""); 850 0 stevel 851 0 stevel return (devpath); 852 0 stevel } 853 0 stevel 854 0 stevel void 855 0 stevel ap_cm_id(apd_t *a, int seq, char *id, size_t bufsize) 856 0 stevel { 857 0 stevel int unit; 858 0 stevel char *name; 859 0 stevel sbd_dev_stat_t *dst; 860 0 stevel 861 0 stevel dst = ap_cm_stat(a, seq); 862 0 stevel 863 0 stevel unit = dst->ds_unit; 864 0 stevel name = dst->ds_name; 865 0 stevel 866 0 stevel /* 867 0 stevel * If the component has a unit number, 868 0 stevel * add it to the id, otherwise just use 869 0 stevel * the component's name. 870 0 stevel */ 871 0 stevel if (unit == -1) 872 0 stevel (void) snprintf(id, bufsize, "%s", name); 873 0 stevel else 874 0 stevel (void) snprintf(id, bufsize, "%s%d", name, unit); 875 0 stevel 876 0 stevel DBG("ap_cm_id(%d)=%s\n", seq, id); 877 0 stevel } 878 0 stevel 879 0 stevel /* 880 0 stevel * Convert a component to a target type. 881 0 stevel */ 882 0 stevel ap_target_t 883 0 stevel ap_cm_type(apd_t *a, int seq) 884 0 stevel { 885 0 stevel ap_target_t c; 886 0 stevel sbd_dev_stat_t *dst; 887 0 stevel 888 0 stevel dst = ap_cm_stat(a, seq); 889 0 stevel 890 0 stevel switch (dst->ds_type) { 891 0 stevel case SBD_COMP_CPU: 892 0 stevel c = AP_CPU; 893 0 stevel break; 894 0 stevel case SBD_COMP_MEM: 895 0 stevel c = AP_MEM; 896 0 stevel break; 897 0 stevel case SBD_COMP_IO: 898 0 stevel c = AP_IO; 899 0 stevel break; 900 0 stevel case SBD_COMP_CMP: 901 0 stevel c = AP_CMP; 902 0 stevel break; 903 0 stevel default: 904 0 stevel c = AP_NONE; 905 0 stevel break; 906 0 stevel } 907 0 stevel 908 0 stevel return (c); 909 0 stevel } 910 0 stevel 911 0 stevel int 912 0 stevel ap_cm_ncap(apd_t *a, int seq) 913 0 stevel { 914 0 stevel sbd_dev_stat_t *dst; 915 0 stevel int ncap; 916 0 stevel 917 0 stevel dst = ap_cm_stat(a, seq); 918 0 stevel 919 0 stevel switch (dst->ds_type) { 920 0 stevel case SBD_COMP_CPU: 921 0 stevel case SBD_COMP_MEM: 922 0 stevel case SBD_COMP_IO: 923 0 stevel ncap = 1; 924 0 stevel break; 925 0 stevel case SBD_COMP_CMP: 926 0 stevel ncap = ((sbd_cmp_stat_t *)dst)->ps_ncores; 927 0 stevel break; 928 0 stevel default: 929 0 stevel ncap = 0; 930 0 stevel break; 931 0 stevel } 932 0 stevel 933 0 stevel return (ncap); 934 0 stevel } 935 0 stevel 936 0 stevel int 937 0 stevel ap_cm_capacity(apd_t *a, int seq, void *cap, int *ncap, cfga_stat_t *ostate) 938 0 stevel { 939 0 stevel int i; 940 0 stevel sbd_dev_stat_t *dst; 941 0 stevel cfga_stat_t os; 942 0 stevel 943 0 stevel if (cap == NULL) 944 0 stevel return (0); 945 0 stevel 946 0 stevel dst = ap_cm_stat(a, seq); 947 0 stevel os = (cfga_stat_t)dst->ds_ostate; 948 0 stevel if (os != CFGA_STAT_CONFIGURED && os != CFGA_STAT_UNCONFIGURED) 949 0 stevel return (0); 950 0 stevel if (ostate) 951 0 stevel *ostate = os; 952 0 stevel 953 0 stevel *ncap = 1; 954 0 stevel 955 0 stevel switch (dst->ds_type) { 956 0 stevel case SBD_COMP_CPU: { 957 0 stevel sbd_cpu_stat_t *cpu = (sbd_cpu_stat_t *)dst; 958 0 stevel *((processorid_t *)cap) = cpu->cs_cpuid; 959 0 stevel break; 960 0 stevel } 961 0 stevel case SBD_COMP_MEM: { 962 0 stevel sbd_mem_stat_t *mem = (sbd_mem_stat_t *)dst; 963 0 stevel *((long *)cap) = mem->ms_totpages; 964 0 stevel break; 965 0 stevel } 966 0 stevel case SBD_COMP_CMP: { 967 0 stevel sbd_cmp_stat_t *cmp = (sbd_cmp_stat_t *)dst; 968 0 stevel processorid_t *cpuid; 969 0 stevel 970 0 stevel cpuid = (processorid_t *)cap; 971 0 stevel for (i = 0; i < cmp->ps_ncores; i++) { 972 0 stevel cpuid[i] = cmp->ps_cpuid[i]; 973 0 stevel } 974 0 stevel 975 0 stevel *ncap = cmp->ps_ncores; 976 0 stevel break; 977 0 stevel } 978 0 stevel default: 979 0 stevel return (0); 980 0 stevel } 981 0 stevel 982 0 stevel DBG("ap_cm_capacity(%d)=(", seq); 983 0 stevel for (i = 0; i < *ncap; i++) { 984 0 stevel DBG("%d ", ((int *)cap)[i]); 985 0 stevel } 986 0 stevel DBG("%d)\n", *ostate); 987 0 stevel 988 0 stevel return (1); 989 0 stevel } 990 0 stevel 991 0 stevel void 992 0 stevel ap_cm_init(apd_t *a, cfga_list_data_t *ap, int seq) 993 0 stevel { 994 0 stevel char *type; 995 0 stevel sbd_stat_t *st; 996 0 stevel sbd_dev_stat_t *dst; 997 0 stevel 998 0 stevel st = (sbd_stat_t *)a->stat; 999 0 stevel dst = st->s_stat + seq; 1000 0 stevel type = ap_dev_type(dst); 1001 0 stevel 1002 0 stevel a->cmstat = (void *)dst; 1003 0 stevel 1004 0 stevel DBG("ap_cm_init bd=%d rs=%d os=%d type=<%s> seq=%d\n", 1005 0 stevel a->bnum, st->s_rstate, dst->ds_ostate, type, seq); 1006 0 stevel 1007 0 stevel (void) strncpy(ap->ap_type, type, sizeof (ap->ap_type)); 1008 0 stevel ap->ap_r_state = (cfga_stat_t)st->s_rstate; 1009 0 stevel ap->ap_o_state = (cfga_stat_t)dst->ds_ostate; 1010 0 stevel ap->ap_cond = (cfga_cond_t)dst->ds_cond; 1011 0 stevel ap->ap_busy = (cfga_busy_t)dst->ds_busy; 1012 0 stevel ap->ap_status_time = dst->ds_time; 1013 0 stevel ap_info(a, ap->ap_info, ap_cm_tgt(dst->ds_type)); 1014 0 stevel } 1015 0 stevel 1016 0 stevel void 1017 0 stevel ap_state(apd_t *a, cfga_stat_t *rs, cfga_stat_t *os) 1018 0 stevel { 1019 0 stevel sbd_stat_t *st; 1020 0 stevel sbd_dev_stat_t *dst; 1021 0 stevel 1022 0 stevel st = (sbd_stat_t *)a->stat; 1023 0 stevel dst = (sbd_dev_stat_t *)a->cmstat; 1024 0 stevel 1025 0 stevel if (rs != NULL) { 1026 0 stevel if (a->tgt == AP_NONE) 1027 0 stevel *rs = CFGA_STAT_NONE; 1028 0 stevel else 1029 0 stevel *rs = (cfga_stat_t)st->s_rstate; 1030 0 stevel } 1031 0 stevel 1032 0 stevel if (os != NULL) { 1033 0 stevel if (a->tgt == AP_NONE) 1034 0 stevel *os = CFGA_STAT_NONE; 1035 0 stevel else if (a->tgt == AP_BOARD) 1036 0 stevel *os = (cfga_stat_t)st->s_ostate; 1037 0 stevel else 1038 0 stevel *os = (cfga_stat_t)dst->ds_ostate; 1039 0 stevel } 1040 0 stevel } 1041 0 stevel 1042 0 stevel #define BI_POWERED 0 1043 0 stevel #define BI_ASSIGNED 1 1044 0 stevel 1045 0 stevel static const char * 1046 0 stevel binfo[] = { 1047 0 stevel "powered-on", 1048 0 stevel ", assigned" 1049 0 stevel }; 1050 0 stevel 1051 0 stevel static const char * 1052 0 stevel binfo_parsable[] = { 1053 0 stevel "powered-on", 1054 0 stevel " assigned" 1055 0 stevel }; 1056 0 stevel 1057 0 stevel static void 1058 0 stevel bd_info(apd_t *a, cfga_info_t info, int parsable) 1059 0 stevel { 1060 0 stevel int i; 1061 0 stevel int nsep; 1062 0 stevel const char **p; 1063 0 stevel sbd_stat_t *st; 1064 0 stevel char *end = &info[sizeof (cfga_info_t)]; 1065 0 stevel 1066 0 stevel DBG("bd_info(%p)\n", (void *)info); 1067 0 stevel 1068 0 stevel st = (sbd_stat_t *)a->stat; 1069 0 stevel 1070 0 stevel if (parsable) { 1071 0 stevel p = binfo_parsable; 1072 0 stevel nsep = 1; 1073 0 stevel } else { 1074 0 stevel p = binfo; 1075 0 stevel nsep = 2; 1076 0 stevel } 1077 0 stevel 1078 0 stevel i = nsep; 1079 0 stevel 1080 0 stevel if (st->s_power) { 1081 0 stevel info += snprintf(info, end - info, p[BI_POWERED]); 1082 0 stevel i = 0; 1083 0 stevel } 1084 0 stevel if (st->s_assigned) 1085 0 stevel info += snprintf(info, end - info, p[BI_ASSIGNED] + i); 1086 0 stevel } 1087 0 stevel 1088 0 stevel #define CI_CPUID 0 1089 0 stevel #define CI_SPEED 1 1090 0 stevel #define CI_ECACHE 2 1091 0 stevel 1092 0 stevel static const char * 1093 0 stevel cpuinfo[] = { 1094 0 stevel "cpuid %d", 1095 0 stevel ", speed %d MHz", 1096 0 stevel ", ecache %d MBytes" 1097 0 stevel }; 1098 0 stevel 1099 0 stevel static const char * 1100 0 stevel cpuinfo_parsable[] = { 1101 0 stevel "cpuid=%d", 1102 0 stevel " speed=%d", 1103 0 stevel " ecache=%d" 1104 0 stevel }; 1105 0 stevel 1106 0 stevel static void 1107 0 stevel cpu_info(apd_t *a, cfga_info_t info, int parsable) 1108 0 stevel { 1109 0 stevel const char **p; 1110 0 stevel sbd_cpu_stat_t *dst; 1111 0 stevel char *end = &info[sizeof (cfga_info_t)]; 1112 0 stevel 1113 0 stevel DBG("cpu_info(%p)\n", (void *)info); 1114 0 stevel 1115 0 stevel dst = (sbd_cpu_stat_t *)a->cmstat; 1116 0 stevel 1117 0 stevel if (parsable) 1118 0 stevel p = cpuinfo_parsable; 1119 0 stevel else 1120 0 stevel p = cpuinfo; 1121 0 stevel 1122 0 stevel info += snprintf(info, end - info, p[CI_CPUID], dst->cs_cpuid); 1123 0 stevel info += snprintf(info, end - info, p[CI_SPEED], dst->cs_speed); 1124 0 stevel info += snprintf(info, end - info, p[CI_ECACHE], dst->cs_ecache); 1125 0 stevel } 1126 0 stevel 1127 0 stevel #define MI_ADDRESS 0 1128 0 stevel #define MI_SIZE 1 1129 0 stevel #define MI_PERMANENT 2 1130 0 stevel #define MI_UNCONFIGURABLE 3 1131 0 stevel #define MI_SOURCE 4 1132 0 stevel #define MI_TARGET 5 1133 0 stevel #define MI_DELETED 6 1134 0 stevel #define MI_REMAINING 7 1135 0 stevel #define MI_INTERLEAVE 8 1136 0 stevel 1137 0 stevel static const char * 1138 0 stevel meminfo_nonparsable[] = { 1139 0 stevel "base address 0x%" PRIx64, 1140 0 stevel ", %lu KBytes total", 1141 0 stevel ", %lu KBytes permanent", 1142 0 stevel ", unconfigurable", 1143 0 stevel ", memory delete requested on %s", 1144 0 stevel ", memory delete in progress on %s", 1145 0 stevel ", %lu KBytes deleted", 1146 0 stevel ", %lu KBytes remaining", 1147 0 stevel ", inter board interleave" 1148 0 stevel }; 1149 0 stevel 1150 0 stevel static const char * 1151 0 stevel meminfo_parsable[] = { 1152 0 stevel "address=0x%" PRIx64, 1153 0 stevel " size=%lu", 1154 0 stevel " permanent=%lu", 1155 0 stevel " unconfigurable", 1156 0 stevel " source=%s", 1157 0 stevel " target=%s", 1158 0 stevel " deleted=%lu", 1159 0 stevel " remaining=%lu", 1160 0 stevel " inter-board-interleave" 1161 0 stevel }; 1162 0 stevel 1163 0 stevel 1164 0 stevel #define _K1 1024 1165 0 stevel 1166 0 stevel /* 1167 0 stevel * This function assumes pagesize > 1024 and that 1168 0 stevel * pagesize is a multiple of 1024. 1169 0 stevel */ 1170 0 stevel static ulong_t 1171 0 stevel pages_to_kbytes(uint_t pgs) 1172 0 stevel { 1173 0 stevel long pagesize; 1174 0 stevel 1175 0 stevel pagesize = sysconf(_SC_PAGESIZE); 1176 0 stevel return (pgs * (pagesize / _K1)); 1177 0 stevel } 1178 0 stevel 1179 0 stevel static uint64_t 1180 0 stevel pages_to_bytes(uint_t pgs) 1181 0 stevel { 1182 0 stevel long pagesize; 1183 0 stevel 1184 0 stevel pagesize = sysconf(_SC_PAGESIZE); 1185 0 stevel return ((uint64_t)pgs * pagesize); 1186 0 stevel } 1187 0 stevel 1188 0 stevel static void 1189 0 stevel mem_info(apd_t *a, cfga_info_t info, int parsable) 1190 0 stevel { 1191 0 stevel const char **p; 1192 0 stevel sbd_mem_stat_t *dst; 1193 0 stevel int want_progress; 1194 0 stevel char *end = &info[sizeof (cfga_info_t)]; 1195 0 stevel 1196 0 stevel DBG("mem_info(%p)\n", (void *)info); 1197 0 stevel 1198 0 stevel dst = (sbd_mem_stat_t *)a->cmstat; 1199 0 stevel 1200 0 stevel if (parsable) 1201 0 stevel p = meminfo_parsable; 1202 0 stevel else 1203 0 stevel p = meminfo_nonparsable; 1204 0 stevel 1205 0 stevel info += snprintf(info, end - info, p[MI_ADDRESS], 1206 0 stevel pages_to_bytes(dst->ms_basepfn)); 1207 0 stevel info += snprintf(info, end - info, p[MI_SIZE], 1208 0 stevel pages_to_kbytes(dst->ms_totpages)); 1209 0 stevel 1210 0 stevel if (dst->ms_noreloc_pages) 1211 0 stevel info += snprintf(info, end - info, p[MI_PERMANENT], 1212 0 stevel pages_to_kbytes(dst->ms_noreloc_pages)); 1213 0 stevel if (!dst->ms_cage_enabled) 1214 0 stevel info += snprintf(info, end - info, p[MI_UNCONFIGURABLE]); 1215 0 stevel if (dst->ms_interleave) 1216 0 stevel info += snprintf(info, end - info, p[MI_INTERLEAVE]); 1217 0 stevel 1218 0 stevel /* 1219 0 stevel * If there is a valid peer physical ap_id specified, 1220 0 stevel * convert it to a logical id. 1221 0 stevel */ 1222 0 stevel want_progress = 0; 1223 0 stevel if (str_valid(dst->ms_peer_ap_id)) { 1224 0 stevel char *cm; 1225 0 stevel char *peer; 1226 0 stevel char physid[MAXPATHLEN]; 1227 0 stevel char logid[MAXPATHLEN]; 1228 0 stevel 1229 0 stevel (void) snprintf(physid, sizeof (physid), "%s%s", 1230 0 stevel DEVDIR, dst->ms_peer_ap_id); 1231 0 stevel 1232 0 stevel /* 1233 0 stevel * Save the component portion of the physid and 1234 0 stevel * add it back after converting to logical format. 1235 0 stevel */ 1236 0 stevel if ((cm = strstr(physid, "::")) != NULL) { 1237 0 stevel *cm = '\0'; 1238 0 stevel cm += 2; 1239 0 stevel } 1240 0 stevel 1241 0 stevel /* attempt to resolve to symlink */ 1242 0 stevel if (ap_symid(a, physid, logid, sizeof (logid)) == 0) 1243 0 stevel peer = logid; 1244 0 stevel else 1245 0 stevel peer = physid; 1246 0 stevel 1247 0 stevel if (dst->ms_peer_is_target) { 1248 0 stevel info += snprintf(info, end - info, p[MI_TARGET], peer); 1249 0 stevel if (cm) 1250 0 stevel info += snprintf(info, end - info, "::%s", cm); 1251 0 stevel want_progress = 1; 1252 0 stevel } else { 1253 0 stevel info += snprintf(info, end - info, p[MI_SOURCE], peer); 1254 0 stevel if (cm) 1255 0 stevel info += snprintf(info, end - info, "::%s", cm); 1256 0 stevel } 1257 0 stevel } 1258 0 stevel if (want_progress || 1259 0 stevel (dst->ms_detpages != 0 && dst->ms_detpages != dst->ms_totpages)) { 1260 0 stevel info += snprintf(info, end - info, p[MI_DELETED], 1261 0 stevel pages_to_kbytes(dst->ms_detpages)); 1262 0 stevel info += snprintf(info, end - info, p[MI_REMAINING], 1263 0 stevel pages_to_kbytes(dst->ms_totpages - 1264 0 stevel dst->ms_detpages)); 1265 0 stevel } 1266 0 stevel } 1267 0 stevel 1268 0 stevel #define II_DEVICE 0 1269 0 stevel #define II_REFERENCED 1 1270 0 stevel 1271 0 stevel static const char * 1272 0 stevel ioinfo[] = { 1273 0 stevel "device %s", 1274 0 stevel ", referenced" 1275 0 stevel }; 1276 0 stevel 1277 0 stevel static const char * 1278 0 stevel ioinfo_parsable[] = { 1279 0 stevel "device=%s", 1280 0 stevel " referenced" 1281 0 stevel }; 1282 0 stevel 1283 0 stevel static void 1284 0 stevel io_info(apd_t *a, cfga_info_t info, int parsable) 1285 0 stevel { 1286 0 stevel const char **p; 1287 0 stevel sbd_io_stat_t *dst; 1288 0 stevel char *end = &info[sizeof (cfga_info_t)]; 1289 0 stevel 1290 0 stevel dst = (sbd_io_stat_t *)a->cmstat; 1291 0 stevel 1292 0 stevel if (parsable) 1293 0 stevel p = ioinfo_parsable; 1294 0 stevel else 1295 0 stevel p = ioinfo; 1296 0 stevel 1297 0 stevel info += snprintf(info, end - info, p[II_DEVICE], dst->is_pathname); 1298 0 stevel if (dst->is_referenced) 1299 0 stevel info += snprintf(info, end - info, p[II_REFERENCED]); 1300 0 stevel } 1301 0 stevel 1302 0 stevel #define PI_CPUID 0 1303 0 stevel #define PI_CPUID_PAIR 1 1304 0 stevel #define PI_CPUID_CONT 2 1305 0 stevel #define PI_CPUID_LAST 3 1306 0 stevel #define PI_SPEED 4 1307 0 stevel #define PI_ECACHE 5 1308 0 stevel 1309 0 stevel static const char * 1310 0 stevel cmpinfo[] = { 1311 0 stevel "cpuid %d", 1312 0 stevel " and %d", 1313 0 stevel ", %d", 1314 0 stevel ", and %d", 1315 0 stevel ", speed %d MHz", 1316 0 stevel ", ecache %d MBytes" 1317 0 stevel }; 1318 0 stevel 1319 0 stevel static const char * 1320 0 stevel cmpinfo_parsable[] = { 1321 0 stevel "cpuid=%d", 1322 0 stevel ",%d", 1323 0 stevel ",%d", 1324 0 stevel ",%d", 1325 0 stevel " speed=%d", 1326 0 stevel " ecache=%d" 1327 0 stevel }; 1328 0 stevel 1329 0 stevel static void 1330 0 stevel cmp_info(apd_t *a, cfga_info_t info, int parsable) 1331 0 stevel { 1332 0 stevel int i; 1333 0 stevel int last; 1334 0 stevel const char **p; 1335 0 stevel sbd_cmp_stat_t *dst; 1336 0 stevel char *end = &info[sizeof (cfga_info_t)]; 1337 0 stevel 1338 0 stevel DBG("cmp_info(%p)\n", (void *)info); 1339 0 stevel 1340 0 stevel dst = (sbd_cmp_stat_t *)a->cmstat; 1341 0 stevel 1342 0 stevel if (parsable) 1343 0 stevel p = cmpinfo_parsable; 1344 0 stevel else 1345 0 stevel p = cmpinfo; 1346 0 stevel 1347 0 stevel /* Print the first cpuid */ 1348 0 stevel info += snprintf(info, end - info, p[PI_CPUID], dst->ps_cpuid[0]); 1349 0 stevel 1350 0 stevel /* 1351 0 stevel * Print the middle cpuids, if necessary. Stop before 1352 0 stevel * the last one, since printing the last cpuid is a 1353 0 stevel * special case for the non parsable form. 1354 0 stevel */ 1355 0 stevel for (i = 1; i < (dst->ps_ncores - 1); i++) { 1356 0 stevel info += snprintf(info, end - info, p[PI_CPUID_CONT], 1357 0 stevel dst->ps_cpuid[i]); 1358 0 stevel } 1359 0 stevel 1360 0 stevel /* Print the last cpuid, if necessary */ 1361 0 stevel if (dst->ps_ncores > 1) { 1362 0 stevel last = (dst->ps_ncores == 2) ? PI_CPUID_PAIR : PI_CPUID_LAST; 1363 0 stevel info += snprintf(info, end - info, 1364 0 stevel dgettext(TEXT_DOMAIN, p[last]), dst->ps_cpuid[i]); 1365 0 stevel } 1366 0 stevel 1367 0 stevel info += snprintf(info, end - info, p[PI_SPEED], dst->ps_speed); 1368 0 stevel info += snprintf(info, end - info, p[PI_ECACHE], dst->ps_ecache); 1369 0 stevel } 1370 0 stevel 1371 0 stevel void 1372 0 stevel ap_info(apd_t *a, cfga_info_t info, ap_target_t tgt) 1373 0 stevel { 1374 0 stevel int parsable = ap_getopt(a, OPT_PARSABLE); 1375 0 stevel 1376 0 stevel DBG("ap_info(%p, %d)\n", (void *)info, parsable); 1377 0 stevel 1378 0 stevel switch (tgt) { 1379 0 stevel case AP_BOARD: 1380 0 stevel bd_info(a, info, parsable); 1381 0 stevel break; 1382 0 stevel case AP_CPU: 1383 0 stevel cpu_info(a, info, parsable); 1384 0 stevel break; 1385 0 stevel case AP_MEM: 1386 0 stevel mem_info(a, info, parsable); 1387 0 stevel break; 1388 0 stevel case AP_IO: 1389 0 stevel io_info(a, info, parsable); 1390 0 stevel break; 1391 0 stevel case AP_CMP: 1392 0 stevel cmp_info(a, info, parsable); 1393 0 stevel break; 1394 0 stevel default: 1395 0 stevel break; 1396 0 stevel } 1397 0 stevel } 1398