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"
31 #include <libdevinfo.h>
34 #include <sys/types.h>
40 #define MAX_INIT_HANDLE_ID 0x7fff
41 #define MAX_TGT_HANDLE_ID 0xffff
46 * Global lock for list of Handles
48 pthread_mutex_t
Handle::staticLock
= PTHREAD_MUTEX_INITIALIZER
;
51 * Tracking for the previous handle we have opened
53 HBA_HANDLE
Handle::prevOpen
= 0;
56 * Tracking for the previous target HBA handle we have opened
58 HBA_HANDLE
Handle::prevTgtOpen
= 0x8000;
61 * Global map from HBA_HANDLE to Handle pointers (our global list)
63 map
<HBA_HANDLE
, Handle
*> Handle::openHandles
;
66 * @memo Create a new open handle for a specified HBA
67 * @precondition HBA port(s) must be loaded
68 * @postcondition An open handle will be present in the global tracking list
69 * and must be closed at some point to prevent leakage. If no
70 * handle could be assigned (the track list is full), an
71 * exception will be thrown. Scope for valid ids in the track
72 * list is [1, MAX_INIT_HANDLE_ID].
73 * @param myhba The HBA to open a handle for
75 Handle::Handle(HBA
*myhba
) {
76 map
<HBA_HANDLE
, Handle
*>::iterator mapend
;
77 Trace
log("Handle::Handle");
80 mapend
= openHandles
.end();
81 /* Start the search for a free id from the previously assigned one */
83 while (id
!= prevOpen
) {
84 /* Exceeds the max valid value, continue the search from 1 */
85 if (id
> MAX_INIT_HANDLE_ID
)
88 if (openHandles
.find(id
) == mapend
) {
89 /* the id is not in use */
95 /* no usable id for now */
97 throw TryAgainException();
101 openHandles
[id
] = this;
106 * @memo Create a new open handle for a specified HBA
107 * @precondition HBA port(s) must be loaded
108 * @postcondition An open handle will be present in the global tracking list
109 * and must be closed at some point to prevent leakage. If no
110 * handle could be assigned (the track list is full), an
111 * exception will be thrown. Scope for valid ids in the track
112 * list is [0x8000, MAX_TGT_HANDLE_ID].
113 * @param myhba The HBA to open a handle for
114 * m The mode of HBA to open handle for
118 Handle::Handle(HBA
*myhba
, MODE m
) {
119 map
<HBA_HANDLE
, Handle
*>::iterator mapend
;
120 Trace
log("Handle::Handle");
125 // if initiator mode call constructor for initiator.
126 if (m
== INITIATOR
) {
127 Handle(myhba
, TARGET
);
130 mapend
= openHandles
.end();
131 /* Start the search for a free id from the previously assigned one */
132 id
= prevTgtOpen
+ 1;
133 while (id
!= prevTgtOpen
) {
135 * Exceeds the max valid target id value,
136 * continue the search from 1.
138 if (id
> MAX_TGT_HANDLE_ID
)
141 if (openHandles
.find(id
) == mapend
) {
142 /* the id is not in use */
147 if (id
== prevTgtOpen
) {
148 /* no usable id for now */
150 throw TryAgainException();
154 openHandles
[id
] = this;
159 * @memo Free up the handle (aka, close it)
160 * @postcondition This handle will be removed from the global list
161 * @exception ... underlying exceptions will be thrown
164 Trace
log("Handle::~Handle");
165 // Remove this handle from the global list
168 openHandles
.erase(openHandles
.find(getHandle()));
175 // Now nuke all internal dynamic allocations
176 typedef map
<uint64_t, HandlePort
*>::const_iterator CI
;
179 for (CI port
= portHandles
.begin(); port
!= portHandles
.end();
192 * @memo Locate a handle in the global list of open handles
193 * @precondition The requested handle must already be open
194 * @exception InvalidHandleException Thrown if the id does not match
196 * @return The open Handle
197 * @param id The id of the handle to fetch
199 * @doc The HBA API uses a simple integer type to represent
200 * an open Handle, but we use an instance of the Handle
201 * class. This interface allows a caller to quickly convert
202 * from the API integer value to related the Handle instance.
204 Handle
* Handle::findHandle(HBA_HANDLE id
) {
205 Trace
log("Handle::findHandle(id)");
209 if (openHandles
.find(id
) == openHandles
.end()) {
210 throw InvalidHandleException();
212 tmp
= openHandles
[id
];
222 * @memo Find an open handle based on Node or Port WWN
223 * @precondition The given HBA must already be open
224 * @exception IllegalWWNException Thrown if no matching open Handle found
225 * @return The open handle matching the wwn argument
226 * @param wwn The Node or Port WWN of the HBA whos open handle
230 Handle
* Handle::findHandle(uint64_t wwn
) {
231 Trace
log("Handle::findHandle(wwn)");
235 for (int i
= 0; i
< openHandles
.size(); i
++) {
236 tmp
= openHandles
[i
];
237 if (tmp
->getHBA()->containsWWN(wwn
)) {
243 } catch (...) { tmp
= NULL
; }
246 throw IllegalWWNException();
252 * @memo Refresh underlying index values
253 * @postcondition All HandlePorts will be reset and prior index values
255 * @exception ... underlying exceptions will be thrown
257 * @doc A number of APIs in the standard interface require
258 * the use of index values for identifying what "thing"
259 * to operate on. When dynamic reconfiguration occurs
260 * these indexes may become inconsistent. This routine
261 * is called to reset the indexes and signify that the caller
262 * no longer holds or will refer to any old indexes.
264 void Handle::refresh() {
265 Trace
log("Handle::refresh");
268 typedef map
<uint64_t, HandlePort
*>::const_iterator CI
;
269 for (CI port
= portHandles
.begin(); port
!= portHandles
.end();
271 port
->second
->refresh();
281 * @memo Close the specified handle
282 * @precondition The handle must be open
283 * @postcondition The handle will be closed and should be discarded.
284 * @param id The handle to close
286 void Handle::closeHandle(HBA_HANDLE id
) {
287 Trace
log("Handle::closeHandle");
288 Handle
*myHandle
= findHandle(id
);
293 * @memo Get the integer value for return to the API
294 * @exception ... underlying exceptions will be thrown
295 * @return The integer value representing the handle
297 * @doc The HBA API uses integer values to represent handles.
298 * Call this routine to convert a Handle instance into
299 * its representative integer value.
301 HBA_HANDLE
Handle::getHandle() {
302 Trace
log("Handle::getHandle");
306 tmp
= (HBA_HANDLE
) id
;
316 * @memo Compare two handles for equality
317 * @return TRUE if the handles are the same
318 * @return FALSE if the handles are different
320 bool Handle::operator==(Handle comp
) {
321 Trace
log("Handle::operator==");
322 return (this->id
== comp
.id
);
326 * @memo Get the underlying Handle port based on index
327 * @return The Handle port for the given port index
328 * @param index The index of the desired port
330 HandlePort
* Handle::getHandlePortByIndex(int index
) {
331 Trace
log("Handle::getHandlePortByIndex");
332 HBAPort
* port
= hba
->getPortByIndex(index
);
333 return (getHandlePort(port
->getPortWWN()));
337 * @memo Get the underlying Handle port based on Port wwn
338 * @exception IllegalWWNException thrown if the wwn is not found
339 * @return The handle port for the specified WWN
340 * @param wwn The Port WWN of the HBA port
343 HandlePort
* Handle::getHandlePort(uint64_t wwn
) {
344 Trace
log("Handle::getHandlePort");
347 // Check to see if the wwn is in the map
348 if (portHandles
.find(wwn
) == portHandles
.end()) {
349 // Not found, add a new one
350 HBAPort
* port
= hba
->getPort(wwn
);
351 portHandles
[wwn
] = new HandlePort(this, hba
, port
);
353 HandlePort
*portHandle
= portHandles
[wwn
];
363 * @memo Get the HBA attributes from the underlying HBA
365 * @see HBA::getHBAAttributes
367 HBA_ADAPTERATTRIBUTES
Handle::getHBAAttributes() {
368 Trace
log("Handle::getHBAAttributes");
371 HBA_ADAPTERATTRIBUTES attributes
= hba
->getHBAAttributes();
383 * @see HBA::doForceLip
385 int Handle::doForceLip() {
386 Trace
log("Handle::doForceLip");
389 int rval
= hba
->doForceLip();
398 HBA_ADAPTERATTRIBUTES
Handle::npivGetHBAAttributes() {
399 Trace
log("Handle::npivGetHBAAttributes");
402 HBA_ADAPTERATTRIBUTES attributes
= hba
->npivGetHBAAttributes();
413 * @memo Get the HBA port attributes from the HBA
414 * @see HBAPort::getPortAttributes
415 * @see HBAPort::getDisoveredAttributes
417 * @doc This routine will return either HBA port
418 * attributes, or discovered port attributes
421 HBA_PORTATTRIBUTES
Handle::getPortAttributes(uint64_t wwn
) {
422 Trace
log("Handle::getPortAttributes");
424 HBA_PORTATTRIBUTES attributes
;
428 // Is this a WWN for one of the adapter ports?
429 if (hba
->containsWWN(wwn
)) {
430 attributes
= hba
->getPort(wwn
)->getPortAttributes(tmp
);
433 } else { // Is this a target we know about?
434 // Loop through all ports and look for the first match
436 for (int i
= 0; i
< hba
->getNumberOfPorts(); i
++) {
439 hba
->getPortByIndex(i
)->getDiscoveredAttributes(
443 } catch (HBAException
&e
) {
448 // If we get to here, then we don't see this WWN on this HBA
449 throw IllegalWWNException();