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 2019, Joyent, Inc.
24 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 #include <devfsadm.h>
30 #include <stdio.h>
31 #include <strings.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <limits.h>
35 #include <unistd.h>
36 #include <config_admin.h>
37 #include <cfg_link.h>
38 #include <sys/types.h>
39 #include <sys/mkdev.h>
40 #include <sys/hotplug/pci/pcihp.h>
41
42 #ifdef DEBUG
43 #define dprint(args) devfsadm_errprint args
44 /*
45 * for use in print routine arg list as a shorthand way to locate node via
46 * "prtconf -D" to avoid messy and cluttered debugging code
47 * don't forget the corresponding "%s%d" format
48 */
49 #define DRVINST(node) di_driver_name(node), di_instance(node)
50 #else
51 #define dprint(args)
52 #endif
53
54
55 static int scsi_cfg_creat_cb(di_minor_t minor, di_node_t node);
56 static int sbd_cfg_creat_cb(di_minor_t minor, di_node_t node);
57 static int usb_cfg_creat_cb(di_minor_t minor, di_node_t node);
58 static char *get_roothub(const char *path, void *cb_arg);
59 static int pci_cfg_creat_cb(di_minor_t minor, di_node_t node);
60 static int ib_cfg_creat_cb(di_minor_t minor, di_node_t node);
61 static int sata_cfg_creat_cb(di_minor_t minor, di_node_t node);
62 static int sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node);
63 static int ccid_cfg_creat_cb(di_minor_t minor, di_node_t node);
64
65 static di_node_t pci_cfg_chassis_node(di_node_t, di_prom_handle_t);
66 static char *pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t);
67 static int pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t,
68 char *, int, int);
69 static int pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t,
70 char *, int);
71 static minor_t pci_cfg_pcidev(di_node_t, di_prom_handle_t);
72 static int pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t,
73 char *, int, char **);
74 static char *pci_cfg_info_data(char *);
75 static int pci_cfg_is_ap_path(di_node_t, di_prom_handle_t);
76 static int pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t,
77 char *, int);
78 static void pci_cfg_rm_invalid_links(char *, char *);
79 static void pci_cfg_rm_link(char *);
80 static void pci_cfg_rm_all(char *);
81 static char *pci_cfg_devpath(di_node_t, di_minor_t);
82 static di_node_t pci_cfg_snapshot(di_node_t, di_minor_t,
83 di_node_t *, di_minor_t *);
84
85 /* flag definitions for di_propall_*(); value "0" is always the default flag */
86 #define DIPROP_PRI_NODE 0x0
87 #define DIPROP_PRI_PROM 0x1
88 static int di_propall_lookup_ints(di_prom_handle_t, int,
89 dev_t, di_node_t, const char *, int **);
90 static int di_propall_lookup_strings(di_prom_handle_t, int,
91 dev_t, di_node_t, const char *, char **);
92 static int serid_printable(uint64_t *seridp);
93 static int di_propall_lookup_slot_names(di_prom_handle_t, int,
94 dev_t, di_node_t, di_slot_name_t **);
95
96
97 /*
98 * NOTE: The CREATE_DEFER flag is private to this module.
99 * NOT to be used by other modules
100 */
101 static devfsadm_create_t cfg_create_cbt[] = {
102 { "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL,
103 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
104 },
105 { "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL,
106 TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
107 },
108 { "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL,
109 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
110 },
111 { "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL,
112 TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
113 },
114 { "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL,
115 TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
116 },
117 { "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL,
118 TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
119 },
120 { "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL,
121 TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb
122 },
123 { "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT, NULL,
124 TYPE_EXACT, ILEVEL_0, sdcard_cfg_creat_cb
125 },
126 { "attachment-point", DDI_NT_CCID_ATTACHMENT_POINT, NULL,
127 TYPE_EXACT, ILEVEL_0, ccid_cfg_creat_cb
128 }
129 };
130
131 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
132
133 static devfsadm_remove_t cfg_remove_cbt[] = {
134 { "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
135 ILEVEL_0, devfsadm_rm_all
136 },
137 { "attachment-point", SBD_CFG_LINK_RE, RM_POST,
138 ILEVEL_0, devfsadm_rm_all
139 },
140 { "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
141 ILEVEL_0, devfsadm_rm_all
142 },
143 { "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
144 ILEVEL_0, devfsadm_rm_all
145 },
146 { "attachment-point", PCI_CFG_LINK_RE, RM_POST,
147 ILEVEL_0, devfsadm_rm_all
148 },
149 { "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT,
150 ILEVEL_0, pci_cfg_rm_all
151 },
152 { "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
153 ILEVEL_0, devfsadm_rm_all
154 },
155 { "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
156 ILEVEL_0, devfsadm_rm_all
157 },
158 { "attachment-point", SDCARD_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
159 ILEVEL_0, devfsadm_rm_all
160 },
161 { "attachment-point", CCID_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
162 ILEVEL_0, devfsadm_rm_all
163 }
164 };
165
166 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
167
168 static int
scsi_cfg_creat_cb(di_minor_t minor,di_node_t node)169 scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
170 {
171 char path[PATH_MAX + 1];
172 char *c_num = NULL, *devfs_path, *mn;
173 devfsadm_enumerate_t rules[3] = {
174 {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
175 {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
176 {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
177 };
178
179 mn = di_minor_name(minor);
180
181 if ((devfs_path = di_devfs_path(node)) == NULL) {
182 return (DEVFSADM_CONTINUE);
183 }
184 (void) strcpy(path, devfs_path);
185 (void) strcat(path, ":");
186 (void) strcat(path, mn);
187 di_devfs_path_free(devfs_path);
188
189 if (ctrl_enumerate_int(path, 1, &c_num, rules, 3, 0, B_FALSE)
190 == DEVFSADM_FAILURE) {
191 /*
192 * Unlike the disks module we don't retry on failure.
193 * If we have multiple "c" numbers for a single physical
194 * controller due to bug 4045879, we will not assign a
195 * c-number/symlink for the controller.
196 */
197 return (DEVFSADM_CONTINUE);
198 }
199
200 (void) strcpy(path, CFG_DIRNAME);
201 (void) strcat(path, "/c");
202 (void) strcat(path, c_num);
203
204 free(c_num);
205
206 (void) devfsadm_mklink(path, node, minor, 0);
207
208 return (DEVFSADM_CONTINUE);
209 }
210
211 static int
sbd_cfg_creat_cb(di_minor_t minor,di_node_t node)212 sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
213 {
214 char path[PATH_MAX + 1];
215
216 (void) strcpy(path, CFG_DIRNAME);
217 (void) strcat(path, "/");
218 (void) strcat(path, di_minor_name(minor));
219 (void) devfsadm_mklink(path, node, minor, 0);
220 return (DEVFSADM_CONTINUE);
221 }
222
223
224 static int
usb_cfg_creat_cb(di_minor_t minor,di_node_t node)225 usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
226 {
227 char *cp, path[PATH_MAX + 1];
228 devfsadm_enumerate_t rules[1] =
229 {"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
230
231 if ((cp = di_devfs_path(node)) == NULL) {
232 return (DEVFSADM_CONTINUE);
233 }
234
235 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
236 di_devfs_path_free(cp);
237
238 if (ctrl_enumerate_int(path, 0, &cp, rules, 1, 0, B_FALSE)) {
239 return (DEVFSADM_CONTINUE);
240 }
241
242 /* create usbN and the symlink */
243 (void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
244 di_minor_name(minor));
245 free(cp);
246
247 (void) devfsadm_mklink(path, node, minor, 0);
248
249 return (DEVFSADM_CONTINUE);
250 }
251
252
253 static int
sata_cfg_creat_cb(di_minor_t minor,di_node_t node)254 sata_cfg_creat_cb(di_minor_t minor, di_node_t node)
255 {
256 char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath;
257 char *minor_nm;
258 devfsadm_enumerate_t rules[1] =
259 {"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR};
260
261 minor_nm = di_minor_name(minor);
262 if (minor_nm == NULL)
263 return (DEVFSADM_CONTINUE);
264
265 devfspath = di_devfs_path(node);
266 if (devfspath == NULL)
267 return (DEVFSADM_CONTINUE);
268
269 (void) strlcpy(path, devfspath, sizeof (path));
270 (void) strlcat(path, ":", sizeof (path));
271 (void) strlcat(path, minor_nm, sizeof (path));
272 di_devfs_path_free(devfspath);
273
274 /* build the physical path from the components */
275 if (ctrl_enumerate_int(path, 0, &buf, rules, 1, 0, B_FALSE) ==
276 DEVFSADM_FAILURE) {
277 return (DEVFSADM_CONTINUE);
278 }
279
280 (void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME,
281 buf, minor_nm);
282 free(buf);
283
284 (void) devfsadm_mklink(l_path, node, minor, 0);
285
286 return (DEVFSADM_CONTINUE);
287 }
288
289 static int
sdcard_cfg_creat_cb(di_minor_t minor,di_node_t node)290 sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node)
291 {
292 char path[PATH_MAX +1], l_path[PATH_MAX], *buf, *devfspath;
293 char *minor_nm;
294 devfsadm_enumerate_t rules[1] =
295 {"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR};
296
297 minor_nm = di_minor_name(minor);
298 if (minor_nm == NULL)
299 return (DEVFSADM_CONTINUE);
300
301 devfspath = di_devfs_path(node);
302 if (devfspath == NULL)
303 return (DEVFSADM_CONTINUE);
304
305 (void) snprintf(path, sizeof (path), "%s:%s", devfspath, minor_nm);
306 di_devfs_path_free(devfspath);
307
308 /* build the physical path from the components */
309 if (ctrl_enumerate_int(path, 0, &buf, rules, 1, 0, B_FALSE) ==
310 DEVFSADM_FAILURE) {
311 return (DEVFSADM_CONTINUE);
312 }
313
314 (void) snprintf(l_path, sizeof (l_path), "%s/sdcard%s/%s",
315 CFG_DIRNAME, buf, minor_nm);
316 free(buf);
317
318 (void) devfsadm_mklink(l_path, node, minor, 0);
319
320 return (DEVFSADM_CONTINUE);
321 }
322
323 /*
324 * get_roothub:
325 * figure out the root hub path to calculate /dev/cfg/usbN
326 */
327 /* ARGSUSED */
328 static char *
get_roothub(const char * path,void * cb_arg)329 get_roothub(const char *path, void *cb_arg)
330 {
331 int i, count = 0;
332 char *physpath, *cp;
333
334 /* make a copy */
335 if ((physpath = strdup(path)) == NULL) {
336 return (NULL);
337 }
338
339 /*
340 * physpath must always have a minor name component
341 */
342 if ((cp = strrchr(physpath, ':')) == NULL) {
343 free(physpath);
344 return (NULL);
345 }
346 *cp++ = '\0';
347
348 /*
349 * No '.' in the minor name indicates a roothub port.
350 */
351 if (strchr(cp, '.') == NULL) {
352 /* roothub device */
353 return (physpath);
354 }
355
356 while (*cp) {
357 if (*cp == '.')
358 count++;
359 cp++;
360 }
361
362 /* Remove as many trailing path components as there are '.'s */
363 for (i = 0; i < count; i++) {
364 if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
365 free(physpath);
366 return (NULL);
367 }
368 /*
369 * Check if there is any usb_mid node in the middle
370 * and remove the node as if there is an extra '.'
371 */
372 if (strstr(cp, "miscellaneous") != NULL) {
373 count++;
374 }
375 *cp = '\0';
376 }
377
378 /* Remove the usb_mid node immediately before the trailing path */
379 if ((cp = strrchr(physpath, '/')) != NULL && (cp != physpath)) {
380 if (strstr(cp, "miscellaneous") != NULL) {
381 *cp = '\0';
382 }
383 }
384
385 return (physpath);
386 }
387
388
389 /*
390 * returns an allocted string containing the device path for <node> and
391 * <minor>
392 */
393 static char *
pci_cfg_devpath(di_node_t node,di_minor_t minor)394 pci_cfg_devpath(di_node_t node, di_minor_t minor)
395 {
396 char *path;
397 char *bufp;
398 char *minor_nm;
399 int buflen;
400
401 path = di_devfs_path(node);
402 minor_nm = di_minor_name(minor);
403 buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
404
405 bufp = malloc(sizeof (char) * buflen);
406 if (bufp != NULL)
407 (void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
408
409 di_devfs_path_free(path);
410 return (bufp);
411 }
412
413
414 static int
di_propall_lookup_ints(di_prom_handle_t ph,int flags,dev_t dev,di_node_t node,const char * prop_name,int ** prop_data)415 di_propall_lookup_ints(di_prom_handle_t ph, int flags,
416 dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
417 {
418 int rv;
419
420 if (flags & DIPROP_PRI_PROM) {
421 rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
422 if (rv < 0)
423 rv = di_prop_lookup_ints(dev, node, prop_name,
424 prop_data);
425 } else {
426 rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
427 if (rv < 0)
428 rv = di_prom_prop_lookup_ints(ph, node, prop_name,
429 prop_data);
430 }
431 return (rv);
432 }
433
434
435 static int
di_propall_lookup_strings(di_prom_handle_t ph,int flags,dev_t dev,di_node_t node,const char * prop_name,char ** prop_data)436 di_propall_lookup_strings(di_prom_handle_t ph, int flags,
437 dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
438 {
439 int rv;
440
441 if (flags & DIPROP_PRI_PROM) {
442 rv = di_prom_prop_lookup_strings(ph, node, prop_name,
443 prop_data);
444 if (rv < 0)
445 rv = di_prop_lookup_strings(dev, node, prop_name,
446 prop_data);
447 } else {
448 rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
449 if (rv < 0)
450 rv = di_prom_prop_lookup_strings(ph, node, prop_name,
451 prop_data);
452 }
453 return (rv);
454 }
455
456
457 static di_node_t
pci_cfg_chassis_node(di_node_t node,di_prom_handle_t ph)458 pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
459 {
460 di_node_t curnode = node;
461 int *firstchas;
462
463 do {
464 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
465 DI_PROP_FIRST_CHAS, &firstchas) >= 0)
466 return (curnode);
467 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
468
469 return (DI_NODE_NIL);
470 }
471
472
473 static int
di_propall_lookup_slot_names(di_prom_handle_t ph,int flags,dev_t dev,di_node_t node,di_slot_name_t ** prop_data)474 di_propall_lookup_slot_names(di_prom_handle_t ph, int flags,
475 dev_t dev, di_node_t node, di_slot_name_t **prop_data)
476 {
477 int rv;
478
479 if (flags & DIPROP_PRI_PROM) {
480 rv = di_prom_prop_lookup_slot_names(ph, node, prop_data);
481 if (rv < 0)
482 rv = di_prop_lookup_slot_names(dev, node, prop_data);
483 } else {
484 rv = di_prop_lookup_slot_names(dev, node, prop_data);
485 if (rv < 0)
486 rv = di_prom_prop_lookup_slot_names(ph, node,
487 prop_data);
488 }
489 return (rv);
490 }
491
492 /*
493 * returns an allocated string containing the slot name for the slot with
494 * device number <pci_dev> on bus <node>
495 */
496 static char *
pci_cfg_slotname(di_node_t node,di_prom_handle_t ph,minor_t pci_dev)497 pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
498 {
499 #ifdef DEBUG
500 char *fnm = "pci_cfg_slotname";
501 #endif
502 int i, count;
503 char *name = NULL;
504 di_slot_name_t *slot_names = NULL;
505
506 count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node,
507 &slot_names);
508 if (count < 0)
509 return (NULL);
510
511 for (i = 0; i < count; i++) {
512 if (slot_names[i].num == (int)pci_dev) {
513 name = strdup(slot_names[i].name);
514 break;
515 }
516 }
517 #ifdef DEBUG
518 if (name == NULL)
519 dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
520 fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node)));
521 #endif
522 if (count > 0)
523 di_slot_names_free(count, slot_names);
524 return (name);
525 }
526
527
528 /*
529 * returns non-zero if we can return a valid attachment point name for <node>,
530 * for its slot identified by child pci device number <pci_dev>, through <buf>
531 *
532 * prioritized naming scheme:
533 * 1) <DI_PROP_SLOT_NAMES property> (see pci_cfg_slotname())
534 * 2) <device-type><DI_PROP_PHYS_SLOT property>
535 * 3) <drv name><drv inst>.<device-type><pci_dev>
536 *
537 * where <device-type> is derived from the DI_PROP_DEV_TYPE property:
538 * if its value is "pciex" then <device-type> is "pcie"
539 * else the raw value is used
540 *
541 * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
542 */
543 static int
pci_cfg_ap_node(minor_t pci_dev,di_node_t node,di_prom_handle_t ph,char * buf,int bufsz,int flags)544 pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
545 char *buf, int bufsz, int flags)
546 {
547 int *nump;
548 int rv;
549 char *str, *devtype;
550
551 rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
552 DI_PROP_DEV_TYPE, &devtype);
553 if (rv < 1)
554 return (0);
555
556 if (strcmp(devtype, PROPVAL_PCIEX) == 0)
557 devtype = DEVTYPE_PCIE;
558
559 if (flags & APNODE_DEFNAME)
560 goto DEF;
561
562 str = pci_cfg_slotname(node, ph, pci_dev);
563 if (str != NULL) {
564 (void) strlcpy(buf, str, bufsz);
565 free(str);
566 return (1);
567 }
568
569 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
570 DI_PROP_PHYS_SLOT, &nump) > 0) {
571 if (*nump > 0) {
572 (void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
573 return (1);
574 }
575 }
576 DEF:
577 (void) snprintf(buf, bufsz, "%s%d.%s%d",
578 di_driver_name(node), di_instance(node), devtype, pci_dev);
579
580 return (1);
581 }
582
583
584 /*
585 * returns non-zero if we can return a valid expansion chassis name for <node>
586 * through <buf>
587 *
588 * prioritized naming scheme:
589 * 1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion>
590 * 2) <IOB_PRE string><full DI_PROP_SERID property in hex>
591 * 3) <IOB_PRE string>
592 *
593 * DI_PROP_SERID encoding <64-bit int: msb ... lsb>:
594 * <24 bits: IEEE company id><40 bits: serial number>
595 *
596 * sun encoding of 40 bit serial number:
597 * first byte = device type indicator
598 * next 4 bytes = 4 ascii characters
599 *
600 * In the unlikely event that serial id contains non-printable characters
601 * the full 64 bit raw hex string will be used for the attachment point.
602 */
603 /*ARGSUSED*/
604 static int
pci_cfg_iob_name(di_minor_t minor,di_node_t node,di_prom_handle_t ph,char * buf,int bufsz)605 pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
606 char *buf, int bufsz)
607 {
608 int64_t *seridp;
609 uint64_t serid;
610 char *idstr;
611
612 if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID,
613 &seridp) < 1) {
614 (void) strlcpy(buf, IOB_PRE, bufsz);
615 return (1);
616 }
617
618 serid = (uint64_t)*seridp;
619
620 if ((serid >> 40) != (uint64_t)IEEE_SUN_ID ||
621 !serid_printable(&serid)) {
622 (void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
623 return (1);
624 }
625
626 /*
627 * the serial id is constructed from lower 40 bits of the serialid
628 * property and is represented by 5 ascii characters. The first
629 * character indicates if the IO Box is PCIe or PCI-X.
630 */
631
632 serid <<= 24;
633 idstr = (char *)&serid;
634 idstr[sizeof (serid) -1] = '\0';
635
636 (void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
637
638 return (1);
639 }
640
641
642 /*
643 * returns the pci device number for <node> if found, else returns PCIDEV_NIL
644 */
645 static minor_t
pci_cfg_pcidev(di_node_t node,di_prom_handle_t ph)646 pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
647 {
648 int rv;
649 int *regp;
650
651 rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG,
652 ®p);
653
654 if (rv < 1) {
655 dprint(("pci_cfg_pcidev: property %s not found "
656 "for %s%d\n", DI_PROP_REG, DRVINST(node)));
657 return (PCIDEV_NIL);
658 }
659
660 return (REG_PCIDEV(regp));
661 }
662
663
664 /*
665 * returns non-zero when it can successfully return an attachment point
666 * through <ap_path> whose length is less than <ap_pathsz>; returns the full
667 * path of the AP through <pathret> which may be larger than <ap_pathsz>.
668 * Callers need to free <pathret>. If it cannot return the full path through
669 * <pathret> it will be set to NULL
670 *
671 * The ap path reflects a subset of the device path from an onboard host slot
672 * up to <node>. We traverse up the device tree starting from <node>, naming
673 * each component using pci_cfg_ap_node(). If we detect that a certain
674 * segment is contained within an expansion chassis, then we skip any bus
675 * nodes in between our current node and the topmost node of the chassis,
676 * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name
677 * of the expansion chassis as given by pci_cfg_iob_name()
678 *
679 * This scheme is always used for <pathret>. If however, the size of
680 * <pathret> is greater than <ap_pathsz> then only the default name as given
681 * by pci_cfg_ap_node() for <node> will be used
682 */
683 static int
pci_cfg_ap_path(di_minor_t minor,di_node_t node,di_prom_handle_t ph,char * ap_path,int ap_pathsz,char ** pathret)684 pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
685 char *ap_path, int ap_pathsz, char **pathret)
686 {
687 #ifdef DEBUG
688 char *fnm = "pci_cfg_ap_path";
689 #endif
690 #define seplen (sizeof (AP_PATH_SEP) - 1)
691 #define iob_pre_len (sizeof (IOB_PRE) - 1)
692 #define ap_path_iob_sep_len (sizeof (AP_PATH_IOB_SEP) - 1)
693
694 char *bufptr;
695 char buf[MAXPATHLEN];
696 char pathbuf[MAXPATHLEN];
697 int bufsz;
698 char *pathptr;
699 char *pathend = NULL;
700 int len;
701 int rv = 0;
702 int chasflag = 0;
703 di_node_t curnode = node;
704 di_node_t chasnode = DI_NODE_NIL;
705 minor_t pci_dev;
706
707 buf[0] = '\0';
708 pathbuf[0] = '\0';
709 pathptr = &pathbuf[sizeof (pathbuf) - 1];
710 *pathptr = '\0';
711
712 /*
713 * as we traverse up the device tree, we prepend components of our
714 * path inside pathbuf, using pathptr and decrementing
715 */
716 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
717 do {
718 bufptr = buf;
719 bufsz = sizeof (buf);
720
721 chasnode = pci_cfg_chassis_node(curnode, ph);
722 if (chasnode != DI_NODE_NIL) {
723 rv = pci_cfg_iob_name(minor, chasnode, ph,
724 bufptr, bufsz);
725 if (rv == 0) {
726 dprint(("%s: cannot create iob name "
727 "for %s%d\n", fnm, DRVINST(node)));
728 *pathptr = '\0';
729 goto OUT;
730 }
731
732 (void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
733 len = strlen(bufptr);
734 bufptr += len;
735 bufsz -= len - 1;
736
737 /* set chasflag when the leaf node is within an iob */
738 if (curnode == node)
739 chasflag = 1;
740 }
741 rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
742 if (rv == 0) {
743 dprint(("%s: cannot create ap node name "
744 "for %s%d\n", fnm, DRVINST(node)));
745 *pathptr = '\0';
746 goto OUT;
747 }
748
749 /*
750 * if we can't fit the entire path in our pathbuf, then use
751 * the default short name and nullify pathptr; also, since
752 * we prepend in the buffer, we must avoid adding a null char
753 */
754 if (curnode != node) {
755 pathptr -= seplen;
756 if (pathptr < pathbuf) {
757 pathptr = pathbuf;
758 *pathptr = '\0';
759 goto DEF;
760 }
761 (void) memcpy(pathptr, AP_PATH_SEP, seplen);
762 }
763 len = strlen(buf);
764 pathptr -= len;
765 if (pathptr < pathbuf) {
766 pathptr = pathbuf;
767 *pathptr = '\0';
768 goto DEF;
769 }
770 (void) memcpy(pathptr, buf, len);
771
772 /* remember the leaf component */
773 if (curnode == node)
774 pathend = pathptr;
775
776 /*
777 * go no further than the hosts' onboard slots
778 */
779 if (chasnode == DI_NODE_NIL)
780 break;
781 curnode = chasnode;
782
783 /*
784 * the pci device number of the current node is used to
785 * identify which slot of the parent's bus (next iteration)
786 * the current node is on
787 */
788 pci_dev = pci_cfg_pcidev(curnode, ph);
789 if (pci_dev == PCIDEV_NIL) {
790 dprint(("%s: cannot obtain pci device number "
791 "for %s%d\n", fnm, DRVINST(node)));
792 *pathptr = '\0';
793 goto OUT;
794 }
795 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
796
797 pathbuf[sizeof (pathbuf) - 1] = '\0';
798 if (strlen(pathptr) < ap_pathsz) {
799 (void) strlcpy(ap_path, pathptr, ap_pathsz);
800 rv = 1;
801 goto OUT;
802 }
803
804 DEF:
805 /*
806 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
807 * <node>'s name ONLY IF it has a serialid# which will make the apid
808 * globally unique
809 */
810 if (chasflag && pathend != NULL) {
811 if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
812 ap_path_iob_sep_len) != 0) &&
813 (strlen(pathend) < ap_pathsz)) {
814 (void) strlcpy(ap_path, pathend, ap_pathsz);
815 rv = 1;
816 goto OUT;
817 }
818 }
819
820 /*
821 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
822 * default name
823 */
824 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
825 rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
826 if (rv == 0) {
827 dprint(("%s: cannot create default ap node name for %s%d\n",
828 fnm, DRVINST(node)));
829 *pathptr = '\0';
830 goto OUT;
831 }
832 if (strlen(buf) < ap_pathsz) {
833 (void) strlcpy(ap_path, buf, ap_pathsz);
834 rv = 1;
835 goto OUT;
836 }
837
838 /*
839 * in this case, cfgadm goes through an expensive process to generate
840 * a purely dynamic logical apid: the framework will look through
841 * the device tree for attachment point minor nodes and will invoke
842 * each plugin responsible for that attachment point class, and if
843 * the plugin returns a logical apid that matches the queried apid
844 * or matches the default apid generated by the cfgadm framework for
845 * that driver/class (occurs when plugin returns an empty logical apid)
846 * then that is what it will use
847 *
848 * it is doubly expensive because the cfgadm pci plugin itself will
849 * also search the entire device tree in the absence of a link
850 */
851 rv = 0;
852 dprint(("%s: cannot create apid for %s%d within length of %d\n",
853 fnm, DRVINST(node), ap_pathsz));
854
855 OUT:
856 ap_path[ap_pathsz - 1] = '\0';
857 *pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
858 return (rv);
859
860 #undef seplen
861 #undef iob_pre_len
862 #undef ap_path_iob_sep_len
863 }
864
865
866 /*
867 * the DI_PROP_AP_NAMES property contains the first integer section of the
868 * ieee1275 "slot-names" property and functions as a bitmask; see comment for
869 * pci_cfg_slotname()
870 *
871 * we use the name of the attachment point minor node if its pci device
872 * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES
873 *
874 * returns non-zero if we return a valid attachment point through <path>
875 */
876 static int
pci_cfg_ap_legacy(di_minor_t minor,di_node_t node,di_prom_handle_t ph,char * ap_path,int ap_pathsz)877 pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
878 char *ap_path, int ap_pathsz)
879 {
880 minor_t pci_dev;
881 int *anp;
882
883 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES,
884 &anp) < 1)
885 return (0);
886
887 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
888 if ((*anp & (1 << pci_dev)) == 0)
889 return (0);
890
891 (void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
892 return (1);
893 }
894
895
896 /*
897 * determine if <node> qualifies for a path style apid
898 */
899 static int
pci_cfg_is_ap_path(di_node_t node,di_prom_handle_t ph)900 pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
901 {
902 char *devtype;
903 di_node_t curnode = node;
904
905 do {
906 if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
907 DI_PROP_DEV_TYPE, &devtype) > 0)
908 if (strcmp(devtype, PROPVAL_PCIEX) == 0)
909 return (1);
910 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
911
912 return (0);
913 }
914
915
916 /*
917 * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
918 * returns an allocated string intendend to be stored in a devlink info (dli)
919 * file
920 *
921 * data format: "Location: <transformed path>"
922 * where <transformed path> is <path> with occurrances of AP_PATH_SEP
923 * replaced by "/"
924 */
925 static char *
pci_cfg_info_data(char * path)926 pci_cfg_info_data(char *path)
927 {
928 #define head "Location: "
929 #define headlen (sizeof (head) - 1)
930 #define seplen (sizeof (AP_PATH_SEP) - 1)
931
932 char *sep, *prev, *np;
933 char *newpath;
934 int pathlen = strlen(path);
935 int len;
936
937 newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
938 np = newpath;
939 (void) strcpy(np, head);
940 np += headlen;
941
942 prev = path;
943 while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
944 len = sep - prev;
945 (void) memcpy(np, prev, len);
946 np += len;
947 *np++ = '/';
948 prev = sep + seplen;
949 }
950 (void) strcpy(np, prev);
951 return (newpath);
952
953 #undef head
954 #undef headlen
955 #undef seplen
956 }
957
958
959 static void
pci_cfg_rm_link(char * file)960 pci_cfg_rm_link(char *file)
961 {
962 char *dlipath;
963
964 dlipath = di_dli_name(file);
965 (void) unlink(dlipath);
966
967 devfsadm_rm_all(file);
968 free(dlipath);
969 }
970
971 /*
972 * removes all registered devlinks to physical path <physpath> except for
973 * the devlink <valid> if not NULL;
974 * <physpath> must include the minor node
975 */
976 static void
pci_cfg_rm_invalid_links(char * physpath,char * valid)977 pci_cfg_rm_invalid_links(char *physpath, char *valid)
978 {
979 char **dnp;
980 char *cp, *vcp;
981 int i, dnlen;
982
983 dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
984 if (dnp == NULL)
985 return;
986
987 if (valid != NULL) {
988 if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
989 vcp = valid + DEV_LEN + 1;
990 else
991 vcp = valid;
992 }
993
994 for (i = 0; i < dnlen; i++) {
995 if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
996 cp = dnp[i] + DEV_LEN + 1;
997 else
998 cp = dnp[i];
999
1000 if (valid != NULL) {
1001 if (strcmp(vcp, cp) == 0)
1002 continue;
1003 }
1004 pci_cfg_rm_link(cp);
1005 }
1006 devfsadm_free_dev_names(dnp, dnlen);
1007 }
1008
1009
1010 /*
1011 * takes a complete devinfo snapshot and returns the root node;
1012 * callers must do a di_fini() on the returned node;
1013 * if the snapshot failed, DI_NODE_NIL is returned instead
1014 *
1015 * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
1016 * in the new snapshot and return it through <ret_node> if it is found,
1017 * else DI_NODE_NIL is returned instead
1018 *
1019 * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
1020 * the matching minor in the new snapshot through <ret_minor> if it is found,
1021 * else DI_MINOR_NIL is returned instead
1022 */
1023 static di_node_t
pci_cfg_snapshot(di_node_t pci_node,di_minor_t pci_minor,di_node_t * ret_node,di_minor_t * ret_minor)1024 pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
1025 di_node_t *ret_node, di_minor_t *ret_minor)
1026 {
1027 di_node_t root_node;
1028 di_node_t node;
1029 di_minor_t minor;
1030 int pci_inst;
1031 dev_t pci_devt;
1032
1033 *ret_node = DI_NODE_NIL;
1034 *ret_minor = DI_MINOR_NIL;
1035
1036 root_node = di_init("/", DINFOCPYALL);
1037 if (root_node == DI_NODE_NIL)
1038 return (DI_NODE_NIL);
1039
1040 /*
1041 * narrow down search by driver, then instance, then minor
1042 */
1043 if (pci_node == DI_NODE_NIL)
1044 return (root_node);
1045
1046 pci_inst = di_instance(pci_node);
1047 node = di_drv_first_node(di_driver_name(pci_node), root_node);
1048 do {
1049 if (pci_inst == di_instance(node)) {
1050 *ret_node = node;
1051 break;
1052 }
1053 } while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
1054
1055 if (node == DI_NODE_NIL)
1056 return (root_node);
1057
1058 /*
1059 * found node, now search minors
1060 */
1061 if (pci_minor == DI_MINOR_NIL)
1062 return (root_node);
1063
1064 pci_devt = di_minor_devt(pci_minor);
1065 minor = DI_MINOR_NIL;
1066 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
1067 if (pci_devt == di_minor_devt(minor)) {
1068 *ret_minor = minor;
1069 break;
1070 }
1071 }
1072 return (root_node);
1073 }
1074
1075
1076 static int
pci_cfg_creat_cb(di_minor_t pci_minor,di_node_t pci_node)1077 pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
1078 {
1079 #ifdef DEBUG
1080 char *fnm = "pci_cfg_creat_cb";
1081 #endif
1082 #define ap_pathsz (sizeof (ap_path))
1083
1084 char ap_path[CFGA_LOG_EXT_LEN];
1085 char linkbuf[MAXPATHLEN];
1086 char *fullpath = NULL;
1087 char *pathinfo = NULL;
1088 char *devpath = NULL;
1089 int rv, fd = -1;
1090 size_t sz;
1091 di_prom_handle_t ph;
1092 di_node_t node;
1093 di_node_t root_node = DI_NODE_NIL;
1094 di_minor_t minor;
1095
1096 ph = di_prom_init();
1097 if (ph == DI_PROM_HANDLE_NIL) {
1098 dprint(("%s: di_prom_init() failed for %s%d\n",
1099 fnm, DRVINST(pci_node)));
1100 goto OUT;
1101 }
1102
1103 /*
1104 * Since incoming nodes from hotplug events are from snapshots that
1105 * do NOT contain parent/ancestor data, we must retake our own
1106 * snapshot and search for the target node
1107 */
1108 root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
1109 if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
1110 minor == DI_MINOR_NIL) {
1111 dprint(("%s: devinfo snapshot or search failed for %s%d\n",
1112 fnm, DRVINST(pci_node)));
1113 goto OUT;
1114 }
1115
1116 if (pci_cfg_is_ap_path(node, ph)) {
1117 rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
1118 &fullpath);
1119 if (rv == 0)
1120 goto OUT;
1121
1122 (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
1123 CFG_DIRNAME, ap_path);
1124
1125 /*
1126 * We must remove existing links because we may have invalid
1127 * apids that are valid links. Since these are not dangling,
1128 * devfsadm will not invoke the remove callback on them.
1129 *
1130 * What are "invalid apids with valid links"? Consider swapping
1131 * an attachment point bus with another while the system is
1132 * down, on the same device path bound to the same drivers
1133 * but with the new AP bus having different properties
1134 * (e.g. serialid#). If the previous apid is not removed,
1135 * there will now be two different links pointing to the same
1136 * attachment point, but only one reflects the correct
1137 * logical apid
1138 */
1139 devpath = pci_cfg_devpath(node, minor);
1140 if (devpath == NULL)
1141 goto OUT;
1142 pci_cfg_rm_invalid_links(devpath, linkbuf);
1143 free(devpath);
1144
1145 (void) devfsadm_mklink(linkbuf, node, minor, 0);
1146
1147 /*
1148 * we store the full logical path of the attachment point for
1149 * cfgadm to display in its info field which is useful when
1150 * the full logical path exceeds the size limit for logical
1151 * apids (CFGA_LOG_EXT_LEN)
1152 *
1153 * for the cfgadm pci plugin to do the same would be expensive
1154 * (i.e. devinfo snapshot + top down exhaustive minor search +
1155 * equivalent of pci_cfg_ap_path() on every invocation)
1156 *
1157 * note that if we do not create a link (pci_cfg_ap_path() is
1158 * not successful), that is what cfgadm will do anyways to
1159 * create a purely dynamic apid
1160 */
1161 pathinfo = pci_cfg_info_data(fullpath);
1162 fd = di_dli_openw(linkbuf);
1163 if (fd < 0)
1164 goto OUT;
1165
1166 sz = strlen(pathinfo) + 1;
1167 rv = write(fd, pathinfo, sz);
1168 if (rv < sz) {
1169 dprint(("%s: could not write full pathinfo to dli "
1170 "file for %s%d\n", fnm, DRVINST(node)));
1171 goto OUT;
1172 }
1173 di_dli_close(fd);
1174 } else {
1175 rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
1176 ap_pathsz);
1177 if (rv == 0)
1178 goto OUT;
1179
1180 (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
1181 CFG_DIRNAME, ap_path);
1182 (void) devfsadm_mklink(linkbuf, node, minor, 0);
1183 }
1184
1185 OUT:
1186 if (fd >= 0)
1187 di_dli_close(fd);
1188 if (fullpath != NULL)
1189 free(fullpath);
1190 if (pathinfo != NULL)
1191 free(pathinfo);
1192 if (ph != DI_PROM_HANDLE_NIL)
1193 di_prom_fini(ph);
1194 if (root_node != DI_NODE_NIL)
1195 di_fini(root_node);
1196 return (DEVFSADM_CONTINUE);
1197
1198 #undef ap_pathsz
1199 }
1200
1201
1202 static void
pci_cfg_rm_all(char * file)1203 pci_cfg_rm_all(char *file)
1204 {
1205 pci_cfg_rm_link(file);
1206 }
1207
1208
1209 /*
1210 * ib_cfg_creat_cb() creates two types of links
1211 * One for the fabric as /dev/cfg/ib
1212 * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
1213 */
1214 static int
ib_cfg_creat_cb(di_minor_t minor,di_node_t node)1215 ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
1216 {
1217 char *cp;
1218 char path[PATH_MAX + 1];
1219
1220 if ((cp = di_devfs_path(node)) == NULL) {
1221 return (DEVFSADM_CONTINUE);
1222 }
1223
1224 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
1225 di_devfs_path_free(cp);
1226
1227 /* create fabric or hca:GUID and the symlink */
1228 if (strstr(path, "ib:fabric") != NULL) {
1229 (void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
1230 } else {
1231 (void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
1232 di_minor_name(minor));
1233 }
1234
1235 (void) devfsadm_mklink(path, node, minor, 0);
1236 return (DEVFSADM_CONTINUE);
1237 }
1238
1239 /*
1240 * This function verifies if the serial id is printable.
1241 */
1242
1243 static int
serid_printable(uint64_t * seridp)1244 serid_printable(uint64_t *seridp)
1245 {
1246
1247 char *ptr;
1248 int i = 0;
1249
1250 for (ptr = (char *)seridp+3; i < 5; ptr++, i++)
1251 if (*ptr < 0x21 || *ptr >= 0x7f)
1252 return (0);
1253
1254 return (1);
1255
1256 }
1257
1258 /*
1259 * Create a link for cfgadm that points back to the normal ccid links in
1260 * /dev/ccid.
1261 */
1262 static int
ccid_cfg_creat_cb(di_minor_t minor,di_node_t node)1263 ccid_cfg_creat_cb(di_minor_t minor, di_node_t node)
1264 {
1265 const char *minor_nm;
1266 char cfg_path[MAXPATHLEN];
1267
1268 if ((minor_nm = di_minor_name(minor)) == NULL) {
1269 return (DEVFSADM_CONTINUE);
1270 }
1271
1272 (void) snprintf(cfg_path, sizeof (cfg_path), "%s/ccid%d/%s",
1273 CFG_DIRNAME, di_instance(node), minor_nm);
1274
1275 (void) devfsadm_mklink(cfg_path, node, minor, 0);
1276 return (DEVFSADM_CONTINUE);
1277 }
1278