xref: /illumos-gate/usr/src/lib/sun_fc/common/Handle.cc (revision d8e10381a0083d7717710b0db7e64707bc0f3ff8)
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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  */
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