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 **
path_get_assoc_descriptors(descriptor_t * desc,dm_desc_type_t type,int * errp)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 *
path_get_attributes(descriptor_t * dp,int * errp)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 *
path_get_descriptor_by_name(char * name,int * errp)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 **
path_get_descriptors(int filter[],int * errp)129 path_get_descriptors(int filter[], int *errp)
130 {
131 return (cache_get_descriptors(DM_PATH, errp));
132 }
133
134 char *
path_get_name(descriptor_t * desc)135 path_get_name(descriptor_t *desc)
136 {
137 return (desc->p.path->name);
138 }
139
140 /* ARGSUSED */
141 nvlist_t *
path_get_stats(descriptor_t * dp,int stat_type,int * errp)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
path_make_descriptors()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
add_path_state(descriptor_t * dp,nvlist_t * attrs)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
add_wwn(descriptor_t * dp,nvlist_t * attrs)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 **
get_assoc_controllers(descriptor_t * desc,int * errp)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 **
get_assoc_drives(descriptor_t * desc,int * errp)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 *
path_state_name(di_path_state_t st)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