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