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