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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 /*
  30  *      Plugin Library for PCI Hot-Plug Controller
  31  */
  32 
  33 #include <stddef.h>
  34 #include <locale.h>
  35 #include <ctype.h>
  36 #include <stdio.h>
  37 #include <stdlib.h>
  38 #include <string.h>
  39 #include <fcntl.h>
  40 #include <unistd.h>
  41 #include <errno.h>
  42 #include <locale.h>
  43 #include <langinfo.h>
  44 #include <time.h>
  45 #include <sys/param.h>
  46 #include <stdarg.h>
  47 #include <libdevinfo.h>
  48 #include <libdevice.h>
  49 
  50 #define CFGA_PLUGIN_LIB
  51 
  52 #include <config_admin.h>
  53 
  54 #include <sys/types.h>
  55 #include <sys/stat.h>
  56 #include <sys/ioctl.h>
  57 #include <sys/dditypes.h>
  58 #include <sys/devctl.h>
  59 #include <sys/modctl.h>
  60 #include <sys/hotplug/hpctrl.h>
  61 #include <sys/pci.h>
  62 #include <libintl.h>
  63 
  64 #include <dirent.h>
  65 #include <limits.h>
  66 #include <sys/mkdev.h>
  67 #include <librcm.h>
  68 #include "../../../../common/pci/pci_strings.h"
  69 
  70 extern const struct pci_class_strings_s class_pci[];
  71 extern int class_pci_items;
  72 
  73 /*
  74  * Set the version number
  75  */
  76 int cfga_version = CFGA_HSL_V2;
  77 
  78 #ifdef  DEBUG
  79 #define PCIHP_DBG       1
  80 #endif
  81 
  82 #if !defined(TEXT_DOMAIN)
  83 #define TEXT_DOMAIN     "SYS_TEST"
  84 #endif
  85 
  86 /*
  87  *      DEBUGING LEVEL
  88  *
  89  *      External routines:  1 - 2
  90  *      Internal routines:  3 - 4
  91  */
  92 #ifdef  PCIHP_DBG
  93 int     pcihp_debug = 1;
  94 #define DBG(level, args) \
  95         { if (pcihp_debug >= (level)) printf args; }
  96 #define DBG_F(level, args) \
  97         { if (pcihp_debug >= (level)) fprintf args; }
  98 #else
  99 #define DBG(level, args)        /* nothing */
 100 #define DBG_F(level, args)      /* nothing */
 101 #endif
 102 
 103 #define CMD_ACQUIRE             0
 104 #define CMD_GETSTAT             1
 105 #define CMD_LIST                2
 106 #define CMD_SLOT_CONNECT        3
 107 #define CMD_SLOT_DISCONNECT     4
 108 #define CMD_SLOT_CONFIGURE      5
 109 #define CMD_SLOT_UNCONFIGURE    6
 110 #define CMD_SLOT_INSERT         7
 111 #define CMD_SLOT_REMOVE         8
 112 #define CMD_OPEN                9
 113 #define CMD_FSTAT               10
 114 #define ERR_CMD_INVAL           11
 115 #define ERR_AP_INVAL            12
 116 #define ERR_AP_ERR              13
 117 #define ERR_OPT_INVAL           14
 118 
 119 static char *
 120 cfga_errstrs[] = {
 121         /* n */ "acquire ",
 122         /* n */ "get-status ",
 123         /* n */ "list ",
 124         /* n */ "connect ",
 125         /* n */ "disconnect ",
 126         /* n */ "configure ",
 127         /* n */ "unconfigure ",
 128         /* n */ "insert ",
 129         /* n */ "remove ",
 130         /* n */ "open ",
 131         /* n */ "fstat ",
 132         /* y */ "invalid command ",
 133         /* y */ "invalid attachment point ",
 134         /* y */ "invalid transition ",
 135         /* y */ "invalid option ",
 136                 NULL
 137 };
 138 
 139 #define HELP_HEADER             1
 140 #define HELP_CONFIG             2
 141 #define HELP_ENABLE_SLOT        3
 142 #define HELP_DISABLE_SLOT       4
 143 #define HELP_ENABLE_AUTOCONF    5
 144 #define HELP_DISABLE_AUTOCONF   6
 145 #define HELP_LED_CNTRL          7
 146 #define HELP_UNKNOWN            8
 147 #define SUCCESS                 9
 148 #define FAILED                  10
 149 #define UNKNOWN                 11
 150 
 151 #define MAXLINE                 256
 152 
 153 /* for type string assembly in get_type() */
 154 #define TPCT(s) (void) strlcat(buf, (s), CFGA_TYPE_LEN)
 155 
 156 extern int errno;
 157 
 158 static void cfga_err(char **errstring, ...);
 159 static cfga_err_t fix_ap_name(char *ap_log_id, const char *ap_id,
 160     char *slot_name, char **errstring);
 161 static void build_control_data(struct hpc_control_data *iocdata, uint_t cmd,
 162     void *retdata);
 163 static cfga_err_t check_options(const char *options);
 164 static void cfga_msg(struct cfga_msg *msgp, const char *str);
 165 static char *findlink(char *ap_phys_id);
 166 
 167 static char *
 168 cfga_strs[] = {
 169 NULL,
 170 "\nPCI hotplug specific commands:",
 171 "\t-c [connect|disconnect|configure|unconfigure|insert|remove] "
 172 "ap_id [ap_id...]",
 173 "\t-x enable_slot  ap_id [ap_id...]",
 174 "\t-x disable_slot ap_id [ap_id...]",
 175 "\t-x enable_autoconfig  ap_id [ap_id...]",
 176 "\t-x disable_autoconfig ap_id [ap_id...]",
 177 "\t-x led[=[fault|power|active|attn],mode=[on|off|blink]] ap_id [ap_id...]",
 178 "\tunknown command or option: ",
 179 "success   ",
 180 "failed   ",
 181 "unknown",
 182 NULL
 183 };
 184 
 185 #define MAX_FORMAT 80
 186 
 187 #define ENABLE_SLOT     0
 188 #define DISABLE_SLOT    1
 189 #define ENABLE_AUTOCNF  2
 190 #define DISABLE_AUTOCNF 3
 191 #define LED             4
 192 #define MODE            5
 193 
 194 /*
 195  * Board Type
 196  */
 197 static char *
 198 board_strs[] = {
 199         /* n */ "???",  /* HPC_BOARD_UNKNOWN */
 200         /* n */ "hp",   /* HPC_BOARD_PCI_HOTPLUG */
 201         /* n */ "nhs",  /* HPC_BOARD_CPCI_NON_HS */
 202         /* n */ "bhs",  /* HPC_BOARD_CPCI_BASIC_HS */
 203         /* n */ "fhs",  /* HPC_BOARD_CPCI_FULL_HS */
 204         /* n */ "hs",   /* HPC_BOARD_CPCI_HS */
 205         /* n */ NULL
 206 };
 207 
 208 /*
 209  * HW functions
 210  */
 211 static char *
 212 func_strs[] = {
 213         /* n */ "enable_slot",
 214         /* n */ "disable_slot",
 215         /* n */ "enable_autoconfig",
 216         /* n */ "disable_autoconfig",
 217         /* n */ "led",
 218         /* n */ "mode",
 219         /* n */ NULL
 220 };
 221 
 222 /*
 223  * LED strings
 224  */
 225 static char *
 226 led_strs[] = {
 227         /* n */ "fault",        /* HPC_FAULT_LED */
 228         /* n */ "power",        /* HPC_POWER_LED */
 229         /* n */ "attn",         /* HPC_ATTN_LED */
 230         /* n */ "active",       /* HPC_ACTIVE_LED */
 231         /* n */ NULL
 232 };
 233 
 234 #define FAULT   0
 235 #define POWER   1
 236 #define ATTN    2
 237 #define ACTIVE  3
 238 
 239 static char *
 240 mode_strs[] = {
 241         /* n */ "off",          /* HPC_LED_OFF */
 242         /* n */ "on",           /* HPC_LED_ON */
 243         /* n */ "blink",        /* HPC_LED_BLINK */
 244         /* n */ NULL
 245 };
 246 
 247 #define OFF     0
 248 #define ON      1
 249 #define BLINK   2
 250 
 251 #define cfga_errstrs(i)         cfga_errstrs[(i)]
 252 
 253 #define cfga_eid(a, b)          (((a) << 8) + (b))
 254 #define MAXDEVS                 32
 255 
 256 typedef enum {
 257         SOLARIS_SLT_NAME,
 258         PROM_SLT_NAME
 259 } slt_name_src_t;
 260 
 261 struct searcharg {
 262         char    *devpath;
 263         char    slotnames[MAXDEVS][MAXNAMELEN];
 264         int     minor;
 265         di_prom_handle_t        promp;
 266         slt_name_src_t  slt_name_src;
 267 };
 268 
 269 static void *private_check;
 270 
 271 static int
 272 get_occupants(const char *ap_id, hpc_occupant_info_t *occupant)
 273 {
 274         int rv;
 275         int fd;
 276         di_node_t ap_node;
 277         char *prop_data;
 278         char *tmp;
 279         char *ptr;
 280         struct stat statbuf;
 281         dev_t devt;
 282 
 283         if ((fd = open(ap_id, O_RDWR)) == -1) {
 284                 DBG(2, ("open = ap_id%s, fd%d\n", ap_id, fd));
 285                 DBG_F(2, (stderr, "open on %s failed\n", ap_id));
 286                 return (CFGA_ERROR);
 287         }
 288 
 289         if (fstat(fd, &statbuf) == -1) {
 290                 DBG(1, ("stat failed: %i\n", errno));
 291                 (void) close(fd);
 292                 return (CFGA_ERROR);
 293         }
 294         (void) close(fd);
 295 
 296         devt = statbuf.st_rdev;
 297 
 298         tmp = (char *)(ap_id + sizeof ("/devices") - 1);
 299         if ((ptr = strrchr(tmp, ':')) != NULL)
 300                 *ptr = '\0';
 301 
 302         ap_node = di_init(tmp, DINFOPROP | DINFOMINOR);
 303         if (ap_node == DI_NODE_NIL) {
 304                 DBG(1, ("dead %i\n", errno));
 305                 return (CFGA_ERROR);
 306         }
 307 
 308 #ifdef  PCIHP_DBG
 309         ptr = di_devfs_path(ap_node);
 310         DBG(1, ("get_occupants: %s\n", ptr));
 311         di_devfs_path_free(ptr);
 312 #endif
 313 
 314         if ((rv = di_prop_lookup_strings(devt, ap_node, "pci-occupant",
 315             &prop_data)) == -1) {
 316                 DBG(1, ("get_occupants: prop_lookup failed: %i\n", errno));
 317                 di_fini(ap_node);
 318                 return (CFGA_ERROR);
 319         }
 320 
 321         if (prop_data && (strcmp(prop_data, "") == 0)) {
 322                 di_fini(ap_node);
 323                 occupant->i = 0;
 324                 occupant->id[0] = NULL;
 325                 return (CFGA_OK);
 326         }
 327 
 328         DBG(1, ("get_occupants: %i devices found\n", rv));
 329         for (occupant->i = 0; occupant->i < rv; occupant->i++) {
 330                 if (occupant->i >= (HPC_MAX_OCCUPANTS - 1)) {
 331                         occupant->i--;
 332                         break;
 333                 }
 334                 occupant->id[occupant->i] = (char *)malloc(
 335                         strlen(prop_data) + sizeof ("/devices"));
 336                 (void) snprintf(occupant->id[occupant->i], strlen(prop_data) +
 337                     sizeof ("/devices"), "/devices%s", prop_data);
 338                 DBG(1, ("%s\n", occupant->id[occupant->i]));
 339                 prop_data += strlen(prop_data) + 1;
 340         }
 341         di_fini(ap_node);
 342 
 343         occupant->id[occupant->i] = NULL;
 344 
 345         return (CFGA_OK);
 346 }
 347 
 348 /*
 349  * let rcm know that the device has indeed been removed and clean
 350  * up rcm data
 351  */
 352 static void
 353 confirm_rcm(hpc_occupant_info_t *occupant, rcm_handle_t *rhandle)
 354 {
 355         DBG(1, ("confirm_rcm\n"));
 356 
 357         if (occupant->i == 0) /* nothing was found to ask rcm about */
 358                 return;
 359 
 360         (void) rcm_notify_remove_list(rhandle, occupant->id, 0, NULL);
 361         (void) rcm_free_handle(rhandle);
 362 
 363         for (; occupant->i >= 0; occupant->i--)
 364                 free(occupant->id[occupant->i]);
 365 }
 366 
 367 static void
 368 fail_rcm(hpc_occupant_info_t *occupant, rcm_handle_t *rhandle)
 369 {
 370         DBG(1, ("fail_rcm\n"));
 371 
 372         if (occupant->i == 0) /* nothing was found to ask rcm about */
 373                 return;
 374 
 375         (void) rcm_notify_online_list(rhandle, occupant->id, 0, NULL);
 376         (void) rcm_free_handle(rhandle);
 377 
 378         for (; occupant->i >= 0; occupant->i--)
 379                 free(occupant->id[occupant->i]);
 380 }
 381 
 382 /*
 383  * copied from scsi_rcm_info_table
 384  *
 385  *      Takes an opaque rcm_info_t pointer and a character pointer, and appends
 386  * the rcm_info_t data in the form of a table to the given character pointer.
 387  */
 388 static void
 389 pci_rcm_info_table(rcm_info_t *rinfo, char **table)
 390 {
 391         int i;
 392         size_t w;
 393         size_t width = 0;
 394         size_t w_rsrc = 0;
 395         size_t w_info = 0;
 396         size_t table_size = 0;
 397         uint_t tuples = 0;
 398         rcm_info_tuple_t *tuple = NULL;
 399         char *rsrc;
 400         char *info;
 401         char *newtable;
 402         static char format[MAX_FORMAT];
 403         const char *infostr;
 404 
 405         /* Protect against invalid arguments */
 406         if (rinfo == NULL || table == NULL)
 407                 return;
 408 
 409         /* Set localized table header strings */
 410         rsrc = dgettext(TEXT_DOMAIN, "Resource");
 411         info = dgettext(TEXT_DOMAIN, "Information");
 412 
 413         /* A first pass, to size up the RCM information */
 414         while (tuple = rcm_info_next(rinfo, tuple)) {
 415                 if ((infostr = rcm_info_info(tuple)) != NULL) {
 416                         tuples++;
 417                         if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
 418                                 w_rsrc = w;
 419                         if ((w = strlen(infostr)) > w_info)
 420                                 w_info = w;
 421                 }
 422         }
 423 
 424         /* If nothing was sized up above, stop early */
 425         if (tuples == 0)
 426                 return;
 427 
 428         /* Adjust column widths for column headings */
 429         if ((w = strlen(rsrc)) > w_rsrc)
 430                 w_rsrc = w;
 431         else if ((w_rsrc - w) % 2)
 432                 w_rsrc++;
 433         if ((w = strlen(info)) > w_info)
 434                 w_info = w;
 435         else if ((w_info - w) % 2)
 436                 w_info++;
 437 
 438         /*
 439          * Compute the total line width of each line,
 440          * accounting for intercolumn spacing.
 441          */
 442         width = w_info + w_rsrc + 4;
 443 
 444         /* Allocate space for the table */
 445         table_size = (2 + tuples) * (width + 1) + 2;
 446         if (*table == NULL) {
 447                 /* zero fill for the strcat() call below */
 448                 *table = calloc(table_size, sizeof (char));
 449                 if (*table == NULL)
 450                         return;
 451         } else {
 452                 newtable = realloc(*table, strlen(*table) + table_size);
 453                 if (newtable == NULL)
 454                         return;
 455                 else
 456                         *table = newtable;
 457         }
 458 
 459         /* Place a table header into the string */
 460 
 461         /* The resource header */
 462         (void) strcat(*table, "\n");
 463         w = strlen(rsrc);
 464         for (i = 0; i < ((w_rsrc - w) / 2); i++)
 465                 (void) strcat(*table, " ");
 466         (void) strcat(*table, rsrc);
 467         for (i = 0; i < ((w_rsrc - w) / 2); i++)
 468                 (void) strcat(*table, " ");
 469 
 470         /* The information header */
 471         (void) strcat(*table, "  ");
 472         w = strlen(info);
 473         for (i = 0; i < ((w_info - w) / 2); i++)
 474                 (void) strcat(*table, " ");
 475         (void) strcat(*table, info);
 476         for (i = 0; i < ((w_info - w) / 2); i++)
 477                 (void) strcat(*table, " ");
 478         /* Underline the headers */
 479         (void) strcat(*table, "\n");
 480         for (i = 0; i < w_rsrc; i++)
 481                 (void) strcat(*table, "-");
 482         (void) strcat(*table, "  ");
 483         for (i = 0; i < w_info; i++)
 484                 (void) strcat(*table, "-");
 485 
 486         /* Construct the format string */
 487         (void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
 488             (int)w_rsrc, (int)w_info);
 489 
 490         /* Add the tuples to the table string */
 491         tuple = NULL;
 492         while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
 493                 if ((infostr = rcm_info_info(tuple)) != NULL) {
 494                         (void) strcat(*table, "\n");
 495                         (void) sprintf(&((*table)[strlen(*table)]),
 496                             format, rcm_info_rsrc(tuple),
 497                             infostr);
 498                 }
 499         }
 500 }
 501 
 502 /*
 503  * Figure out what device is about to be unconfigured or disconnected
 504  * and make sure rcm is ok with it.
 505  * hangs on to a list of handles so they can then be confirmed or denied
 506  * if either getting the occupant list or talking to rcm fails
 507  * return CFGA_ERROR so that things can go on without rcm
 508  */
 509 static int
 510 check_rcm(const char *ap_id, hpc_occupant_info_t *occupant,
 511     rcm_handle_t **rhandlep, char **errstring, cfga_flags_t flags)
 512 {
 513         int rv;
 514         rcm_info_t *rinfo;
 515         rcm_handle_t *rhandle;
 516         uint_t rcmflags;
 517 
 518         if (get_occupants(ap_id, occupant) != 0) {
 519                 DBG(1, ("check_rcm: failed to get occupants\n"));
 520                 return (CFGA_ERROR);
 521         }
 522 
 523         if (occupant->i == 0) {
 524                 DBG(1, ("check_rcm: no drivers attaching to occupants\n"));
 525                 return (CFGA_OK);
 526         }
 527 
 528         if (rcm_alloc_handle(NULL, 0, NULL, &rhandle)
 529             != RCM_SUCCESS) {
 530                 DBG(1, ("check_rcm: blocked by rcm failure\n"));
 531                 return (CFGA_ERROR);
 532         }
 533 
 534         rcmflags = (flags & CFGA_FLAG_FORCE) ? RCM_FORCE : 0;
 535         rv = rcm_request_offline_list(rhandle, occupant->id, rcmflags, &rinfo);
 536 
 537         if (rv == RCM_FAILURE) {
 538                 DBG(1, ("check_rcm: blocked by rcm failure 2\n"));
 539                 pci_rcm_info_table(rinfo, errstring);
 540                 rcm_free_info(rinfo);
 541                 fail_rcm(occupant, rhandle);
 542                 return (CFGA_BUSY);
 543         }
 544         if (rv == RCM_CONFLICT) {
 545                 DBG(1, ("check_rcm: blocked by %i\n",
 546                     rcm_info_pid(rinfo)));
 547                 pci_rcm_info_table(rinfo, errstring);
 548                 rcm_free_info(rinfo);
 549                 (void) rcm_free_handle(rhandle);
 550                 for (; occupant->i >= 0; occupant->i--)
 551                         free(occupant->id[occupant->i]);
 552                 return (CFGA_BUSY);
 553         }
 554 
 555         rcm_free_info(rinfo);
 556         *rhandlep = rhandle;
 557 
 558         /* else */
 559         return (CFGA_OK);
 560 }
 561 
 562 
 563 /*
 564  * Transitional Diagram:
 565  *
 566  *  empty               unconfigure
 567  * (remove)     ^|  (physically insert card)
 568  *                      |V
 569  * disconnect   configure
 570  * "-c DISCONNECT"      ^|      "-c CONNECT"
 571  *                              |V      "-c CONFIGURE"
 572  * connect      unconfigure     ->   connect    configure
 573  *                                              <-
 574  *                                      "-c UNCONFIGURE"
 575  *
 576  */
 577 /*ARGSUSED*/
 578 cfga_err_t
 579 cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id,
 580     const char *options, struct cfga_confirm *confp,
 581     struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
 582 {
 583         int rv;
 584         devctl_hdl_t            dcp;
 585         devctl_ap_state_t       state;
 586         ap_rstate_t             rs;
 587         ap_ostate_t             os;
 588         hpc_occupant_info_t occupants;
 589         rcm_handle_t *rhandle;
 590 
 591         if ((rv = check_options(options)) != CFGA_OK) {
 592                 return (rv);
 593         }
 594 
 595         if (errstring != NULL)
 596                 *errstring = NULL;
 597 
 598         rv = CFGA_OK;
 599         DBG(1, ("cfga_change_state:(%s)\n", ap_id));
 600 
 601         if ((dcp = devctl_ap_acquire((char *)ap_id, 0)) == NULL) {
 602                 if (rv == EBUSY) {
 603                         cfga_err(errstring, CMD_ACQUIRE, ap_id, 0);
 604                         DBG(1, ("cfga_change_state: device is busy\n"));
 605                         rv = CFGA_BUSY;
 606                 } else
 607                         rv = CFGA_ERROR;
 608                 return (rv);
 609         }
 610 
 611         if (devctl_ap_getstate(dcp, NULL, &state) == -1) {
 612                 DBG(2, ("cfga_change_state: devctl ap getstate failed\n"));
 613                 cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
 614                 devctl_release((devctl_hdl_t)dcp);
 615                 if (rv == EBUSY)
 616                         rv = CFGA_BUSY;
 617                 else
 618                         rv = CFGA_ERROR;
 619                 return (rv);
 620         }
 621 
 622         rs = state.ap_rstate;
 623         os = state.ap_ostate;
 624 
 625         DBG(1, ("cfga_change_state: rs is %d\n", state.ap_rstate));
 626         DBG(1, ("cfga_change_state: os is %d\n", state.ap_ostate));
 627         switch (state_change_cmd) {
 628         case CFGA_CMD_CONNECT:
 629                 if ((rs == AP_RSTATE_EMPTY) ||
 630                     (rs == AP_RSTATE_CONNECTED) ||
 631                     (os == AP_OSTATE_CONFIGURED)) {
 632                         cfga_err(errstring, ERR_AP_ERR, 0);
 633                         rv = CFGA_INVAL;
 634                 } else {
 635                         /* Lets connect the slot */
 636                         if (devctl_ap_connect(dcp, NULL) == -1) {
 637                                 rv = CFGA_ERROR;
 638                                 cfga_err(errstring,
 639                                     CMD_SLOT_CONNECT, 0);
 640                         }
 641                 }
 642 
 643                 break;
 644 
 645         case CFGA_CMD_DISCONNECT:
 646                 DBG(1, ("disconnect\n"));
 647 
 648                 if (os == AP_OSTATE_CONFIGURED) {
 649                         if ((rv = check_rcm(ap_id, &occupants, &rhandle,
 650                             errstring, flags)) == CFGA_BUSY) {
 651                                 break;
 652                         } else if (rv == CFGA_OK) {
 653                                 if (devctl_ap_unconfigure(dcp, NULL) == -1) {
 654                                         if (errno == EBUSY)
 655                                                 rv = CFGA_BUSY;
 656                                         else
 657                                                 rv = CFGA_ERROR;
 658                                         cfga_err(errstring,
 659                                             CMD_SLOT_DISCONNECT, 0);
 660                                         fail_rcm(&occupants, rhandle);
 661                                         break;
 662                                 } else {
 663                                         confirm_rcm(&occupants, rhandle);
 664                                 }
 665                         } else { /* rv == CFGA_ERROR */
 666                                 if (devctl_ap_unconfigure(dcp, NULL) == -1) {
 667                                         if (errno == EBUSY)
 668                                                 rv = CFGA_BUSY;
 669                                         else
 670                                                 rv = CFGA_ERROR;
 671                                         break;
 672                                 } else {
 673                                         rv = CFGA_OK;
 674                                 }
 675                         }
 676                 }
 677 
 678                 if (rs == AP_RSTATE_CONNECTED) {
 679                         if (devctl_ap_disconnect(dcp, NULL) == -1) {
 680                                 rv = CFGA_ERROR;
 681                                 cfga_err(errstring, CMD_SLOT_DISCONNECT, 0);
 682                                 break;
 683                         }
 684                 } else {
 685                         cfga_err(errstring, ERR_AP_ERR, 0);
 686                         rv = CFGA_INVAL;
 687                 }
 688 
 689                 break;
 690 
 691         case CFGA_CMD_CONFIGURE:
 692                 if (rs == AP_RSTATE_DISCONNECTED) {
 693                         if (devctl_ap_connect(dcp, NULL) == -1) {
 694                                 rv = CFGA_ERROR;
 695                                 cfga_err(errstring, CMD_SLOT_CONNECT, 0);
 696                                 break;
 697                         }
 698                 }
 699 
 700                 /*
 701                  * for multi-func device we allow multiple
 702                  * configure on the same slot because one
 703                  * func can be configured and other one won't
 704                  */
 705                 if (devctl_ap_configure(dcp, NULL) == -1) {
 706                         rv = CFGA_ERROR;
 707                         cfga_err(errstring, CMD_SLOT_CONFIGURE, 0);
 708                         if ((rs == AP_RSTATE_DISCONNECTED) &&
 709                                         (devctl_ap_disconnect(dcp, NULL)
 710                                                                 == -1)) {
 711                                 rv = CFGA_ERROR;
 712                                 cfga_err(errstring,
 713                                     CMD_SLOT_CONFIGURE, 0);
 714                         }
 715                         break;
 716                 }
 717 
 718                 break;
 719 
 720         case CFGA_CMD_UNCONFIGURE:
 721                 DBG(1, ("unconfigure\n"));
 722 
 723                 if (os == AP_OSTATE_CONFIGURED) {
 724                         if ((rv = check_rcm(ap_id, &occupants, &rhandle,
 725                             errstring, flags)) == CFGA_BUSY) {
 726                                 break;
 727                         } else if (rv == CFGA_OK) {
 728                                 if (devctl_ap_unconfigure(dcp, NULL) == -1) {
 729                                         if (errno == EBUSY)
 730                                                 rv = CFGA_BUSY;
 731                                         else {
 732                                                 if (errno == ENOTSUP)
 733                                                         rv = CFGA_OPNOTSUPP;
 734                                                 else
 735                                                         rv = CFGA_ERROR;
 736                                         }
 737                                         cfga_err(errstring,
 738                                             CMD_SLOT_UNCONFIGURE, 0);
 739                                         fail_rcm(&occupants, rhandle);
 740                                 } else {
 741                                         confirm_rcm(&occupants, rhandle);
 742                                 }
 743                         } else { /* rv == CFGA_ERROR */
 744                                 if (devctl_ap_unconfigure(dcp, NULL) == -1) {
 745                                         if (errno == EBUSY)
 746                                                 rv = CFGA_BUSY;
 747                                         else {
 748                                                 if (errno == ENOTSUP)
 749                                                         rv = CFGA_OPNOTSUPP;
 750                                                 else
 751                                                         rv = CFGA_ERROR;
 752                                         }
 753                                         cfga_err(errstring,
 754                                             CMD_SLOT_UNCONFIGURE, 0);
 755                                 } else {
 756                                         rv = CFGA_OK;
 757                                 }
 758                         }
 759                 } else {
 760                         cfga_err(errstring, ERR_AP_ERR, 0);
 761                         rv = CFGA_INVAL;
 762                 }
 763 
 764                 DBG(1, ("uncofigure rv:(%i)\n", rv));
 765                 break;
 766 
 767         case CFGA_CMD_LOAD:
 768                 if ((os == AP_OSTATE_UNCONFIGURED) &&
 769                     (rs == AP_RSTATE_DISCONNECTED)) {
 770                         if (devctl_ap_insert(dcp, NULL) == -1) {
 771                                 rv = CFGA_ERROR;
 772                                 cfga_err(errstring, CMD_SLOT_INSERT, 0);
 773                         }
 774                 } else {
 775                         cfga_err(errstring, ERR_AP_ERR, 0);
 776                         rv = CFGA_INVAL;
 777                 }
 778 
 779                 break;
 780 
 781         case CFGA_CMD_UNLOAD:
 782                 if ((os == AP_OSTATE_UNCONFIGURED) &&
 783                     (rs == AP_RSTATE_DISCONNECTED)) {
 784                         if (devctl_ap_remove(dcp, NULL) == -1) {
 785                                 rv = CFGA_ERROR;
 786                                 cfga_err(errstring, CMD_SLOT_REMOVE, 0);
 787                         }
 788                 } else {
 789                                 cfga_err(errstring, ERR_AP_ERR, 0);
 790                                 rv = CFGA_INVAL;
 791                         }
 792 
 793                 break;
 794 
 795         default:
 796                 rv = CFGA_OPNOTSUPP;
 797                 break;
 798         }
 799 
 800         devctl_release((devctl_hdl_t)dcp);
 801         return (rv);
 802 }
 803 
 804 /*
 805  * Building iocdatat to pass it to nexus
 806  *
 807  *      iocdata->cmd ==  HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT
 808  *                      HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG
 809  *                      HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE
 810  *                      HPC_CTRL_GET_SLOT_STATE/HPC_CTRL_GET_SLOT_INFO
 811  *                      HPC_CTRL_DEV_CONFIGURE/HPC_CTRL_DEV_UNCONFIGURE
 812  *                      HPC_CTRL_GET_BOARD_TYPE
 813  *
 814  */
 815 static void
 816 build_control_data(struct hpc_control_data *iocdata, uint_t cmd,
 817     void *retdata)
 818 {
 819         iocdata->cmd = cmd;
 820         iocdata->data = retdata;
 821 }
 822 
 823 /*
 824  * building logical name from ap_id
 825  */
 826 /*ARGSUSED2*/
 827 static void
 828 get_logical_name(const char *ap_id, char *buf, dev_t rdev)
 829 {
 830         char *bufptr, *bufptr2, *pci, *apid;
 831 
 832         DBG(1, ("get_logical_name: %s\n", ap_id));
 833 
 834         if ((apid = malloc(MAXPATHLEN)) == NULL) {
 835                 DBG(1, ("malloc failed\n"));
 836                 return;
 837         }
 838 
 839         (void) memset(apid, 0, MAXPATHLEN);
 840         (void) strncpy(apid, ap_id, strlen(ap_id));
 841 
 842         /* needs to look for last /, not first */
 843         bufptr = strrchr(apid, '/');
 844 
 845         bufptr2 = strrchr(apid, ':');
 846         pci = ++bufptr;
 847         bufptr = strchr(pci, ',');
 848         if (bufptr != NULL) {
 849                 *bufptr = '\0';
 850         }
 851 
 852         bufptr = strchr(pci, '@');
 853         if (bufptr != NULL) {
 854                 *bufptr = '\0';
 855                 bufptr++;
 856         }
 857 
 858         DBG(1, ("%s\n%s\n%s\n", pci, bufptr, bufptr2));
 859 
 860         (void) strcat(buf, pci);
 861         (void) strcat(buf, bufptr);
 862         (void) strcat(buf, bufptr2);
 863         free(apid);
 864 }
 865 
 866 static cfga_err_t
 867 prt_led_mode(const char *ap_id, int repeat, char **errstring,
 868     struct cfga_msg *msgp)
 869 {
 870         hpc_led_info_t  power_led_info = {HPC_POWER_LED, 0};
 871         hpc_led_info_t  fault_led_info = {HPC_FAULT_LED, 0};
 872         hpc_led_info_t  attn_led_info = {HPC_ATTN_LED, 0};
 873         hpc_led_info_t  active_led_info = {HPC_ACTIVE_LED, 0};
 874         struct hpc_control_data iocdata;
 875         struct stat     statbuf;
 876         char  *buff;
 877         int     fd;
 878         hpc_slot_info_t         slot_info;
 879         char *cp, line[MAXLINE];
 880         int len = MAXLINE;
 881 
 882         DBG(1, ("prt_led_mod function\n"));
 883         if (!repeat)
 884                 cfga_msg(msgp, "Ap_Id\t\t\tLed");
 885 
 886         if ((fd = open(ap_id, O_RDWR)) == -1) {
 887                 DBG(2, ("open = ap_id%s, fd%d\n", ap_id, fd));
 888                 DBG_F(2, (stderr, "open on %s failed\n", ap_id));
 889                 cfga_err(errstring, CMD_OPEN,  ap_id, 0);
 890                 return (CFGA_ERROR);
 891         }
 892 
 893         if (fstat(fd, &statbuf) == -1) {
 894                 DBG(2, ("fstat = ap_id%s, fd%d\n", ap_id, fd));
 895                 DBG_F(2, (stderr, "fstat on %s failed\n", ap_id));
 896                 cfga_err(errstring, CMD_FSTAT, ap_id, 0);
 897                 return (CFGA_ERROR);
 898         }
 899 
 900         if ((buff = malloc(MAXPATHLEN)) == NULL) {
 901                 cfga_err(errstring, "malloc ", 0);
 902                 return (CFGA_ERROR);
 903         }
 904 
 905         (void) memset(buff, 0, MAXPATHLEN);
 906 
 907         DBG(1, ("ioctl boardtype\n"));
 908 
 909         build_control_data(&iocdata, HPC_CTRL_GET_SLOT_INFO,
 910             (void *)&slot_info);
 911 
 912         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
 913                 get_logical_name(ap_id, slot_info.pci_slot_name, 0);
 914                 DBG(1, ("ioctl failed slotinfo: %s\n",
 915                     slot_info.pci_slot_name));
 916         } else {
 917 
 918                 /*
 919                  * the driver will report back things like hpc0_slot0
 920                  * this needs to be changed to things like pci1:hpc0_slot0
 921                  */
 922                 if (fix_ap_name(buff, ap_id, slot_info.pci_slot_name,
 923                     errstring) != CFGA_OK) {
 924                         free(buff);
 925                         (void) close(fd);
 926                         return (CFGA_ERROR);
 927                 }
 928                 DBG(1, ("ioctl slotinfo: %s\n", buff));
 929         }
 930 
 931         cp = line;
 932         (void) snprintf(cp, len, "%s\t\t", buff);
 933         len -= strlen(cp);
 934         cp += strlen(cp);
 935 
 936         free(buff);
 937 
 938         build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &power_led_info);
 939         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
 940                 (void) snprintf(cp, len, "%s=%s,",
 941                     led_strs[power_led_info.led], cfga_strs[UNKNOWN]);
 942                 len -= strlen(cp);
 943                 cp += strlen(cp);
 944         } else {
 945                 (void) snprintf(cp, len, "%s=%s,", led_strs[power_led_info.led],
 946                     mode_strs[power_led_info.state]);
 947                 len -= strlen(cp);
 948                 cp += strlen(cp);
 949         }
 950 
 951         DBG(1, ("%s:%d\n", led_strs[power_led_info.led], power_led_info.state));
 952 
 953         build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &fault_led_info);
 954         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
 955                 (void) snprintf(cp, len, "%s=%s,",
 956                     led_strs[fault_led_info.led], cfga_strs[UNKNOWN]);
 957                 len -= strlen(cp);
 958                 cp += strlen(cp);
 959         } else {
 960                 (void) snprintf(cp, len, "%s=%s,",
 961                     led_strs[fault_led_info.led],
 962                     mode_strs[fault_led_info.state]);
 963                 len -= strlen(cp);
 964                 cp += strlen(cp);
 965         }
 966         DBG(1, ("%s:%d\n", led_strs[fault_led_info.led], fault_led_info.state));
 967 
 968         build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &attn_led_info);
 969         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
 970                 (void) snprintf(cp, len, "%s=%s,",
 971                     led_strs[attn_led_info.led], cfga_strs[UNKNOWN]);
 972                 len -= strlen(cp);
 973                 cp += strlen(cp);
 974         } else {
 975                 (void) snprintf(cp, len, "%s=%s,",
 976                     led_strs[attn_led_info.led],
 977                     mode_strs[attn_led_info.state]);
 978                 len -= strlen(cp);
 979                 cp += strlen(cp);
 980         }
 981         DBG(1, ("%s:%d\n", led_strs[attn_led_info.led], attn_led_info.state));
 982 
 983         build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &active_led_info);
 984         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
 985                 (void) snprintf(cp, len, "%s=%s", led_strs[active_led_info.led],
 986                     cfga_strs[UNKNOWN]);
 987         } else {
 988                 (void) snprintf(cp, len, "%s=%s",
 989                     led_strs[active_led_info.led],
 990                     mode_strs[active_led_info.state]);
 991         }
 992         cfga_msg(msgp, line);   /* print the message */
 993         DBG(1, ("%s:%d\n", led_strs[active_led_info.led],
 994             active_led_info.state));
 995 
 996         (void) close(fd);
 997 
 998         return (CFGA_OK);
 999 }
