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