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