4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
35 #include <libdevinfo.h>
36 #define CFGA_PLUGIN_LIB
37 #include <config_admin.h>
42 ap_symid(apd_t
*a
, char *apid
, char *symid
, size_t bufsize
)
46 char path
[MAXPATHLEN
];
52 n
= sprintf(path
, "/dev/cfg/");
55 if ((dirp
= opendir(path
)) == NULL
)
60 while ((dp
= readdir(dirp
)) != NULL
) {
66 (void) strcat(path
, dp
->d_name
);
67 if ((len
= readlink(path
, buf
, sizeof (buf
))) == (size_t)-1)
73 while (strncmp(cp
, "../", len
) == 0)
76 cp
--; /* Get the '/' */
78 if (strcmp(cp
, apid
) == 0) {
79 (void) snprintf(symid
, bufsize
, "%s", dp
->d_name
);
85 (void) closedir(dirp
);
90 ap_logid(apd_t
*a
, char *apid
)
95 if ((buf
= calloc(1, MAXPATHLEN
)) == NULL
)
99 * Look for a symlink. On any error, fallback to
100 * driver and instance based logical ap_ids.
102 if (ap_symid(a
, apid
, buf
, MAXPATHLEN
) == 0)
105 n
= snprintf(buf
, MAXPATHLEN
, "%s%d:%s",
106 a
->drv
, a
->inst
, a
->minor
);
108 * Append the dynamic portion, if any.
111 (void) snprintf(&buf
[n
], MAXPATHLEN
- n
, "::%s", a
->cid
);
117 ap_parse(apd_t
*a
, const char *ap_id
)
139 if (!str_valid(ap_id
)) {
144 if ((a
->path
= strdup(ap_id
)) == NULL
) {
150 * For a physical ap_id, look only at the base part.
151 * For a logical/symbolic one, use the entire ap_id.
153 if (strncmp(a
->path
, DEVDIR
, strlen(DEVDIR
)) == 0) {
155 base
= strrchr((const char *)a
->path
, '/') + 1;
159 if ((a
->target
= strdup(a
->path
)) == NULL
) {
165 if ((s
= strchr(base
, ':')) == NULL
|| s
[1] == ':') {
167 * No ':' found, or got a '::'. If this is a physical
168 * ap_id, it must have a minor separtor ':' which must
169 * appear before the dynamic part (starting with '::').
170 * For a symbolic ap_id, skip looking for driver/minor
180 * Look for driver name/instance only up to the first ':',
181 * i.e. up to the minor node name.
185 if ((p
= strchr(base
, '@')) != NULL
) {
187 * Get the driver name/instance.
190 if ((a
->drv
= strdup(base
)) == NULL
) {
196 i
= strtol(p
, &q
, 10);
206 * Need to go to the end of the string before the :: if any
207 * If the string is null then we are done
215 s
+= (strlen(s
) - len
);
221 else if (strncmp(p
, "::", 2) != 0) {
226 * Save the component id.
234 * Get the operation target, e.g. slot0, slot0::cpu0.
235 * At this point, a->path points to the /devices path
236 * minus the dynamic part, for a physical ap_id. In
237 * the case of a logical ap_id, the target is already
240 if (phys
!= 0 && (a
->target
= ap_logid(a
, a
->path
)) == NULL
) {
245 if (a
->tgt
== AP_BOARD
)
248 while ((*p
!= '\0') && !isdigit(*p
))
252 * Get the component unit number, if present.
254 i
= strtol(p
, &s
, 10);
256 * There must be no characters after the unit number.
264 * Disallow leading zeroes, e.g. cpu00, cpu01, cpu001.
265 * If there are 2 or more digits and the first is a zero,
268 if ((s
-p
) >= 2 && *p
== '0') {
277 if ((a
->cname
= strdup(a
->cid
)) == NULL
)
285 ap_err(a
, ERR_CM_INVAL
, a
->cid
);
292 DBG("path=<%s> ", a
->path
? a
->path
: "");
293 DBG("drv=<%s> inst=%d minor=<%s> ",
294 a
->drv
? a
->drv
: "", a
->inst
, a
->minor
? a
->minor
: "");
295 DBG("target=<%s>\n", a
->target
? a
->target
: "");
296 DBG("cid=<%s> ", a
->cid
? a
->cid
: "");
297 DBG("cname=<%s> ", a
->cname
? a
->cname
: "");
298 DBG("cnum=%d\n", a
->cnum
);
299 DBG("tgt=%d opts=%x\n", a
->tgt
, a
->opts
.flags
);
301 return (rc
== ERR_NONE
? 0 : -1);
307 * The first set of commands in the table are in sequencing order,
308 * for example, the first group starts with assign and ends with
309 * configure. command sequencer relies on this ordering.
319 "notify add capacity",
322 "request delete capacity",
326 "notify capacity change",
342 return (ap_cmd_names
[min(i
, CMD_NONE
)]);
362 return (ap_opt_names
[i
]);
366 * Command descriptor.
368 * Each command has a (command) mask specifying the AP target classes
369 * it operates on, e.g. the assign command applies only to boards.
370 * In addition each AP target class has a separate option mask specifying
371 * which command options are valid for that target class.
372 * A global value mask specifies which options require values.
377 uint_t omask
[AP_NCLASS
];
381 * Command option definitions.
383 #define SHFT(i) ((uint_t)1 << (i))
385 #define ALLOPT 0xffffffff
386 #define CMNOPT (SHFT(OPT_VERBOSE)|SHFT(OPT_PLATFORM)|SHFT(OPT_SIM))
387 #define CMFOPT (CMNOPT|SHFT(OPT_FORCE))
388 #define STSOPT (CMNOPT|SHFT(OPT_PARSABLE))
389 #define BRDDCN (CMNOPT|SHFT(OPT_UNASSIGN)|SHFT(OPT_NOPOWEROFF))
391 #define BRD SHFT(AP_BOARD)
392 #define BIO SHFT(AP_BOARD)|SHFT(AP_IO)
393 #define ALL (BRD|SHFT(AP_CPU)|SHFT(AP_MEM)|SHFT(AP_IO)|SHFT(AP_CMP))
398 * cmd cmd board cpu mem io cmp
399 * cmask omask omask omask omask omask
401 {CMD_ASSIGN
, BRD
, 0, CMNOPT
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
402 {CMD_UNASSIGN
, BRD
, 0, CMNOPT
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
403 {CMD_POWERON
, BRD
, 0, CMNOPT
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
404 {CMD_POWEROFF
, BRD
, 0, CMNOPT
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
405 {CMD_CONNECT
, BRD
, 0, CMFOPT
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
406 {CMD_DISCONNECT
, BRD
, 0, BRDDCN
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
407 {CMD_CONFIGURE
, ALL
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
408 {CMD_UNCONFIGURE
, ALL
, 0, CMFOPT
, CMFOPT
, CMFOPT
, CMFOPT
, CMNOPT
},
409 {CMD_RCM_OFFLINE
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
410 {CMD_RCM_ONLINE
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
411 {CMD_RCM_SUSPEND
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
412 {CMD_RCM_RESUME
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
413 {CMD_RCM_CAP_ADD
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
414 {CMD_RCM_CAP_DEL
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
415 {CMD_RCM_CAP_NOTIFY
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
416 {CMD_RCM_REMOVE
, BIO
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
417 {CMD_TEST
, BRD
, 0, CMFOPT
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
418 {CMD_STATUS
, ALL
, 0, STSOPT
, STSOPT
, STSOPT
, STSOPT
, STSOPT
},
419 {CMD_GETNCM
, BRD
, 0, CMNOPT
, NULOPT
, NULOPT
, NULOPT
, NULOPT
},
420 {CMD_PASSTHRU
, ALL
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
421 {CMD_HELP
, ALL
, 0, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
, CMNOPT
},
422 {CMD_ERRTEST
, ALL
, 0, ALLOPT
, ALLOPT
, ALLOPT
, ALLOPT
, ALLOPT
},
423 {CMD_NONE
, 0, 0, 0, 0, 0, 0, 0 }
427 * Global mask for options that require values.
430 SHFT(OPT_CODE)|SHFT(OPT_MID)|SHFT(OPT_ERR)| \
431 SHFT(OPT_PLATFORM)|SHFT(OPT_SKIP))
440 dbg("vmask=0x%x\n", AP_VMASK
);
441 dbg("%23s%5s%5s%9s%9s%9s%9s%9s\n",
442 "cmd", "msk", "none", "brd", "cpu", "mem", "io", "cmp");
444 for (acp
= ap_cmds
; acp
->cmd
!= CMD_NONE
; acp
++) {
445 dbg("%23s%5x%5x", ap_cmd_name(acp
->cmd
), acp
->cmask
,
446 acp
->omask
[AP_NONE
]);
447 for (i
= AP_BOARD
; i
< AP_NCLASS
; i
++) {
448 dbg("%9x", acp
->omask
[i
]);
456 ap_state_cmd(cfga_cmd_t i
, int *cmd
)
464 case CFGA_CMD_CONNECT
:
467 case CFGA_CMD_DISCONNECT
:
470 case CFGA_CMD_CONFIGURE
:
473 case CFGA_CMD_UNCONFIGURE
:
477 case CFGA_CMD_UNLOAD
:
501 for (i
= 0, p
= ap_cmd_names
; *p
!= NULL
; p
++, i
++)
502 if (strcmp(*p
, name
) == 0)
511 ap_opt_parse(apd_t
*a
, ap_cmd_t
*acp
, const char *options
)
517 * Set default values.
520 opts
->mid
= (char *)a
->class;
521 opts
->err
= ERR_CMD_FAIL
;
526 if ((optstr
= strdup(options
)) == NULL
) {
527 ap_err(a
, ERR_NOMEM
);
533 if (acp
->cmd
== CMD_PASSTHRU
)
536 while (*optstr
!= '\0') {
545 opt
= getsubopt(&optstr
, ap_opt_names
, &value
);
547 DBG("opt=%d\n", opt
);
550 ap_err(a
, ERR_OPT_INVAL
, value
);
554 optname
= ap_opt_names
[opt
];
555 omask
= acp
->omask
[a
->tgt
];
557 i
= mask(opt
) & omask
;
559 DBG("tgt=%d opt=%x omask=%x\n", a
->tgt
, mask(opt
), omask
);
562 ap_err(a
, ERR_OPT_INVAL
, optname
);
567 * Check whether the option requires a value.
569 i
= mask(opt
) & AP_VMASK
;
570 if (i
!= 0 && value
== NULL
) {
571 ap_err(a
, ERR_OPT_NOVAL
, optname
);
573 } else if (i
== 0 && value
!= NULL
) {
574 ap_err(a
, ERR_OPT_VAL
, optname
);
579 assert(opt
!= OPT_CODE
); /* XXX prefix */
582 * Set the options's value.
590 i
= strtol(value
, &p
, 10);
598 i
= strtol(value
, &p
, 10);
603 i
= ap_cmd("poweroff");
604 opts
->skip
|= mask(i
);
606 case OPT_SKIP
: /* for debugging */
608 * The skip value may be a ':' separated
609 * list of steps (commands) to be skipped
612 for (p
= strtok(value
, ":"); p
!= NULL
;
613 p
= strtok(NULL
, ":")) {
614 if ((i
= ap_cmd(p
)) == CMD_NONE
) {
615 ap_err(a
, ERR_CMD_INVAL
, p
);
618 opts
->skip
|= mask(i
);
622 opts
->platform
= value
;
625 ap_err(a
, ERR_OPT_INVAL
, optname
);
640 for (acp
= ap_cmds
; acp
->cmd
!= CMD_NONE
; acp
++)
644 if (acp
->cmd
== CMD_NONE
)
651 ap_cmd_parse(apd_t
*a
, const char *f
, const char *options
, int *cmd
)
666 if ((c
= ap_cmd((char *)f
)) == CMD_NONE
||
667 (acp
= ap_cmdp(c
)) == NULL
) {
668 ap_err(a
, ERR_CMD_INVAL
, f
);
673 * Change a->statonly to 1, if the case is CMD_STATUS. We are only
674 * wanting to read the devices and no more
677 * Get the status for all components if either the list all
678 * option being specified or if we are configuring/unconfiguring
679 * the board. The latter is needed for the RCM interface.
683 all
= ap_getopt(a
, OPT_LIST_ALL
);
687 case CMD_UNCONFIGURE
:
690 all
= (a
->tgt
== AP_BOARD
);
699 if ((rc
= apd_init(a
, all
)) != CFGA_OK
)
705 * Get the target here in case it is a component in which
706 * case its type is known after the initialization.
711 DBG("cmd=%s(%d) tmask=0x%x cmask=0x%x omask=0x%x\n",
712 ap_cmd_name(c
), c
, target
, acp
->cmask
, acp
->omask
[tgt
]);
714 if ((acp
->cmask
& target
) == 0)
715 ap_err(a
, ERR_CMD_NOTSUPP
, c
);
716 else if (options
!= NULL
&& acp
->omask
[tgt
] == 0)
717 ap_err(a
, ERR_OPT_INVAL
, options
);
718 else if (ap_opt_parse(a
, acp
, options
) != -1) {
720 rc
= ap_platopts_check(a
, c
, c
);
736 if ((a
->tgt
== AP_BOARD
) && ap_getopt(a
, OPT_LIST_ALL
))