xref: /illumos-gate/usr/src/cmd/devfsadm/cfg_link.c (revision 03831d35)
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 2005 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 #define	SATA_CFG_LINK_RE	"^cfg/((sata[0-9]+)/([0-9]+)([.]([0-9])+)*)$"
41 
42 #define	CFG_DIRNAME		"cfg"
43 
44 static int	scsi_cfg_creat_cb(di_minor_t minor, di_node_t node);
45 static int	sbd_cfg_creat_cb(di_minor_t minor, di_node_t node);
46 static int	usb_cfg_creat_cb(di_minor_t minor, di_node_t node);
47 static char	*get_roothub(const char *path, void *cb_arg);
48 static int	pci_cfg_creat_cb(di_minor_t minor, di_node_t node);
49 static int	ib_cfg_creat_cb(di_minor_t minor, di_node_t node);
50 static int	sata_cfg_creat_cb(di_minor_t minor, di_node_t node);
51 
52 /*
53  * NOTE: The CREATE_DEFER flag is private to this module.
54  *	 NOT to be used by other modules
55  */
56 static devfsadm_create_t cfg_create_cbt[] = {
57 	{ "attachment-point", "ddi_ctl:attachment_point:scsi", NULL,
58 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
59 	},
60 	{ "attachment-point", "ddi_ctl:attachment_point:sbd", NULL,
61 	    TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
62 	},
63 	{ "fc-attachment-point", "ddi_ctl:attachment_point:fc", NULL,
64 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
65 	},
66 	{ "attachment-point", "ddi_ctl:attachment_point:usb", NULL,
67 	    TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
68 	},
69 	{ "attachment-point", "ddi_ctl:attachment_point:pci", NULL,
70 	    TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
71 	},
72 	{ "attachment-point", "ddi_ctl:attachment_point:ib", NULL,
73 	    TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
74 	},
75 	{ "attachment-point", "ddi_ctl:attachment_point:sata", NULL,
76 	    TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb
77 	}
78 };
79 
80 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
81 
82 static devfsadm_remove_t cfg_remove_cbt[] = {
83 	{ "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
84 	    ILEVEL_0, devfsadm_rm_all
85 	},
86 	{ "attachment-point", SBD_CFG_LINK_RE, RM_POST,
87 	    ILEVEL_0, devfsadm_rm_all
88 	},
89 	{ "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
90 	    ILEVEL_0, devfsadm_rm_all
91 	},
92 	{ "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
93 	    ILEVEL_0, devfsadm_rm_all
94 	},
95 	{ "attachment-point", PCI_CFG_LINK_RE, RM_POST,
96 	    ILEVEL_0, devfsadm_rm_all
97 	},
98 	{ "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
99 	    ILEVEL_0, devfsadm_rm_all
100 	},
101 	{ "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
102 	    ILEVEL_0, devfsadm_rm_all
103 	}
104 };
105 
106 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
107 
108 static int
109 scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
110 {
111 	char path[PATH_MAX + 1];
112 	char *c_num = NULL, *devfs_path, *mn;
113 	devfsadm_enumerate_t rules[3] = {
114 	    {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
115 	    {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
116 	    {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
117 	};
118 
119 	mn = di_minor_name(minor);
120 
121 	if ((devfs_path = di_devfs_path(node)) == NULL) {
122 		return (DEVFSADM_CONTINUE);
123 	}
124 	(void) strcpy(path, devfs_path);
125 	(void) strcat(path, ":");
126 	(void) strcat(path, mn);
127 	di_devfs_path_free(devfs_path);
128 
129 	if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3)
130 	    == DEVFSADM_FAILURE) {
131 		/*
132 		 * Unlike the disks module we don't retry on failure.
133 		 * If we have multiple "c" numbers for a single physical
134 		 * controller due to bug 4045879, we will not assign a
135 		 * c-number/symlink for the controller.
136 		 */
137 		return (DEVFSADM_CONTINUE);
138 	}
139 
140 	(void) strcpy(path, CFG_DIRNAME);
141 	(void) strcat(path, "/c");
142 	(void) strcat(path, c_num);
143 
144 	free(c_num);
145 
146 	(void) devfsadm_mklink(path, node, minor, 0);
147 
148 	return (DEVFSADM_CONTINUE);
149 }
150 
151 static int
152 sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
153 {
154 	char path[PATH_MAX + 1];
155 
156 	(void) strcpy(path, CFG_DIRNAME);
157 	(void) strcat(path, "/");
158 	(void) strcat(path, di_minor_name(minor));
159 	(void) devfsadm_mklink(path, node, minor, 0);
160 	return (DEVFSADM_CONTINUE);
161 }
162 
163 
164 static int
165 usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
166 {
167 	char *cp, path[PATH_MAX + 1];
168 	devfsadm_enumerate_t rules[1] =
169 		{"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
170 
171 	if ((cp = di_devfs_path(node)) == NULL) {
172 		return (DEVFSADM_CONTINUE);
173 	}
174 
175 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
176 	di_devfs_path_free(cp);
177 
178 	if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) {
179 		return (DEVFSADM_CONTINUE);
180 	}
181 
182 	/* create usbN and the symlink */
183 	(void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
184 	    di_minor_name(minor));
185 	free(cp);
186 
187 	(void) devfsadm_mklink(path, node, minor, 0);
188 
189 	return (DEVFSADM_CONTINUE);
190 }
191 
192 
193 static int
194 sata_cfg_creat_cb(di_minor_t minor, di_node_t node)
195 {
196 	char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath;
197 	char *minor_nm;
198 	devfsadm_enumerate_t rules[1] =
199 		{"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR};
200 
201 	minor_nm = di_minor_name(minor);
202 	if (minor_nm == NULL)
203 		return (DEVFSADM_CONTINUE);
204 
205 	devfspath = di_devfs_path(node);
206 	if (devfspath == NULL)
207 		return (DEVFSADM_CONTINUE);
208 
209 	(void) strlcpy(path, devfspath, sizeof (path));
210 	(void) strlcat(path, ":", sizeof (path));
211 	(void) strlcat(path, minor_nm, sizeof (path));
212 	di_devfs_path_free(devfspath);
213 
214 	/* build the physical path from the components */
215 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
216 	    DEVFSADM_FAILURE) {
217 		return (DEVFSADM_CONTINUE);
218 	}
219 
220 	(void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME,
221 			buf, minor_nm);
222 	free(buf);
223 
224 	(void) devfsadm_mklink(l_path, node, minor, 0);
225 
226 	return (DEVFSADM_CONTINUE);
227 }
228 
229 
230 /*
231  * get_roothub:
232  *	figure out the root hub path to calculate /dev/cfg/usbN
233  */
234 /* ARGSUSED */
235 static char *
236 get_roothub(const char *path, void *cb_arg)
237 {
238 	int  i, count = 0;
239 	char *physpath, *cp;
240 
241 	/* make a copy */
242 	if ((physpath = strdup(path)) == NULL) {
243 		return (NULL);
244 	}
245 
246 	/*
247 	 * physpath must always have a minor name component
248 	 */
249 	if ((cp = strrchr(physpath, ':')) == NULL) {
250 		free(physpath);
251 		return (NULL);
252 	}
253 	*cp++ = '\0';
254 
255 	/*
256 	 * No '.' in the minor name indicates a roothub port.
257 	 */
258 	if (strchr(cp, '.') == NULL) {
259 		/* roothub device */
260 		return (physpath);
261 	}
262 
263 	while (*cp) {
264 		if (*cp == '.')
265 			count++;
266 		cp++;
267 	}
268 
269 	/* Remove as many trailing path components as there are '.'s */
270 	for (i = 0; i < count; i++) {
271 		if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
272 			free(physpath);
273 			return (NULL);
274 		}
275 		*cp = '\0';
276 	}
277 
278 	return (physpath);
279 }
280 
281 
282 /*
283  * pci_cfg_creat_cb() search the <device mask> data from
284  * "slot-names" PROM property for the match device number,
285  * then create device link with the right slot label.
286  */
287 static int
288 pci_cfg_creat_cb(di_minor_t minor, di_node_t node)
289 {
290 	char		*minor_name, *dev_path;
291 	char		path[PATH_MAX + 1];
292 	int		*devlink_flags;
293 	minor_t		pci_dev;
294 	di_node_t	dev_node;
295 
296 	minor_name = di_minor_name(minor);
297 	pci_dev = (minor->dev_minor) & 0xFF;
298 
299 	dev_path = di_devfs_path(node);
300 	dev_node = di_init(dev_path, DINFOCPYALL);
301 	if ((di_prop_lookup_ints(DDI_DEV_T_ANY, dev_node,
302 			"ap-names", &devlink_flags)) > 0) {
303 		if ((*devlink_flags) & (1 << pci_dev)) {
304 			(void) snprintf(path, sizeof (path), "%s/%s",
305 			    CFG_DIRNAME, minor_name);
306 			(void) devfsadm_mklink(path, node, minor, 0);
307 		}
308 	}
309 	di_fini(dev_node);
310 	(void) di_devfs_path_free(dev_path);
311 
312 	return (DEVFSADM_CONTINUE);
313 }
314 
315 
316 /*
317  * ib_cfg_creat_cb() creates two types of links
318  * One for the fabric as /dev/cfg/ib
319  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
320  */
321 static int
322 ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
323 {
324 	char	*cp;
325 	char	path[PATH_MAX + 1];
326 
327 	if ((cp = di_devfs_path(node)) == NULL) {
328 		return (DEVFSADM_CONTINUE);
329 	}
330 
331 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
332 	di_devfs_path_free(cp);
333 
334 	/* create fabric or hca:GUID and the symlink */
335 	if (strstr(path, "ib:fabric") != NULL) {
336 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
337 	} else {
338 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
339 		    di_minor_name(minor));
340 	}
341 
342 	(void) devfsadm_mklink(path, node, minor, 0);
343 	return (DEVFSADM_CONTINUE);
344 }
345