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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sun_sas.h> 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <fcntl.h> 31 #include <unistd.h> 32 #include <dirent.h> 33 #include <libdevinfo.h> 34 35 /* 36 * structure for di_devlink_walk 37 */ 38 typedef struct walk_devlink { 39 char *path; 40 size_t len; 41 char **linkpp; 42 } walk_devlink_t; 43 44 /* 45 * callback funtion for di_devlink_walk 46 * Find matching /dev link for the given path argument. 47 * devlink element and callback function argument. 48 * The input path is expected to not have "/devices". 49 */ 50 static int 51 get_devlink(di_devlink_t devlink, void *arg) 52 { 53 const char ROUTINE[] = "get_devlink"; 54 walk_devlink_t *warg = (walk_devlink_t *)arg; 55 56 /* 57 * When path is specified, it doesn't have minor 58 * name. Therefore, the ../.. prefixes needs to be stripped. 59 */ 60 if (warg->path) { 61 char *content = (char *)di_devlink_content(devlink); 62 char *start = strstr(content, "/devices"); 63 64 if (start == NULL || 65 strncmp(start, warg->path, warg->len) != 0 || 66 /* make it sure the device path has minor name */ 67 start[warg->len] != ':') { 68 return (DI_WALK_CONTINUE); 69 } 70 } 71 72 *(warg->linkpp) = strdup(di_devlink_path(devlink)); 73 log(LOG_DEBUG, ROUTINE, "Walk terminate"); 74 return (DI_WALK_TERMINATE); 75 } 76 77 /* 78 * Convert /devices paths to /dev sym-link paths. 79 * The mapping buffer OSDeviceName paths will be 80 * converted to short names. 81 * mappings The target mappings data to convert to short names 82 * 83 * If no link is found, the long path is left as is. 84 * Note: The NumberOfEntries field MUST not be greater than the size 85 * of the array passed in. 86 */ 87 void 88 convertDevpathToDevlink(PSMHBA_TARGETMAPPING mappings) 89 { 90 const char ROUTINE[] = "convertDevpathToLink"; 91 di_devlink_handle_t hdl; 92 walk_devlink_t warg; 93 int j; 94 char *minor_path, *devlinkp; 95 96 if ((hdl = di_devlink_init(NULL, 0)) == NULL) { 97 log(LOG_DEBUG, ROUTINE, "di_devlink failed: errno:%d", 98 strerror(errno)); 99 return; 100 } 101 102 for (j = 0; j < mappings->NumberOfEntries; j++) { 103 if (strchr(mappings->entry[j].ScsiId.OSDeviceName, ':')) { 104 /* search link for minor node */ 105 minor_path = mappings->entry[j].ScsiId.OSDeviceName; 106 if (strstr(minor_path, "/devices") != NULL) { 107 minor_path = mappings->entry[j].ScsiId. 108 OSDeviceName + strlen("/devices"); 109 } 110 warg.path = NULL; 111 } else { 112 minor_path = NULL; 113 if (strstr(mappings->entry[j].ScsiId.OSDeviceName, 114 "/devices") != NULL) { 115 warg.len = strlen(mappings->entry[j].ScsiId. 116 OSDeviceName) - strlen("/devices"); 117 warg.path = mappings->entry[j]. 118 ScsiId.OSDeviceName + strlen("/devices"); 119 } else { 120 warg.len = strlen(mappings->entry[j].ScsiId. 121 OSDeviceName); 122 warg.path = mappings->entry[j].ScsiId. 123 OSDeviceName; 124 } 125 } 126 127 devlinkp = NULL; 128 warg.linkpp = &devlinkp; 129 (void) di_devlink_walk(hdl, NULL, minor_path, DI_PRIMARY_LINK, 130 (void *)&warg, get_devlink); 131 132 if (devlinkp != NULL) { 133 (void) snprintf(mappings->entry[j].ScsiId.OSDeviceName, 134 sizeof (mappings->entry[j].ScsiId.OSDeviceName), 135 "%s", devlinkp); 136 free(devlinkp); 137 } 138 139 } 140 141 (void) di_devlink_fini(&hdl); 142 } 143 144 /* 145 * Finds controller path for a give device path. 146 * 147 * Return value: /dev link for dir and minor name. 148 */ 149 static HBA_STATUS 150 lookupLink(char *path, char *link, const char *dir, const char *mname) 151 { 152 const char ROUTINE[] = "lookupLink"; 153 DIR *dp; 154 char buf[MAXPATHLEN]; 155 char node[MAXPATHLEN]; 156 char *charptr; 157 struct dirent *newdirp, *dirp; 158 ssize_t count; 159 int dirplen; 160 char *subpath; 161 char tmpPath[MAXPATHLEN]; 162 163 if ((dp = opendir(dir)) == NULL) { 164 log(LOG_DEBUG, ROUTINE, 165 "Unable to open %s to find controller number.", dir); 166 return (HBA_STATUS_ERROR); 167 } 168 169 if (link == NULL) { 170 log(LOG_DEBUG, ROUTINE, 171 "Invalid argument for storing the link."); 172 return (HBA_STATUS_ERROR); 173 } 174 175 /* 176 * dirplen is large enough to fit the largest path- 177 * struct dirent includes one byte (the terminator) 178 * so we don't add 1 to the calculation here. 179 */ 180 dirplen = pathconf(dir, _PC_NAME_MAX); 181 dirplen = ((dirplen <= 0) ? MAXNAMELEN : dirplen) + 182 sizeof (struct dirent); 183 dirp = (struct dirent *)malloc(dirplen); 184 if (dirp == NULL) { 185 OUT_OF_MEMORY(ROUTINE); 186 return (HBA_STATUS_ERROR); 187 } 188 189 while ((readdir_r(dp, dirp, &newdirp)) == 0 && newdirp != NULL) { 190 if (strcmp(dirp->d_name, ".") == 0 || 191 strcmp(dirp->d_name, "..") == 0) { 192 continue; 193 } 194 /* 195 * set to another pointer since dirp->d_name length is 1 196 * that will store only the first char 'c' from the name. 197 */ 198 charptr = dirp->d_name; 199 (void) snprintf(node, strlen(charptr) + strlen(dir) + 2, 200 "%s/%s", dir, charptr); 201 if (count = readlink(node, buf, sizeof (buf))) { 202 subpath = NULL; 203 subpath = strstr(buf, path); 204 buf[count] = '\0'; 205 if (subpath != NULL) { 206 (void) strlcpy(tmpPath, path, MAXPATHLEN); 207 (void) strlcat(tmpPath, mname, MAXPATHLEN); 208 /* 209 * if device path has substring of path 210 * and exactally matching with :scsi suffix 211 */ 212 if (strcmp(subpath, tmpPath) == 0) { 213 (void) strlcpy(link, node, MAXPATHLEN); 214 (void) closedir(dp); 215 S_FREE(dirp); 216 return (HBA_STATUS_OK); 217 } 218 } 219 } 220 } 221 222 (void) closedir(dp); 223 S_FREE(dirp); 224 return (HBA_STATUS_ERROR); 225 } 226 227 /* 228 * Finds controller path for a give device path. 229 * 230 * Return vale:i smp devlink. 231 */ 232 HBA_STATUS 233 lookupControllerLink(char *path, char *link) 234 { 235 const char dir[] = "/dev/cfg"; 236 const char mname[] = ":scsi"; 237 return (lookupLink(path, link, dir, mname)); 238 } 239 240 /* 241 * Finds smp devlink for a give smp path. 242 * 243 * Return vale: smp devlink. 244 */ 245 HBA_STATUS 246 lookupSMPLink(char *path, char *link) 247 { 248 const char dir[] = "/dev/smp"; 249 const char mname[] = ":smp"; 250 return (lookupLink(path, link, dir, mname)); 251 } 252