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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <sys/types.h>
33 #include <libdevinfo.h>
36 * structure for di_devlink_walk
38 typedef struct walk_devlink
{
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".
51 get_devlink(di_devlink_t devlink
, void *arg
)
53 const char ROUTINE
[] = "get_devlink";
54 walk_devlink_t
*warg
= (walk_devlink_t
*)arg
;
57 * When path is specified, it doesn't have minor
58 * name. Therefore, the ../.. prefixes needs to be stripped.
61 char *content
= (char *)di_devlink_content(devlink
);
62 char *start
= strstr(content
, "/devices");
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
);
72 *(warg
->linkpp
) = strdup(di_devlink_path(devlink
));
73 log(LOG_DEBUG
, ROUTINE
, "Walk terminate");
74 return (DI_WALK_TERMINATE
);
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
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.
88 convertDevpathToDevlink(PSMHBA_TARGETMAPPING mappings
)
90 const char ROUTINE
[] = "convertDevpathToLink";
91 di_devlink_handle_t hdl
;
94 char *minor_path
, *devlinkp
;
96 if ((hdl
= di_devlink_init(NULL
, 0)) == NULL
) {
97 log(LOG_DEBUG
, ROUTINE
, "di_devlink failed: errno:%d",
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");
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");
120 warg
.len
= strlen(mappings
->entry
[j
].ScsiId
.
122 warg
.path
= mappings
->entry
[j
].ScsiId
.
128 warg
.linkpp
= &devlinkp
;
129 (void) di_devlink_walk(hdl
, NULL
, minor_path
, DI_PRIMARY_LINK
,
130 (void *)&warg
, get_devlink
);
132 if (devlinkp
!= NULL
) {
133 (void) snprintf(mappings
->entry
[j
].ScsiId
.OSDeviceName
,
134 sizeof (mappings
->entry
[j
].ScsiId
.OSDeviceName
),
141 (void) di_devlink_fini(&hdl
);
145 * Finds controller path for a give device path.
147 * Return value: /dev link for dir and minor name.
150 lookupLink(char *path
, char *link
, const char *dir
, const char *mname
)
152 const char ROUTINE
[] = "lookupLink";
154 char buf
[MAXPATHLEN
];
155 char node
[MAXPATHLEN
];
157 struct dirent
*newdirp
, *dirp
;
161 char tmpPath
[MAXPATHLEN
];
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
);
170 log(LOG_DEBUG
, ROUTINE
,
171 "Invalid argument for storing the link.");
172 return (HBA_STATUS_ERROR
);
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.
180 dirplen
= pathconf(dir
, _PC_NAME_MAX
);
181 dirplen
= ((dirplen
<= 0) ? MAXNAMELEN
: dirplen
) +
182 sizeof (struct dirent
);
183 dirp
= (struct dirent
*)malloc(dirplen
);
185 OUT_OF_MEMORY(ROUTINE
);
186 return (HBA_STATUS_ERROR
);
189 while ((readdir_r(dp
, dirp
, &newdirp
)) == 0 && newdirp
!= NULL
) {
190 if (strcmp(dirp
->d_name
, ".") == 0 ||
191 strcmp(dirp
->d_name
, "..") == 0) {
195 * set to another pointer since dirp->d_name length is 1
196 * that will store only the first char 'c' from the name.
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
))) {
203 subpath
= strstr(buf
, path
);
205 if (subpath
!= NULL
) {
206 (void) strlcpy(tmpPath
, path
, MAXPATHLEN
);
207 (void) strlcat(tmpPath
, mname
, MAXPATHLEN
);
209 * if device path has substring of path
210 * and exactally matching with :scsi suffix
212 if (strcmp(subpath
, tmpPath
) == 0) {
213 (void) strlcpy(link
, node
, MAXPATHLEN
);
216 return (HBA_STATUS_OK
);
224 return (HBA_STATUS_ERROR
);
228 * Finds controller path for a give device path.
230 * Return vale:i smp devlink.
233 lookupControllerLink(char *path
, char *link
)
235 const char dir
[] = "/dev/cfg";
236 const char mname
[] = ":scsi";
237 return (lookupLink(path
, link
, dir
, mname
));
241 * Finds smp devlink for a give smp path.
243 * Return vale: smp devlink.
246 lookupSMPLink(char *path
, char *link
)
248 const char dir
[] = "/dev/smp";
249 const char mname
[] = ":smp";
250 return (lookupLink(path
, link
, dir
, mname
));