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