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 ** 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 * 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 * 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 ** 127 path_get_descriptors(int filter[], int *errp) 128 { 129 return (cache_get_descriptors(DM_PATH, errp)); 130 } 131 132 char * 133 path_get_name(descriptor_t *desc) 134 { 135 return (desc->p.path->name); 136 } 137 138 /* ARGSUSED */ 139 nvlist_t * 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 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 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 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 ** 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 ** 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 * 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