2 .\" Copyright (c) 2007, Sun Microsystems, Inc., All Rights Reserved
3 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
4 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
5 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
6 .TH LDI_EV_REGISTER_CALLBACKS 9F "Oct 24, 2012"
8 ldi_ev_register_callbacks \- add a notify and/or finalize callback
12 #include <sys/sunldi.h>
14 \fBint\fR \fBldi_ev_register_callbacks\fR(\fIldi_handle_t lh\fR,
15 \fIldi_ev_cookie_t *cookie\fR, \fIldi_ev_callback_t *callb\fR,
16 \fBvoid\fR \fI*arg\fR, \fIldi_callback_id_t *id\fR);
22 Solaris DDI specific (Solaris DDI)
27 \fB\fIldi_handle_t lh\fR\fR
31 A layered handle representing the device for which the event notification was
38 \fB\fIldi_ev_cookie_t *cookie\fR\fR
42 An opaque event cookie for the event type returned by a previous call to
43 \fBldi_ev_get_cookie\fR(9F).
49 \fB\fIldi_ev_callback_t *callb\fR\fR
53 A data structure which currently has the following members:
57 struct ldi_ev_callback {
59 int (*cb_notify)(ldi_handle_t,
60 ldi_ev_cookie_t cookie,
61 void *arg, void *ev_data);
62 void (*cb_finalize)(ldi_handle_t,
63 ldi_ev_cookie_t cookie,
78 Version of callback vector. Must be set to \fBLDI_EV_CB_VERS\fR by the caller.
80 The arguments passed into the callbacks when they are invoked, include:
84 \fB\fBint ldi_result\fR\fR
88 The actual result of the state change operation/event passed to finalize
89 callback: \fBLDI_EV_SUCCESS\fR: The state change succeeded
90 \fBLDI_EV_FAILURE\fR: The state change failed.
96 \fB\fBvoid *ev_data\fR\fR
110 \fB\fBvoid\fR *\fIarg\fR\fR
114 A pointer to opaque caller private data.
120 \fB\fIldi_callback_id_t *id\fR\fR
124 Unique system wide registration id returned by ldi_ev_register_callbacks(9F)
125 upon successful registration.
131 The \fBldi_ev_register_callbacks()\fR interface allows layered drivers to
132 register notify and finalize callbacks for certain events. These events are
133 listed in the \fBldi_ev_get_cookie\fR(9F) man page. The notify callback is
134 invoked only for events that can be blocked, just before the event occurs. The
135 notify event is not called for events serviced by the \fBNDI\fR event service
136 framework since such events are by definition asynchronous. Only the finalize
137 callback is invoked for such events. Layered drivers that have registered
138 notify callbacks for that event have the opportunity of blocking such events.
139 The finalize callback is invoked once the final disposition of the state of a
140 device (specifically a device minor node) is known. The callback is invoked
141 with this result, either \fBLDI_EV_SUCCESS\fR (state change succeeded) or
142 \fBLDI_EV_FAILURE\fR (state change failed). This allows layered driver
143 consumers to finalize any changes they made in response to a previous "notify"
147 For example, a layered driver's notify callback may be invoked in response to a
148 \fBLDI_EV_OFFLINE\fR event. The layered driver may reconfigure itself to stop
149 using the device and permit the change to go forward. Once that happens, the
150 \fBI/O\fR framework attempts to actually take the device offline. This offline
151 attempt can have two possible outcomes: success or failure. In the former case,
152 the finalize callback is invoked with the \fIldi_result\fR argument set to
153 \fBLDI_EV_SUCCESS\fR and the layered driver knows that the device has been
154 taken offline. In the latter case, finalize is invoked with the
155 \fIldi_result\fR set to \fBLDI_EV_FAILURE\fR and the layered driver knows that
156 the state change failed. In this case, it may choose to reconfigure itself to
157 start using the device again.
160 Finalize callbacks can be registered for all events including events that
164 A layered driver can also propagate these events up the software stack by using
165 interfaces offered by the \fBLDI\fR event framework. The layered driver may use
166 \fBldi_ev_notify()\fR to propagate notify events occurring on minors it imports
167 onto minors it exports. Similarly, it may use \fBldi_ev_finalize()\fR to
168 propagate finalize events. Both \fBldi_ev_notify()\fR and
169 \fBldi_ev_finalize()\fR propagate events to device contracts as well as LDI
170 callbacks registered against the exported minor nodes.
173 The \fBLDI\fR event framework has the following guarantees and requirements
174 with respect to these callbacks:
178 The \fBnotify()\fR callback is invoked before an event (represented by the
179 event cookie) occurs on a device (represented by the layered driver handle) and
180 is invoked only for events that can be blocked. If the callback returns
181 \fBLDI_EV_FAILURE\fR, the event is blocked. If the callback returns
182 \fBLDI_EV_SUCCESS\fR, the event is allowed to proceed. If any other value is
183 returned, it is an error. An error message is logged and the event is blocked.
184 An example of an event that can be blocked and for which notify callbacks may
185 be invoked is the offline event \fBLDI_EV_OFFLINE\fR.
190 The finalize callback is invoked for all events (including events that
191 cannot be blocked) after the event has occurred. It is invoked with either
192 \fBLDI_EV_SUCCESS\fR indicating that the event successfully happened or
193 \fBLDI_EV_FAILURE\fR indicating that the event did not occur. The finalize
194 callback returns no values. Good examples of events that cannot be blocked are
195 the degrade event (\fBLDI_EV_DEGRADE\fR) and events serviced by the \fBNDI\fR
196 event service framework.
201 Layered drivers may register one or both of these callbacks (that is, only
202 for a notify event or only for a finalize event or for both) against any
203 \fBLDI\fR handle that they may possess. If a finalize or notify event is not
204 being registered, the corresponding pointer in the \fIldi_ev_callback_t\fR
205 structure must be set to \fBNULL\fR. It is an error to attempt a registration
206 with both callbacks set to \fBNULL\fR.
211 A notify and/or finalize callback is invoked only if the corresponding
212 \fBLDI\fR handle is open. If an \fBLDI\fR handle against which the callbacks
213 are registered is closed, the corresponding finalize and notify callbacks is
214 not invoked as it is assumed that the layered driver is no longer interested in
215 the device. See number 5 below for the exception to this rule.
220 A layered driver that closes it's \fBLDI\fR handle in it's notify routine
221 receives the corresponding finalize callback after the event has occurred.
222 Because the \fBLDI\fR handle has been closed, the finalize callback is invoked
223 with a \fBNULL\fR \fBLDI\fR handle. It is the responsibility of the layered
224 driver to maintain state in it's private "\fIarg\fR" parameter so that it can
225 reopen the device (if desired) in it's finalize callback.
227 One example where this may happen is with the \fBLDI_EV_OFFLINE\fR event. A
228 layered driver's notify callback may be invoked for an offline event. The
229 layered driver may choose to allow this event to proceed. In that case, since
230 it has a layered open of the device, it must close the \fBLDI\fR handle so that
231 the offline event can succeed (an offline of a device does not succeed if there
232 is any open of the device, layered or otherwise). Since the layered driver has
233 closed the \fBLDI\fR handle in the notify routine, it's finalize callback (if
234 any) is invoked with a \fBNULL\fR \fBLDI\fR handle. It is the responsibility of
235 the layered driver to maintain state (such as the device path or \fBdevid\fR)
236 in it's private "\fIarg\fR" parameter, so that in the finalize routine, it can
237 do a layered open of the device if the device offline failed.
239 This is the only exception where the finalize callback is invoked if the
240 \fBLDI\fR handle has been closed. In all other cases if the \fBLDI\fR handle
241 has been closed, no corresponding callbacks is invoked.
246 In order for the offline event to succeed (\fBLDI_EV_OFFLINE\fR), it is
247 imperative that there be no opens (including \fBLDI\fR handles) to the device.
248 If a layered driver's notify callback is invoked for an offline event and the
249 driver intends to allow the offline to proceed, the driver must close the
250 corresponding \fBLDI\fR handle.
255 The notify and finalize callbacks are not automatically unregistered even if
256 the corresponding \fBLDI\fR handle has been closed. It is the responsibility of
257 the layered driver to unregister these callbacks when they are not required. It
258 may do so using the \fBldi_ev_remove_callbacks\fR(9F) interface. The \fBLDI\fR
259 framework may panic if the entity registering the callback (such as a
260 \fBdip\fR, \fBdev_t\fR or \fBmodule\fR) no longer exists on the system and the
261 corresponding callbacks have not been unregistered.
266 The \fBLDI\fR event framework guarantees that if a layered driver receives a
267 notify event, it also receives a finalize event except if the layered consumer
268 itself blocked the event (that is, it returned \fBLDI_EV_FAILURE\fR from it's
269 notify callback. In this case, the layered driver knows that the event has been
270 blocked and therefore does not need the finalize callback.
275 If a layered driver propagates notify events on minors it imports to minors
276 it exports, it must first propagate these events up the software stack via
277 \fBldi_eve_notify()\fR in it's notify callback. It must do so before attempting
278 to check if it blocks the event. This is required, because a layered driver
279 cannot release the device if consumers up the stack are still using the device.
280 If \fBldi_ev_notify()\fR returns \fBLDI_EV_FAILURE\fR, the callback must
281 immediately return \fBLDI_EV_FAILURE\fR from it's notify callback. If
282 \fBldi_ev_notify()\fR returns \fBLDI_EV_SUCCESS\fR, then the state change is
283 permissible as far as consumers higher up in the software stack are concerned.
284 The layered driver must then determine if it can permit the state change. If
285 the state change is to be allowed, the layered driver must return
286 \fBLDI_EV_SUCCESS\fR. If the layered driver determines that the state change
287 should not be permitted, it must invoke \fBldi_ev_finalize()\fR on minors it
288 exports with a result of \fBLDI_EV_FAILURE\fR (to inform consumers up the
289 stack) and then return \fBLDI_EV_FAILURE\fR from it's notify callback.
294 The \fBLDI\fR event framework generates finalize events at the earliest
295 point where a failure is detected. If the failure is detected in the framework
296 (such as in \fBldi_ev_notify()\fR) the framework generates the finalize events.
297 In the event that a failure is first detected in a layered driver (that is, in
298 the notify callback of a layered driver) the layered driver must use
299 \fBldi_ev_finalize()\fR to send finalize events up the software stack . See
300 the examples for code snippets describing this scenario.
305 The finalize callback must first reconfigure itself before attempting to
306 propagate the event up the software stack via \fBldi_ev_finalize\fR(9F). This
307 is so that the minors it exports are available and ready for use before the
308 finalize event is propagated up the software stack.
313 It may so happen that the event propagated up the software stack is not the
314 same as the event for which a layered driver's notify/finalize callback is
315 invoked. For example, a layered driver's callback(s) may be invoked for an
316 offline event, but the driver may choose to only propagate the degraded event
317 to its consumers (since it may have a mirror/copy of the data on the device.)
318 In that case, the layered driver must generate a different event cookie (that
319 is, one corresponding to the degraded event via \fBldi_ev_get_cookie\fR(9F))
320 and use that cookie in its propagation calls (that is, \fBldi_ev_notify\fR(9F)
321 and \fBldi_ev_finalize\fR(9F)).
325 Once the registration of the callback(s) is successful, an opaque
326 \fIldi_callback_id_t\fR structure is returned which may be used to
327 unregister the callback(s) later.
331 The return values for this function are:
335 \fB\fBLDI_EV_SUCCESS\fR\fR
339 Callback(s) added successfully.
345 \fB\fBLDI_EV_FAILURE\fR\fR
349 Failed to add callback(s).
355 This function can be called from user and kernel contexts only.
358 \fBExample 1 \fRRegistration and Callbacks for the OFFLINE Event
361 The following example shows how the \fBldi_ev_register_callbacks()\fR function
362 performs a registration and callback for the offline event:
371 ldi_ev_callback_t callb;
372 ldi_ev_cookie_t off_cookie;
374 if (ldi_ev_get_cookie(lh, LDI_EV_OFFLINE, &off_cookie)
379 callb.cb_vers = LDI_EV_CB_VERS;
380 callb.cb_notify = off_notify;
381 callb.cb_finalize = off_finalize;
383 if (ldi_ev_register_callbacks(lh, off_cookie, &callb, arg, &id)
389 event_unregister(ldi_callback_id_t id)
391 ldi_ev_remove_callbacks(id);
395 off_notify(ldi_handle_t lh, ldi_ev_cookie_t off_cookie, void *arg,
399 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_OFFLINE) == 0);
401 /* Map imported minors to exported minor */
402 widget_map(lh, &minor, &spec_type);
405 * Call ldi_ev_notify() to propagate events to our consumers.
406 * This *must* happen before we check if offline should be blocked
408 if (ldi_ev_notify(dip, minor, spec_type, off_cookie, ev_data)
410 return (LDI_EV_FAILURE);
413 * Next, check if we can allow the offline
415 if (widget_check(lh) == WIDGET_SUCCESS) {
416 widget_save_path(arg, lh);
417 widget_reconfigure(lh, RELEASE);
419 return (LDI_EV_SUCCESS)
423 * We cannot permit the offline. The first layer that detects
424 * failure i.e. us, must generate finalize events for our
427 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_FAILURE, off_cookie,
430 return (LDI_EV_FAILURE);
435 * The finalize callback will only be called if we returned LDI_EV_SUCCESS
436 * in our notify callback. ldi_result passed in may be SUCCESS or FAILURE
439 off_finalize(ldi_handle_t NULL_lh, ldi_ev_cookie_t off_cookie,
440 int ldi_result, void *arg, void *ev_data)
444 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_OFFLINE) == 0);
446 path = widget_get_path(arg);
448 widget_map_by_path(path, &minor, &spec_type);
450 if (ldi_result == LDI_EV_SUCCESS) {
451 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_SUCCESS,
452 off_cookie, ev_data);
456 /* The offline failed. Reopen the device */
457 ldi_open_by_name(path, &lh);
458 widget_reconfigure(lh, REACQUIRE);
460 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_FAILURE, off_cookie,
467 \fBExample 2 \fRRegistration and Callbacks for the DEGRADE Event
470 The following example shows how the \fBldi_ev_register_callbacks()\fR function
471 performs a registration and callback for the degrade event:
480 ldi_ev_callback_t callb;
481 ldi_ev_cookie_t dgrd_cookie;
483 if (ldi_ev_get_cookie(lh, LDI_EV_DEGRADE, &dgrd_cookie)
487 /* no notify callbacks allowed for degrade events */
488 callb.cb_vers = LDI_EV_CB_VERS;
489 callb.cb_notify = NULL; /* NULL, notify cannot be used for
491 callb.cb_finalize = dgrd_finalize;
493 if (ldi_ev_register_callbacks(lh, dgrd_cookie, &callb, arg, &id)
499 event_unregister(ldi_callback_id_t id)
501 ldi_ev_remove_callbacks(id);
505 * For degrade events. ldi_result will always be LDI_EV_SUCCESS
508 dgrd_finalize(ldi_handle_t lh, ldi_ev_cookie_t off_cookie,
509 int ldi_result, void *arg, void *ev_data)
511 ASSERT(ldi_result == LDI_EV_SUCCESS);
512 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_DEGRADE) == 0);
514 widget_map(lh, &minor, &spec_type);
516 widget_reconfigure(lh, RELEASE);
518 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_SUCCESS, d
519 grd_cookie, ev_data);
527 \fBldi_ev_finalize\fR(9F), \fBldi_ev_get_cookie\fR(9F),
528 \fBldi_ev_notify\fR(9F), \fBldi_ev_remove_callbacks\fR(9F)