1000 
1001 /*ARGSUSED*/
1002 cfga_err_t
1003 cfga_private_func(const char *function, const char *ap_id,
1004     const char *options, struct cfga_confirm *confp,
1005     struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
1006 {
1007         char *str;
1008         int   len, fd, i = 0, repeat = 0;
1009         char buf[MAXNAMELEN];
1010         char ptr;
1011         hpc_led_info_t  led_info;
1012         struct hpc_control_data iocdata;
1013         cfga_err_t rv;
1014 
1015         DBG(1, ("cfgadm_private_func: ap_id:%s\n", ap_id));
1016         DBG(2, ("  options: %s\n", (options == NULL)?"null":options));
1017         DBG(2, ("  confp: %x\n", confp));
1018         DBG(2, ("  cfga_msg: %x\n", cfga_msg));
1019         DBG(2, ("  flag: %d\n", flags));
1020 
1021         if ((rv = check_options(options)) != CFGA_OK) {
1022                 return (rv);
1023         }
1024 
1025         if (private_check == confp)
1026                 repeat = 1;
1027         else
1028                 private_check = (void*)confp;
1029 
1030         /* XXX change const 6 to func_str[i] != NULL */
1031         for (i = 0, str = func_strs[i], len = strlen(str); i < 6; i++) {
1032                 str = func_strs[i];
1033                 len = strlen(str);
1034                 if (strncmp(function, str, len) == 0)
1035                         break;
1036         }
1037 
1038         switch (i) {
1039                 case ENABLE_SLOT:
1040                         build_control_data(&iocdata,
1041                                 HPC_CTRL_ENABLE_SLOT, 0);
1042                         break;
1043                 case DISABLE_SLOT:
1044                         build_control_data(&iocdata,
1045                                 HPC_CTRL_DISABLE_SLOT, 0);
1046                         break;
1047                 case ENABLE_AUTOCNF:
1048                         build_control_data(&iocdata,
1049                                 HPC_CTRL_ENABLE_AUTOCFG, 0);
1050                         break;
1051                 case DISABLE_AUTOCNF:
1052                         build_control_data(&iocdata,
1053                                 HPC_CTRL_DISABLE_AUTOCFG, 0);
1054                         break;
1055                 case LED:
1056                         /* set mode */
1057                         ptr = function[len++];
1058                         if (ptr == '=') {
1059                                 str = (char *)function;
1060                                 for (str = (str+len++), i = 0; *str != ',';
1061                                     i++, str++) {
1062                                         if (i == (MAXNAMELEN - 1))
1063                                                 break;
1064 
1065                                         buf[i] = *str;
1066                                         DBG_F(2, (stdout, "%c\n", buf[i]));
1067                                 }
1068                                 buf[i] = '\0'; str++;
1069                                 DBG(2, ("buf = %s\n", buf));
1070 
1071                                 /* ACTIVE=3,ATTN=2,POWER=1,FAULT=0 */
1072                                 if (strcmp(buf, led_strs[POWER]) == 0)
1073                                         led_info.led = HPC_POWER_LED;
1074                                 else if (strcmp(buf, led_strs[FAULT]) == 0)
1075                                         led_info.led = HPC_FAULT_LED;
1076                                 else if (strcmp(buf, led_strs[ATTN]) == 0)
1077                                         led_info.led = HPC_ATTN_LED;
1078                                 else if (strcmp(buf, led_strs[ACTIVE]) == 0)
1079                                         led_info.led = HPC_ACTIVE_LED;
1080                                 else return (CFGA_INVAL);
1081 
1082                                 len = strlen(func_strs[MODE]);
1083                                 if ((strncmp(str, func_strs[MODE], len) == 0) &&
1084                                     (*(str+(len)) == '=')) {
1085                                     for (str = (str+(++len)), i = 0;
1086                                         *str != NULL; i++, str++) {
1087                                                 buf[i] = *str;
1088 
1089                                     }
1090                                 }
1091                                 buf[i] = '\0';
1092                                 DBG(2, ("buf_mode= %s\n", buf));
1093 
1094                                 /* ON = 1, OFF = 0 */
1095                                 if (strcmp(buf, mode_strs[ON]) == 0)
1096                                         led_info.state = HPC_LED_ON;
1097                                 else if (strcmp(buf, mode_strs[OFF]) == 0)
1098                                         led_info.state = HPC_LED_OFF;
1099                                 else if (strcmp(buf, mode_strs[BLINK]) == 0)
1100                                         led_info.state = HPC_LED_BLINK;
1101                                 else return (CFGA_INVAL);
1102 
1103                                 /* sendin  */
1104                                 build_control_data(&iocdata,
1105                                     HPC_CTRL_SET_LED_STATE,
1106                                     (void *)&led_info);
1107                                 break;
1108                         } else if (ptr == '\0') {
1109                                 /* print mode */
1110                                 DBG(1, ("Print mode\n"));
1111                                 return (prt_led_mode(ap_id, repeat, errstring,
1112                                     msgp));
1113                         }
1114                 default:
1115                         DBG(1, ("default\n"));
1116                         errno = EINVAL;
1117                         return (CFGA_INVAL);
1118         }
1119 
1120         if ((fd = open(ap_id, O_RDWR)) == -1) {
1121                 DBG(1, ("open failed\n"));
1122                 return (CFGA_ERROR);
1123         }
1124 
1125         DBG(1, ("open = ap_id=%s, fd=%d\n", ap_id, fd));
1126 
1127         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
1128                 DBG(1, ("ioctl failed\n"));
1129                 (void) close(fd);
1130                 return (CFGA_ERROR);
1131         }
1132 
1133         (void) close(fd);
1134 
1135         return (CFGA_OK);
1136 }
1137 
1138 /*ARGSUSED*/
1139 cfga_err_t cfga_test(const char *ap_id, const char *options,
1140     struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
1141 {
1142         cfga_err_t rv;
1143         if (errstring != NULL)
1144                 *errstring = NULL;
1145 
1146         if ((rv = check_options(options)) != CFGA_OK) {
1147                 return (rv);
1148         }
1149 
1150         DBG(1, ("cfga_test:(%s)\n", ap_id));
1151         /* will need to implement pci CTRL command */
1152         return (CFGA_NOTSUPP);
1153 }
1154 
1155 static int
1156 fixup_slotname(int rval, int *intp, struct searcharg *slotarg)
1157 {
1158 
1159 /*
1160  * The slot-names property describes the external labeling of add-in slots.
1161  * This property is an encoded array, an integer followed by a list of
1162  * strings. The return value from di_prop_lookup_ints for slot-names is -1.
1163  * The expected return value should be the number of elements.
1164  * Di_prop_decode_common does not decode encoded data from software,
1165  * such as the solaris device tree, unlike from the prom.
1166  * Di_prop_decode_common takes the size of the encoded data and mods
1167  * it with the size of int. The size of the encoded data for slot-names is 9
1168  * and the size of int is 4, yielding a non zero result. A value of -1 is used
1169  * to indicate that the number of elements can not be determined.
1170  * Di_prop_decode_common can be modified to decode encoded data from the solaris
1171  * device tree.
1172  */
1173 
1174         if ((slotarg->slt_name_src == PROM_SLT_NAME) && (rval == -1)) {
1175                 return (DI_WALK_TERMINATE);
1176         } else {
1177                 int i;
1178                 char *tmptr = (char *)(intp+1);
1179                 DBG(1, ("slot-bitmask: %x \n", *intp));
1180 
1181                 rval = (rval -1) * 4;
1182 
1183                 for (i = 0; i <= slotarg->minor; i++) {
1184                         DBG(2, ("curr slot-name: %s \n", tmptr));
1185 
1186                         if (i >= MAXDEVS)
1187                                 return (DI_WALK_TERMINATE);
1188 
1189                         if ((*intp >> i) & 1) {
1190                                 /* assign tmptr */
1191                                 DBG(2, ("slot-name: %s \n", tmptr));
1192                                 if (i == slotarg->minor)
1193                                         (void) strcpy(slotarg->slotnames[i],
1194                                             tmptr);
1195                                 /* wind tmptr to next \0 */
1196                                 while (*tmptr != '\0') {
1197                                         tmptr++;
1198                                 }
1199                                 tmptr++;
1200                         } else {
1201                                 /* point at unknown string */
1202                                 if (i == slotarg->minor)
1203                                         (void) strcpy(slotarg->slotnames[i],
1204                                             "unknown");
1205                         }
1206                 }
1207         }
1208         return (DI_WALK_TERMINATE);
1209 }
1210 
1211 static int
1212 find_slotname(di_node_t din, di_minor_t dim, void *arg)
1213 {
1214         struct searcharg *slotarg = (struct searcharg *)arg;
1215         di_prom_handle_t ph = (di_prom_handle_t)slotarg->promp;
1216         di_prom_prop_t  prom_prop;
1217         di_prop_t       solaris_prop;
1218         int *intp, rval;
1219         char *devname;
1220         char fulldevname[MAXNAMELEN];
1221 
1222         slotarg->minor = dim->dev_minor % 256;
1223 
1224         DBG(2, ("minor number:(%i)\n", slotarg->minor));
1225         DBG(2, ("hot plug slots found so far:(%i)\n", 0));
1226 
1227         if ((devname = di_devfs_path(din)) != NULL) {
1228                 (void) snprintf(fulldevname, MAXNAMELEN,
1229                     "/devices%s:%s", devname, di_minor_name(dim));
1230                 di_devfs_path_free(devname);
1231         }
1232 
1233         if (strcmp(fulldevname, slotarg->devpath) == 0) {
1234 
1235                 /*
1236                  * Check the Solaris device tree first
1237                  * in the case of a DR operation
1238                  */
1239                 solaris_prop = di_prop_hw_next(din, DI_PROP_NIL);
1240                 while (solaris_prop != DI_PROP_NIL) {
1241                         if (strcmp("slot-names", di_prop_name(solaris_prop))
1242                             == 0) {
1243                                 rval = di_prop_lookup_ints(DDI_DEV_T_ANY,
1244                                     din, di_prop_name(solaris_prop), &intp);
1245                                 slotarg->slt_name_src = SOLARIS_SLT_NAME;
1246 
1247                                 return (fixup_slotname(rval, intp, slotarg));
1248                         }
1249                         solaris_prop = di_prop_hw_next(din, solaris_prop);
1250                 }
1251 
1252                 /*
1253                  * Check the prom device tree which is populated at boot.
1254                  * If this fails, give up and set the slot name to null.
1255                  */
1256                 prom_prop = di_prom_prop_next(ph, din, DI_PROM_PROP_NIL);
1257                 while (prom_prop != DI_PROM_PROP_NIL) {
1258                         if (strcmp("slot-names", di_prom_prop_name(prom_prop))
1259                             == 0) {
1260                                 rval = di_prom_prop_lookup_ints(ph,
1261                                     din, di_prom_prop_name(prom_prop), &intp);
1262                                 slotarg->slt_name_src = PROM_SLT_NAME;
1263 
1264                                 return (fixup_slotname(rval, intp, slotarg));
1265                         }
1266                         prom_prop = di_prom_prop_next(ph, din, prom_prop);
1267                 }
1268                 *slotarg->slotnames[slotarg->minor] = '\0';
1269                 return (DI_WALK_TERMINATE);
1270         } else
1271                 return (DI_WALK_CONTINUE);
1272 }
1273 
1274 static int
1275 find_physical_slot_names(const char *devcomp, struct searcharg *slotarg)
1276 {
1277         di_node_t root_node;
1278 
1279         DBG(1, ("find_physical_slot_names\n"));
1280 
1281         if ((root_node = di_init("/", DINFOCPYALL|DINFOPATH))
1282                 == DI_NODE_NIL) {
1283                 DBG(1, ("di_init() failed\n"));
1284                 return (NULL);
1285         }
1286 
1287         slotarg->devpath = (char *)devcomp;
1288 
1289         if ((slotarg->promp = di_prom_init()) == DI_PROM_HANDLE_NIL) {
1290                 DBG(1, ("di_prom_init() failed\n"));
1291                 di_fini(root_node);
1292                 return (NULL);
1293         }
1294 
1295         (void) di_walk_minor(root_node, "ddi_ctl:attachment_point:pci",
1296                 0, (void *)slotarg, find_slotname);
1297 
1298         di_prom_fini(slotarg->promp);
1299         di_fini(root_node);
1300         if (slotarg->slotnames[0] != NULL)
1301                 return (0);
1302         else
1303                 return (-1);
1304 }
1305 
1306 static void
1307 get_type(hpc_board_type_t boardtype, hpc_card_info_t cardinfo, char *buf)
1308 {
1309         int i;
1310 
1311         DBG(1, ("class: %i\n", cardinfo.base_class));
1312         DBG(1, ("subclass: %i\n", cardinfo.sub_class));
1313 
1314         if (cardinfo.base_class == PCI_CLASS_NONE) {
1315                 TPCT("unknown");
1316                 return;
1317         }
1318 
1319         for (i = 0; i < class_pci_items; i++) {
1320                 if ((cardinfo.base_class == class_pci[i].base_class) &&
1321                     (cardinfo.sub_class == class_pci[i].sub_class) &&
1322                     (cardinfo.prog_class == class_pci[i].prog_class)) {
1323                         TPCT(class_pci[i].short_desc);
1324                         break;
1325                 }
1326         }
1327 
1328         if (i == class_pci_items)
1329                 TPCT("unknown");
1330 
1331         TPCT("/");
1332         switch (boardtype) {
1333         case HPC_BOARD_PCI_HOTPLUG:
1334         case HPC_BOARD_CPCI_NON_HS:
1335         case HPC_BOARD_CPCI_BASIC_HS:
1336         case HPC_BOARD_CPCI_FULL_HS:
1337         case HPC_BOARD_CPCI_HS:
1338                 TPCT(board_strs[boardtype]);
1339                 break;
1340         case HPC_BOARD_UNKNOWN:
1341         default:
1342                 TPCT(board_strs[HPC_BOARD_UNKNOWN]);
1343         }
1344 }
1345 
1346 /*
1347  * call-back function for di_devlink_walk
1348  * if the link lives in /dev/cfg copy its name
1349  */
1350 static int
1351 found_devlink(di_devlink_t link, void *ap_log_id)
1352 {
1353         if (strncmp("/dev/cfg/", di_devlink_path(link), 9) == 0) {
1354                 /* copy everything but /dev/cfg/ */
1355                 (void) strcpy((char *)ap_log_id, di_devlink_path(link) + 9);
1356                 DBG(1, ("found_devlink: %s\n", (char *)ap_log_id));
1357                 return (DI_WALK_TERMINATE);
1358         }
1359         return (DI_WALK_CONTINUE);
1360 }
1361 
1362 /*
1363  * Walk throught the cached /dev link tree looking for links to the ap
1364  * if none are found return an error
1365  */
1366 static cfga_err_t
1367 check_devlinks(char *ap_log_id, const char *ap_id)
1368 {
1369         di_devlink_handle_t hdl;
1370 
1371         DBG(1, ("check_devlinks: %s\n", ap_id));
1372 
1373         hdl = di_devlink_init(NULL, 0);
1374 
1375         if (strncmp("/devices/", ap_id, 9) == 0) {
1376                 /* ap_id is a valid minor_path with /devices prepended */
1377                 (void) di_devlink_walk(hdl, NULL, ap_id + 8, DI_PRIMARY_LINK,
1378                     (void *)ap_log_id, found_devlink);
1379         } else {
1380                 DBG(1, ("check_devlinks: invalid ap_id: %s\n", ap_id));
1381                 return (CFGA_ERROR);
1382         }
1383 
1384         (void) di_devlink_fini(&hdl);
1385 
1386         if (ap_log_id[0] != '\0')
1387                 return (CFGA_OK);
1388         else
1389                 return (CFGA_ERROR);
1390 }
1391 
1392 /*
1393  * most of this is needed to compensate for
1394  * differences between various platforms
1395  */
1396 static cfga_err_t
1397 fix_ap_name(char *ap_log_id, const char *ap_id, char *slot_name,
1398     char **errstring)
1399 {
1400         char *buf;
1401         char *tmp;
1402         char *ptr;
1403 
1404         di_node_t ap_node;
1405 
1406         ap_log_id[0] = '\0';
1407 
1408         if (check_devlinks(ap_log_id, ap_id) == CFGA_OK)
1409                 return (CFGA_OK);
1410 
1411         DBG(1, ("fix_ap_name: %s\n", ap_id));
1412 
1413         if ((buf = malloc(strlen(ap_id) + 1)) == NULL) {
1414                 DBG(1, ("malloc failed\n"));
1415                 return (CFGA_ERROR);
1416         }
1417         (void) strcpy(buf, ap_id);
1418         tmp = buf + sizeof ("/devices") - 1;
1419 
1420         ptr = strchr(tmp, ':');
1421         ptr[0] = '\0';
1422 
1423         DBG(1, ("fix_ap_name: %s\n", tmp));
1424 
1425         ap_node = di_init(tmp, DINFOMINOR);
1426         if (ap_node == DI_NODE_NIL) {
1427                 cfga_err(errstring, "di_init ", 0);
1428                 DBG(1, ("fix_ap_name: failed to snapshot node\n"));
1429                 return (CFGA_ERROR);
1430         }
1431 
1432         (void) snprintf(ap_log_id, strlen(ap_id) + 1, "%s%i:%s",
1433             di_driver_name(ap_node), di_instance(ap_node), slot_name);
1434 
1435         DBG(1, ("fix_ap_name: %s\n", ap_log_id));
1436 
1437         di_fini(ap_node);
1438 
1439         free(buf);
1440         return (CFGA_OK);
1441 }
1442 
1443 
1444 static int
1445 findlink_cb(di_devlink_t devlink, void *arg)
1446 {
1447         (*(char **)arg) = strdup(di_devlink_path(devlink));
1448 
1449         return (DI_WALK_TERMINATE);
1450 }
1451 
1452 /*
1453  * returns an allocated string containing the full path to the devlink for
1454  * <ap_phys_id> in the devlink database; we expect only one devlink per
1455  * <ap_phys_id> so we return the first encountered
1456  */
1457 static char *
1458 findlink(char *ap_phys_id)
1459 {
1460         di_devlink_handle_t hdl;
1461         char *path = NULL;
1462 
1463         hdl = di_devlink_init(NULL, 0);
1464 
1465         if (strncmp("/devices/", ap_phys_id, 9) == 0)
1466                 ap_phys_id += 8;
1467 
1468         (void) di_devlink_walk(hdl, "^cfg/.+$", ap_phys_id, DI_PRIMARY_LINK,
1469             (void *)&path, findlink_cb);
1470 
1471         (void) di_devlink_fini(&hdl);
1472         return (path);
1473 }
1474 
1475 
1476 /*
1477  * returns CFGA_OK if it can succesfully retrieve the devlink info associated
1478  * with devlink for <ap_phys_id> which will be returned through <ap_info>
1479  */
1480 cfga_err_t
1481 get_dli(char *dlpath, char *ap_info, int ap_info_sz)
1482 {
1483         int fd;
1484 
1485         fd = di_dli_openr(dlpath);
1486         if (fd < 0)
1487                 return (CFGA_ERROR);
1488 
1489         (void) read(fd, ap_info, ap_info_sz);
1490         ap_info[ap_info_sz - 1] = '\0';
1491 
1492         di_dli_close(fd);
1493         return (CFGA_OK);
1494 }
1495 
1496 
1497 /*ARGSUSED*/
1498 cfga_err_t
1499 cfga_list_ext(const char *ap_id, cfga_list_data_t **cs,
1500     int *nlist, const char *options, const char *listopts, char **errstring,
1501     cfga_flags_t flags)
1502 {
1503         devctl_hdl_t            dcp;
1504         struct hpc_control_data iocdata;
1505         devctl_ap_state_t       state;
1506         hpc_board_type_t        boardtype;
1507         hpc_card_info_t         cardinfo;
1508         hpc_slot_info_t         slot_info;
1509         struct  searcharg       slotname_arg;
1510         int                     fd;
1511         int                     rv = CFGA_OK;
1512         char                    *dlpath = NULL;
1513 
1514         if ((rv = check_options(options)) != CFGA_OK) {
1515                 return (rv);
1516         }
1517 
1518         if (errstring != NULL)
1519                 *errstring = NULL;
1520 
1521         (void) memset(&slot_info, 0, sizeof (hpc_slot_info_t));
1522 
1523         DBG(1, ("cfga_list_ext:(%s)\n", ap_id));
1524 
1525         if (cs == NULL || nlist == NULL) {
1526                 rv = CFGA_ERROR;
1527                 return (rv);
1528         }
1529 
1530         *nlist = 1;
1531 
1532         if ((*cs = malloc(sizeof (cfga_list_data_t))) == NULL) {
1533                 cfga_err(errstring, "malloc ", 0);
1534                 DBG(1, ("malloc failed\n"));
1535                 rv = CFGA_ERROR;
1536                 return (rv);
1537         }
1538         (void) memset(*cs, 0, sizeof (cfga_list_data_t));
1539 
1540         if ((dcp = devctl_ap_acquire((char *)ap_id, 0)) == NULL) {
1541                 cfga_err(errstring, CMD_GETSTAT, 0);
1542                 DBG(2, ("cfga_list_ext::(devctl_ap_acquire())\n"));
1543                 rv = CFGA_ERROR;
1544                 return (rv);
1545         }
1546 
1547         if (devctl_ap_getstate(dcp, NULL, &state) == -1) {
1548                 cfga_err(errstring, ERR_AP_ERR, ap_id, 0);
1549                 devctl_release((devctl_hdl_t)dcp);
1550                 DBG(2, ("cfga_list_ext::(devctl_ap_getstate())\n"));
1551                 rv = CFGA_ERROR;
1552                 return (rv);
1553         }
1554 
1555         switch (state.ap_rstate) {
1556                 case AP_RSTATE_EMPTY:
1557                         (*cs)->ap_r_state = CFGA_STAT_EMPTY;
1558                         DBG(2, ("ap_rstate = CFGA_STAT_EMPTY\n"));
1559                         break;
1560                 case AP_RSTATE_DISCONNECTED:
1561                         (*cs)->ap_r_state = CFGA_STAT_DISCONNECTED;
1562                         DBG(2, ("ap_rstate = CFGA_STAT_DISCONNECTED\n"));
1563                         break;
1564                 case AP_RSTATE_CONNECTED:
1565                         (*cs)->ap_r_state = CFGA_STAT_CONNECTED;
1566                         DBG(2, ("ap_rstate = CFGA_STAT_CONNECTED\n"));
1567                         break;
1568         default:
1569                 cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
1570                 rv = CFGA_ERROR;
1571                 devctl_release((devctl_hdl_t)dcp);
1572                 return (rv);
1573         }
1574 
1575         switch (state.ap_ostate) {
1576                 case AP_OSTATE_CONFIGURED:
1577                         (*cs)->ap_o_state = CFGA_STAT_CONFIGURED;
1578                         DBG(2, ("ap_ostate = CFGA_STAT_CONFIGURED\n"));
1579                         break;
1580                 case AP_OSTATE_UNCONFIGURED:
1581                         (*cs)->ap_o_state = CFGA_STAT_UNCONFIGURED;
1582                         DBG(2, ("ap_ostate = CFGA_STAT_UNCONFIGURED\n"));
1583                         break;
1584         default:
1585                 cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
1586                 rv = CFGA_ERROR;
1587                 devctl_release((devctl_hdl_t)dcp);
1588                 return (rv);
1589         }
1590 
1591         switch (state.ap_condition) {
1592                 case AP_COND_OK:
1593                         (*cs)->ap_cond = CFGA_COND_OK;
1594                         DBG(2, ("ap_cond = CFGA_COND_OK\n"));
1595                         break;
1596                 case AP_COND_FAILING:
1597                         (*cs)->ap_cond = CFGA_COND_FAILING;
1598                         DBG(2, ("ap_cond = CFGA_COND_FAILING\n"));
1599                         break;
1600                 case AP_COND_FAILED:
1601                         (*cs)->ap_cond = CFGA_COND_FAILED;
1602                         DBG(2, ("ap_cond = CFGA_COND_FAILED\n"));
1603                         break;
1604                 case AP_COND_UNUSABLE:
1605                         (*cs)->ap_cond = CFGA_COND_UNUSABLE;
1606                         DBG(2, ("ap_cond = CFGA_COND_UNUSABLE\n"));
1607                         break;
1608                 case AP_COND_UNKNOWN:
1609                         (*cs)->ap_cond = CFGA_COND_UNKNOWN;
1610                         DBG(2, ("ap_cond = CFGA_COND_UNKNOW\n"));
1611                         break;
1612         default:
1613                 cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
1614                 rv = CFGA_ERROR;
1615                 devctl_release((devctl_hdl_t)dcp);
1616                 return (rv);
1617         }
1618         (*cs)->ap_busy = (int)state.ap_in_transition;
1619 
1620         devctl_release((devctl_hdl_t)dcp);
1621 
1622         if ((fd = open(ap_id, O_RDWR)) == -1) {
1623                 cfga_err(errstring, ERR_AP_ERR, ap_id, 0);
1624                 (*cs)->ap_status_time = 0;
1625                 boardtype = HPC_BOARD_UNKNOWN;
1626                 cardinfo.base_class = PCI_CLASS_NONE;
1627                 get_logical_name(ap_id, slot_info.pci_slot_name, 0);
1628                 DBG(2, ("open on %s failed\n", ap_id));
1629                 goto cont;
1630         }
1631         DBG(1, ("open = ap_id=%s, fd=%d\n", ap_id, fd));
1632 
1633         (*cs)->ap_status_time = state.ap_last_change;
1634 
1635         /* need board type and a way to get to hpc_slot_info */
1636         build_control_data(&iocdata, HPC_CTRL_GET_BOARD_TYPE,
1637             (void *)&boardtype);
1638 
1639         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
1640                 boardtype = HPC_BOARD_UNKNOWN;
1641         }
1642         DBG(1, ("ioctl boardtype\n"));
1643 
1644         build_control_data(&iocdata, HPC_CTRL_GET_SLOT_INFO,
1645             (void *)&slot_info);
1646 
1647         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
1648                 get_logical_name(ap_id, slot_info.pci_slot_name, 0);
1649                 DBG(1, ("ioctl failed slotinfo: %s\n",
1650                     slot_info.pci_slot_name));
1651         } else {
1652 
1653                 /*
1654                  * the driver will report back things like hpc0_slot0
1655                  * this needs to be changed to things like pci1:hpc0_slot0
1656                  */
1657                 rv = fix_ap_name((*cs)->ap_log_id,
1658                     ap_id, slot_info.pci_slot_name, errstring);
1659                 DBG(1, ("ioctl slotinfo: %s\n", (*cs)->ap_log_id));
1660         }
1661 
1662         build_control_data(&iocdata, HPC_CTRL_GET_CARD_INFO,
1663             (void *)&cardinfo);
1664 
1665         if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) {
1666                 DBG(1, ("ioctl failed\n"));
1667                 cardinfo.base_class = PCI_CLASS_NONE;
1668         }
1669 
1670         DBG(1, ("ioctl cardinfo: %d\n", cardinfo.base_class));
1671         DBG(1, ("ioctl subclass: %d\n", cardinfo.sub_class));
1672         DBG(1, ("ioctl headertype: %d\n", cardinfo.header_type));
1673 
1674         (void) close(fd);
1675 
1676 cont:
1677         (void) strcpy((*cs)->ap_phys_id, ap_id);    /* physical path of AP */
1678 
1679         dlpath = findlink((*cs)->ap_phys_id);
1680         if (dlpath != NULL) {
1681                 if (get_dli(dlpath, (*cs)->ap_info,
1682                     sizeof ((*cs)->ap_info)) != CFGA_OK)
1683                         (*cs)->ap_info[0] = '\0';
1684                 free(dlpath);
1685         }
1686 
1687         if ((*cs)->ap_log_id[0] == '\0')
1688                 (void) strcpy((*cs)->ap_log_id, slot_info.pci_slot_name);
1689 
1690         if ((*cs)->ap_info[0] == '\0') {
1691                 /* slot_names of bus node  */
1692                 if (find_physical_slot_names(ap_id, &slotname_arg) != -1)
1693                         (void) strcpy((*cs)->ap_info,
1694                             slotname_arg.slotnames[slotname_arg.minor]);
1695         }
1696 
1697         /* class_code/subclass/boardtype */
1698         get_type(boardtype, cardinfo, (*cs)->ap_type);
1699 
1700         DBG(1, ("cfga_list_ext return success\n"));
1701         rv = CFGA_OK;
1702 
1703         return (rv);
1704 }
1705 
1706 /*
1707  * This routine prints a single line of help message
1708  */
1709 static void
1710 cfga_msg(struct cfga_msg *msgp, const char *str)
1711 {
1712         DBG(2, ("<%s>", str));
1713 
1714         if (msgp == NULL || msgp->message_routine == NULL)
1715                 return;
1716 
1717         (*msgp->message_routine)(msgp->appdata_ptr, str);
1718         (*msgp->message_routine)(msgp->appdata_ptr, "\n");
1719 }
1720 
1721 static cfga_err_t
1722 check_options(const char *options)
1723 {
1724         struct cfga_msg *msgp = NULL;
1725 
1726         if (options) {
1727                 cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN]));
1728                 cfga_msg(msgp, options);
1729                 return (CFGA_INVAL);
1730         }
1731         return (CFGA_OK);
1732 }
1733 
1734 /*ARGSUSED*/
1735 cfga_err_t
1736 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1737 {
1738         if (options) {
1739                 cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN]));
1740                 cfga_msg(msgp, options);
1741         }
1742         DBG(1, ("cfga_help\n"));
1743 
1744         cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_HEADER]));
1745         cfga_msg(msgp, cfga_strs[HELP_CONFIG]);
1746         cfga_msg(msgp, cfga_strs[HELP_ENABLE_SLOT]);
1747         cfga_msg(msgp, cfga_strs[HELP_DISABLE_SLOT]);
1748         cfga_msg(msgp, cfga_strs[HELP_ENABLE_AUTOCONF]);
1749         cfga_msg(msgp, cfga_strs[HELP_DISABLE_AUTOCONF]);
1750         cfga_msg(msgp, cfga_strs[HELP_LED_CNTRL]);
1751         return (CFGA_OK);
1752 }
1753 
1754 /*
1755  * cfga_err() accepts a variable number of message IDs and constructs
1756  * a corresponding error string which is returned via the errstring argument.
1757  * cfga_err() calls gettext() to internationalize proper messages.
1758  */
1759 static void
1760 cfga_err(char **errstring, ...)
1761 {
1762         int a;
1763         int i;
1764         int n;
1765         int len;
1766         int flen;
1767         char *p;
1768         char *q;
1769         char *s[32];
1770         char *failed;
1771         va_list ap;
1772 
1773         /*
1774          * If errstring is null it means user in not interested in getting
1775          * error status. So we don't do all the work
1776          */
1777         if (errstring == NULL) {
1778                 return;
1779         }
1780         va_start(ap, errstring);
1781 
1782         failed = dgettext(TEXT_DOMAIN, cfga_strs[FAILED]);
1783         flen = strlen(failed);
1784 
1785         for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
1786                 switch (a) {
1787                 case CMD_GETSTAT:
1788                 case CMD_LIST:
1789                 case CMD_SLOT_CONNECT:
1790                 case CMD_SLOT_DISCONNECT:
1791                 case CMD_SLOT_CONFIGURE:
1792                 case CMD_SLOT_UNCONFIGURE:
1793                         p =  cfga_errstrs(a);
1794                         len += (strlen(p) + flen);
1795                         s[n] = p;
1796                         s[++n] = cfga_strs[FAILED];
1797 
1798                         DBG(2, ("<%s>", p));
1799                         DBG(2, (cfga_strs[FAILED]));
1800                         break;
1801 
1802                 case ERR_CMD_INVAL:
1803                 case ERR_AP_INVAL:
1804                 case ERR_OPT_INVAL:
1805                 case ERR_AP_ERR:
1806                         switch (a) {
1807                         case ERR_CMD_INVAL:
1808                                 p = dgettext(TEXT_DOMAIN,
1809                                     cfga_errstrs[ERR_CMD_INVAL]);
1810                                 break;
1811                         case ERR_AP_INVAL:
1812                                 p = dgettext(TEXT_DOMAIN,
1813                                     cfga_errstrs[ERR_AP_INVAL]);
1814                                 break;
1815                         case ERR_OPT_INVAL:
1816                                 p = dgettext(TEXT_DOMAIN,
1817                                     cfga_errstrs[ERR_OPT_INVAL]);
1818                                 break;
1819                         case ERR_AP_ERR:
1820                                 p = dgettext(TEXT_DOMAIN,
1821                                     cfga_errstrs[ERR_AP_ERR]);
1822                                 break;
1823                         }
1824 
1825                         if ((q = va_arg(ap, char *)) != NULL) {
1826                                 len += (strlen(p) + strlen(q));
1827                                 s[n] = p;
1828                                 s[++n] = q;
1829                                 DBG(2, ("<%s>", p));
1830                                 DBG(2, ("<%s>", q));
1831                                 break;
1832                         } else {
1833                                 len += strlen(p);
1834                                 s[n] = p;
1835 
1836                         }
1837                         DBG(2, ("<%s>", p));
1838                         break;
1839 
1840                 default:
1841                         n--;
1842                         break;
1843                 }
1844         }
1845 
1846         DBG(2, ("\n"));
1847         va_end(ap);
1848 
1849         if ((p = calloc(len + 1, 1)) == NULL)
1850                 return;
1851 
1852         for (i = 0; i < n; i++) {
1853                 (void) strlcat(p, s[i], len + 1);
1854                 DBG(2, ("i:%d, %s\n", i, s[i]));
1855         }
1856 
1857         *errstring = p;
1858 #ifdef  DEBUG
1859         printf("%s\n", *errstring);
1860         free(*errstring);
1861 #endif
1862 }
1863 
1864 /*
1865  * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
1866  */