xref: /illumos-gate/usr/src/lib/sun_fc/common/HBAList.cc (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 
28 #include "HBAList.h"
29 #include "Exceptions.h"
30 #include "Trace.h"
31 #include "sun_fc_version.h"
32 #include <string>
33 #include <sstream>
34 #include "FCHBA.h"
35 #include "TgtFCHBA.h"
36 
37 using namespace std;
38 
39 /**
40  * @memo	    Private constructor (used to create singleton instance)
41  * @see		    HBAList::instance
42  */
43 HBAList::HBAList() { }
44 
45 /**
46  * Internal singleton instance
47  */
48 HBAList* HBAList::_instance = 0;
49 
50 /**
51  * Max number of adapters that this class supports.
52  */
53 const int32_t HBAList::HBA_MAX_PER_LIST = INT_MAX;
54 
55 /**
56  * @memo	    Free up resources held by this HBA list
57  * @postcondition   All memory used by this list will be freed
58  * @return	    HBA_STATUS_OK on success
59  *
60  */
61 HBA_STATUS HBAList::unload() {
62 	Trace log("HBAList::unload");
63 	lock();
64 	_instance = NULL;
65 	unlock();
66 	return (HBA_STATUS_OK);
67 }
68 
69 /**
70  * @memo	    Fetch the singleton instance
71  * @return	    The singleton instance
72  *
73  * @doc		    Only one instance of HBAList must be present
74  *		    per address space at a time.  The singleton design pattern
75  *		    is used to enforce this behavior.
76  */
77 HBAList* HBAList::instance() {
78 	Trace log("HBAList::instance");
79 	if (_instance == 0) {
80 	    _instance = new HBAList();
81 	}
82 	return (_instance);
83 }
84 
85 /**
86  * @memo	    Fetch an HBA based on name.
87  *		    Always returns  non-null or throw an Exception.
88  * @precondition    HBAs must be loaded in the list
89  * @postcondition   A handle will be opened.  The caller must close the handle
90  *		    at some later time to prevent leakage.
91  * @exception	    BadArgumentException if the name is not properly formatted
92  * @exception	    IllegalIndexException if the name does not match any
93  *		    present HBAs within this list.
94  * @return	    A valid handle for future API calls
95  * @param	    name The name of the HBA to open
96  *
97  * @doc		    This routine will always return a handle (ie, non null)
98  *		    or will throw an exception.
99  */
100 Handle* HBAList::openHBA(string name) {
101 	Trace log("HBAList::openHBA(name)");
102 	int index = -1;
103 	try {
104 	    string::size_type offset = name.find_last_of("-");
105 	    if (offset >= 0) {
106 		string indexString = name.substr(offset+1);
107 		index = atoi(indexString.c_str());
108 	    }
109 	} catch (...) {
110 	    throw BadArgumentException();
111 	}
112 	lock();
113 	if (index < 0 || index > hbas.size()) {
114 	    unlock();
115 	    throw IllegalIndexException();
116 	} else {
117 	    HBA *tmp = hbas[index];
118 	    unlock();
119 	    tmp->validatePresent();
120 	    return (new Handle(tmp));
121 	}
122 }
123 
124 /**
125  * @memo	    Fetch an target mode FC HBA based on name.
126  *		    Always returns  non-null or throw an Exception.
127  * @precondition    Target mode HBAs must be loaded in the list
128  * @postcondition   A handle will be opened.  The caller must close the handle
129  *		    at some later time to prevent leakage.
130  * @exception	    BadArgumentException if the name is not properly formatted
131  * @exception	    IllegalIndexException if the name does not match any
132  *		    present HBAs within this list.
133  * @return	    A valid handle for future API calls
134  * @param	    name The name of the target mode HBA to open
135  *
136  * @doc		    This routine will always return a handle (ie, non null)
137  *		    or will throw an exception.
138  */
139 Handle* HBAList::openTgtHBA(string name) {
140 	Trace log("HBAList::openHBA(name)");
141 	int index = -1;
142 	try {
143 	    string::size_type offset = name.find_last_of("-");
144 	    if (offset >= 0) {
145 		string indexString = name.substr(offset+1);
146 		index = atoi(indexString.c_str());
147 	    }
148 	} catch (...) {
149 	    throw BadArgumentException();
150 	}
151 	lock();
152 	if (index < 0 || index > tgthbas.size()) {
153 	    unlock();
154 	    throw IllegalIndexException();
155 	} else {
156 	    HBA *tmp = tgthbas[index];
157 	    unlock();
158 	    tmp->validatePresent();
159 	    return (new Handle(tmp));
160 	}
161 }
162 
163 /**
164  * @memo	    Get the name of an HBA at the given index
165  * @precondition    HBAs must be loaded in the list
166  * @exception	    IllegalIndexException Thrown if the index doesn't match any
167  *		    HBA in the list
168  * @return	    The name of the specified HBA
169  * @param	    index The zero based index of the desired HBA
170  *
171  */
172 string HBAList::getHBAName(int index) {
173 	Trace log("HBAList::getHBAName");
174 	lock();
175 	if (index < 0 || index > hbas.size()) {
176 	    unlock();
177 	    throw IllegalIndexException();
178 	} else {
179 	    HBA *tmp = hbas[index];
180 	    unlock();
181 	    tmp->validatePresent();
182 	    char buf[128];
183 	    snprintf(buf, 128, "%s-%d", tmp->getName().c_str(), index);
184 	    string name = buf;
185 	    return (name);
186 	}
187 }
188 
189 /**
190  * @memo	    Get the name of an target mode HBA at the given index
191  * @precondition    Target mode HBAs must be loaded in the list
192  * @exception	    IllegalIndexException Thrown if the index doesn't match any
193  *		    HBA in the list
194  * @return	    The name of the specified target mode HBA
195  * @param	    index The zero based index of the desired target mode HBA
196  *
197  */
198 string HBAList::getTgtHBAName(int index) {
199 	Trace log("HBAList::getTgtHBAName");
200 	lock();
201 	if (index < 0 || index > tgthbas.size()) {
202 	    unlock();
203 	    throw IllegalIndexException();
204 	} else {
205 	    HBA *tmp = tgthbas[index];
206 	    unlock();
207 	    tmp->validatePresent();
208 	    char buf[128];
209 	    snprintf(buf, 128, "%s-%d", tmp->getName().c_str(), index);
210 	    string name = buf;
211 	    return (name);
212 	}
213 }
214 
215 /**
216  * @memo	    Open an HBA based on a WWN
217  * @precondition    HBAs must be loaded in the list
218  * @postcondition   A handle will be opened.  The caller must close the handle
219  *		    at some later time to prevent leakage.
220  * @exception	    IllegalWWNException Thrown if the wwn doesn't match any
221  *		    HBA in the list
222  * @return	    A valid Handle for later use by API calls
223  * @param	    wwn The node or any port WWN of HBA to open
224  * @see		    HBA::containsWWN
225  *
226  * @doc		    This routine will accept both Node and Port WWNs based
227  *		    on the HBA routine containsWWN
228  */
229 Handle* HBAList::openHBA(uint64_t wwn) {
230 
231 	Trace log("HBAList::openHBA(wwn)");
232 	lock();
233 	HBA *tmp;
234 	for (int i = 0; i < hbas.size(); i++) {
235 	    if (hbas[i]->containsWWN(wwn)) {
236 		tmp = hbas[i];
237 		unlock();
238 		tmp->validatePresent();
239 		return (new Handle(tmp));
240 	    }
241 	}
242 	unlock();
243 	throw IllegalWWNException();
244 }
245 
246 /**
247  * @memo	    Open an target mode HBA based on a WWN
248  * @precondition    Targee mode HBAs must be loaded in the list
249  * @postcondition   A handle will be opened.  The caller must close the handle
250  *		    at some later time to prevent leakage.
251  * @exception	    IllegalWWNException Thrown if the wwn doesn't match any
252  *		    target mode HBA in the list
253  * @return	    A valid Handle for later use by API calls
254  * @param	    The node WWN or any port WWN of target mode HBA to open
255  * @see		    HBA::containsWWN
256  *
257  * @doc		    This routine will accept both Node and Port WWNs based
258  *		    on the HBA routine containsWWN
259  */
260 Handle* HBAList::openTgtHBA(uint64_t wwn) {
261 
262 	Trace log("HBAList::openTgtHBA(wwn)");
263 	lock();
264 	HBA *tmp;
265 	for (int i = 0; i < tgthbas.size(); i++) {
266 	    if (tgthbas[i]->containsWWN(wwn)) {
267 		tmp = tgthbas[i];
268 		unlock();
269 		tmp->validatePresent();
270 		return (new Handle(tmp));
271 	    }
272 	}
273 	unlock();
274 	throw IllegalWWNException();
275 }
276 
277 /**
278  * @memo	    Get the number of adapters present in the list
279  * @postcondition   List of HBAs will be loaded
280  * @exception	    ... Underlying exceptions will be thrown
281  * @return	    The number of adapters in the list
282  *
283  * @doc		    This routine will triger discovery of HBAs on the system.
284  *		    It will also handle addition/removal of HBAs in the list
285  *		    based on dynamic reconfiguration operations.  The max
286  *		    number of HBAs that HBA API supports is up to the
287  *		    uint32_t size.  VSL supports up to int32_t size thus
288  *		    it gives enough room for the HBA API library
289  *		    to handle up to max uint32_t number if adapters.
290  */
291 int HBAList::getNumberofAdapters() {
292 	Trace log("HBAList::getNumberofAdapters");
293 	lock();
294 
295 	try {
296 	if (hbas.size() == 0) {
297 	    // First pass, just store them all blindly
298 	    FCHBA::loadAdapters(hbas);
299 	} else {
300 	    // Second pass, do the update operation
301 	    vector<HBA*> tmp;
302 	    FCHBA::loadAdapters(tmp);
303 	    bool matched;
304 	    for (int i = 0; i < tmp.size(); i++) {
305 		matched = false;
306 		for (int j = 0; j < hbas.size(); j++) {
307 		    if (*tmp[i] == *hbas[j]) {
308 			matched = true;
309 			break;
310 		    }
311 		}
312 		if (matched) {
313 		    delete (tmp[i]);
314 		} else {
315 		    hbas.insert(hbas.end(), tmp[i]);
316 		}
317 	    }
318 	}
319 	} catch (...) {
320 	    unlock();
321 	    throw;
322 	}
323 
324 	unlock();
325 
326 	// When there is more than HBA_MAX_PER_LIST(= int32_max)
327 	// VSL returns an error so it is safe to cast it here.
328 	return ((uint32_t)hbas.size());
329 }
330 
331 /**
332  * @memo	    Get the number of target mode adapters present in the list
333  * @postcondition   List of TgtHBAs will be loaded
334  * @exception	    ... Underlying exceptions will be thrown
335  * @return	    The number of target mode adapters in the list
336  *
337  * @doc		    This routine will triger discovery of Target mode HBAs on
338  *		    the system. It will also handle addition/removal of Target
339  * 		    mode HBAs in the list based on dynamic reconfiguration
340  *		    operations. The max number of target mode HBAs that
341  *		    HBA API supports is up to the
342  *		    uint32_t size.  VSL supports up to int32_t size thus
343  *		    it gives enough room for the HBA API library
344  *		    to handle up to max uint32_t number of adapters.
345  */
346 int HBAList::getNumberofTgtAdapters() {
347 	Trace log("HBAList::getNumberofTgtAdapters");
348 	lock();
349 
350 	try {
351 	    if (tgthbas.size() == 0) {
352 		// First pass, just store them all blindly
353 		TgtFCHBA::loadAdapters(tgthbas);
354 	    } else {
355 		// Second pass, do the update operation
356 		vector<HBA*> tmp;
357 		TgtFCHBA::loadAdapters(tmp);
358 		bool matched;
359 		for (int i = 0; i < tmp.size(); i++) {
360 		    matched = false;
361 		    for (int j = 0; j < tgthbas.size(); j++) {
362 			if (*tmp[i] == *tgthbas[j]) {
363 			    matched = true;
364 			    break;
365 			}
366 		    }
367 		    if (matched) {
368 			delete (tmp[i]);
369 		    } else {
370 			tgthbas.insert(tgthbas.end(), tmp[i]);
371 		    }
372 		}
373 	    }
374 	} catch (...) {
375 	    unlock();
376 	    throw;
377 	}
378 
379 	unlock();
380 
381 	// When there is more than HBA_MAX_PER_LIST(= int32_max)
382 	// VSL returns an error so it is safe to cast it here.
383 	return ((uint32_t)tgthbas.size());
384 }
385 
386 /**
387  * @memo	    Load the list
388  * @return	    HBA_STATUS_OK
389  *
390  * @doc		    Currently this routine is a no-op and may be a cantidate
391  *		    for removal in the future.
392  */
393 HBA_STATUS HBAList::load() {
394 	Trace log("HBAList::load");
395 
396 	// No lock is required since no VSL specific action requried.
397 	return (HBA_STATUS_OK);
398 }
399 
400 /**
401  * @memo	    Free up resources
402  */
403 HBAList::~HBAList() {
404 	Trace log("HBAList::~HBAList");
405 	for (int i = 0; i < hbas.size(); i++) {
406 	    delete (hbas[i]);
407 	}
408 	for (int i = 0; i < tgthbas.size(); i++) {
409 	    delete (tgthbas[i]);
410 	}
411 }
412 
413 HBA_LIBRARYATTRIBUTES HBAList::getVSLAttributes() {
414 	HBA_LIBRARYATTRIBUTES attrs;
415 	char	build_time[] = BUILD_TIME;
416 	attrs.final = 0;
417 	memset(&attrs, 0, sizeof(attrs));
418 	strlcpy(attrs.VName, VSL_NAME, sizeof (attrs.VName));
419 	strlcpy(attrs.VVersion, VSL_STRING_VERSION, sizeof (attrs.VVersion));
420 	strptime(build_time, "%c", &attrs.build_date);
421 
422 	return (attrs);
423 }
424