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