xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4v/mdesc/disk_discovery.c (revision e7cbe64f7a72dae5cb44f100db60ca88f3313c65)
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 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 "mdescplugin.h"
30 
31 static char *device_format_disk_name(char *devfs_path);
32 static char *device_get_disk_name_from_dir(char *basedir, char *path);
33 static cfga_list_data_t *device_get_disk_cfga_info(char *cfgpath);
34 
35 /* These 3 variable are defined and set in mdescplugin.c */
36 extern picl_nodehdl_t	root_node;
37 extern md_t		*mdp;
38 extern mde_cookie_t	rootnode;
39 
40 /* This routine is defined in cpu_prop_update.c */
41 extern void set_prop_info(ptree_propinfo_t *propinfo, int size, char *name,
42     int type);
43 
44 int
45 disk_discovery(void)
46 {
47 	int			status = PICL_FAILURE;
48 	picl_nodehdl_t		discovery_node;
49 	picl_nodehdl_t		new_node;
50 	ptree_propinfo_t	propinfo;
51 	picl_prophdl_t		proph;
52 	char			*cfgpath, *dev_path, *nac;
53 	cfga_list_data_t	*disk_data;
54 	int			x, num_nodes, ndisks;
55 	mde_cookie_t		*disklistp;
56 
57 	num_nodes = md_node_count(mdp);
58 
59 	disklistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes);
60 	if (disklistp == NULL) {
61 		return (status);
62 	}
63 
64 	/*
65 	 * Starting at the root node, scan the "fwd" dag for
66 	 * all the disks in this description.
67 	 */
68 
69 	ndisks = md_scan_dag(mdp, rootnode, md_find_name(mdp, "disk_nac"),
70 	    md_find_name(mdp, "fwd"), disklistp);
71 
72 	if (ndisks <= 0) {
73 		return (status);
74 	}
75 
76 	status = ptree_create_and_add_node(root_node, DISK_DISCOVERY_NAME,
77 	    PICL_CLASS_PICL, &discovery_node);
78 	if (status != PICL_SUCCESS)
79 		return (status);
80 
81 	for (x = 0; x < ndisks; x++) {
82 		if (md_get_prop_str(mdp, disklistp[x], "phys_path",
83 			&dev_path) != 0) {
84 			continue;
85 		}
86 
87 		if (md_get_prop_str(mdp, disklistp[x], "nac_name",
88 			&nac) != 0) {
89 			continue;
90 		}
91 
92 		(void) ptree_create_and_add_node(discovery_node, "disk",
93 		    PICL_CLASS_DISK, &new_node);
94 
95 		set_prop_info(&propinfo, PICL_PROPNAMELEN_MAX, "Path",
96 		    PICL_PTYPE_CHARSTRING);
97 
98 		(void) ptree_create_and_add_prop(new_node, &propinfo,
99 		    (void *)dev_path, &proph);
100 
101 		set_prop_info(&propinfo, PICL_PROPNAMELEN_MAX, "Location",
102 		    PICL_PTYPE_CHARSTRING);
103 
104 		(void) ptree_create_and_add_prop(new_node, &propinfo,
105 		    (void *)nac, &proph);
106 
107 		set_prop_info(&propinfo, PICL_PROPNAMELEN_MAX, "State",
108 		    PICL_PTYPE_CHARSTRING);
109 
110 		cfgpath = device_format_disk_name(dev_path);
111 
112 		if (cfgpath == NULL) {
113 			(void) ptree_create_and_add_prop(new_node, &propinfo,
114 			    (void *)strdup(UNCONFIGURED), &proph);
115 			continue;
116 		}
117 
118 		disk_data = device_get_disk_cfga_info(cfgpath);
119 		if (disk_data == NULL) {
120 			continue;
121 		}
122 
123 		switch (disk_data->ap_o_state) {
124 		case CFGA_STAT_UNCONFIGURED:
125 			(void) ptree_create_and_add_prop(new_node, &propinfo,
126 			    (void *)strdup(UNCONFIGURED), &proph);
127 			break;
128 
129 		case CFGA_STAT_CONFIGURED:
130 			(void) ptree_create_and_add_prop(new_node, &propinfo,
131 			    (void *)strdup(CONFIGURED), &proph);
132 			break;
133 
134 		default:
135 			break;
136 		}
137 	}
138 	return (status);
139 }
140 
141 static cfga_list_data_t *
142 device_get_disk_cfga_info(char *cfgpath)
143 {
144 	char			**apid_names;
145 	char			apid_name[CFGA_AP_LOG_ID_LEN];
146 	cfga_err_t		cfga_err;
147 	struct cfga_list_data	*list_data;
148 	int			list_len, count;
149 
150 	(void) strcpy(apid_name, cfgpath);
151 
152 	apid_names = (char **)malloc(2 * sizeof (char *));
153 	apid_names[0] = apid_name;
154 	apid_names[1] = NULL;
155 
156 	cfga_err = config_list_ext(1, (char * const *)apid_names, &list_data,
157 	    &list_len, NULL, NULL, NULL, CFGA_FLAG_LIST_ALL);
158 	free(apid_names);
159 
160 	if (cfga_err != CFGA_OK || list_len == 0) {
161 		return (NULL);
162 	}
163 
164 	/* free any extra entries if this is not unique */
165 	if (list_len > 1) {
166 		for (count = 1; count < list_len; count++) {
167 			free(&list_data[count]);
168 		}
169 	}
170 
171 	return (&list_data[0]);
172 }
173 
174 
175 static char *
176 device_format_disk_name(char *devfs_path)
177 {
178 	char	devname[256];
179 	char	*diskname, *dev_cpy;
180 	char	apid_name[CFGA_AP_LOG_ID_LEN];
181 
182 	(void) snprintf(devname, sizeof (devname), "/devices%s:a,raw",
183 	    devfs_path);
184 
185 	diskname = device_get_disk_name_from_dir("/dev/rdsk", devname);
186 	if (diskname != NULL) {
187 		*strrchr(diskname, 's') = '\0';
188 		dev_cpy = strdup(diskname);
189 		*strchr(dev_cpy, 't') = '\0';
190 
191 		(void) snprintf(apid_name, sizeof (apid_name), "%s::dsk/%s",
192 			dev_cpy, diskname);
193 		return (strdup(apid_name));
194 	}
195 
196 	return (NULL);
197 }
198 
199 /*
200  * Getting a disk name is annoying.  Walking controllers
201  * doesn't work if disks were added out of order (ie a new
202  * controller card was installed), and DKIO controller numbers
203  * seem to always be 0.  So we do it the old fashioned way:
204  *
205  * We get a target name (in the /devices tree), and we want
206  * the node in /dev/rdsk that is a symlink to it.  So we walk
207  * /dev/rdsk, stating each entry.  Since stat follows the symlink
208  * automatically, we just compare the device and inode numbers
209  * to the device and inode numbers of the target.  According to
210  * the stat man page, this constitues a unique match.  The only
211  * little cleanup is that this includes a slice #, which we take
212  *  off.
213  */
214 
215 static char *
216 device_get_disk_name_from_dir(char *basedir, char *path)
217 {
218 	DIR		*dir;
219 	struct dirent	*dirent;
220 	struct stat	srcstat, targstat;
221 	int		loc_err;
222 	char		fullname[256 + MAXNAMLEN];
223 	char		*ptr;
224 
225 	loc_err = stat(path, &srcstat);
226 	if (loc_err < 0) {
227 		return (NULL);
228 	}
229 
230 	dir = opendir(basedir);
231 	if (dir == NULL) {
232 		return (NULL);
233 	}
234 
235 	while ((dirent = readdir(dir)) != NULL) {
236 		(void) snprintf(fullname, sizeof (fullname),
237 			"%s/%s", basedir, dirent->d_name);
238 
239 		loc_err = stat(fullname, &targstat);
240 		if (loc_err == 0) {
241 			if ((memcmp((void *)&(targstat.st_ino),
242 				(void *)&(srcstat.st_ino),
243 				sizeof (ino_t)) == 0) &&
244 				(memcmp((void *)&(targstat.st_dev),
245 				(void *)&(srcstat.st_dev),
246 				sizeof (dev_t)) == 0)) {
247 
248 				ptr = strdup(dirent->d_name);
249 
250 				(void) closedir(dir);
251 				return (ptr);
252 			}
253 		}
254 	}
255 
256 	(void) closedir(dir);
257 	return (NULL);
258 }
259