xref: /illumos-gate/usr/src/lib/libdiskmgt/common/path.c (revision 8e458de0baeb1fee50643403223bc7e909a48464)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <fcntl.h>
29 #include <libdevinfo.h>
30 #include <stdlib.h>
31 #include <sys/sunddi.h>
32 #include <sys/types.h>
33 
34 #include "libdiskmgt.h"
35 #include "disks_private.h"
36 
37 static int		add_path_state(descriptor_t *dp, nvlist_t *attrs);
38 static int		add_wwn(descriptor_t *dp, nvlist_t *attrs);
39 static descriptor_t	**get_assoc_drives(descriptor_t *desc, int *errp);
40 static descriptor_t	**get_assoc_controllers(descriptor_t *desc, int *errp);
41 static char		*path_state_name(di_path_state_t st);
42 
43 descriptor_t **
44 path_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type, int *errp)
45 {
46 	switch (type) {
47 	case DM_DRIVE:
48 	    return (get_assoc_drives(desc, errp));
49 	case DM_CONTROLLER:
50 	    return (get_assoc_controllers(desc, errp));
51 	}
52 
53 	*errp = EINVAL;
54 	return (NULL);
55 }
56 
57 nvlist_t *
58 path_get_attributes(descriptor_t *dp, int *errp)
59 {
60 	path_t		*pp;
61 	nvlist_t	*attrs = NULL;
62 
63 	pp = dp->p.path;
64 
65 	if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
66 	    *errp = ENOMEM;
67 	    return (NULL);
68 	}
69 
70 	if (nvlist_add_string(attrs, DM_CTYPE, pp->ctype) != 0) {
71 	    nvlist_free(attrs);
72 	    *errp = ENOMEM;
73 	    return (NULL);
74 	}
75 
76 	/*
77 	 * We add the path state and wwn attributes only for descriptors that
78 	 * we got via their association to a specific drive (since these
79 	 * attributes are drive specific).
80 	 */
81 	if (dp->name != NULL) {
82 	    if (add_path_state(dp, attrs) != 0) {
83 		nvlist_free(attrs);
84 		*errp = ENOMEM;
85 		return (NULL);
86 	    }
87 	    if (add_wwn(dp, attrs) != 0) {
88 		nvlist_free(attrs);
89 		*errp = ENOMEM;
90 		return (NULL);
91 	    }
92 	}
93 
94 	*errp = 0;
95 	return (attrs);
96 }
97 
98 descriptor_t *
99 path_get_descriptor_by_name(char *name, int *errp)
100 {
101 	descriptor_t	**paths;
102 	int		i;
103 	descriptor_t	*path = NULL;
104 
105 	paths = cache_get_descriptors(DM_PATH, errp);
106 	if (*errp != 0) {
107 	    return (NULL);
108 	}
109 
110 	for (i = 0; paths[i]; i++) {
111 	    if (libdiskmgt_str_eq(name, paths[i]->p.path->name)) {
112 		path = paths[i];
113 	    } else {
114 		/* clean up the unused descriptors */
115 		cache_free_descriptor(paths[i]);
116 	    }
117 	}
118 	free(paths);
119 
120 	if (path == NULL) {
121 	    *errp = ENODEV;
122 	}
123 
124 	return (path);
125 }
126 
127 /* ARGSUSED */
128 descriptor_t **
129 path_get_descriptors(int filter[], int *errp)
130 {
131 	return (cache_get_descriptors(DM_PATH, errp));
132 }
133 
134 char *
135 path_get_name(descriptor_t *desc)
136 {
137 	return (desc->p.path->name);
138 }
139 
140 /* ARGSUSED */
141 nvlist_t *
142 path_get_stats(descriptor_t *dp, int stat_type, int *errp)
143 {
144 	/* There are no stat types defined for paths */
145 	*errp = EINVAL;
146 	return (NULL);
147 }
148 
149 int
150 path_make_descriptors()
151 {
152 	int		error;
153 	controller_t	*cp;
154 
155 	cp = cache_get_controllerlist();
156 	while (cp != NULL) {
157 	    if (cp->paths != NULL) {
158 		int i;
159 
160 		for (i = 0; cp->paths[i]; i++) {
161 		    cache_load_desc(DM_PATH, cp->paths[i], NULL, NULL, &error);
162 		    if (error != 0) {
163 			return (error);
164 		    }
165 		}
166 	    }
167 	    cp = cp->next;
168 	}
169 
170 	return (0);
171 }
172 
173 /*
174  * This is called when we have a name in the descriptor name field.  That
175  * only will be the case when the descriptor was created by getting the
176  * association from a drive to the path.  Since we filled in the name with
177  * the drive device id in that case, we can use the device id to look up the
178  * drive-path state.
179  */
180 static int
181 add_path_state(descriptor_t *dp, nvlist_t *attrs)
182 {
183 	ddi_devid_t	devid;
184 	path_t		*pp;
185 	int		i;
186 	int		status = 0;
187 
188 	if (devid_str_decode(dp->name, &devid, NULL) != 0) {
189 	    return (0);
190 	}
191 
192 	/* find the index of the correct drive assoc. */
193 	pp = dp->p.path;
194 	for (i = 0; pp->disks[i] && pp->states[i] != -1; i++) {
195 	    if (pp->disks[i]->devid != NULL &&
196 		devid_compare(pp->disks[i]->devid, devid) == 0) {
197 
198 		/* add the corresponding state */
199 		if (nvlist_add_string(attrs, DM_PATH_STATE,
200 		    path_state_name(pp->states[i])) != 0) {
201 		    status = ENOMEM;
202 		}
203 		break;
204 	    }
205 	}
206 	devid_free(devid);
207 
208 	return (status);
209 }
210 
211 /*
212  * This is called when we have a name in the descriptor name field.  That
213  * only will be the case when the descriptor was created by getting the
214  * association from a drive to the path.  Since we filled in the name with
215  * the drive device id in that case, we can use the device id to look up the
216  * drive wwn.
217  */
218 static int
219 add_wwn(descriptor_t *dp, nvlist_t *attrs)
220 {
221 	ddi_devid_t	devid;
222 	path_t		*pp;
223 	int		i;
224 	int		status = 0;
225 
226 	if (devid_str_decode(dp->name, &devid, NULL) != 0) {
227 	    return (0);
228 	}
229 
230 	/* find the index of the correct drive assoc. */
231 	pp = dp->p.path;
232 	for (i = 0; pp->disks[i] && pp->states[i] != -1; i++) {
233 	    if (pp->disks[i]->devid != NULL &&
234 		devid_compare(pp->disks[i]->devid, devid) == 0) {
235 
236 		/* add the corresponding state */
237 		if (nvlist_add_string(attrs, DM_WWN, pp->wwns[i]) != 0) {
238 		    status = ENOMEM;
239 		}
240 		break;
241 	    }
242 	}
243 	devid_free(devid);
244 
245 	return (status);
246 }
247 
248 static descriptor_t **
249 get_assoc_controllers(descriptor_t *desc, int *errp)
250 {
251 	path_t		*pp;
252 	descriptor_t	**controllers;
253 	int		i;
254 
255 	pp = desc->p.path;
256 
257 	/* a path can have just one controller */
258 
259 	controllers = (descriptor_t **)calloc(2, sizeof (descriptor_t *));
260 	if (controllers == NULL) {
261 	    *errp = ENOMEM;
262 	    return (NULL);
263 	}
264 
265 	i = 0;
266 	if (pp->controller != NULL) {
267 	    controllers[i++] = cache_get_desc(DM_CONTROLLER,
268 		pp->controller, NULL, NULL, errp);
269 	    if (*errp != 0) {
270 		cache_free_descriptors(controllers);
271 		return (NULL);
272 	    }
273 	}
274 
275 	controllers[i] = NULL;
276 
277 	*errp = 0;
278 	return (controllers);
279 }
280 
281 static descriptor_t **
282 get_assoc_drives(descriptor_t *desc, int *errp)
283 {
284 	path_t		*pp;
285 	descriptor_t	**drives;
286 	int		cnt;
287 	int		i;
288 
289 	pp = desc->p.path;
290 
291 	/* Count how many we have. */
292 	for (cnt = 0; pp->disks[cnt]; cnt++);
293 
294 	/* make the snapshot */
295 	drives = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
296 	if (drives == NULL) {
297 	    *errp = ENOMEM;
298 	    return (NULL);
299 	}
300 
301 	for (i = 0; pp->disks[i]; i++) {
302 	    drives[i] = cache_get_desc(DM_DRIVE, pp->disks[i], NULL, NULL,
303 		errp);
304 	    if (*errp != 0) {
305 		cache_free_descriptors(drives);
306 		return (NULL);
307 	    }
308 	}
309 	drives[i] = NULL;
310 
311 	*errp = 0;
312 	return (drives);
313 }
314 
315 static char *
316 path_state_name(di_path_state_t st)
317 {
318 	switch (st) {
319 	    case DI_PATH_STATE_ONLINE:
320 		return ("online");
321 	    case DI_PATH_STATE_STANDBY:
322 		return ("standby");
323 	    case DI_PATH_STATE_OFFLINE:
324 		return ("offline");
325 	    case DI_PATH_STATE_FAULT:
326 		return ("faulted");
327 	}
328 	return ("unknown");
329 }
330