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