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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include "FCSyseventBridge.h"
27 #include "Exceptions.h"
29 #include "AdapterAddEvent.h"
30 #include "AdapterEvent.h"
31 #include "AdapterPortEvent.h"
32 #include "AdapterDeviceEvent.h"
33 #include "TargetEvent.h"
35 #include <libnvpair.h>
41 FCSyseventBridge
* FCSyseventBridge::_instance
= NULL
;
43 FCSyseventBridge
* FCSyseventBridge::getInstance() {
44 Trace
log("FCSyseventBridge::getInstance");
45 if (_instance
== NULL
) {
46 _instance
= new FCSyseventBridge();
53 void FCSyseventBridge::addListener(AdapterAddEventListener
*listener
) {
56 adapterAddEventListeners
.insert(adapterAddEventListeners
.begin(),
58 validateRegistration();
65 void FCSyseventBridge::addListener(AdapterEventListener
*listener
, HBA
*hba
) {
68 adapterEventListeners
.insert(adapterEventListeners
.begin(), listener
);
69 validateRegistration();
76 void FCSyseventBridge::addListener(AdapterPortEventListener
*listener
,
80 adapterPortEventListeners
.insert(adapterPortEventListeners
.begin(),
82 validateRegistration();
89 void FCSyseventBridge::addListener(AdapterDeviceEventListener
*listener
,
93 adapterDeviceEventListeners
.insert(adapterDeviceEventListeners
.begin(),
95 validateRegistration();
102 void FCSyseventBridge::addListener(TargetEventListener
*listener
,
103 HBAPort
*port
, uint64_t targetWWN
, bool filter
) {
106 targetEventListeners
.insert(targetEventListeners
.begin(), listener
);
107 validateRegistration();
115 void FCSyseventBridge::removeListener(AdapterAddEventListener
*listener
) {
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
);
127 throw InvalidHandleException();
134 void FCSyseventBridge::removeListener(AdapterEventListener
*listener
) {
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
);
146 throw InvalidHandleException();
153 void FCSyseventBridge::removeListener(AdapterPortEventListener
*listener
) {
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
);
165 throw InvalidHandleException();
172 void FCSyseventBridge::removeListener(AdapterDeviceEventListener
*listener
) {
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
);
184 throw InvalidHandleException();
191 void FCSyseventBridge::removeListener(TargetEventListener
*listener
) {
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
);
203 throw InvalidHandleException();
210 extern "C" void static_dispatch(sysevent_t
*ev
) {
211 Trace
log("static_dispatch");
212 FCSyseventBridge::getInstance()->dispatch(ev
);
215 void FCSyseventBridge::dispatch(sysevent_t
*ev
) {
216 Trace
log("FCSyseventBridge::dispatch");
217 nvlist_t
*list
= NULL
;
221 log
.debug("Null event.");
225 if (sysevent_get_attr_list(ev
, &list
) || list
== NULL
) {
226 log
.debug("Empty event.");
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
);
235 sysevent_get_time(ev
, &when
);
237 // Now that we know what type of event it is, handle it accordingly
238 if (eventClass
== "EC_sunfc") {
240 // All events of this class type have instance and port-wwn for
243 if (nvlist_lookup_uint32(list
, (char *)"instance",
246 "Improperly formed event: no instance field.");
251 uint32_t rawPortWWNLength
;
253 if (nvlist_lookup_byte_array(list
, (char *)"port-wwn",
254 &rawPortWWN
, &rawPortWWNLength
)) {
256 "Improperly formed event: no port-wwn field.");
261 // Now deal with the specific details of each subclass type
262 if (eventSubClass
== "ESC_sunfc_port_offline") {
264 // Create event instance
265 AdapterPortEvent
event(
266 wwnConversion(rawPortWWN
),
267 AdapterPortEvent::OFFLINE
,
270 // Dispatch to interested parties.
273 typedef vector
<AdapterPortEventListener
*>::iterator Iter
;
274 for (Iter tmp
= adapterPortEventListeners
.begin();
275 tmp
!= adapterPortEventListeners
.end(); tmp
++) {
276 (*tmp
)->dispatch(event
);
285 } else if (eventSubClass
== "ESC_sunfc_port_online") {
287 // Create event instance
288 AdapterPortEvent
event(
289 wwnConversion(rawPortWWN
),
290 AdapterPortEvent::ONLINE
,
293 // Dispatch to interested parties.
296 typedef vector
<AdapterPortEventListener
*>::iterator Iter
;
297 for (Iter tmp
= adapterPortEventListeners
.begin();
298 tmp
!= adapterPortEventListeners
.end(); tmp
++) {
299 (*tmp
)->dispatch(event
);
308 } else if (eventSubClass
== "ESC_sunfc_device_online") {
309 AdapterDeviceEvent
event(
310 wwnConversion(rawPortWWN
),
311 AdapterDeviceEvent::ONLINE
,
315 typedef vector
<AdapterDeviceEventListener
*>::iterator Iter
;
316 for (Iter tmp
= adapterDeviceEventListeners
.begin();
317 tmp
!= adapterDeviceEventListeners
.end(); tmp
++) {
318 (*tmp
)->dispatch(event
);
327 } else if (eventSubClass
== "ESC_sunfc_device_offline") {
328 AdapterDeviceEvent
event(
329 wwnConversion(rawPortWWN
),
330 AdapterDeviceEvent::OFFLINE
,
334 typedef vector
<AdapterDeviceEventListener
*>::iterator Iter
;
335 for (Iter tmp
= adapterDeviceEventListeners
.begin();
336 tmp
!= adapterDeviceEventListeners
.end(); tmp
++) {
337 (*tmp
)->dispatch(event
);
346 } else if (eventSubClass
== "ESC_sunfc_port_rscn") {
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.
354 uint32_t affected_page
;
355 nvpair_t
*attr
= NULL
;
356 for (attr
= nvlist_next_nvpair(list
, NULL
);
358 attr
= nvlist_next_nvpair(list
, attr
)) {
359 string name
= nvpair_name(attr
);
360 if (name
.find("affected_page_") != name
.npos
) {
362 if (nvpair_value_uint32(attr
, &affected_page
)) {
364 "Improperly formed event: "
365 "corrupt affected_page field");
368 // Create event instance
369 AdapterPortEvent
event(
370 wwnConversion(rawPortWWN
),
371 AdapterPortEvent::FABRIC
,
374 // Dispatch to interested parties.
376 typedef vector
<AdapterPortEventListener
*>::iterator Iter
;
378 for (Iter tmp
= adapterPortEventListeners
.begin();
379 tmp
!= adapterPortEventListeners
.end(); tmp
++) {
380 (*tmp
)->dispatch(event
);
390 } else if (eventSubClass
== "ESC_sunfc_target_add") {
391 uchar_t
*rawTargetPortWWN
;
392 uint32_t rawTargetPortWWNLength
;
394 if (nvlist_lookup_byte_array(list
, (char *)"target-port-wwn",
395 &rawTargetPortWWN
, &rawTargetPortWWNLength
)) {
397 "Improperly formed event: no target-port-wwn field.");
402 // Create event instance
403 AdapterPortEvent
event(
404 wwnConversion(rawPortWWN
),
405 AdapterPortEvent::NEW_TARGETS
,
408 // Dispatch to interested parties.
411 typedef vector
<AdapterPortEventListener
*>::iterator Iter
;
412 for (Iter tmp
= adapterPortEventListeners
.begin();
413 tmp
!= adapterPortEventListeners
.end(); tmp
++) {
414 (*tmp
)->dispatch(event
);
422 } else if (eventSubClass
== "ESC_sunfc_target_remove") {
423 uchar_t
*rawTargetPortWWN
;
424 uint32_t rawTargetPortWWNLength
;
426 if (nvlist_lookup_byte_array(list
, (char *)"target-port-wwn",
427 &rawTargetPortWWN
, &rawTargetPortWWNLength
)) {
429 "Improperly formed event: no target-port-wwn field.");
433 // Create event instance
435 wwnConversion(rawPortWWN
),
436 wwnConversion(rawTargetPortWWN
),
437 TargetEvent::REMOVED
);
439 // Dispatch to interested parties.
442 typedef vector
<TargetEventListener
*>::iterator Iter
;
443 for (Iter tmp
= targetEventListeners
.begin();
444 tmp
!= targetEventListeners
.end(); tmp
++) {
445 (*tmp
)->dispatch(event
);
453 } else if (eventSubClass
== "ESC_sunfc_port_attach") {
454 // Create event instance
455 AdapterAddEvent
event(wwnConversion(rawPortWWN
));
456 // Dispatch to interested parties.
459 typedef vector
<AdapterAddEventListener
*>::iterator Iter
;
460 for (Iter tmp
= adapterAddEventListeners
.begin();
461 tmp
!= adapterAddEventListeners
.end(); tmp
++) {
462 (*tmp
)->dispatch(event
);
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.
476 // Create event instance
478 wwnConversion(rawPortWWN
),
479 AdapterEvent::REMOVE
);
481 // Dispatch to interested parties.
484 typedef vector
<AdapterEventListener
*>::iterator Iter
;
485 for (Iter tmp
= adapterEventListeners
.begin();
486 tmp
!= adapterEventListeners
.end(); tmp
++) {
487 (*tmp
)->dispatch(event
);
498 "Unrecognized subclass \"%s\": Ignoring event",
499 eventSubClass
.c_str());
502 // This should not happen, as we only asked for specific classes.
504 "Unrecognized class \"%s\": Ignoring event",
510 void FCSyseventBridge::validateRegistration() {
511 Trace
log("FCSyseventBridge::validateRegistration");
513 count
= adapterAddEventListeners
.size() +
514 adapterEventListeners
.size() +
515 adapterPortEventListeners
.size() +
516 targetEventListeners
.size();
518 handle
= sysevent_bind_handle(static_dispatch
);
519 if (handle
== NULL
) {
521 "Unable to bind sysevent handle.");
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"
535 if (sysevent_subscribe_event(handle
,
536 "EC_sunfc", (const char **)subclass_list
, 9)) {
538 "Unable to subscribe to sun_fc events.");
539 sysevent_unbind_handle(handle
);
542 } else if (count
== 0 && handle
!= NULL
) {
543 // Remove subscription
544 sysevent_unbind_handle(handle
);
549 int32_t FCSyseventBridge::getMaxListener() {