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 "Handle.h" 29 #include "Exceptions.h" 30 #include "Trace.h" 31 #include <libdevinfo.h> 32 #include <iostream> 33 #include <iomanip> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 #include <stropts.h> 39 40 #define MAX_INIT_HANDLE_ID 0x7fff 41 #define MAX_TGT_HANDLE_ID 0xffff 42 43 using namespace std; 44 45 /** 46 * Global lock for list of Handles 47 */ 48 pthread_mutex_t Handle::staticLock = PTHREAD_MUTEX_INITIALIZER; 49 50 /** 51 * Tracking for the previous handle we have opened 52 */ 53 HBA_HANDLE Handle::prevOpen = 0; 54 55 /** 56 * Tracking for the previous target HBA handle we have opened 57 */ 58 HBA_HANDLE Handle::prevTgtOpen = 0x8000; 59 60 /** 61 * Global map from HBA_HANDLE to Handle pointers (our global list) 62 */ 63 map<HBA_HANDLE, Handle*> Handle::openHandles; 64 65 /** 66 * @memo Create a new open handle for a specified HBA 67 * @precondition HBA port(s) must be loaded 68 * @postcondition An open handle will be present in the global tracking list 69 * and must be closed at some point to prevent leakage. If no 70 * handle could be assigned (the track list is full), an 71 * exception will be thrown. Scope for valid ids in the track 72 * list is [1, MAX_INIT_HANDLE_ID]. 73 * @param myhba The HBA to open a handle for 74 */ 75 Handle::Handle(HBA *myhba) { 76 map<HBA_HANDLE, Handle*>::iterator mapend; 77 Trace log("Handle::Handle"); 78 modeVal = INITIATOR; 79 lock(&staticLock); 80 mapend = openHandles.end(); 81 /* Start the search for a free id from the previously assigned one */ 82 id = prevOpen + 1; 83 while (id != prevOpen) { 84 /* Exceeds the max valid value, continue the search from 1 */ 85 if (id > MAX_INIT_HANDLE_ID) 86 id = 1; 87 88 if (openHandles.find(id) == mapend) { 89 /* the id is not in use */ 90 break; 91 } 92 id ++; 93 } 94 if (id == prevOpen) { 95 /* no usable id for now */ 96 unlock(&staticLock); 97 throw TryAgainException(); 98 } 99 prevOpen = id; 100 hba = myhba; 101 openHandles[id] = this; 102 unlock(&staticLock); 103 } 104 105 /** 106 * @memo Create a new open handle for a specified HBA 107 * @precondition HBA port(s) must be loaded 108 * @postcondition An open handle will be present in the global tracking list 109 * and must be closed at some point to prevent leakage. If no 110 * handle could be assigned (the track list is full), an 111 * exception will be thrown. Scope for valid ids in the track 112 * list is [0x8000, MAX_TGT_HANDLE_ID]. 113 * @param myhba The HBA to open a handle for 114 * m The mode of HBA to open handle for 115 */ 116 #if 0 117 // appears unused 118 Handle::Handle(HBA *myhba, MODE m) { 119 map<HBA_HANDLE, Handle*>::iterator mapend; 120 Trace log("Handle::Handle"); 121 lock(&staticLock); 122 modeVal = m; 123 124 125 // if initiator mode call constructor for initiator. 126 if (m == INITIATOR) { 127 Handle(myhba, TARGET); 128 } 129 130 mapend = openHandles.end(); 131 /* Start the search for a free id from the previously assigned one */ 132 id = prevTgtOpen + 1; 133 while (id != prevTgtOpen) { 134 /* 135 * Exceeds the max valid target id value, 136 * continue the search from 1. 137 */ 138 if (id > MAX_TGT_HANDLE_ID) 139 id = 0x8001; 140 141 if (openHandles.find(id) == mapend) { 142 /* the id is not in use */ 143 break; 144 } 145 id ++; 146 } 147 if (id == prevTgtOpen) { 148 /* no usable id for now */ 149 unlock(&staticLock); 150 throw TryAgainException(); 151 } 152 prevTgtOpen = id; 153 hba = myhba; 154 openHandles[id] = this; 155 unlock(&staticLock); 156 } 157 #endif 158 /** 159 * @memo Free up the handle (aka, close it) 160 * @postcondition This handle will be removed from the global list 161 * @exception ... underlying exceptions will be thrown 162 */ 163 Handle::~Handle() { 164 Trace log("Handle::~Handle"); 165 // Remove this handle from the global list 166 lock(&staticLock); 167 try { 168 openHandles.erase(openHandles.find(getHandle())); 169 unlock(&staticLock); 170 } catch (...) { 171 unlock(&staticLock); 172 throw; 173 } 174 175 // Now nuke all internal dynamic allocations 176 typedef map<uint64_t, HandlePort *>::const_iterator CI; 177 lock(); 178 try { 179 for (CI port = portHandles.begin(); port != portHandles.end(); 180 port++) { 181 delete port->second; 182 } 183 portHandles.clear(); 184 unlock(); 185 } catch (...) { 186 unlock(); 187 throw; 188 } 189 } 190 191 /** 192 * @memo Locate a handle in the global list of open handles 193 * @precondition The requested handle must already be open 194 * @exception InvalidHandleException Thrown if the id does not match 195 * an open handle 196 * @return The open Handle 197 * @param id The id of the handle to fetch 198 * 199 * @doc The HBA API uses a simple integer type to represent 200 * an open Handle, but we use an instance of the Handle 201 * class. This interface allows a caller to quickly convert 202 * from the API integer value to related the Handle instance. 203 */ 204 Handle* Handle::findHandle(HBA_HANDLE id) { 205 Trace log("Handle::findHandle(id)"); 206 Handle *tmp = NULL; 207 lock(&staticLock); 208 try { 209 if (openHandles.find(id) == openHandles.end()) { 210 throw InvalidHandleException(); 211 } 212 tmp = openHandles[id]; 213 unlock(&staticLock); 214 return (tmp); 215 } catch (...) { 216 unlock(&staticLock); 217 throw; 218 } 219 } 220 221 /** 222 * @memo Find an open handle based on Node or Port WWN 223 * @precondition The given HBA must already be open 224 * @exception IllegalWWNException Thrown if no matching open Handle found 225 * @return The open handle matching the wwn argument 226 * @param wwn The Node or Port WWN of the HBA whos open handle 227 * is requested. 228 * 229 */ 230 Handle* Handle::findHandle(uint64_t wwn) { 231 Trace log("Handle::findHandle(wwn)"); 232 Handle *tmp = NULL; 233 lock(&staticLock); 234 try { 235 for (int i = 0; i < openHandles.size(); i++) { 236 tmp = openHandles[i]; 237 if (tmp->getHBA()->containsWWN(wwn)) { 238 unlock(&staticLock); 239 return (tmp); 240 } 241 } 242 tmp = NULL; 243 } catch (...) { tmp = NULL; } 244 unlock(&staticLock); 245 if (tmp == NULL) { 246 throw IllegalWWNException(); 247 } 248 return (tmp); 249 } 250 251 /** 252 * @memo Refresh underlying index values 253 * @postcondition All HandlePorts will be reset and prior index values 254 * will be undefined. 255 * @exception ... underlying exceptions will be thrown 256 * 257 * @doc A number of APIs in the standard interface require 258 * the use of index values for identifying what "thing" 259 * to operate on. When dynamic reconfiguration occurs 260 * these indexes may become inconsistent. This routine 261 * is called to reset the indexes and signify that the caller 262 * no longer holds or will refer to any old indexes. 263 */ 264 void Handle::refresh() { 265 Trace log("Handle::refresh"); 266 lock(); 267 try { 268 typedef map<uint64_t, HandlePort *>::const_iterator CI; 269 for (CI port = portHandles.begin(); port != portHandles.end(); 270 port++) { 271 port->second->refresh(); 272 } 273 unlock(); 274 } catch (...) { 275 unlock(); 276 throw; 277 } 278 } 279 280 /** 281 * @memo Close the specified handle 282 * @precondition The handle must be open 283 * @postcondition The handle will be closed and should be discarded. 284 * @param id The handle to close 285 */ 286 void Handle::closeHandle(HBA_HANDLE id) { 287 Trace log("Handle::closeHandle"); 288 Handle *myHandle = findHandle(id); 289 delete myHandle; 290 } 291 292 /** 293 * @memo Get the integer value for return to the API 294 * @exception ... underlying exceptions will be thrown 295 * @return The integer value representing the handle 296 * 297 * @doc The HBA API uses integer values to represent handles. 298 * Call this routine to convert a Handle instance into 299 * its representative integer value. 300 */ 301 HBA_HANDLE Handle::getHandle() { 302 Trace log("Handle::getHandle"); 303 HBA_HANDLE tmp; 304 lock(); 305 try { 306 tmp = (HBA_HANDLE) id; 307 unlock(); 308 return (tmp); 309 } catch (...) { 310 unlock(); 311 throw; 312 } 313 } 314 315 /** 316 * @memo Compare two handles for equality 317 * @return TRUE if the handles are the same 318 * @return FALSE if the handles are different 319 */ 320 bool Handle::operator==(Handle comp) { 321 Trace log("Handle::operator=="); 322 return (this->id == comp.id); 323 } 324 325 /** 326 * @memo Get the underlying Handle port based on index 327 * @return The Handle port for the given port index 328 * @param index The index of the desired port 329 */ 330 HandlePort* Handle::getHandlePortByIndex(int index) { 331 Trace log("Handle::getHandlePortByIndex"); 332 HBAPort* port = hba->getPortByIndex(index); 333 return (getHandlePort(port->getPortWWN())); 334 } 335 336 /** 337 * @memo Get the underlying Handle port based on Port wwn 338 * @exception IllegalWWNException thrown if the wwn is not found 339 * @return The handle port for the specified WWN 340 * @param wwn The Port WWN of the HBA port 341 * 342 */ 343 HandlePort* Handle::getHandlePort(uint64_t wwn) { 344 Trace log("Handle::getHandlePort"); 345 lock(); 346 try { 347 // Check to see if the wwn is in the map 348 if (portHandles.find(wwn) == portHandles.end()) { 349 // Not found, add a new one 350 HBAPort* port = hba->getPort(wwn); 351 portHandles[wwn] = new HandlePort(this, hba, port); 352 } 353 HandlePort *portHandle = portHandles[wwn]; 354 unlock(); 355 return (portHandle); 356 } catch (...) { 357 unlock(); 358 throw; 359 } 360 } 361 362 /** 363 * @memo Get the HBA attributes from the underlying HBA 364 * 365 * @see HBA::getHBAAttributes 366 */ 367 HBA_ADAPTERATTRIBUTES Handle::getHBAAttributes() { 368 Trace log("Handle::getHBAAttributes"); 369 lock(); 370 try { 371 HBA_ADAPTERATTRIBUTES attributes = hba->getHBAAttributes(); 372 unlock(); 373 return (attributes); 374 } catch (...) { 375 unlock(); 376 throw; 377 } 378 } 379 380 HBA_ADAPTERATTRIBUTES Handle::npivGetHBAAttributes() { 381 Trace log("Handle::npivGetHBAAttributes"); 382 lock(); 383 try { 384 HBA_ADAPTERATTRIBUTES attributes = hba->npivGetHBAAttributes(); 385 unlock(); 386 return (attributes); 387 } catch (...) { 388 unlock(); 389 throw; 390 } 391 } 392 393 394 /** 395 * @memo Get the HBA port attributes from the HBA 396 * @see HBAPort::getPortAttributes 397 * @see HBAPort::getDisoveredAttributes 398 * 399 * @doc This routine will return either HBA port 400 * attributes, or discovered port attributes 401 * 402 */ 403 HBA_PORTATTRIBUTES Handle::getPortAttributes(uint64_t wwn) { 404 Trace log("Handle::getPortAttributes"); 405 uint64_t tmp; 406 HBA_PORTATTRIBUTES attributes; 407 408 lock(); 409 try { 410 // Is this a WWN for one of the adapter ports? 411 if (hba->containsWWN(wwn)) { 412 attributes = hba->getPort(wwn)->getPortAttributes(tmp); 413 unlock(); 414 return (attributes); 415 } else { // Is this a target we know about? 416 // Loop through all ports and look for the first match 417 418 for (int i = 0; i < hba->getNumberOfPorts(); i++) { 419 try { 420 attributes = 421 hba->getPortByIndex(i)->getDiscoveredAttributes( 422 wwn, tmp); 423 unlock(); 424 return (attributes); 425 } catch (HBAException &e) { 426 continue; 427 } 428 } 429 430 // If we get to here, then we don't see this WWN on this HBA 431 throw IllegalWWNException(); 432 } 433 } catch (...) { 434 unlock(); 435 throw; 436 } 437 } 438