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