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