1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27
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>
39
40 #define MAX_INIT_HANDLE_ID 0x7fff
41 #define MAX_TGT_HANDLE_ID 0xffff
42
43 using namespace std;
44
45 /**
46 * Global lock for list of Handles
47 */
48 pthread_mutex_t Handle::staticLock = PTHREAD_MUTEX_INITIALIZER;
49
50 /**
51 * Tracking for the previous handle we have opened
52 */
53 HBA_HANDLE Handle::prevOpen = 0;
54
55 /**
56 * Tracking for the previous target HBA handle we have opened
57 */
58 HBA_HANDLE Handle::prevTgtOpen = 0x8000;
59
60 /**
61 * Global map from HBA_HANDLE to Handle pointers (our global list)
62 */
63 map<HBA_HANDLE, Handle*> Handle::openHandles;
64
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
74 */
Handle(HBA * myhba)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;
87
88 if (openHandles.find(id) == mapend) {
89 /* the id is not in use */
90 break;
91 }
92 id ++;
93 }
94 if (id == prevOpen) {
95 /* no usable id for now */
96 unlock(&staticLock);
97 throw TryAgainException();
98 }
99 prevOpen = id;
100 hba = myhba;
101 openHandles[id] = this;
102 unlock(&staticLock);
103 }
104
105 /**
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
115 */
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;
123
124
125 // if initiator mode call constructor for initiator.
126 if (m == INITIATOR) {
127 Handle(myhba, TARGET);
128 }
129
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) {
134 /*
135 * Exceeds the max valid target id value,
136 * continue the search from 1.
137 */
138 if (id > MAX_TGT_HANDLE_ID)
139 id = 0x8001;
140
141 if (openHandles.find(id) == mapend) {
142 /* the id is not in use */
143 break;
144 }
145 id ++;
146 }
147 if (id == prevTgtOpen) {
148 /* no usable id for now */
149 unlock(&staticLock);
150 throw TryAgainException();
151 }
152 prevTgtOpen = id;
153 hba = myhba;
154 openHandles[id] = this;
155 unlock(&staticLock);
156 }
157 #endif
158 /**
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
162 */
~Handle()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;
173 }
174
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;
182 }
183 portHandles.clear();
184 unlock();
185 } catch (...) {
186 unlock();
187 throw;
188 }
189 }
190
191 /**
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
198 *
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.
203 */
findHandle(HBA_HANDLE id)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();
211 }
212 tmp = openHandles[id];
213 unlock(&staticLock);
214 return (tmp);
215 } catch (...) {
216 unlock(&staticLock);
217 throw;
218 }
219 }
220
221 /**
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.
228 *
229 */
findHandle(uint64_t wwn)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);
240 }
241 }
242 tmp = NULL;
243 } catch (...) { tmp = NULL; }
244 unlock(&staticLock);
245 if (tmp == NULL) {
246 throw IllegalWWNException();
247 }
248 return (tmp);
249 }
250
251 /**
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
256 *
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.
263 */
refresh()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();
272 }
273 unlock();
274 } catch (...) {
275 unlock();
276 throw;
277 }
278 }
279
280 /**
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
285 */
closeHandle(HBA_HANDLE id)286 void Handle::closeHandle(HBA_HANDLE id) {
287 Trace log("Handle::closeHandle");
288 Handle *myHandle = findHandle(id);
289 delete myHandle;
290 }
291
292 /**
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
296 *
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.
300 */
getHandle()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;
312 }
313 }
314
315 /**
316 * @memo Compare two handles for equality
317 * @return TRUE if the handles are the same
318 * @return FALSE if the handles are different
319 */
operator ==(Handle comp)320 bool Handle::operator==(Handle comp) {
321 Trace log("Handle::operator==");
322 return (this->id == comp.id);
323 }
324
325 /**
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
329 */
getHandlePortByIndex(int index)330 HandlePort* Handle::getHandlePortByIndex(int index) {
331 Trace log("Handle::getHandlePortByIndex");
332 HBAPort* port = hba->getPortByIndex(index);
333 return (getHandlePort(port->getPortWWN()));
334 }
335
336 /**
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
341 *
342 */
getHandlePort(uint64_t wwn)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);
352 }
353 HandlePort *portHandle = portHandles[wwn];
354 unlock();
355 return (portHandle);
356 } catch (...) {
357 unlock();
358 throw;
359 }
360 }
361
362 /**
363 * @memo Get the HBA attributes from the underlying HBA
364 *
365 * @see HBA::getHBAAttributes
366 */
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;
377 }
378 }
379
380 /**
381 * @memo Do FORCELIP
382 *
383 * @see HBA::doForceLip
384 */
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;
395 }
396 }
397
npivGetHBAAttributes()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;
408 }
409 }
410
411
412 /**
413 * @memo Get the HBA port attributes from the HBA
414 * @see HBAPort::getPortAttributes
415 * @see HBAPort::getDisoveredAttributes
416 *
417 * @doc This routine will return either HBA port
418 * attributes, or discovered port attributes
419 *
420 */
getPortAttributes(uint64_t wwn)421 HBA_PORTATTRIBUTES Handle::getPortAttributes(uint64_t wwn) {
422 Trace log("Handle::getPortAttributes");
423 uint64_t tmp;
424 HBA_PORTATTRIBUTES attributes;
425
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
435
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;
445 }
446 }
447
448 // If we get to here, then we don't see this WWN on this HBA
449 throw IllegalWWNException();
450 }
451 } catch (...) {
452 unlock();
453 throw;
454 }
455 }
456