Kernel Functions for Drivers ldievregistercallbacks(9F)
NAME
ldievregistercallbacks - add a notify and/or finalize
callback
SYNOPSIS
#include
int ldievgetcookie(ldihandlet lh, ldievcookiet *cookie,
ldievcallbackt *callb, void *arg, ldievcallbackidt *id);
INTERFACE LEVEL
Solaris DI specific (Solaris DI)
PARAMETERS
ldihandlet lh
A layered handle representing the device for which the
event notification was requested.
ldievcookiet *cookie
An opaque event cookie for the event type returned by a
previous call to ldievgetcookie(9F).
ldievcallbackt *callb
A data structure which currently has the following
members:
struct ldievcallback {
uintt cbvers;
int (*cbnotify)(ldihandlet,
ldievcookiet cookie,
void *arg, void *evdata);
void (*cbfinalize)(ldihandlet,
ldievcookiet cookie,
int ldiresult,
void *arg,
void *evdata);
} ldievcallbackt;
where
cbvers Version of callback vector. Must be set to
LDIEVCBVERS by the caller.
The arguments passed into the callbacks when
they are invoked, include:
SunOS 5.11 Last change: 21 Aug 2007 1
Kernel Functions for Drivers ldievregistercallbacks(9F)
int ldiresult
The actual result of the state change
operation/event passed to finalize call-
back: LDIEVSUCES: The state change
succeeded LDIEVFAILURE: The state
change failed.
void *evdata
Event specific data.
void *arg
A pointer to opaque caller private data.
ldievcallbackidt *id
Unique system wide registration id returned by
ldievregistercallbacks(9F) upon successful registra-
tion.
DESCRIPTION
The ldievregistercallbacks() interface allows layered
drivers to register notify and finalize callbacks for cer-
tain events. These events are listed in the
ldievgetcookie(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 ser-
viced by the NDI event service framework since such events
are by definition asynchronous. Only the finalize callback
is invoked for such events. Layered drivers that have
registered notify callbacks for that event have the oppor-
tunity 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 LDIEVSUCES (state
change succeeded) or LDIEVFAILURE (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 LDIEVOFLINE 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
SunOS 5.11 Last change: 21 Aug 2007 2
Kernel Functions for Drivers ldievregistercallbacks(9F)
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 ldiresult argument set to LDIEVSUCES
and the layered driver knows that the device has been taken
offline. In the latter case, finalize is invoked with the
ldiresult set to LDIEVFAILURE 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 includ-
ing 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 ldievnotify() to
propagate notify events occurring on minors it imports onto
minors it exports. Similarly, it may use ldievfinalize()
to propagate finalize events. Both ldievnotify() and
ldievfinalize() 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
(represented by the event cookie) occurs on a dev-
ice (represented by the layered driver handle) and
is invoked only for events that can be blocked. If
the callback returns LDIEVFAILURE, the event is
blocked. If the callback returns LDIEVSUCES,
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
LDIEVOFLINE.
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
LDIEVSUCES indicating that the event success-
fully happened or LDIEVFAILURE 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
(LDIEVDEGRADE) and events serviced by the NDI
SunOS 5.11 Last change: 21 Aug 2007 3
Kernel Functions for Drivers ldievregistercallbacks(9F)
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 possess. If a finalize or
notify event is not being registered, the
corresponding pointer in the ldievcallbackt
structure must be set to NUL. It is an error to
attempt a registration with both callbacks set to
NUL.
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 corresponding finalize and notify
callbacks is not invoked as it is assumed that the
layered driver is no longer interested in the dev-
ice. 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 final-
ize callback is invoked with a NUL 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 callback.
One example where this may happen is with the
LDIEVOFLINE 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 dev-
ice does not succeed if there is any open of the
device, layered or otherwise). Since the layered
driver has closed the LDI handle in the notify rou-
tine, it's finalize callback (if any) is invoked
with a NUL 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" parame-
ter, 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 call-
back is invoked if the LDI handle has been closed.
In all other cases if the LDI handle has been
SunOS 5.11 Last change: 21 Aug 2007 4
Kernel Functions for Drivers ldievregistercallbacks(9F)
closed, no corresponding callbacks is invoked.
6. In order for the offline event to succeed
(LDIEVOFLINE), it is imperative that there be no
opens (including LDI handles) 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
corresponding LDI handle.
7. The notify and finalize callbacks are not automati-
cally 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
ldievremovecallbacks(9F) interface. The LDI
framework may panic if the entity registering the
callback (such as a dip, devt or module) no longer
exists on the system and the corresponding call-
backs have not been unregistered.
8. The LDI event framework guarantees that if a lay-
ered driver receives a notify event, it also
receives a finalize event except if the layered
consumer itself blocked the event (that is, it
returned LDIEVFAILURE from it's notify callback.
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 ldievenotify() 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
ldievnotify() returns LDIEVFAILURE, the call-
back must immediately return LDIEVFAILURE from
it's notify callback. If ldievnotify() returns
LDIEVSUCES, then the state change is permissi-
ble as far as consumers higher up in the software
stack are concerned. 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 LDIEVSUCES. If the layered driver
determines that the state change should not be per-
mitted, it must invoke ldievfinalize() on minors
it exports with a result of LDIEVFAILURE (to
inform consumers up the stack) and then return
LDIEVFAILURE from it's notify callback.
SunOS 5.11 Last change: 21 Aug 2007 5
Kernel Functions for Drivers ldievregistercallbacks(9F)
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 ldievnotify()) 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 ldievfinalize() 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 ldievfinalize(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 mirror/copy of the data on the device.) In that
case, the layered driver must generate a different
event cookie (that is, one corresponding to the
degraded event via ldievgetcookie(9F)) and use
that cookie in its propagation calls (that is,
ldievnotify(9F) and ldievfinalize(9F)).
Once the registration of the callback(s) is successful, an
opaque ldievcallbackidt structure is returned which may
be used to unregister the callback(s) later.
RETURN VALUES
The return values for this function are:
LDIEVSUCES
Callback(s) added successfully.
LDIEVFAILURE
Failed to add callback(s).
CONTEXT
SunOS 5.11 Last change: 21 Aug 2007 6
Kernel Functions for Drivers ldievregistercallbacks(9F)
This function can be called from user and kernel contexts
only.
EXAMPLES
Example 1 Registration and Callbacks for the OFLINE Event
The following example shows how the
ldievregistercallbacks() function performs a registration
and callback for the offline event:
static int
eventregister(void)
{
ldihandlet lh;
ldievcallbackt callb;
ldievcookiet offcookie;
if (ldievgetcookie(lh, LDIEVOFLINE, &offcookie)
== LDIEVFAILURE)
goto fail;
callb.cbvers = LDIEVCBVERS;
callb.cbnotify = offnotify;
callb.cbfinalize = offfinalize;
if (ldievregistercallbacks(lh, offcookie, &callb, arg, &id)
!= LDIEVSUCES)
goto fail;
}
static void
eventunregister(ldievcallbackidt id)
{
ldievremovecallbacks(id);
}
static int
offnotify(ldihandlet lh, ldievcookiet offcookie, void *arg,
void *evdata)
{
ASERT(strcmp(ldievgettype(offcookie), LDIEVOFLINE) == 0);
/* Map imported minors to exported minor */
widgetmap(lh, &minor, &spectype);
/*
* Call ldievnotify() to propagate events to our consumers.
* This *must* happen before we check if offline should be blocked
SunOS 5.11 Last change: 21 Aug 2007 7
Kernel Functions for Drivers ldievregistercallbacks(9F)
*/
if (ldievnotify(dip, minor, spectype, offcookie, evdata)
!= LDIEVSUCES)
return (LDIEVFAILURE);
/*
* Next, check if we can allow the offline
*/
if (widgetcheck(lh) == WIDGETSUCES) {
widgetsavepath(arg, lh);
widgetreconfigure(lh, RELEASE);
ldiclose(lh);
return (LDIEVSUCES)
}
/*
* We cannot permit the offline. The first layer that detects
* failure i.e. us, must generate finalize events for our
consumers
*/
ldievfinalize(dip, minor, spectype, LDIEVFAILURE, offcookie,
evdata);
return (LDIEVFAILURE);
}
/*
/*
* The finalize callback will only be called if we returned LDIEVSUCES
* in our notify callback. ldiresult passed in may be SUCES or FAILURE
*/
static void
offfinalize(ldihandlet NULlh, ldievcookiet offcookie,
int ldiresult, void *arg, void *evdata)
{
ldihandlet lh;
ASERT(strcmp(ldievgettype(offcookie), LDIEVOFLINE) == 0);
path = widgetgetpath(arg);
widgetmapbypath(path, &minor, &spectype);
if (ldiresult == LDIEVSUCES) {
ldievfinalize(dip, minor, spectype, LDIEVSUCES,
offcookie, evdata);
return;
}
/* The offline failed. Reopen the device */
ldiopenbyname(path, &lh);
widgetreconfigure(lh, REACQUIRE);
SunOS 5.11 Last change: 21 Aug 2007 8
Kernel Functions for Drivers ldievregistercallbacks(9F)
ldievfinalize(dip, minor, spectype, LDIEVFAILURE, offcookie,
evdata);
}
Example 2 Registration and Callbacks for the DEGRADE Event
The following example shows how the
ldievregistercallbacks() function performs a registration
and callback for the degrade event:
static int
eventregister(void)
{
ldihandlet lh;
ldievcallbackt callb;
ldievcookiet dgrdcookie;
if (ldievgetcookie(lh, LDIEVDEGRADE, &dgrdcookie)
== LDIEVFAILURE)
goto fail;
/* no notify callbacks allowed for degrade events */
callb.cbvers = LDIEVCBVERS;
callb.cbnotify = NUL; /* NUL, notify cannot be used for
DEGRADE */
callb.cbfinalize = dgrdfinalize;
if (ldievregistercallbacks(lh, dgrdcookie, &callb, arg, &id)
!= LDIEVSUCES)
goto fail;
}
static void
eventunregister(ldievcallbackidt id)
{
ldievremovecallbacks(id);
}
/*
* For degrade events. ldiresult will always be LDIEVSUCES
*/
static void
dgrdfinalize(ldihandlet lh, ldievcookiet offcookie,
int ldiresult, void *arg, void *evdata)
{
ASERT(ldiresult == LDIEVSUCES);
ASERT(strcmp(ldievgettype(offcookie), LDIEVDEGRADE) == 0);
widgetmap(lh, &minor, &spectype);
SunOS 5.11 Last change: 21 Aug 2007 9
Kernel Functions for Drivers ldievregistercallbacks(9F)
widgetreconfigure(lh, RELEASE);
ldievfinalize(dip, minor, spectype, LDIEVSUCES, d
grdcookie, evdata);
}
SEE ALSO
ldievfinalize(9F), ldievgetcookie(9F),
ldievnotify(9F), ldievremovecallbacks(9F)
SunOS 5.11 Last change: 21 Aug 2007 10
|