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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include "Exceptions.h"
33 #include <sys/types.h>
43 #define NSECS_PER_SEC 1000000000l
44 #define BUSY_SLEEP NSECS_PER_SEC/10 /* 1/10 second */
45 #define BUSY_RETRY_TIMER 3000000000UL /* Retry for 3 seconds */
50 * Max number of Adatper ports per HBA that VSL supports.
53 const uint8_t HBA::HBA_PORT_MAX
= UCHAR_MAX
;
56 * @memo Add a new port to this HBA
57 * @precondition Port must be a valid port on this HBA
58 * @postcondition Port will be exposed as one of the ports on this HBA
59 * @exception Throws InternalError when the HBA port count exceeds
60 * max number of ports and throws any underlying exception
61 * @param port The Port to add to this HBA
63 * @doc When discovering HBAs and their ports, use this
64 * routine to add a port to its existing HBA instance.
66 void HBA::addPort(HBAPort
* port
) {
67 Trace
log("HBA::addPort");
69 // support hba with up to UCHAR_MAX number of ports.
70 if (portsByIndex
.size() + 1 > HBA_PORT_MAX
) {
72 throw InternalError("HBA Port count exceeds max number of ports");
76 portsByWWN
[port
->getPortWWN()] = port
;
77 portsByIndex
.insert(portsByIndex
.end(), port
);
86 * @memo Return number of ports to this HBA
87 * @exception No exception for this method.
89 * @doc Returns the number of ports on this HBA. The max
90 * number of ports that VSL support is up to max uint8_t
93 uint8_t HBA::getNumberOfPorts() {
94 Trace
log("HBA::getNumberOfPorts");
95 return (uint8_t)portsByIndex
.size();
99 * @memo Retrieve an HBA port based on a Port WWN
100 * @exception IllegalWWNException Thrown if WWN does not match any
102 * @return HBAPort* to the port with a matching Port WWN
103 * @param wwn The wwn of the desired HBA port
105 * @doc Fetch an HBA port based on WWN. If the port is not
106 * found, an exception will be thrown. NULL will never
109 HBAPort
* HBA::getPort(uint64_t wwn
) {
110 Trace
log("HBA::getPort");
111 HBAPort
*port
= NULL
;
114 log
.debug("getPort(wwn): WWN %016llx", wwn
);
117 // Make sure it is in the map
118 if (portsByWWN
.find(wwn
) == portsByWWN
.end()) {
119 throw IllegalWWNException();
121 port
= portsByWWN
[wwn
];
131 * Iterator for WWN to HBAPort map type
133 typedef map
<uint64_t, HBAPort
*>::const_iterator CI
;
136 * @memo Return true if this HBA contains the stated WWN
138 * @exception ... underlying exceptions will be thrown
139 * @return TRUE if the wwn is found
140 * @return FALSE if the wwn is not found
141 * @param wwn The wwn to look for
144 bool HBA::containsWWN(uint64_t wwn
) {
145 Trace
log("HBA::containsWWN");
149 for (CI port
= portsByWWN
.begin(); port
!= portsByWWN
.end();
151 if (port
->second
->getPortWWN() == wwn
) {
155 if (port
->second
->getNodeWWN() == wwn
) {
169 * @memo Fetch the port based on index.
170 * @exception IllegalIndexException Thrown if the index is not valid
171 * @return HBAPort* the port matching the index
172 * @param index - the zero based index of the port to retrieve
175 HBAPort
* HBA::getPortByIndex(int index
) {
176 Trace
log("HBA::getPortByIndex");
179 log
.debug("Port index size %d index %d ", portsByIndex
.size(),
182 if (index
>= portsByIndex
.size() || index
< 0) {
183 throw IllegalIndexException();
186 HBAPort
*tmp
= portsByIndex
[index
];
196 * @memo Compare two HBAs for equality
197 * @precondition Both HBAs should be fully discovered (all ports added)
198 * @exception ... underlying exceptions will be thrown
199 * @return TRUE The two HBA instances represent the same HBA
200 * @return FALSE The two HBA instances are different
202 * @doc This routine will compare each port within both
203 * HBAs and verify they are the same. The ports must
204 * have been added in the same order.
206 bool HBA::operator==(HBA
&comp
) {
207 Trace
log("HBA::operator==");
212 if (portsByIndex
.size() == comp
.portsByIndex
.size()) {
213 if (portsByIndex
.size() > 0) {
214 ret
= (*portsByIndex
[0] == *comp
.portsByIndex
[0]);
226 * @memo Set the RNID data for all the ports in this HBA
227 * @precondition All ports must be added
228 * @postcondition Each port will have the same RNID value set
229 * @exception ... underlying exceptions will be thrown. Partial failure
230 * is possible and will not be cleaned up.
231 * @param info The RNID information to program for each HBA port
232 * @see HBAPort::setRNID
235 void HBA::setRNID(HBA_MGMTINFO info
) {
236 Trace
log("HBA::setRNID");
240 for (CI port
= portsByWWN
.begin(); port
!= portsByWWN
.end();
242 port
->second
->setRNID(info
);
252 * @memo Verify that this HBA is present on the system
253 * @exception UnavailableException Thrown when HBA not present
254 * @see HBAPort::validatePresent
256 * @doc This routine is used to verify that a given HBA
257 * has not been removed through dynamic reconfiguration.
258 * If the HBA is present, the routine will return.
259 * If the HBA is not present (if any port is not present)
260 * an exception will be thrown
262 void HBA::validatePresent() {
263 Trace
log("HBA::validatePresent");
266 for (CI port
= portsByWWN
.begin(); port
!= portsByWWN
.end();
268 port
->second
->validatePresent();
278 * Opens a file, throwing exceptions on error.
280 int HBA::_open(std::string path
, int flag
) {
281 Trace
log("HBA::open");
284 if ((fd
= open(path
.c_str(), flag
)) < 0) {
285 log
.debug("Unable to open \"%s\" - reason (%d) %s",
286 path
.c_str(), errno
, strerror(errno
));
287 if (errno
== EBUSY
) {
288 throw BusyException();
289 } else if (errno
== EAGAIN
) {
290 throw TryAgainException();
291 } else if (errno
== ENOTSUP
) {
292 throw NotSupportedException();
293 } else if (errno
== ENOENT
) {
294 throw UnavailableException();
296 string msg
= "Unable to open ";
305 * Issues IOCTL, throwing exceptions on error.
306 * Note, if the IOCTL succeeds, but some IOCTL specific
307 * error is recorded in the response, this routine
308 * will not throw an exception.
310 void HBA::_ioctl(int fd
, int type
, uchar_t
*arg
) {
311 Trace
log("HBA::ioctl");
316 hrtime_t start
= gethrtime();
317 hrtime_t end
= start
+ BUSY_RETRY_TIMER
;
319 ts
.tv_nsec
= BUSY_SLEEP
;
320 for (cur
= start
; cur
< end
; cur
= gethrtime()) {
322 if (ioctl(fd
, type
, arg
) != 0) {
323 if (errno
== EAGAIN
) {
325 nanosleep(&ts
, NULL
);
327 } else if (errno
== EBUSY
) {
329 nanosleep(&ts
, NULL
);
331 } else if (errno
== ENOTSUP
) {
332 throw NotSupportedException();
333 } else if (errno
== ENOENT
) {
334 throw UnavailableException();
336 throw IOError("IOCTL failed");
343 if (saved_errno
== EAGAIN
) {
344 throw TryAgainException();
345 } else if (saved_errno
== EBUSY
) {
346 throw BusyException();
348 throw IOError("IOCTL failed");
354 Trace
log("HBA::~HBA");
355 for (int i
= 0; i
< getNumberOfPorts(); i
++) {
356 delete (getPortByIndex(i
));