FCSyseventBridge.cc revision 7836:4e95154b5b7a
133965Sjdp/*
2218822Sdim * CDDL HEADER START
377298Sobrien *
433965Sjdp * The contents of this file are subject to the terms of the
533965Sjdp * Common Development and Distribution License (the "License").
633965Sjdp * You may not use this file except in compliance with the License.
733965Sjdp *
833965Sjdp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
933965Sjdp * or http://www.opensolaris.org/os/licensing.
1033965Sjdp * See the License for the specific language governing permissions
1133965Sjdp * and limitations under the License.
1233965Sjdp *
1333965Sjdp * When distributing Covered Code, include this CDDL HEADER in each
1433965Sjdp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1533965Sjdp * If applicable, add the following below this CDDL HEADER, with the
1633965Sjdp * fields enclosed by brackets "[]" replaced with your own identifying
1733965Sjdp * information: Portions Copyright [yyyy] [name of copyright owner]
1833965Sjdp *
1933965Sjdp * CDDL HEADER END
2033965Sjdp */
2133965Sjdp/*
22104834Sobrien * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2333965Sjdp * Use is subject to license terms.
2433965Sjdp */
2533965Sjdp
2677298Sobrien
2733965Sjdp
2833965Sjdp#include "FCSyseventBridge.h"
2933965Sjdp#include "Exceptions.h"
3033965Sjdp#include "Trace.h"
3177298Sobrien#include "AdapterAddEvent.h"
3233965Sjdp#include "AdapterEvent.h"
3333965Sjdp#include "AdapterPortEvent.h"
3433965Sjdp#include "AdapterDeviceEvent.h"
3533965Sjdp#include "TargetEvent.h"
3677298Sobrien#include "sun_fc.h"
3733965Sjdp#include <libnvpair.h>
3833965Sjdp#include <iostream>
3933965Sjdp
4033965Sjdpusing namespace std;
4177298Sobrien
4233965SjdpFCSyseventBridge* FCSyseventBridge::_instance = NULL;
4333965Sjdp
4433965SjdpFCSyseventBridge* FCSyseventBridge::getInstance() {
4533965Sjdp    Trace log("FCSyseventBridge::getInstance");
4633965Sjdp    if (_instance == NULL) {
4733965Sjdp	_instance = new FCSyseventBridge();
4833965Sjdp    }
4933965Sjdp    return (_instance);
5033965Sjdp
5133965Sjdp}
5233965Sjdp
5333965Sjdp
5433965Sjdpvoid FCSyseventBridge::addListener(AdapterAddEventListener *listener) {
5533965Sjdp    lock();
5633965Sjdp    try {
5777298Sobrien	adapterAddEventListeners.insert(adapterAddEventListeners.begin(),
5833965Sjdp		listener);
5977298Sobrien	validateRegistration();
6033965Sjdp	unlock();
6133965Sjdp    } catch (...) {
6277298Sobrien	unlock();
6333965Sjdp	throw;
6433965Sjdp    }
6533965Sjdp}
6633965Sjdpvoid FCSyseventBridge::addListener(AdapterEventListener *listener, HBA *hba) {
6777298Sobrien    lock();
6833965Sjdp    try {
6933965Sjdp	adapterEventListeners.insert(adapterEventListeners.begin(), listener);
7033965Sjdp	validateRegistration();
7177298Sobrien	unlock();
7233965Sjdp    } catch (...) {
7377298Sobrien	unlock();
74130561Sobrien	throw;
75130561Sobrien    }
7633965Sjdp}
7777298Sobrienvoid FCSyseventBridge::addListener(AdapterPortEventListener *listener,
7877298Sobrien	    HBAPort *port) {
7977298Sobrien    lock();
8077298Sobrien    try {
8177298Sobrien	adapterPortEventListeners.insert(adapterPortEventListeners.begin(),
8233965Sjdp		listener);
8333965Sjdp	validateRegistration();
8433965Sjdp	unlock();
8533965Sjdp    } catch (...) {
8633965Sjdp	unlock();
8777298Sobrien	throw;
8877298Sobrien    }
8933965Sjdp}
9077298Sobrienvoid FCSyseventBridge::addListener(AdapterDeviceEventListener *listener,
9177298Sobrien    HBAPort *port) {
9233965Sjdp	lock();
9377298Sobrien	try {
9477298Sobrien		adapterDeviceEventListeners.insert(adapterDeviceEventListeners.begin(),
9533965Sjdp		    listener);
9677298Sobrien		validateRegistration();
9733965Sjdp		unlock();
9833965Sjdp	} catch (...) {
9933965Sjdp		unlock();
10033965Sjdp		throw;
10133965Sjdp	}
10233965Sjdp}
10333965Sjdpvoid FCSyseventBridge::addListener(TargetEventListener *listener,
10433965Sjdp	    HBAPort *port, uint64_t targetWWN, bool filter) {
10533965Sjdp    lock();
10633965Sjdp    try {
10733965Sjdp	targetEventListeners.insert(targetEventListeners.begin(), listener);
10833965Sjdp	validateRegistration();
10977298Sobrien	unlock();
11077298Sobrien    } catch (...) {
11133965Sjdp	unlock();
11233965Sjdp	throw;
11333965Sjdp    }
11433965Sjdp}
11533965Sjdp
11633965Sjdpvoid FCSyseventBridge::removeListener(AdapterAddEventListener *listener) {
11733965Sjdp    lock();
11833965Sjdp    try {
11933965Sjdp	typedef vector<AdapterAddEventListener *>::iterator Iter;
12033965Sjdp	for (Iter tmp = adapterAddEventListeners.begin();
12133965Sjdp		tmp != adapterAddEventListeners.end(); tmp++) {
12233965Sjdp	    if (*tmp == listener) {
12333965Sjdp		adapterAddEventListeners.erase(tmp);
12433965Sjdp		unlock();
12533965Sjdp		return;
12633965Sjdp	    }
12733965Sjdp	}
12877298Sobrien	throw InvalidHandleException();
12977298Sobrien    } catch (...) {
13033965Sjdp	unlock();
13133965Sjdp	throw;
13233965Sjdp    }
13333965Sjdp}
13433965Sjdp
13533965Sjdpvoid FCSyseventBridge::removeListener(AdapterEventListener *listener) {
13633965Sjdp    lock();
13733965Sjdp    try {
13833965Sjdp	typedef vector<AdapterEventListener *>::iterator Iter;
13933965Sjdp	for (Iter tmp = adapterEventListeners.begin();
14033965Sjdp		tmp != adapterEventListeners.end(); tmp++) {
14133965Sjdp	    if (*tmp == listener) {
14233965Sjdp		adapterEventListeners.erase(tmp);
14333965Sjdp		unlock();
14433965Sjdp		return;
14533965Sjdp	    }
14633965Sjdp	}
14733965Sjdp	throw InvalidHandleException();
14833965Sjdp    } catch (...) {
14933965Sjdp	unlock();
15033965Sjdp	throw;
15133965Sjdp    }
15233965Sjdp}
15333965Sjdp
15433965Sjdpvoid FCSyseventBridge::removeListener(AdapterPortEventListener *listener) {
15533965Sjdp    lock();
15633965Sjdp    try {
15733965Sjdp	typedef vector<AdapterPortEventListener *>::iterator Iter;
15833965Sjdp	for (Iter tmp = adapterPortEventListeners.begin();
15933965Sjdp		tmp != adapterPortEventListeners.end(); tmp++) {
16033965Sjdp	    if (*tmp == listener) {
16177298Sobrien		adapterPortEventListeners.erase(tmp);
16277298Sobrien		unlock();
16333965Sjdp		return;
16433965Sjdp	    }
16533965Sjdp	}
16633965Sjdp	throw InvalidHandleException();
16733965Sjdp    } catch (...) {
16833965Sjdp	unlock();
16977298Sobrien	throw;
17033965Sjdp    }
17133965Sjdp}
17277298Sobrien
17377298Sobrienvoid FCSyseventBridge::removeListener(AdapterDeviceEventListener *listener) {
17433965Sjdp	lock();
17533965Sjdp	try {
17633965Sjdp		typedef vector<AdapterDeviceEventListener *>::iterator Iter;
17733965Sjdp		for (Iter tmp = adapterDeviceEventListeners.begin();
17833965Sjdp		    tmp != adapterDeviceEventListeners.end(); tmp++) {
17933965Sjdp			if (*tmp == listener) {
18033965Sjdp				adapterDeviceEventListeners.erase(tmp);
18133965Sjdp				unlock();
18233965Sjdp				return;
18333965Sjdp			}
18433965Sjdp		}
18577298Sobrien		throw InvalidHandleException();
18633965Sjdp	} catch (...) {
18733965Sjdp		unlock();
18833965Sjdp		throw;
189	}
190}
191
192void 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
211extern "C" void static_dispatch(sysevent_t *ev) {
212    Trace log("static_dispatch");
213    FCSyseventBridge::getInstance()->dispatch(ev);
214}
215
216void 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
511void 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
550int32_t FCSyseventBridge::getMaxListener() {
551    return (INT_MAX);
552}
553