xref: /illumos-gate/usr/src/cmd/devfsadm/cfg_link.c (revision 1cb6af97c6f66f456d4f726ef056e1ebc0f73305)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <devfsadm.h>
30 #include <stdio.h>
31 #include <strings.h>
32 #include <stdlib.h>
33 #include <limits.h>
34 
35 #define	SCSI_CFG_LINK_RE	"^cfg/c[0-9]+$"
36 #define	SBD_CFG_LINK_RE		"^cfg/((((N[0-9]+[.])?(SB|IB))?[0-9]+)|[abcd])$"
37 #define	USB_CFG_LINK_RE		"^cfg/((usb[0-9]+)/([0-9]+)([.]([0-9])+)*)$"
38 #define	PCI_CFG_LINK_RE		"^cfg/[:alnum:]$"
39 #define	IB_CFG_LINK_RE		"^cfg/(hca[0-9A-F]+)$"
40 
41 #define	CFG_DIRNAME		"cfg"
42 
43 static int	scsi_cfg_creat_cb(di_minor_t minor, di_node_t node);
44 static int	sbd_cfg_creat_cb(di_minor_t minor, di_node_t node);
45 static int	usb_cfg_creat_cb(di_minor_t minor, di_node_t node);
46 static char	*get_roothub(const char *path, void *cb_arg);
47 static int	pci_cfg_creat_cb(di_minor_t minor, di_node_t node);
48 static int	ib_cfg_creat_cb(di_minor_t minor, di_node_t node);
49 
50 /*
51  * NOTE: The CREATE_DEFER flag is private to this module.
52  *	 NOT to be used by other modules
53  */
54 static devfsadm_create_t cfg_create_cbt[] = {
55 	{ "attachment-point", "ddi_ctl:attachment_point:scsi", NULL,
56 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
57 	},
58 	{ "attachment-point", "ddi_ctl:attachment_point:sbd", NULL,
59 	    TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
60 	},
61 	{ "fc-attachment-point", "ddi_ctl:attachment_point:fc", NULL,
62 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
63 	},
64 	{ "attachment-point", "ddi_ctl:attachment_point:usb", NULL,
65 	    TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
66 	},
67 	{ "attachment-point", "ddi_ctl:attachment_point:pci", NULL,
68 	    TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
69 	},
70 	{ "attachment-point", "ddi_ctl:attachment_point:ib", NULL,
71 	    TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
72 	}
73 };
74 
75 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
76 
77 static devfsadm_remove_t cfg_remove_cbt[] = {
78 	{ "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
79 	    ILEVEL_0, devfsadm_rm_all
80 	},
81 	{ "attachment-point", SBD_CFG_LINK_RE, RM_POST,
82 	    ILEVEL_0, devfsadm_rm_all
83 	},
84 	{ "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
85 	    ILEVEL_0, devfsadm_rm_all
86 	},
87 	{ "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
88 	    ILEVEL_0, devfsadm_rm_all
89 	},
90 	{ "attachment-point", PCI_CFG_LINK_RE, RM_POST,
91 	    ILEVEL_0, devfsadm_rm_all
92 	},
93 	{ "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
94 	    ILEVEL_0, devfsadm_rm_all
95 	}
96 };
97 
98 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
99 
100 static int
101 scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
102 {
103 	char path[PATH_MAX + 1];
104 	char *c_num = NULL, *devfs_path, *mn;
105 	devfsadm_enumerate_t rules[3] = {
106 	    {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
107 	    {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
108 	    {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
109 	};
110 
111 	mn = di_minor_name(minor);
112 
113 	if ((devfs_path = di_devfs_path(node)) == NULL) {
114 		return (DEVFSADM_CONTINUE);
115 	}
116 	(void) strcpy(path, devfs_path);
117 	(void) strcat(path, ":");
118 	(void) strcat(path, mn);
119 	di_devfs_path_free(devfs_path);
120 
121 	if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3)
122 	    == DEVFSADM_FAILURE) {
123 		/*
124 		 * Unlike the disks module we don't retry on failure.
125 		 * If we have multiple "c" numbers for a single physical
126 		 * controller due to bug 4045879, we will not assign a
127 		 * c-number/symlink for the controller.
128 		 */
129 		return (DEVFSADM_CONTINUE);
130 	}
131 
132 	(void) strcpy(path, CFG_DIRNAME);
133 	(void) strcat(path, "/c");
134 	(void) strcat(path, c_num);
135 
136 	free(c_num);
137 
138 	(void) devfsadm_mklink(path, node, minor, 0);
139 
140 	return (DEVFSADM_CONTINUE);
141 }
142 
143 static int
144 sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
145 {
146 	char path[PATH_MAX + 1];
147 
148 	(void) strcpy(path, CFG_DIRNAME);
149 	(void) strcat(path, "/");
150 	(void) strcat(path, di_minor_name(minor));
151 	(void) devfsadm_mklink(path, node, minor, 0);
152 	return (DEVFSADM_CONTINUE);
153 }
154 
155 
156 static int
157 usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
158 {
159 	char *cp, path[PATH_MAX + 1];
160 	devfsadm_enumerate_t rules[1] =
161 		{"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
162 
163 	if ((cp = di_devfs_path(node)) == NULL) {
164 		return (DEVFSADM_CONTINUE);
165 	}
166 
167 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
168 	di_devfs_path_free(cp);
169 
170 	if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) {
171 		return (DEVFSADM_CONTINUE);
172 	}
173 
174 	/* create usbN and the symlink */
175 	(void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
176 	    di_minor_name(minor));
177 	free(cp);
178 
179 	(void) devfsadm_mklink(path, node, minor, 0);
180 
181 	return (DEVFSADM_CONTINUE);
182 }
183 
184 
185 /*
186  * get_roothub:
187  *	figure out the root hub path to calculate /dev/cfg/usbN
188  */
189 /* ARGSUSED */
190 static char *
191 get_roothub(const char *path, void *cb_arg)
192 {
193 	int  i, count = 0;
194 	char *physpath, *cp;
195 
196 	/* make a copy */
197 	if ((physpath = strdup(path)) == NULL) {
198 		return (NULL);
199 	}
200 
201 	/*
202 	 * physpath must always have a minor name component
203 	 */
204 	if ((cp = strrchr(physpath, ':')) == NULL) {
205 		free(physpath);
206 		return (NULL);
207 	}
208 	*cp++ = '\0';
209 
210 	/*
211 	 * No '.' in the minor name indicates a roothub port.
212 	 */
213 	if (strchr(cp, '.') == NULL) {
214 		/* roothub device */
215 		return (physpath);
216 	}
217 
218 	while (*cp) {
219 		if (*cp == '.')
220 			count++;
221 		cp++;
222 	}
223 
224 	/* Remove as many trailing path components as there are '.'s */
225 	for (i = 0; i < count; i++) {
226 		if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
227 			free(physpath);
228 			return (NULL);
229 		}
230 		*cp = '\0';
231 	}
232 
233 	return (physpath);
234 }
235 
236 
237 /*
238  * pci_cfg_creat_cb() search the <device mask> data from
239  * "slot-names" PROM property for the match device number,
240  * then create device link with the right slot label.
241  */
242 static int
243 pci_cfg_creat_cb(di_minor_t minor, di_node_t node)
244 {
245 	char		*minor_name, *dev_path;
246 	char		path[PATH_MAX + 1];
247 	int		*devlink_flags;
248 	minor_t		pci_dev;
249 	di_node_t	dev_node;
250 
251 	minor_name = di_minor_name(minor);
252 	pci_dev = (minor->dev_minor) & 0xFF;
253 
254 	dev_path = di_devfs_path(node);
255 	dev_node = di_init(dev_path, DINFOCPYALL);
256 	if ((di_prop_lookup_ints(DDI_DEV_T_ANY, dev_node,
257 			"ap-names", &devlink_flags)) > 0) {
258 		if ((*devlink_flags) & (1 << pci_dev)) {
259 			(void) snprintf(path, sizeof (path), "%s/%s",
260 			    CFG_DIRNAME, minor_name);
261 			(void) devfsadm_mklink(path, node, minor, 0);
262 		}
263 	}
264 	di_fini(dev_node);
265 	(void) di_devfs_path_free(dev_path);
266 
267 	return (DEVFSADM_CONTINUE);
268 }
269 
270 
271 /*
272  * ib_cfg_creat_cb() creates two types of links
273  * One for the fabric as /dev/cfg/ib
274  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
275  */
276 static int
277 ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
278 {
279 	char	*cp;
280 	char	path[PATH_MAX + 1];
281 
282 	if ((cp = di_devfs_path(node)) == NULL) {
283 		return (DEVFSADM_CONTINUE);
284 	}
285 
286 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
287 	di_devfs_path_free(cp);
288 
289 	/* create fabric or hca:GUID and the symlink */
290 	if (strstr(path, "ib:fabric") != NULL) {
291 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
292 	} else {
293 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
294 		    di_minor_name(minor));
295 	}
296 
297 	(void) devfsadm_mklink(path, node, minor, 0);
298 	return (DEVFSADM_CONTINUE);
299 }
300