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