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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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