ldi_ev_register_callbacks man page on SmartOS

Man page or keyword search:  
man Server   16655 pages
apropos Keyword Search (all sections)
Output format
SmartOS logo
[printable version]

LDI_EV_REGISTER_CALLBACKS(9F)			 LDI_EV_REGISTER_CALLBACKS(9F)

NAME
       ldi_ev_register_callbacks - add a notify and/or finalize callback

SYNOPSIS
       #include <sys/sunldi.h>

       int ldi_ev_register_callbacks(ldi_handle_t lh,
	     ldi_ev_cookie_t *cookie, ldi_ev_callback_t *callb,
	     void *arg, ldi_callback_id_t *id);

INTERFACE LEVEL
       Solaris DDI specific (Solaris DDI)

PARAMETERS
       ldi_handle_t lh

	   A  layered handle representing the device for which the event noti‐
	   fication was requested.

       ldi_ev_cookie_t *cookie

	   An opaque event cookie for the event type returned  by  a  previous
	   call to ldi_ev_get_cookie(9F).

       ldi_ev_callback_t *callb

	   A data structure which currently has the following members:

	     struct ldi_ev_callback {
		     uint_t  cb_vers;
		     int     (*cb_notify)(ldi_handle_t,
					  ldi_ev_cookie_t cookie,
					  void *arg, void *ev_data);
		     void    (*cb_finalize)(ldi_handle_t,
					    ldi_ev_cookie_t cookie,
					    int ldi_result,
					    void *arg,
					    void *ev_data);
	      } ldi_ev_callback_t;

	   where

	   cb_vers
		      Version	of   callback	vector.	  Must	 be   set   to
		      LDI_EV_CB_VERS by the caller.

		      The arguments passed into the callbacks  when  they  are
		      invoked, include:

		      int ldi_result

			  The	actual	result	of  the	 state	change	opera‐
			  tion/event passed to finalize callback:  LDI_EV_SUC‐
			  CESS: The state change succeeded LDI_EV_FAILURE: The
			  state change failed.

		      void *ev_data

			  Event specific data.

       void *arg

	   A pointer to opaque caller private data.

       ldi_callback_id_t *id

	   Unique  system  wide	 registration  id  returned  by	 ldi_ev_regis‐
	   ter_callbacks(9F) upon successful registration.

