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 #include "FCSyseventBridge.h" 27 #include "Exceptions.h" 28 #include "Trace.h" 29 #include "AdapterAddEvent.h" 30 #include "AdapterEvent.h" 31 #include "AdapterPortEvent.h" 32 #include "AdapterDeviceEvent.h" 33 #include "TargetEvent.h" 34 #include "sun_fc.h" 35 #include <libnvpair.h> 36 #include <iostream> 37 #include <climits> 38 39 using namespace std; 40 41 FCSyseventBridge* FCSyseventBridge::_instance = NULL; 42 43 FCSyseventBridge* FCSyseventBridge::getInstance() { 44 Trace log("FCSyseventBridge::getInstance"); 45 if (_instance == NULL) { 46 _instance = new FCSyseventBridge(); 47 } 48 return (_instance); 49 50 } 51 52 53 void FCSyseventBridge::addListener(AdapterAddEventListener *listener) { 54 lock(); 55 try { 56 adapterAddEventListeners.insert(adapterAddEventListeners.begin(), 57 listener); 58 validateRegistration(); 59 unlock(); 60 } catch (...) { 61 unlock(); 62 throw; 63 } 64 } 65 void FCSyseventBridge::addListener(AdapterEventListener *listener, HBA *hba) { 66 lock(); 67 try { 68 adapterEventListeners.insert(adapterEventListeners.begin(), listener); 69 validateRegistration(); 70 unlock(); 71 } catch (...) { 72 unlock(); 73 throw; 74 } 75 } 76 void FCSyseventBridge::addListener(AdapterPortEventListener *listener, 77 HBAPort *port) { 78 lock(); 79 try { 80 adapterPortEventListeners.insert(adapterPortEventListeners.begin(), 81 listener); 82 validateRegistration(); 83 unlock(); 84 } catch (...) { 85 unlock(); 86 throw; 87 } 88 } 89 void FCSyseventBridge::addListener(AdapterDeviceEventListener *listener, 90 HBAPort *port) { 91 lock(); 92 try { 93 adapterDeviceEventListeners.insert(adapterDeviceEventListeners.begin(), 94 listener); 95 validateRegistration(); 96 unlock(); 97 } catch (...) { 98 unlock(); 99 throw; 100 } 101 } 102 void FCSyseventBridge::addListener(TargetEventListener *listener, 103 HBAPort *port, uint64_t targetWWN, bool filter) { 104 lock(); 105 try { 106 targetEventListeners.insert(targetEventListeners.begin(), listener); 107 validateRegistration(); 108 unlock(); 109 } catch (...) { 110 unlock(); 111 throw; 112 } 113 } 114 115 void FCSyseventBridge::removeListener(AdapterAddEventListener *listener) { 116 lock(); 117 try { 118 typedef vector<AdapterAddEventListener *>::iterator Iter; 119 for (Iter tmp = adapterAddEventListeners.begin(); 120 tmp != adapterAddEventListeners.end(); tmp++) { 121 if (*tmp == listener) { 122 adapterAddEventListeners.erase(tmp); 123 unlock(); 124 return; 125 } 126 } 127 throw InvalidHandleException(); 128 } catch (...) { 129 unlock(); 130 throw; 131 } 132 } 133 134 void FCSyseventBridge::removeListener(AdapterEventListener *listener) { 135 lock(); 136 try { 137 typedef vector<AdapterEventListener *>::iterator Iter; 138 for (Iter tmp = adapterEventListeners.begin(); 139 tmp != adapterEventListeners.end(); tmp++) { 140 if (*tmp == listener) { 141 adapterEventListeners.erase(tmp); 142 unlock(); 143 return; 144 } 145 } 146 throw InvalidHandleException(); 147 } catch (...) { 148 unlock(); 149 throw; 150 } 151 } 152 153 void FCSyseventBridge::removeListener(AdapterPortEventListener *listener) { 154 lock(); 155 try { 156 typedef vector<AdapterPortEventListener *>::iterator Iter; 157 for (Iter tmp = adapterPortEventListeners.begin(); 158 tmp != adapterPortEventListeners.end(); tmp++) { 159 if (*tmp == listener) { 160 adapterPortEventListeners.erase(tmp); 161 unlock(); 162 return; 163 } 164 } 165 throw InvalidHandleException(); 166 } catch (...) { 167 unlock(); 168 throw; 169 } 170 } 171 172 void FCSyseventBridge::removeListener(AdapterDeviceEventListener *listener) { 173 lock(); 174 try { 175 typedef vector<AdapterDeviceEventListener *>::iterator Iter; 176 for (Iter tmp = adapterDeviceEventListeners.begin(); 177 tmp != adapterDeviceEventListeners.end(); tmp++) { 178 if (*tmp == listener) { 179 adapterDeviceEventListeners.erase(tmp); 180 unlock(); 181 return; 182 } 183 } 184 throw InvalidHandleException(); 185 } catch (...) { 186 unlock(); 187 throw; 188 } 189 } 190 191 void FCSyseventBridge::removeListener(TargetEventListener *listener) { 192 lock(); 193 try { 194 typedef vector<TargetEventListener *>::iterator Iter; 195 for (Iter tmp = targetEventListeners.begin(); 196 tmp != targetEventListeners.end(); tmp++) { 197 if (*tmp == listener) { 198 targetEventListeners.erase(tmp); 199 unlock(); 200 return; 201 } 202 } 203 throw InvalidHandleException(); 204 } catch (...) { 205 unlock(); 206 throw; 207 } 208 } 209 210 extern "C" void static_dispatch(sysevent_t *ev) { 211 Trace log("static_dispatch"); 212 FCSyseventBridge::getInstance()->dispatch(ev); 213 } 214 215 void FCSyseventBridge::dispatch(sysevent_t *ev) { 216 Trace log("FCSyseventBridge::dispatch"); 217 nvlist_t *list = NULL; 218 hrtime_t when; 219 220 if (ev == NULL) { 221 log.debug("Null event."); 222 return; 223 } 224 225 if (sysevent_get_attr_list(ev, &list) || list == NULL) { 226 log.debug("Empty event."); 227 return; 228 } 229 230 string eventVendor = sysevent_get_vendor_name(ev); 231 string eventPublisher = sysevent_get_pub_name(ev); 232 string eventClass = sysevent_get_class_name(ev); 233 string eventSubClass = sysevent_get_subclass_name(ev); 234 235 sysevent_get_time(ev, &when); 236 237 // Now that we know what type of event it is, handle it accordingly 238 if (eventClass == "EC_sunfc") { 239 240 // All events of this class type have instance and port-wwn for 241 // the HBA port. 242 uint32_t instance; 243 if (nvlist_lookup_uint32(list, (char *)"instance", 244 &instance)) { 245 log.genericIOError( 246 "Improperly formed event: no instance field."); 247 nvlist_free(list); 248 return; 249 } 250 uchar_t *rawPortWWN; 251 uint32_t rawPortWWNLength; 252 253 if (nvlist_lookup_byte_array(list, (char *)"port-wwn", 254 &rawPortWWN, &rawPortWWNLength)) { 255 log.genericIOError( 256 "Improperly formed event: no port-wwn field."); 257 nvlist_free(list); 258 return; 259 } 260 261 // Now deal with the specific details of each subclass type 262 if (eventSubClass == "ESC_sunfc_port_offline") { 263 264 // Create event instance 265 AdapterPortEvent event( 266 wwnConversion(rawPortWWN), 267 AdapterPortEvent::OFFLINE, 268 0); 269 270 // Dispatch to interested parties. 271 lock(); 272 try { 273 typedef vector<AdapterPortEventListener *>::iterator Iter; 274 for (Iter tmp = adapterPortEventListeners.begin(); 275 tmp != adapterPortEventListeners.end(); tmp++) { 276 (*tmp)->dispatch(event); 277 } 278 } catch (...) { 279 unlock(); 280 nvlist_free(list); 281 throw; 282 } 283 unlock(); 284 285 } else if (eventSubClass == "ESC_sunfc_port_online") { 286 287 // Create event instance 288 AdapterPortEvent event( 289 wwnConversion(rawPortWWN), 290 AdapterPortEvent::ONLINE, 291 0); 292 293 // Dispatch to interested parties. 294 lock(); 295 try { 296 typedef vector<AdapterPortEventListener *>::iterator Iter; 297 for (Iter tmp = adapterPortEventListeners.begin(); 298 tmp != adapterPortEventListeners.end(); tmp++) { 299 (*tmp)->dispatch(event); 300 } 301 } catch (...) { 302 unlock(); 303 nvlist_free(list); 304 throw; 305 } 306 unlock(); 307 308 } else if (eventSubClass == "ESC_sunfc_device_online") { 309 AdapterDeviceEvent event( 310 wwnConversion(rawPortWWN), 311 AdapterDeviceEvent::ONLINE, 312 0); 313 lock(); 314 try { 315 typedef vector<AdapterDeviceEventListener *>::iterator Iter; 316 for (Iter tmp = adapterDeviceEventListeners.begin(); 317 tmp != adapterDeviceEventListeners.end(); tmp++) { 318 (*tmp)->dispatch(event); 319 } 320 } catch (...) { 321 unlock(); 322 nvlist_free(list); 323 throw; 324 } 325 unlock(); 326 327 } else if (eventSubClass == "ESC_sunfc_device_offline") { 328 AdapterDeviceEvent event( 329 wwnConversion(rawPortWWN), 330 AdapterDeviceEvent::OFFLINE, 331 0); 332 lock(); 333 try { 334 typedef vector<AdapterDeviceEventListener *>::iterator Iter; 335 for (Iter tmp = adapterDeviceEventListeners.begin(); 336 tmp != adapterDeviceEventListeners.end(); tmp++) { 337 (*tmp)->dispatch(event); 338 } 339 } catch (...) { 340 unlock(); 341 nvlist_free(list); 342 throw; 343 } 344 unlock(); 345 346 } else if (eventSubClass == "ESC_sunfc_port_rscn") { 347 /* 348 * RSCNs are a little tricky. There can be multiple 349 * affected page properties, each numbered. To make sure 350 * we get them all, we loop through all properties 351 * in the nvlist and if their name begins with "affected_page_" 352 * then we send an event for them. 353 */ 354 uint32_t affected_page; 355 nvpair_t *attr = NULL; 356 for (attr = nvlist_next_nvpair(list, NULL); 357 attr != NULL; 358 attr = nvlist_next_nvpair(list, attr)) { 359 string name = nvpair_name(attr); 360 if (name.find("affected_page_") != name.npos) { 361 362 if (nvpair_value_uint32(attr, &affected_page)) { 363 log.genericIOError( 364 "Improperly formed event: " 365 "corrupt affected_page field"); 366 continue; 367 } 368 // Create event instance 369 AdapterPortEvent event( 370 wwnConversion(rawPortWWN), 371 AdapterPortEvent::FABRIC, 372 affected_page); 373 374 // Dispatch to interested parties. 375 lock(); 376 typedef vector<AdapterPortEventListener *>::iterator Iter; 377 try { 378 for (Iter tmp = adapterPortEventListeners.begin(); 379 tmp != adapterPortEventListeners.end(); tmp++) { 380 (*tmp)->dispatch(event); 381 } 382 } catch (...) { 383 unlock(); 384 nvlist_free(list); 385 throw; 386 } 387 unlock(); 388 } 389 } 390 } else if (eventSubClass == "ESC_sunfc_target_add") { 391 uchar_t *rawTargetPortWWN; 392 uint32_t rawTargetPortWWNLength; 393 394 if (nvlist_lookup_byte_array(list, (char *)"target-port-wwn", 395 &rawTargetPortWWN, &rawTargetPortWWNLength)) { 396 log.genericIOError( 397 "Improperly formed event: no target-port-wwn field."); 398 nvlist_free(list); 399 return; 400 } 401 402 // Create event instance 403 AdapterPortEvent event( 404 wwnConversion(rawPortWWN), 405 AdapterPortEvent::NEW_TARGETS, 406 0); 407 408 // Dispatch to interested parties. 409 lock(); 410 try { 411 typedef vector<AdapterPortEventListener *>::iterator Iter; 412 for (Iter tmp = adapterPortEventListeners.begin(); 413 tmp != adapterPortEventListeners.end(); tmp++) { 414 (*tmp)->dispatch(event); 415 } 416 } catch (...) { 417 unlock(); 418 nvlist_free(list); 419 throw; 420 } 421 unlock(); 422 } else if (eventSubClass == "ESC_sunfc_target_remove") { 423 uchar_t *rawTargetPortWWN; 424 uint32_t rawTargetPortWWNLength; 425 426 if (nvlist_lookup_byte_array(list, (char *)"target-port-wwn", 427 &rawTargetPortWWN, &rawTargetPortWWNLength)) { 428 log.genericIOError( 429 "Improperly formed event: no target-port-wwn field."); 430 nvlist_free(list); 431 return; 432 } 433 // Create event instance 434 TargetEvent event( 435 wwnConversion(rawPortWWN), 436 wwnConversion(rawTargetPortWWN), 437 TargetEvent::REMOVED); 438 439 // Dispatch to interested parties. 440 lock(); 441 try { 442 typedef vector<TargetEventListener *>::iterator Iter; 443 for (Iter tmp = targetEventListeners.begin(); 444 tmp != targetEventListeners.end(); tmp++) { 445 (*tmp)->dispatch(event); 446 } 447 } catch (...) { 448 unlock(); 449 nvlist_free(list); 450 throw; 451 } 452 unlock(); 453 } else if (eventSubClass == "ESC_sunfc_port_attach") { 454 // Create event instance 455 AdapterAddEvent event(wwnConversion(rawPortWWN)); 456 // Dispatch to interested parties. 457 lock(); 458 try { 459 typedef vector<AdapterAddEventListener *>::iterator Iter; 460 for (Iter tmp = adapterAddEventListeners.begin(); 461 tmp != adapterAddEventListeners.end(); tmp++) { 462 (*tmp)->dispatch(event); 463 } 464 } catch (...) { 465 unlock(); 466 nvlist_free(list); 467 throw; 468 } 469 unlock(); 470 } else if (eventSubClass == "ESC_sunfc_port_detach") { 471 // Technically, we should probably try to coalesce 472 // all detach events for the same multi-ported adapter 473 // and only send one event to the client, but for now, 474 // we'll just blindly send duplicates. 475 476 // Create event instance 477 AdapterEvent event( 478 wwnConversion(rawPortWWN), 479 AdapterEvent::REMOVE); 480 481 // Dispatch to interested parties. 482 lock(); 483 try { 484 typedef vector<AdapterEventListener *>::iterator Iter; 485 for (Iter tmp = adapterEventListeners.begin(); 486 tmp != adapterEventListeners.end(); tmp++) { 487 (*tmp)->dispatch(event); 488 } 489 } catch (...) { 490 unlock(); 491 nvlist_free(list); 492 throw; 493 } 494 unlock(); 495 496 } else { 497 log.genericIOError( 498 "Unrecognized subclass \"%s\": Ignoring event", 499 eventSubClass.c_str()); 500 } 501 } else { 502 // This should not happen, as we only asked for specific classes. 503 log.genericIOError( 504 "Unrecognized class \"%s\": Ignoring event", 505 eventClass.c_str()); 506 } 507 nvlist_free(list); 508 } 509 510 void FCSyseventBridge::validateRegistration() { 511 Trace log("FCSyseventBridge::validateRegistration"); 512 uint64_t count = 0; 513 count = adapterAddEventListeners.size() + 514 adapterEventListeners.size() + 515 adapterPortEventListeners.size() + 516 targetEventListeners.size(); 517 if (count == 1) { 518 handle = sysevent_bind_handle(static_dispatch); 519 if (handle == NULL) { 520 log.genericIOError( 521 "Unable to bind sysevent handle."); 522 return; 523 } 524 const char *subclass_list[9] = { 525 "ESC_sunfc_port_attach", 526 "ESC_sunfc_port_detach", 527 "ESC_sunfc_port_offline", 528 "ESC_sunfc_port_online", 529 "ESC_sunfc_port_rscn", 530 "ESC_sunfc_target_add", 531 "ESC_sunfc_target_remove", 532 "ESC_sunfc_device_online", 533 "ESC_sunfc_device_offline" 534 }; 535 if (sysevent_subscribe_event(handle, 536 "EC_sunfc", (const char **)subclass_list, 9)) { 537 log.genericIOError( 538 "Unable to subscribe to sun_fc events."); 539 sysevent_unbind_handle(handle); 540 handle = NULL; 541 } 542 } else if (count == 0 && handle != NULL) { 543 // Remove subscription 544 sysevent_unbind_handle(handle); 545 handle == NULL; 546 } // Else do nothing 547 } 548 549 int32_t FCSyseventBridge::getMaxListener() { 550 return (INT_MAX); 551 } 552