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