4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
35 #include <config_admin.h>
37 #include <sys/types.h>
38 #include <sys/mkdev.h>
39 #include <sys/hotplug/pci/pcihp.h>
42 #define dprint(args) devfsadm_errprint args
44 * for use in print routine arg list as a shorthand way to locate node via
45 * "prtconf -D" to avoid messy and cluttered debugging code
46 * don't forget the corresponding "%s%d" format
48 #define DRVINST(node) di_driver_name(node), di_instance(node)
54 static int scsi_cfg_creat_cb(di_minor_t minor
, di_node_t node
);
55 static int sbd_cfg_creat_cb(di_minor_t minor
, di_node_t node
);
56 static int usb_cfg_creat_cb(di_minor_t minor
, di_node_t node
);
57 static char *get_roothub(const char *path
, void *cb_arg
);
58 static int pci_cfg_creat_cb(di_minor_t minor
, di_node_t node
);
59 static int ib_cfg_creat_cb(di_minor_t minor
, di_node_t node
);
60 static int sata_cfg_creat_cb(di_minor_t minor
, di_node_t node
);
61 static int sdcard_cfg_creat_cb(di_minor_t minor
, di_node_t node
);
63 static di_node_t
pci_cfg_chassis_node(di_node_t
, di_prom_handle_t
);
64 static char *pci_cfg_slotname(di_node_t
, di_prom_handle_t
, minor_t
);
65 static int pci_cfg_ap_node(minor_t
, di_node_t
, di_prom_handle_t
,
67 static int pci_cfg_iob_name(di_minor_t
, di_node_t
, di_prom_handle_t
,
69 static minor_t
pci_cfg_pcidev(di_node_t
, di_prom_handle_t
);
70 static int pci_cfg_ap_path(di_minor_t
, di_node_t
, di_prom_handle_t
,
71 char *, int, char **);
72 static char *pci_cfg_info_data(char *);
73 static int pci_cfg_is_ap_path(di_node_t
, di_prom_handle_t
);
74 static int pci_cfg_ap_legacy(di_minor_t
, di_node_t
, di_prom_handle_t
,
76 static void pci_cfg_rm_invalid_links(char *, char *);
77 static void pci_cfg_rm_link(char *);
78 static void pci_cfg_rm_all(char *);
79 static char *pci_cfg_devpath(di_node_t
, di_minor_t
);
80 static di_node_t
pci_cfg_snapshot(di_node_t
, di_minor_t
,
81 di_node_t
*, di_minor_t
*);
83 /* flag definitions for di_propall_*(); value "0" is always the default flag */
84 #define DIPROP_PRI_NODE 0x0
85 #define DIPROP_PRI_PROM 0x1
86 static int di_propall_lookup_ints(di_prom_handle_t
, int,
87 dev_t
, di_node_t
, const char *, int **);
88 static int di_propall_lookup_strings(di_prom_handle_t
, int,
89 dev_t
, di_node_t
, const char *, char **);
90 static int serid_printable(uint64_t *seridp
);
91 static int di_propall_lookup_slot_names(di_prom_handle_t
, int,
92 dev_t
, di_node_t
, di_slot_name_t
**);
96 * NOTE: The CREATE_DEFER flag is private to this module.
97 * NOT to be used by other modules
99 static devfsadm_create_t cfg_create_cbt
[] = {
100 { "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT
, NULL
,
101 TYPE_EXACT
| CREATE_DEFER
, ILEVEL_0
, scsi_cfg_creat_cb
103 { "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT
, NULL
,
104 TYPE_EXACT
, ILEVEL_0
, sbd_cfg_creat_cb
106 { "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT
, NULL
,
107 TYPE_EXACT
| CREATE_DEFER
, ILEVEL_0
, scsi_cfg_creat_cb
109 { "attachment-point", DDI_NT_USB_ATTACHMENT_POINT
, NULL
,
110 TYPE_EXACT
, ILEVEL_0
, usb_cfg_creat_cb
112 { "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT
, NULL
,
113 TYPE_EXACT
, ILEVEL_0
, pci_cfg_creat_cb
115 { "attachment-point", DDI_NT_IB_ATTACHMENT_POINT
, NULL
,
116 TYPE_EXACT
, ILEVEL_0
, ib_cfg_creat_cb
118 { "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT
, NULL
,
119 TYPE_EXACT
, ILEVEL_0
, sata_cfg_creat_cb
121 { "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT
, NULL
,
122 TYPE_EXACT
, ILEVEL_0
, sdcard_cfg_creat_cb
126 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt
);
128 static devfsadm_remove_t cfg_remove_cbt
[] = {
129 { "attachment-point", SCSI_CFG_LINK_RE
, RM_POST
,
130 ILEVEL_0
, devfsadm_rm_all
132 { "attachment-point", SBD_CFG_LINK_RE
, RM_POST
,
133 ILEVEL_0
, devfsadm_rm_all
135 { "fc-attachment-point", SCSI_CFG_LINK_RE
, RM_POST
,
136 ILEVEL_0
, devfsadm_rm_all
138 { "attachment-point", USB_CFG_LINK_RE
, RM_POST
|RM_HOT
|RM_ALWAYS
,
139 ILEVEL_0
, devfsadm_rm_all
141 { "attachment-point", PCI_CFG_LINK_RE
, RM_POST
,
142 ILEVEL_0
, devfsadm_rm_all
144 { "attachment-point", PCI_CFG_PATH_LINK_RE
, RM_POST
|RM_HOT
,
145 ILEVEL_0
, pci_cfg_rm_all
147 { "attachment-point", IB_CFG_LINK_RE
, RM_POST
|RM_HOT
|RM_ALWAYS
,
148 ILEVEL_0
, devfsadm_rm_all
150 { "attachment-point", SATA_CFG_LINK_RE
, RM_POST
|RM_HOT
|RM_ALWAYS
,
151 ILEVEL_0
, devfsadm_rm_all
153 { "attachment-point", SDCARD_CFG_LINK_RE
, RM_POST
|RM_HOT
|RM_ALWAYS
,
154 ILEVEL_0
, devfsadm_rm_all
158 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt
);
161 scsi_cfg_creat_cb(di_minor_t minor
, di_node_t node
)
163 char path
[PATH_MAX
+ 1];
164 char *c_num
= NULL
, *devfs_path
, *mn
;
165 devfsadm_enumerate_t rules
[3] = {
166 {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT
},
167 {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR
},
168 {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT
}
171 mn
= di_minor_name(minor
);
173 if ((devfs_path
= di_devfs_path(node
)) == NULL
) {
174 return (DEVFSADM_CONTINUE
);
176 (void) strcpy(path
, devfs_path
);
177 (void) strcat(path
, ":");
178 (void) strcat(path
, mn
);
179 di_devfs_path_free(devfs_path
);
181 if (ctrl_enumerate_int(path
, 1, &c_num
, rules
, 3, 0, B_FALSE
)
182 == DEVFSADM_FAILURE
) {
184 * Unlike the disks module we don't retry on failure.
185 * If we have multiple "c" numbers for a single physical
186 * controller due to bug 4045879, we will not assign a
187 * c-number/symlink for the controller.
189 return (DEVFSADM_CONTINUE
);
192 (void) strcpy(path
, CFG_DIRNAME
);
193 (void) strcat(path
, "/c");
194 (void) strcat(path
, c_num
);
198 (void) devfsadm_mklink(path
, node
, minor
, 0);
200 return (DEVFSADM_CONTINUE
);
204 sbd_cfg_creat_cb(di_minor_t minor
, di_node_t node
)
206 char path
[PATH_MAX
+ 1];
208 (void) strcpy(path
, CFG_DIRNAME
);
209 (void) strcat(path
, "/");
210 (void) strcat(path
, di_minor_name(minor
));
211 (void) devfsadm_mklink(path
, node
, minor
, 0);
212 return (DEVFSADM_CONTINUE
);
217 usb_cfg_creat_cb(di_minor_t minor
, di_node_t node
)
219 char *cp
, path
[PATH_MAX
+ 1];
220 devfsadm_enumerate_t rules
[1] =
221 {"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK
, NULL
, get_roothub
};
223 if ((cp
= di_devfs_path(node
)) == NULL
) {
224 return (DEVFSADM_CONTINUE
);
227 (void) snprintf(path
, sizeof (path
), "%s:%s", cp
, di_minor_name(minor
));
228 di_devfs_path_free(cp
);
230 if (ctrl_enumerate_int(path
, 0, &cp
, rules
, 1, 0, B_FALSE
)) {
231 return (DEVFSADM_CONTINUE
);
234 /* create usbN and the symlink */
235 (void) snprintf(path
, sizeof (path
), "%s/usb%s/%s", CFG_DIRNAME
, cp
,
236 di_minor_name(minor
));
239 (void) devfsadm_mklink(path
, node
, minor
, 0);
241 return (DEVFSADM_CONTINUE
);
246 sata_cfg_creat_cb(di_minor_t minor
, di_node_t node
)
248 char path
[PATH_MAX
+ 1], l_path
[PATH_MAX
], *buf
, *devfspath
;
250 devfsadm_enumerate_t rules
[1] =
251 {"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR
};
253 minor_nm
= di_minor_name(minor
);
254 if (minor_nm
== NULL
)
255 return (DEVFSADM_CONTINUE
);
257 devfspath
= di_devfs_path(node
);
258 if (devfspath
== NULL
)
259 return (DEVFSADM_CONTINUE
);
261 (void) strlcpy(path
, devfspath
, sizeof (path
));
262 (void) strlcat(path
, ":", sizeof (path
));
263 (void) strlcat(path
, minor_nm
, sizeof (path
));
264 di_devfs_path_free(devfspath
);
266 /* build the physical path from the components */
267 if (ctrl_enumerate_int(path
, 0, &buf
, rules
, 1, 0, B_FALSE
) ==
269 return (DEVFSADM_CONTINUE
);
272 (void) snprintf(l_path
, sizeof (l_path
), "%s/sata%s/%s", CFG_DIRNAME
,
276 (void) devfsadm_mklink(l_path
, node
, minor
, 0);
278 return (DEVFSADM_CONTINUE
);
282 sdcard_cfg_creat_cb(di_minor_t minor
, di_node_t node
)
284 char path
[PATH_MAX
+1], l_path
[PATH_MAX
], *buf
, *devfspath
;
286 devfsadm_enumerate_t rules
[1] =
287 {"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR
};
289 minor_nm
= di_minor_name(minor
);
290 if (minor_nm
== NULL
)
291 return (DEVFSADM_CONTINUE
);
293 devfspath
= di_devfs_path(node
);
294 if (devfspath
== NULL
)
295 return (DEVFSADM_CONTINUE
);
297 (void) snprintf(path
, sizeof (path
), "%s:%s", devfspath
, minor_nm
);
298 di_devfs_path_free(devfspath
);
300 /* build the physical path from the components */
301 if (ctrl_enumerate_int(path
, 0, &buf
, rules
, 1, 0, B_FALSE
) ==
303 return (DEVFSADM_CONTINUE
);
306 (void) snprintf(l_path
, sizeof (l_path
), "%s/sdcard%s/%s",
307 CFG_DIRNAME
, buf
, minor_nm
);
310 (void) devfsadm_mklink(l_path
, node
, minor
, 0);
312 return (DEVFSADM_CONTINUE
);
317 * figure out the root hub path to calculate /dev/cfg/usbN
321 get_roothub(const char *path
, void *cb_arg
)
327 if ((physpath
= strdup(path
)) == NULL
) {
332 * physpath must always have a minor name component
334 if ((cp
= strrchr(physpath
, ':')) == NULL
) {
341 * No '.' in the minor name indicates a roothub port.
343 if (strchr(cp
, '.') == NULL
) {
354 /* Remove as many trailing path components as there are '.'s */
355 for (i
= 0; i
< count
; i
++) {
356 if ((cp
= strrchr(physpath
, '/')) == NULL
|| (cp
== physpath
)) {
361 * Check if there is any usb_mid node in the middle
362 * and remove the node as if there is an extra '.'
364 if (strstr(cp
, "miscellaneous") != NULL
) {
370 /* Remove the usb_mid node immediately before the trailing path */
371 if ((cp
= strrchr(physpath
, '/')) != NULL
&& (cp
!= physpath
)) {
372 if (strstr(cp
, "miscellaneous") != NULL
) {
382 * returns an allocted string containing the device path for <node> and
386 pci_cfg_devpath(di_node_t node
, di_minor_t minor
)
393 path
= di_devfs_path(node
);
394 minor_nm
= di_minor_name(minor
);
395 buflen
= snprintf(NULL
, 0, "%s:%s", path
, minor_nm
) + 1;
397 bufp
= malloc(sizeof (char) * buflen
);
399 (void) snprintf(bufp
, buflen
, "%s:%s", path
, minor_nm
);
401 di_devfs_path_free(path
);
407 di_propall_lookup_ints(di_prom_handle_t ph
, int flags
,
408 dev_t dev
, di_node_t node
, const char *prop_name
, int **prop_data
)
412 if (flags
& DIPROP_PRI_PROM
) {
413 rv
= di_prom_prop_lookup_ints(ph
, node
, prop_name
, prop_data
);
415 rv
= di_prop_lookup_ints(dev
, node
, prop_name
,
418 rv
= di_prop_lookup_ints(dev
, node
, prop_name
, prop_data
);
420 rv
= di_prom_prop_lookup_ints(ph
, node
, prop_name
,
428 di_propall_lookup_strings(di_prom_handle_t ph
, int flags
,
429 dev_t dev
, di_node_t node
, const char *prop_name
, char **prop_data
)
433 if (flags
& DIPROP_PRI_PROM
) {
434 rv
= di_prom_prop_lookup_strings(ph
, node
, prop_name
,
437 rv
= di_prop_lookup_strings(dev
, node
, prop_name
,
440 rv
= di_prop_lookup_strings(dev
, node
, prop_name
, prop_data
);
442 rv
= di_prom_prop_lookup_strings(ph
, node
, prop_name
,
450 pci_cfg_chassis_node(di_node_t node
, di_prom_handle_t ph
)
452 di_node_t curnode
= node
;
456 if (di_propall_lookup_ints(ph
, 0, DDI_DEV_T_ANY
, curnode
,
457 DI_PROP_FIRST_CHAS
, &firstchas
) >= 0)
459 } while ((curnode
= di_parent_node(curnode
)) != DI_NODE_NIL
);
461 return (DI_NODE_NIL
);
466 di_propall_lookup_slot_names(di_prom_handle_t ph
, int flags
,
467 dev_t dev
, di_node_t node
, di_slot_name_t
**prop_data
)
471 if (flags
& DIPROP_PRI_PROM
) {
472 rv
= di_prom_prop_lookup_slot_names(ph
, node
, prop_data
);
474 rv
= di_prop_lookup_slot_names(dev
, node
, prop_data
);
476 rv
= di_prop_lookup_slot_names(dev
, node
, prop_data
);
478 rv
= di_prom_prop_lookup_slot_names(ph
, node
,
485 * returns an allocated string containing the slot name for the slot with
486 * device number <pci_dev> on bus <node>
489 pci_cfg_slotname(di_node_t node
, di_prom_handle_t ph
, minor_t pci_dev
)
492 char *fnm
= "pci_cfg_slotname";
496 di_slot_name_t
*slot_names
= NULL
;
498 count
= di_propall_lookup_slot_names(ph
, 0, DDI_DEV_T_ANY
, node
,
503 for (i
= 0; i
< count
; i
++) {
504 if (slot_names
[i
].num
== (int)pci_dev
) {
505 name
= strdup(slot_names
[i
].name
);
511 dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
512 fnm
, (int)pci_dev
, DI_PROP_SLOT_NAMES
, DRVINST(node
)));
515 di_slot_names_free(count
, slot_names
);
521 * returns non-zero if we can return a valid attachment point name for <node>,
522 * for its slot identified by child pci device number <pci_dev>, through <buf>
524 * prioritized naming scheme:
525 * 1) <DI_PROP_SLOT_NAMES property> (see pci_cfg_slotname())
526 * 2) <device-type><DI_PROP_PHYS_SLOT property>
527 * 3) <drv name><drv inst>.<device-type><pci_dev>
529 * where <device-type> is derived from the DI_PROP_DEV_TYPE property:
530 * if its value is "pciex" then <device-type> is "pcie"
531 * else the raw value is used
533 * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
536 pci_cfg_ap_node(minor_t pci_dev
, di_node_t node
, di_prom_handle_t ph
,
537 char *buf
, int bufsz
, int flags
)
543 rv
= di_propall_lookup_strings(ph
, 0, DDI_DEV_T_ANY
, node
,
544 DI_PROP_DEV_TYPE
, &devtype
);
548 if (strcmp(devtype
, PROPVAL_PCIEX
) == 0)
549 devtype
= DEVTYPE_PCIE
;
551 if (flags
& APNODE_DEFNAME
)
554 str
= pci_cfg_slotname(node
, ph
, pci_dev
);
556 (void) strlcpy(buf
, str
, bufsz
);
561 if (di_propall_lookup_ints(ph
, 0, DDI_DEV_T_ANY
, node
,
562 DI_PROP_PHYS_SLOT
, &nump
) > 0) {
564 (void) snprintf(buf
, bufsz
, "%s%d", devtype
, *nump
);
569 (void) snprintf(buf
, bufsz
, "%s%d.%s%d",
570 di_driver_name(node
), di_instance(node
), devtype
, pci_dev
);
577 * returns non-zero if we can return a valid expansion chassis name for <node>
580 * prioritized naming scheme:
581 * 1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion>
582 * 2) <IOB_PRE string><full DI_PROP_SERID property in hex>
583 * 3) <IOB_PRE string>
585 * DI_PROP_SERID encoding <64-bit int: msb ... lsb>:
586 * <24 bits: IEEE company id><40 bits: serial number>
588 * sun encoding of 40 bit serial number:
589 * first byte = device type indicator
590 * next 4 bytes = 4 ascii characters
592 * In the unlikely event that serial id contains non-printable characters
593 * the full 64 bit raw hex string will be used for the attachment point.
597 pci_cfg_iob_name(di_minor_t minor
, di_node_t node
, di_prom_handle_t ph
,
598 char *buf
, int bufsz
)
604 if (di_prop_lookup_int64(DDI_DEV_T_ANY
, node
, DI_PROP_SERID
,
606 (void) strlcpy(buf
, IOB_PRE
, bufsz
);
610 serid
= (uint64_t)*seridp
;
612 if ((serid
>> 40) != (uint64_t)IEEE_SUN_ID
||
613 !serid_printable(&serid
)) {
614 (void) snprintf(buf
, bufsz
, "%s%llx", IOB_PRE
, serid
);
619 * the serial id is constructed from lower 40 bits of the serialid
620 * property and is represented by 5 ascii characters. The first
621 * character indicates if the IO Box is PCIe or PCI-X.
625 idstr
= (char *)&serid
;
626 idstr
[sizeof (serid
) -1] = '\0';
628 (void) snprintf(buf
, bufsz
, "%s%s", IOB_PRE
, idstr
);
635 * returns the pci device number for <node> if found, else returns PCIDEV_NIL
638 pci_cfg_pcidev(di_node_t node
, di_prom_handle_t ph
)
643 rv
= di_propall_lookup_ints(ph
, 0, DDI_DEV_T_ANY
, node
, DI_PROP_REG
,
647 dprint(("pci_cfg_pcidev: property %s not found "
648 "for %s%d\n", DI_PROP_REG
, DRVINST(node
)));
652 return (REG_PCIDEV(regp
));
657 * returns non-zero when it can successfully return an attachment point
658 * through <ap_path> whose length is less than <ap_pathsz>; returns the full
659 * path of the AP through <pathret> which may be larger than <ap_pathsz>.
660 * Callers need to free <pathret>. If it cannot return the full path through
661 * <pathret> it will be set to NULL
663 * The ap path reflects a subset of the device path from an onboard host slot
664 * up to <node>. We traverse up the device tree starting from <node>, naming
665 * each component using pci_cfg_ap_node(). If we detect that a certain
666 * segment is contained within an expansion chassis, then we skip any bus
667 * nodes in between our current node and the topmost node of the chassis,
668 * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name
669 * of the expansion chassis as given by pci_cfg_iob_name()
671 * This scheme is always used for <pathret>. If however, the size of
672 * <pathret> is greater than <ap_pathsz> then only the default name as given
673 * by pci_cfg_ap_node() for <node> will be used
676 pci_cfg_ap_path(di_minor_t minor
, di_node_t node
, di_prom_handle_t ph
,
677 char *ap_path
, int ap_pathsz
, char **pathret
)
680 char *fnm
= "pci_cfg_ap_path";
682 #define seplen (sizeof (AP_PATH_SEP) - 1)
683 #define iob_pre_len (sizeof (IOB_PRE) - 1)
684 #define ap_path_iob_sep_len (sizeof (AP_PATH_IOB_SEP) - 1)
687 char buf
[MAXPATHLEN
];
688 char pathbuf
[MAXPATHLEN
];
691 char *pathend
= NULL
;
695 di_node_t curnode
= node
;
696 di_node_t chasnode
= DI_NODE_NIL
;
701 pathptr
= &pathbuf
[sizeof (pathbuf
) - 1];
705 * as we traverse up the device tree, we prepend components of our
706 * path inside pathbuf, using pathptr and decrementing
708 pci_dev
= PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor
));
711 bufsz
= sizeof (buf
);
713 chasnode
= pci_cfg_chassis_node(curnode
, ph
);
714 if (chasnode
!= DI_NODE_NIL
) {
715 rv
= pci_cfg_iob_name(minor
, chasnode
, ph
,
718 dprint(("%s: cannot create iob name "
719 "for %s%d\n", fnm
, DRVINST(node
)));
724 (void) strncat(bufptr
, AP_PATH_IOB_SEP
, bufsz
);
725 len
= strlen(bufptr
);
729 /* set chasflag when the leaf node is within an iob */
730 if ((curnode
== node
) != NULL
)
733 rv
= pci_cfg_ap_node(pci_dev
, curnode
, ph
, bufptr
, bufsz
, 0);
735 dprint(("%s: cannot create ap node name "
736 "for %s%d\n", fnm
, DRVINST(node
)));
742 * if we can't fit the entire path in our pathbuf, then use
743 * the default short name and nullify pathptr; also, since
744 * we prepend in the buffer, we must avoid adding a null char
746 if (curnode
!= node
) {
748 if (pathptr
< pathbuf
) {
753 (void) memcpy(pathptr
, AP_PATH_SEP
, seplen
);
757 if (pathptr
< pathbuf
) {
762 (void) memcpy(pathptr
, buf
, len
);
764 /* remember the leaf component */
769 * go no further than the hosts' onboard slots
771 if (chasnode
== DI_NODE_NIL
)
776 * the pci device number of the current node is used to
777 * identify which slot of the parent's bus (next iteration)
778 * the current node is on
780 pci_dev
= pci_cfg_pcidev(curnode
, ph
);
781 if (pci_dev
== PCIDEV_NIL
) {
782 dprint(("%s: cannot obtain pci device number "
783 "for %s%d\n", fnm
, DRVINST(node
)));
787 } while ((curnode
= di_parent_node(curnode
)) != DI_NODE_NIL
);
789 pathbuf
[sizeof (pathbuf
) - 1] = '\0';
790 if (strlen(pathptr
) < ap_pathsz
) {
791 (void) strlcpy(ap_path
, pathptr
, ap_pathsz
);
798 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
799 * <node>'s name ONLY IF it has a serialid# which will make the apid
802 if (chasflag
&& pathend
!= NULL
) {
803 if ((strncmp(pathend
+ iob_pre_len
, AP_PATH_IOB_SEP
,
804 ap_path_iob_sep_len
) != 0) &&
805 (strlen(pathend
) < ap_pathsz
)) {
806 (void) strlcpy(ap_path
, pathend
, ap_pathsz
);
813 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
816 pci_dev
= PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor
));
817 rv
= pci_cfg_ap_node(pci_dev
, node
, ph
, buf
, bufsz
, APNODE_DEFNAME
);
819 dprint(("%s: cannot create default ap node name for %s%d\n",
820 fnm
, DRVINST(node
)));
824 if (strlen(buf
) < ap_pathsz
) {
825 (void) strlcpy(ap_path
, buf
, ap_pathsz
);
831 * in this case, cfgadm goes through an expensive process to generate
832 * a purely dynamic logical apid: the framework will look through
833 * the device tree for attachment point minor nodes and will invoke
834 * each plugin responsible for that attachment point class, and if
835 * the plugin returns a logical apid that matches the queried apid
836 * or matches the default apid generated by the cfgadm framework for
837 * that driver/class (occurs when plugin returns an empty logical apid)
838 * then that is what it will use
840 * it is doubly expensive because the cfgadm pci plugin itself will
841 * also search the entire device tree in the absence of a link
844 dprint(("%s: cannot create apid for %s%d within length of %d\n",
845 fnm
, DRVINST(node
), ap_pathsz
));
848 ap_path
[ap_pathsz
- 1] = '\0';
849 *pathret
= (*pathptr
== '\0') ? NULL
: strdup(pathptr
);
854 #undef ap_path_iob_sep_len
859 * the DI_PROP_AP_NAMES property contains the first integer section of the
860 * ieee1275 "slot-names" property and functions as a bitmask; see comment for
863 * we use the name of the attachment point minor node if its pci device
864 * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES
866 * returns non-zero if we return a valid attachment point through <path>
869 pci_cfg_ap_legacy(di_minor_t minor
, di_node_t node
, di_prom_handle_t ph
,
870 char *ap_path
, int ap_pathsz
)
875 if (di_propall_lookup_ints(ph
, 0, DDI_DEV_T_ANY
, node
, DI_PROP_AP_NAMES
,
879 pci_dev
= PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor
));
880 if ((*anp
& (1 << pci_dev
)) == 0)
883 (void) strlcpy(ap_path
, di_minor_name(minor
), ap_pathsz
);
889 * determine if <node> qualifies for a path style apid
892 pci_cfg_is_ap_path(di_node_t node
, di_prom_handle_t ph
)
895 di_node_t curnode
= node
;
898 if (di_propall_lookup_strings(ph
, 0, DDI_DEV_T_ANY
, curnode
,
899 DI_PROP_DEV_TYPE
, &devtype
) > 0)
900 if (strcmp(devtype
, PROPVAL_PCIEX
) == 0)
902 } while ((curnode
= di_parent_node(curnode
)) != DI_NODE_NIL
);
909 * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
910 * returns an allocated string intendend to be stored in a devlink info (dli)
913 * data format: "Location: <transformed path>"
914 * where <transformed path> is <path> with occurrances of AP_PATH_SEP
918 pci_cfg_info_data(char *path
)
920 #define head "Location: "
921 #define headlen (sizeof (head) - 1)
922 #define seplen (sizeof (AP_PATH_SEP) - 1)
924 char *sep
, *prev
, *np
;
926 int pathlen
= strlen(path
);
929 newpath
= malloc(sizeof (char) * (headlen
+ pathlen
+ 1));
931 (void) strcpy(np
, head
);
935 while ((sep
= strstr(prev
, AP_PATH_SEP
)) != NULL
) {
937 (void) memcpy(np
, prev
, len
);
942 (void) strcpy(np
, prev
);
952 pci_cfg_rm_link(char *file
)
956 dlipath
= di_dli_name(file
);
957 (void) unlink(dlipath
);
959 devfsadm_rm_all(file
);
964 * removes all registered devlinks to physical path <physpath> except for
965 * the devlink <valid> if not NULL;
966 * <physpath> must include the minor node
969 pci_cfg_rm_invalid_links(char *physpath
, char *valid
)
975 dnp
= devfsadm_lookup_dev_names(physpath
, NULL
, &dnlen
);
980 if (strncmp(valid
, DEV
"/", DEV_LEN
+ 1) == 0)
981 vcp
= valid
+ DEV_LEN
+ 1;
986 for (i
= 0; i
< dnlen
; i
++) {
987 if (strncmp(dnp
[i
], DEV
"/", DEV_LEN
+ 1) == 0)
988 cp
= dnp
[i
] + DEV_LEN
+ 1;
993 if (strcmp(vcp
, cp
) == 0)
998 devfsadm_free_dev_names(dnp
, dnlen
);
1003 * takes a complete devinfo snapshot and returns the root node;
1004 * callers must do a di_fini() on the returned node;
1005 * if the snapshot failed, DI_NODE_NIL is returned instead
1007 * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
1008 * in the new snapshot and return it through <ret_node> if it is found,
1009 * else DI_NODE_NIL is returned instead
1011 * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
1012 * the matching minor in the new snapshot through <ret_minor> if it is found,
1013 * else DI_MINOR_NIL is returned instead
1016 pci_cfg_snapshot(di_node_t pci_node
, di_minor_t pci_minor
,
1017 di_node_t
*ret_node
, di_minor_t
*ret_minor
)
1019 di_node_t root_node
;
1025 *ret_node
= DI_NODE_NIL
;
1026 *ret_minor
= DI_MINOR_NIL
;
1028 root_node
= di_init("/", DINFOCPYALL
);
1029 if (root_node
== DI_NODE_NIL
)
1030 return (DI_NODE_NIL
);
1033 * narrow down search by driver, then instance, then minor
1035 if (pci_node
== DI_NODE_NIL
)
1038 pci_inst
= di_instance(pci_node
);
1039 node
= di_drv_first_node(di_driver_name(pci_node
), root_node
);
1041 if (pci_inst
== di_instance(node
)) {
1045 } while ((node
= di_drv_next_node(node
)) != DI_NODE_NIL
);
1047 if (node
== DI_NODE_NIL
)
1051 * found node, now search minors
1053 if (pci_minor
== DI_MINOR_NIL
)
1056 pci_devt
= di_minor_devt(pci_minor
);
1057 minor
= DI_MINOR_NIL
;
1058 while ((minor
= di_minor_next(node
, minor
)) != DI_MINOR_NIL
) {
1059 if (pci_devt
== di_minor_devt(minor
)) {
1069 pci_cfg_creat_cb(di_minor_t pci_minor
, di_node_t pci_node
)
1072 char *fnm
= "pci_cfg_creat_cb";
1074 #define ap_pathsz (sizeof (ap_path))
1076 char ap_path
[CFGA_LOG_EXT_LEN
];
1077 char linkbuf
[MAXPATHLEN
];
1078 char *fullpath
= NULL
;
1079 char *pathinfo
= NULL
;
1080 char *devpath
= NULL
;
1083 di_prom_handle_t ph
;
1085 di_node_t root_node
= DI_NODE_NIL
;
1088 ph
= di_prom_init();
1089 if (ph
== DI_PROM_HANDLE_NIL
) {
1090 dprint(("%s: di_prom_init() failed for %s%d\n",
1091 fnm
, DRVINST(pci_node
)));
1096 * Since incoming nodes from hotplug events are from snapshots that
1097 * do NOT contain parent/ancestor data, we must retake our own
1098 * snapshot and search for the target node
1100 root_node
= pci_cfg_snapshot(pci_node
, pci_minor
, &node
, &minor
);
1101 if (root_node
== DI_NODE_NIL
|| node
== DI_NODE_NIL
||
1102 minor
== DI_MINOR_NIL
) {
1103 dprint(("%s: devinfo snapshot or search failed for %s%d\n",
1104 fnm
, DRVINST(pci_node
)));
1108 if (pci_cfg_is_ap_path(node
, ph
)) {
1109 rv
= pci_cfg_ap_path(minor
, node
, ph
, ap_path
, ap_pathsz
,
1114 (void) snprintf(linkbuf
, sizeof (linkbuf
), "%s/%s",
1115 CFG_DIRNAME
, ap_path
);
1118 * We must remove existing links because we may have invalid
1119 * apids that are valid links. Since these are not dangling,
1120 * devfsadm will not invoke the remove callback on them.
1122 * What are "invalid apids with valid links"? Consider swapping
1123 * an attachment point bus with another while the system is
1124 * down, on the same device path bound to the same drivers
1125 * but with the new AP bus having different properties
1126 * (e.g. serialid#). If the previous apid is not removed,
1127 * there will now be two different links pointing to the same
1128 * attachment point, but only one reflects the correct
1131 devpath
= pci_cfg_devpath(node
, minor
);
1132 if (devpath
== NULL
)
1134 pci_cfg_rm_invalid_links(devpath
, linkbuf
);
1137 (void) devfsadm_mklink(linkbuf
, node
, minor
, 0);
1140 * we store the full logical path of the attachment point for
1141 * cfgadm to display in its info field which is useful when
1142 * the full logical path exceeds the size limit for logical
1143 * apids (CFGA_LOG_EXT_LEN)
1145 * for the cfgadm pci plugin to do the same would be expensive
1146 * (i.e. devinfo snapshot + top down exhaustive minor search +
1147 * equivalent of pci_cfg_ap_path() on every invocation)
1149 * note that if we do not create a link (pci_cfg_ap_path() is
1150 * not successful), that is what cfgadm will do anyways to
1151 * create a purely dynamic apid
1153 pathinfo
= pci_cfg_info_data(fullpath
);
1154 fd
= di_dli_openw(linkbuf
);
1158 sz
= strlen(pathinfo
) + 1;
1159 rv
= write(fd
, pathinfo
, sz
);
1161 dprint(("%s: could not write full pathinfo to dli "
1162 "file for %s%d\n", fnm
, DRVINST(node
)));
1167 rv
= pci_cfg_ap_legacy(minor
, node
, ph
, ap_path
,
1172 (void) snprintf(linkbuf
, sizeof (linkbuf
), "%s/%s",
1173 CFG_DIRNAME
, ap_path
);
1174 (void) devfsadm_mklink(linkbuf
, node
, minor
, 0);
1180 if (fullpath
!= NULL
)
1182 if (pathinfo
!= NULL
)
1184 if (ph
!= DI_PROM_HANDLE_NIL
)
1186 if (root_node
!= DI_NODE_NIL
)
1188 return (DEVFSADM_CONTINUE
);
1195 pci_cfg_rm_all(char *file
)
1197 pci_cfg_rm_link(file
);
1202 * ib_cfg_creat_cb() creates two types of links
1203 * One for the fabric as /dev/cfg/ib
1204 * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
1207 ib_cfg_creat_cb(di_minor_t minor
, di_node_t node
)
1210 char path
[PATH_MAX
+ 1];
1212 if ((cp
= di_devfs_path(node
)) == NULL
) {
1213 return (DEVFSADM_CONTINUE
);
1216 (void) snprintf(path
, sizeof (path
), "%s:%s", cp
, di_minor_name(minor
));
1217 di_devfs_path_free(cp
);
1219 /* create fabric or hca:GUID and the symlink */
1220 if (strstr(path
, "ib:fabric") != NULL
) {
1221 (void) snprintf(path
, sizeof (path
), "%s/ib", CFG_DIRNAME
);
1223 (void) snprintf(path
, sizeof (path
), "%s/hca:%s", CFG_DIRNAME
,
1224 di_minor_name(minor
));
1227 (void) devfsadm_mklink(path
, node
, minor
, 0);
1228 return (DEVFSADM_CONTINUE
);
1232 * This function verifies if the serial id is printable.
1236 serid_printable(uint64_t *seridp
)
1242 for (ptr
= (char *)seridp
+3; i
< 5; ptr
++, i
++)
1243 if (*ptr
< 0x21 || *ptr
>= 0x7f)