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
40using namespace std;
41
42/**
43 * @memo	    Private constructor (used to create singleton instance)
44 * @see		    HBAList::instance
45 */
46HBAList::HBAList() { }
47
48/**
49 * Internal singleton instance
50 */
51HBAList* HBAList::_instance = 0;
52
53/**
54 * Max number of adapters that this class supports.
55 */
56const 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 */
64HBA_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 */
80HBAList* 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 */
103Handle* 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 */
142Handle* 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 */
175string 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 */
201string 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 */
232Handle* 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 */
263Handle* 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 */
294int 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 */
349int 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 */
396HBA_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 */
406HBAList::~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
416HBA_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