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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include "Exceptions.h"
35 #include <sys/types.h>
36 #include <sys/mkdev.h>
42 #include <libdevinfo.h>
47 * Standard definition for general topology lookup (See T11 FC-FS)
49 const int HBAPort::RNID_GENERAL_TOPOLOGY_DATA_FORMAT
= 0xDF;
50 const uint8_t HBAPort::HBA_NPIV_PORT_MAX
= UCHAR_MAX
;
53 * @memo Construct a new deafult HBA Port
59 * @memo Compare two HBA ports for equality
60 * @return TRUE if both ports are the same
61 * @return FALSE if the ports are different
63 * @doc Comparison is based on Node WWN, Port WWN and path
65 bool HBAPort::operator==(HBAPort
&comp
) {
66 return (this->getPortWWN() == comp
.getPortWWN() &&
67 this->getNodeWWN() == comp
.getNodeWWN() &&
68 this->getPath() == comp
.getPath());
72 * @memo Validate that the port is still present in the system
73 * @exception UnavailableException if the port is not present
75 * @doc If the port is still present on the system, the routine
76 * will return normally. If the port is not present
77 * an exception will be thrown.
79 void HBAPort::validatePresent() {
80 Trace
log("HBAPort::validatePresent");
81 string path
= getPath();
83 if (stat(path
.c_str(), &sbuf
) == -1) {
84 if (errno
== ENOENT
) {
85 throw UnavailableException();
87 log
.debug("Unable to stat %s: %s", path
.c_str(),
89 throw InternalError();
96 * structure for di_devlink_walk
98 typedef struct walk_devlink
{
105 * @memo callback funtion for di_devlink_walk
106 * @postcondition Find matching /dev link for the given path argument.
107 * @param devlink element and callback function argument.
109 * @doc The input path is expected to not have "/devices".
112 get_devlink(di_devlink_t devlink
, void *arg
) {
113 Trace
log("get_devlink");
114 walk_devlink_t
*warg
= (walk_devlink_t
*)arg
;
117 * When path is specified, it doesn't have minor
118 * name. Therefore, the ../.. prefixes needs to be stripped.
121 // di_devlink_content contains /devices
122 char *content
= (char *)di_devlink_content(devlink
);
123 char *start
= strstr(content
, "/devices");
126 strncmp(start
, warg
->path
, warg
->len
) != 0 ||
127 // make it sure the device path has minor name
128 start
[warg
->len
] != ':')
129 return (DI_WALK_CONTINUE
);
132 *(warg
->linkpp
) = strdup(di_devlink_path(devlink
));
133 return (DI_WALK_TERMINATE
);
137 * @memo Convert /devices paths to /dev sym-link paths.
138 * @postcondition The mapping buffer OSDeviceName paths will be
139 * converted to short names.
140 * @param mappings The target mappings data to convert to
144 * is found, the long path is left as is.
145 * Note: The NumberOfEntries field MUST not be greater than the size
146 * of the array passed in.
148 void HBAPort::convertToShortNames(PHBA_FCPTARGETMAPPINGV2 mappings
) {
149 Trace
log("HBAPort::convertToShortNames");
150 di_devlink_handle_t hdl
;
152 char *minor_path
, *devlinkp
;
154 if ((hdl
= di_devlink_init(NULL
, 0)) == NULL
) {
155 log
.internalError("di_devlink_init failed. Errno:%d", errno
);
156 // no need to check further, just return here.
160 for (int j
= 0; j
< mappings
->NumberOfEntries
; j
++) {
161 if (strchr(mappings
->entry
[j
].ScsiId
.OSDeviceName
, ':')) {
162 // search link for minor node
163 minor_path
= mappings
->entry
[j
].ScsiId
.OSDeviceName
;
164 if (strstr(minor_path
, "/devices") != NULL
) {
165 minor_path
= mappings
->entry
[j
].ScsiId
.OSDeviceName
+
168 minor_path
= mappings
->entry
[j
].ScsiId
.OSDeviceName
;
173 if (strstr(mappings
->entry
[j
].ScsiId
.OSDeviceName
,
174 "/devices") != NULL
) {
175 warg
.len
= strlen (mappings
->entry
[j
].ScsiId
.OSDeviceName
) -
177 warg
.path
= mappings
->entry
[j
].ScsiId
.OSDeviceName
+
180 warg
.len
= strlen(mappings
->entry
[j
].ScsiId
.OSDeviceName
);
181 warg
.path
= mappings
->entry
[j
].ScsiId
.OSDeviceName
;
186 warg
.linkpp
= &devlinkp
;
187 (void) di_devlink_walk(hdl
, NULL
, minor_path
, DI_PRIMARY_LINK
,
188 (void *)&warg
, get_devlink
);
190 if (devlinkp
!= NULL
) {
191 snprintf(mappings
->entry
[j
].ScsiId
.OSDeviceName
,
192 sizeof (mappings
->entry
[j
].ScsiId
.OSDeviceName
),
195 } // else leave OSDeviceName alone.
199 di_devlink_fini(&hdl
);
204 * Finds controller path for a give device path.
206 * Return vale: controller path.
208 string
HBAPort::lookupControllerPath(string path
) {
209 Trace
log("lookupControllerPath");
211 char buf
[MAXPATHLEN
];
212 char node
[MAXPATHLEN
];
213 struct dirent
**dirpp
, *dirp
;
214 const char dir
[] = "/dev/cfg";
216 uchar_t
*dir_buf
= new uchar_t
[sizeof (struct dirent
) + MAXPATHLEN
];
218 if ((dp
= opendir(dir
)) == NULL
) {
219 string tmp
= "Unable to open ";
221 tmp
+= "to find controller number.";
226 dirp
= (struct dirent
*) dir_buf
;
228 while ((readdir_r(dp
, dirp
, dirpp
)) == 0 && dirp
!= NULL
) {
229 if (strcmp(dirp
->d_name
, ".") == 0 ||
230 strcmp(dirp
->d_name
, "..") == 0) {
233 sprintf(node
, "%s/%s", dir
, dirp
->d_name
);
234 if ((count
= readlink(node
,buf
,sizeof(buf
)))) {
236 if (strstr(buf
, path
.c_str())) {
237 string cfg_path
= dir
;
239 cfg_path
+= dirp
->d_name
;
249 throw InternalError("Unable to find controller path");
252 void HBAPort::addPort(HBANPIVPort
*port
) {
253 Trace
log("HBAPort::addPort");
255 // support hba with up to UCHAR_MAX number of ports.
256 if (npivportsByIndex
.size() + 1 > HBA_NPIV_PORT_MAX
) {
258 throw InternalError("HBA NPIV Port count exceeds max number of ports");
262 npivportsByWWN
[port
->getPortWWN()] = port
;
263 npivportsByIndex
.insert(npivportsByIndex
.end(), port
);
271 HBANPIVPort
* HBAPort::getPort(uint64_t wwn
) {
272 Trace
log("HBAPort::getPort");
273 HBANPIVPort
*port
= NULL
;
277 if (npivportsByWWN
.find(wwn
) == npivportsByWWN
.end()) {
278 throw IllegalWWNException();
280 port
= npivportsByWWN
[wwn
];
289 HBANPIVPort
* HBAPort::getPortByIndex(int index
) {
290 Trace
log("HBAPort::getPortByIndex");
293 if (index
>= npivportsByIndex
.size() || index
< 0) {
294 throw IllegalIndexException();
296 HBANPIVPort
*tmp
= npivportsByIndex
[index
];