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 */
HBAList()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 */
unload()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 */
instance()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 */
openHBA(string name)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 */
openTgtHBA(string name)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 */
getHBAName(int index)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 */
getTgtHBAName(int index)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 */
openHBA(uint64_t wwn)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 */
openTgtHBA(uint64_t wwn)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 */
getNumberofAdapters()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 */
getNumberofTgtAdapters()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 */
load()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 */
~HBAList()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
getVSLAttributes()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