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