DESCRIPTION
       The  ldi_ev_register_callbacks()	 interface  allows  layered drivers to
       register notify and finalize callbacks for certain events. These events
       are  listed  in the ldi_ev_get_cookie(9F) man page. The notify callback
       is invoked only for events that can be blocked, just before  the	 event
       occurs.	The  notify event is not called for events serviced by the NDI
       event  service framework since such events are by definition  asynchro‐
       nous.  Only   the finalize callback is invoked for such events. Layered
       drivers that have registered notify callbacks for that event  have  the
       opportunity  of blocking such events.  The finalize callback is invoked
       once the final disposition of the state of  a  device  (specifically  a
       device  minor node) is known. The callback is invoked with this result,
       either LDI_EV_SUCCESS (state change succeeded) or LDI_EV_FAILURE (state
       change  failed).	 This  allows layered driver consumers to finalize any
       changes they made in response to a previous "notify" callback.

       For example, a layered driver's	notify	callback  may  be  invoked  in
       response	 to a LDI_EV_OFFLINE event. The layered driver may reconfigure
       itself to stop using the device and permit the change  to  go  forward.
       Once  that  happens,  the  I/O  framework attempts to actually take the
       device offline. This offline attempt can have  two  possible  outcomes:
       success	or  failure.  In  the  former  case,  the finalize callback is
       invoked with the ldi_result argument set to LDI_EV_SUCCESS and the lay‐
       ered driver knows that the device has been taken offline. In the latter
       case, finalize is invoked with the ldi_result set to LDI_EV_FAILURE and
       the layered driver knows that the state change failed. In this case, it
       may choose to reconfigure itself to start using the device again.

       Finalize callbacks can be registered for all  events  including	events
       that cannot be blocked.

       A  layered driver can also propagate these events up the software stack
       by using interfaces offered by the LDI  event  framework.  The  layered
       driver  may use ldi_ev_notify() to propagate notify events occurring on
       minors it imports  onto	minors	it  exports.  Similarly,  it  may  use
       ldi_ev_finalize()  to  propagate	 finalize events. Both ldi_ev_notify()
       and ldi_ev_finalize() propagate events to device contracts as  well  as
       LDI callbacks  registered against the exported minor nodes.

       The  LDI	 event framework has the following guarantees and requirements
       with respect to these callbacks:

	   1.	  The notify() callback is invoked  before  an	event  (repre‐
		  sented  by the event cookie) occurs on a device (represented
		  by the layered driver handle) and is invoked only for events
		  that can be blocked. If the callback returns LDI_EV_FAILURE,
		  the event is blocked. If the	callback  returns  LDI_EV_SUC‐
		  CESS, the event is allowed to proceed. If any other value is
		  returned, it is an error. An error message is logged and the
		  event	 is  blocked.	An  example  of	 an  event that can be
		  blocked and for which notify callbacks may be invoked is the
		  offline event LDI_EV_OFFLINE.

	   2.	  The  finalize	 callback is invoked for all events (including
		  events that cannot be blocked) after the event has occurred.
		  It is invoked with either LDI_EV_SUCCESS indicating that the
		  event successfully  happened	or  LDI_EV_FAILURE  indicating
		  that	the event did not occur. The finalize callback returns
		  no values. Good examples of events that  cannot  be  blocked
		  are  the  degrade event (LDI_EV_DEGRADE) and events serviced
		  by the NDI event service framework.

	   3.	  Layered drivers may register one or both of these  callbacks
		  (that	 is,  only  for	 a notify event or only for a finalize
		  event or for both) against any LDI handle that they may pos‐
		  sess. If a finalize or notify event is not being registered,
		  the corresponding pointer in the ldi_ev_callback_t structure
		  must	be  set to NULL. It is an error to attempt a registra‐
		  tion with both callbacks set to NULL.

	   4.	  A notify and/or finalize callback is	invoked	 only  if  the
		  corresponding	 LDI  handle is open. If an LDI handle against
		  which the callbacks are registered  is  closed,  the	corre‐
		  sponding  finalize and notify callbacks is not invoked as it
		  is assumed that the layered driver is no  longer  interested
		  in  the device. See number 5 below for the exception to this
		  rule.

	   5.	  A layered driver that closes it's LDI handle in it's	notify
		  routine  receives  the corresponding finalize callback after
		  the event has occurred.  Because the	LDI  handle  has  been
		  closed,  the	finalize  callback  is invoked with a NULL LDI
		  handle. It is the responsibility of the  layered  driver  to
		  maintain  state  in  it's private "arg" parameter so that it
		  can reopen the device (if desired) in	 it's  finalize	 call‐
		  back.

		  One example where this may happen is with the LDI_EV_OFFLINE
		  event. A layered driver's notify callback may be invoked for
		  an  offline  event.  The  layered driver may choose to allow
		  this event to proceed. In that case, since it has a  layered
		  open of the device, it must close the LDI handle so that the
		  offline event can succeed (an offline of a device  does  not
		  succeed  if there is any open of the device, layered or oth‐
		  erwise). Since the layered driver has closed the LDI	handle
		  in  the  notify  routine, it's finalize callback (if any) is
		  invoked with a NULL LDI handle. It is the responsibility  of
		  the  layered	driver	to  maintain state (such as the device
		  path or devid) in it's private "arg" parameter, so  that  in
		  the finalize routine, it can do a layered open of the device
		  if the device offline failed.

		  This is the only exception where the	finalize  callback  is
		  invoked  if  the  LDI	 handle	 has been closed. In all other
		  cases if the LDI handle has been  closed,  no	 corresponding
		  callbacks is invoked.

	   6.	  In  order for the offline event to succeed (LDI_EV_OFFLINE),
		  it is imperative that there be no opens (including LDI  han‐
		  dles)	 to the device.	 If a layered driver's notify callback
		  is invoked for an offline event and the  driver  intends  to
		  allow the offline to proceed, the driver must close the cor‐
		  responding LDI handle.

	   7.	  The notify and  finalize  callbacks  are  not	 automatically
		  unregistered	even  if the corresponding LDI handle has been
		  closed. It is the responsibility of the  layered  driver  to
		  unregister  these  callbacks	when they are not required. It
		  may do so using the  ldi_ev_remove_callbacks(9F)  interface.
		  The  LDI  framework  may panic if the entity registering the
		  callback (such as a dip, dev_t or module) no	longer	exists
		  on  the system and the corresponding callbacks have not been
		  unregistered.

	   8.	  The LDI event framework guarantees that if a layered	driver
		  receives  a  notify event, it also receives a finalize event
		  except if the layered	 consumer  itself  blocked  the	 event
		  (that	 is, it returned LDI_EV_FAILURE from it's notify call‐
		  back. In this case, the layered driver knows that the	 event
		  has  been  blocked  and therefore does not need the finalize
		  callback.

	   9.	  If a layered driver propagates notify events	on  minors  it
		  imports  to minors it exports, it must first propagate these
		  events up the software stack via  ldi_eve_notify()  in  it's
		  notify callback. It must do so before attempting to check if
		  it blocks the event. This is	required,  because  a  layered
		  driver  cannot  release the device if consumers up the stack
		  are still using  the	device.	  If  ldi_ev_notify()  returns
		  LDI_EV_FAILURE,   the	  callback   must  immediately	return
		  LDI_EV_FAILURE from it's notify callback. If ldi_ev_notify()
		  returns LDI_EV_SUCCESS, then the state change is permissible
		  as far as consumers higher up in the software stack are con‐
		  cerned.   The	 layered  driver must then determine if it can
		  permit the state change.  If	the  state  change  is	to  be
		  allowed,  the	 layered driver must return LDI_EV_SUCCESS. If
		  the layered driver determines that the state	change	should
		  not  be  permitted,  it  must	 invoke	 ldi_ev_finalize()  on
		  minors it exports with a result of LDI_EV_FAILURE (to inform
		  consumers  up the stack) and then return LDI_EV_FAILURE from
		  it's notify callback.

	   10.	  The LDI event framework generates  finalize  events  at  the
		  earliest  point  where a failure is detected. If the failure
		  is detected in the framework (such  as  in  ldi_ev_notify())
		  the  framework  generates the finalize events.  In the event
		  that a failure is first detected in a layered	 driver	 (that
		  is,  in the notify callback of a layered driver) the layered
		  driver must use ldi_ev_finalize()  to send  finalize	events
		  up  the  software stack . See the examples for code snippets
		  describing this scenario.

	   11.	  The finalize callback must first reconfigure	itself	before
		  attempting  to propagate the event up the software stack via
		  ldi_ev_finalize(9F). This is so that the minors  it  exports
		  are available and ready for use before the finalize event is
		  propagated up the software stack.

	   12.	  It may so happen that the event propagated up	 the  software
		  stack	 is  not  the  same  as	 the event for which a layered
		  driver's notify/finalize callback is invoked. For example, a
		  layered  driver's  callback(s) may be invoked for an offline
		  event, but the driver	 may  choose  to  only	propagate  the
		  degraded  event  to  its consumers (since it may have a mir‐
		  ror/copy of the data on the device.)	In that case, the lay‐
		  ered driver must generate a different event cookie (that is,
		  one	corresponding	 to    the    degraded	  event	   via
		  ldi_ev_get_cookie(9F))  and  use that cookie in its propaga‐
		  tion calls (that  is,	 ldi_ev_notify(9F)  and	 ldi_ev_final‐
		  ize(9F)).

       Once  the  registration	of  the	 callback(s)  is successful, an opaque
       ldi_callback_id_t structure is returned which may be used to unregister
       the callback(s) later.

RETURN VALUES
       The return values for this function are:

       LDI_EV_SUCCESS

	   Callback(s) added successfully.

       LDI_EV_FAILURE

	   Failed to add callback(s).

CONTEXT
       This function can be called from user and kernel contexts only.

EXAMPLES
       Example 1 Registration and Callbacks for the OFFLINE Event

       The  following  example shows how the ldi_ev_register_callbacks() func‐
       tion performs a registration and callback for the offline event:

	 static int
	 event_register(void)
	 {
		 ldi_handle_t lh;
		 ldi_ev_callback_t callb;
		 ldi_ev_cookie_t off_cookie;

		 if (ldi_ev_get_cookie(lh, LDI_EV_OFFLINE, &off_cookie)
		     == LDI_EV_FAILURE)
			 goto fail;

		 callb.cb_vers = LDI_EV_CB_VERS;
		 callb.cb_notify = off_notify;
		 callb.cb_finalize = off_finalize;

		 if (ldi_ev_register_callbacks(lh, off_cookie, &callb, arg, &id)
		     != LDI_EV_SUCCESS)
			 goto fail;
	 }

	 static void
	 event_unregister(ldi_callback_id_t id)
	 {
		 ldi_ev_remove_callbacks(id);
	 }

	 static int
	 off_notify(ldi_handle_t lh, ldi_ev_cookie_t off_cookie, void *arg,
	     void *ev_data)
	 {

		 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_OFFLINE) == 0);

		 /* Map imported minors to exported minor */
		 widget_map(lh, &minor, &spec_type);

		 /*
		  * Call ldi_ev_notify() to propagate events to our consumers.
		  * This *must* happen before we check if offline should be blocked
		  */
		 if (ldi_ev_notify(dip, minor, spec_type, off_cookie, ev_data)
		     != LDI_EV_SUCCESS)
			 return (LDI_EV_FAILURE);

		 /*
		  * Next, check if we can allow the offline
		  */
		 if (widget_check(lh) == WIDGET_SUCCESS) {
			 widget_save_path(arg, lh);
			 widget_reconfigure(lh, RELEASE);
			 ldi_close(lh);
			 return (LDI_EV_SUCCESS)
		 }

		 /*
		  * We cannot permit the offline. The first layer that detects
		  * failure i.e. us, must generate finalize events for our
		    consumers
		  */
		 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_FAILURE, off_cookie,
		     ev_data);

		 return (LDI_EV_FAILURE);
	 }

	 /*
	 /*
	  * The finalize callback will only be called if we returned LDI_EV_SUCCESS
	  * in our notify callback. ldi_result passed in may be SUCCESS or FAILURE
	  */
	 static void
	 off_finalize(ldi_handle_t NULL_lh, ldi_ev_cookie_t off_cookie,
	     int ldi_result, void *arg, void *ev_data)
	 {
		 ldi_handle_t lh;

		 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_OFFLINE) == 0);

		 path = widget_get_path(arg);

		 widget_map_by_path(path, &minor, &spec_type);

		 if (ldi_result == LDI_EV_SUCCESS) {
			 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_SUCCESS,
			     off_cookie, ev_data);
			 return;
		 }

		 /* The offline failed. Reopen the device */
		 ldi_open_by_name(path, &lh);
		 widget_reconfigure(lh, REACQUIRE);

		 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_FAILURE, off_cookie,
		     ev_data);
	 }

       Example 2 Registration and Callbacks for the DEGRADE Event

       The following example shows how the  ldi_ev_register_callbacks()	 func‐
       tion performs a registration and callback for the degrade event:

	 static int
	 event_register(void)
	 {
		 ldi_handle_t lh;
		 ldi_ev_callback_t callb;
		 ldi_ev_cookie_t dgrd_cookie;

		 if (ldi_ev_get_cookie(lh, LDI_EV_DEGRADE, &dgrd_cookie)
		     == LDI_EV_FAILURE)
			 goto fail;

		 /* no notify callbacks allowed for degrade events */
		 callb.cb_vers = LDI_EV_CB_VERS;
		 callb.cb_notify = NULL; /* NULL, notify cannot be used for
					    DEGRADE */
		 callb.cb_finalize = dgrd_finalize;

		 if (ldi_ev_register_callbacks(lh, dgrd_cookie, &callb, arg, &id)
		     != LDI_EV_SUCCESS)
			 goto fail;
	 }

	 static void
	 event_unregister(ldi_callback_id_t id)
	 {
		 ldi_ev_remove_callbacks(id);
	 }

	 /*
	  * For degrade events. ldi_result will always be LDI_EV_SUCCESS
	  */
	 static void
	 dgrd_finalize(ldi_handle_t lh, ldi_ev_cookie_t off_cookie,
	     int ldi_result, void *arg, void *ev_data)
	 {
		 ASSERT(ldi_result == LDI_EV_SUCCESS);
		 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_DEGRADE) == 0);

		 widget_map(lh, &minor, &spec_type);

		 widget_reconfigure(lh, RELEASE);

		 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_SUCCESS, d
		     grd_cookie, ev_data);
	 }

SEE ALSO
       ldi_ev_finalize(9F),	 ldi_ev_get_cookie(9F),	    ldi_ev_notify(9F),
       ldi_ev_remove_callbacks(9F)

				 Oct 24, 2012	 LDI_EV_REGISTER_CALLBACKS(9F)
[top]

List of man pages available for SmartOS

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net