dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / sun_fc / common / Handle.cc
blob3099f6a4e73e1de21dc455a493f7ef87569714cb
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 #include "Handle.h"
29 #include "Exceptions.h"
30 #include "Trace.h"
31 #include <libdevinfo.h>
32 #include <iostream>
33 #include <iomanip>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <stropts.h>
40 #define MAX_INIT_HANDLE_ID 0x7fff
41 #define MAX_TGT_HANDLE_ID 0xffff
43 using namespace std;
45 /**
46 * Global lock for list of Handles
48 pthread_mutex_t Handle::staticLock = PTHREAD_MUTEX_INITIALIZER;
50 /**
51 * Tracking for the previous handle we have opened
53 HBA_HANDLE Handle::prevOpen = 0;
55 /**
56 * Tracking for the previous target HBA handle we have opened
58 HBA_HANDLE Handle::prevTgtOpen = 0x8000;
60 /**
61 * Global map from HBA_HANDLE to Handle pointers (our global list)
63 map<HBA_HANDLE, Handle*> Handle::openHandles;
65 /**
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");
78 modeVal = INITIATOR;
79 lock(&staticLock);
80 mapend = openHandles.end();
81 /* Start the search for a free id from the previously assigned one */
82 id = prevOpen + 1;
83 while (id != prevOpen) {
84 /* Exceeds the max valid value, continue the search from 1 */
85 if (id > MAX_INIT_HANDLE_ID)
86 id = 1;
88 if (openHandles.find(id) == mapend) {
89 /* the id is not in use */
90 break;
92 id ++;
94 if (id == prevOpen) {
95 /* no usable id for now */
96 unlock(&staticLock);
97 throw TryAgainException();
99 prevOpen = id;
100 hba = myhba;
101 openHandles[id] = this;
102 unlock(&staticLock);
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
116 #if 0
117 // appears unused
118 Handle::Handle(HBA *myhba, MODE m) {
119 map<HBA_HANDLE, Handle*>::iterator mapend;
120 Trace log("Handle::Handle");
121 lock(&staticLock);
122 modeVal = m;
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)
139 id = 0x8001;
141 if (openHandles.find(id) == mapend) {
142 /* the id is not in use */
143 break;
145 id ++;
147 if (id == prevTgtOpen) {
148 /* no usable id for now */
149 unlock(&staticLock);
150 throw TryAgainException();
152 prevTgtOpen = id;
153 hba = myhba;
154 openHandles[id] = this;
155 unlock(&staticLock);
157 #endif
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
163 Handle::~Handle() {
164 Trace log("Handle::~Handle");
165 // Remove this handle from the global list
166 lock(&staticLock);
167 try {
168 openHandles.erase(openHandles.find(getHandle()));
169 unlock(&staticLock);
170 } catch (...) {
171 unlock(&staticLock);
172 throw;
175 // Now nuke all internal dynamic allocations
176 typedef map<uint64_t, HandlePort *>::const_iterator CI;
177 lock();
178 try {
179 for (CI port = portHandles.begin(); port != portHandles.end();
180 port++) {
181 delete port->second;
183 portHandles.clear();
184 unlock();
185 } catch (...) {
186 unlock();
187 throw;
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
195 * an open handle
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)");
206 Handle *tmp = NULL;
207 lock(&staticLock);
208 try {
209 if (openHandles.find(id) == openHandles.end()) {
210 throw InvalidHandleException();
212 tmp = openHandles[id];
213 unlock(&staticLock);
214 return (tmp);
215 } catch (...) {
216 unlock(&staticLock);
217 throw;
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
227 * is requested.
230 Handle* Handle::findHandle(uint64_t wwn) {
231 Trace log("Handle::findHandle(wwn)");
232 Handle *tmp = NULL;
233 lock(&staticLock);
234 try {
235 for (int i = 0; i < openHandles.size(); i++) {
236 tmp = openHandles[i];
237 if (tmp->getHBA()->containsWWN(wwn)) {
238 unlock(&staticLock);
239 return (tmp);
242 tmp = NULL;
243 } catch (...) { tmp = NULL; }
244 unlock(&staticLock);
245 if (tmp == NULL) {
246 throw IllegalWWNException();
248 return (tmp);
252 * @memo Refresh underlying index values
253 * @postcondition All HandlePorts will be reset and prior index values
254 * will be undefined.
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");
266 lock();
267 try {
268 typedef map<uint64_t, HandlePort *>::const_iterator CI;
269 for (CI port = portHandles.begin(); port != portHandles.end();
270 port++) {
271 port->second->refresh();
273 unlock();
274 } catch (...) {
275 unlock();
276 throw;
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);
289 delete myHandle;
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");
303 HBA_HANDLE tmp;
304 lock();
305 try {
306 tmp = (HBA_HANDLE) id;
307 unlock();
308 return (tmp);
309 } catch (...) {
310 unlock();
311 throw;
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");
345 lock();
346 try {
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];
354 unlock();
355 return (portHandle);
356 } catch (...) {
357 unlock();
358 throw;
363 * @memo Get the HBA attributes from the underlying HBA
365 * @see HBA::getHBAAttributes
367 HBA_ADAPTERATTRIBUTES Handle::getHBAAttributes() {
368 Trace log("Handle::getHBAAttributes");
369 lock();
370 try {
371 HBA_ADAPTERATTRIBUTES attributes = hba->getHBAAttributes();
372 unlock();
373 return (attributes);
374 } catch (...) {
375 unlock();
376 throw;
381 * @memo Do FORCELIP
383 * @see HBA::doForceLip
385 int Handle::doForceLip() {
386 Trace log("Handle::doForceLip");
387 lock();
388 try {
389 int rval = hba->doForceLip();
390 unlock();
391 return (rval);
392 } catch (...) {
393 unlock();
394 throw;
398 HBA_ADAPTERATTRIBUTES Handle::npivGetHBAAttributes() {
399 Trace log("Handle::npivGetHBAAttributes");
400 lock();
401 try {
402 HBA_ADAPTERATTRIBUTES attributes = hba->npivGetHBAAttributes();
403 unlock();
404 return (attributes);
405 } catch (...) {
406 unlock();
407 throw;
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");
423 uint64_t tmp;
424 HBA_PORTATTRIBUTES attributes;
426 lock();
427 try {
428 // Is this a WWN for one of the adapter ports?
429 if (hba->containsWWN(wwn)) {
430 attributes = hba->getPort(wwn)->getPortAttributes(tmp);
431 unlock();
432 return (attributes);
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++) {
437 try {
438 attributes =
439 hba->getPortByIndex(i)->getDiscoveredAttributes(
440 wwn, tmp);
441 unlock();
442 return (attributes);
443 } catch (HBAException &e) {
444 continue;
448 // If we get to here, then we don't see this WWN on this HBA
449 throw IllegalWWNException();
451 } catch (...) {
452 unlock();
453 throw;