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