1ldi_ev_register_callbacks(K9eFr)nel Functions for Drivledris_ev_register_callbacks(9F)
2
3
4
6 ldi_ev_register_callbacks - add a notify and/or finalize callback
7
9 #include <sys/sunldi.h>
10
11 int ldi_ev_get_cookie(ldi_handle_t lh, ldi_ev_cookie_t *cookie,
12 ldi_ev_callback_t *callb, void *arg, ldi_ev_callback_id_t *id);
13
14
16 Solaris DDI specific (Solaris DDI)
17
19 ldi_handle_t lh
20
21 A layered handle representing the device for which the event noti‐
22 fication was requested.
23
24
25 ldi_ev_cookie_t *cookie
26
27 An opaque event cookie for the event type returned by a previous
28 call to ldi_ev_get_cookie(9F).
29
30
31 ldi_ev_callback_t *callb
32
33 A data structure which currently has the following members:
34
35 struct ldi_ev_callback {
36 uint_t cb_vers;
37 int (*cb_notify)(ldi_handle_t,
38 ldi_ev_cookie_t cookie,
39 void *arg, void *ev_data);
40 void (*cb_finalize)(ldi_handle_t,
41 ldi_ev_cookie_t cookie,
42 int ldi_result,
43 void *arg,
44 void *ev_data);
45 } ldi_ev_callback_t;
46
47 where
48
49 cb_vers Version of callback vector. Must be set to
50 LDI_EV_CB_VERS by the caller.
51
52 The arguments passed into the callbacks when they are
53 invoked, include:
54
55 int ldi_result
56
57 The actual result of the state change opera‐
58 tion/event passed to finalize callback: LDI_EV_SUC‐
59 CESS: The state change succeeded LDI_EV_FAILURE: The
60 state change failed.
61
62
63 void *ev_data
64
65 Event specific data.
66
67
68
69
70 void *arg
71
72 A pointer to opaque caller private data.
73
74
75 ldi_ev_callback_id_t *id
76
77 Unique system wide registration id returned by ldi_ev_regis‐
78 ter_callbacks(9F) upon successful registration.
79
80
82 The ldi_ev_register_callbacks() interface allows layered drivers to
83 register notify and finalize callbacks for certain events. These events
84 are listed in the ldi_ev_get_cookie(9F) man page. The notify callback
85 is invoked only for events that can be blocked, just before the event
86 occurs. The notify event is not called for events serviced by the NDI
87 event service framework since such events are by definition asynchro‐
88 nous. Only the finalize callback is invoked for such events. Layered
89 drivers that have registered notify callbacks for that event have the
90 opportunity of blocking such events. The finalize callback is invoked
91 once the final disposition of the state of a device (specifically a
92 device minor node) is known. The callback is invoked with this result,
93 either LDI_EV_SUCCESS (state change succeeded) or LDI_EV_FAILURE (state
94 change failed). This allows layered driver consumers to finalize any
95 changes they made in response to a previous "notify" callback.
96
97
98 For example, a layered driver's notify callback may be invoked in
99 response to a LDI_EV_OFFLINE event. The layered driver may reconfigure
100 itself to stop using the device and permit the change to go forward.
101 Once that happens, the I/O framework attempts to actually take the
102 device offline. This offline attempt can have two possible outcomes:
103 success or failure. In the former case, the finalize callback is
104 invoked with the ldi_result argument set to LDI_EV_SUCCESS and the lay‐
105 ered driver knows that the device has been taken offline. In the latter
106 case, finalize is invoked with the ldi_result set to LDI_EV_FAILURE and
107 the layered driver knows that the state change failed. In this case, it
108 may choose to reconfigure itself to start using the device again.
109
110
111 Finalize callbacks can be registered for all events including events
112 that cannot be blocked.
113
114
115 A layered driver can also propagate these events up the software stack
116 by using interfaces offered by the LDI event framework. The layered
117 driver may use ldi_ev_notify() to propagate notify events occurring on
118 minors it imports onto minors it exports. Similarly, it may use
119 ldi_ev_finalize() to propagate finalize events. Both ldi_ev_notify()
120 and ldi_ev_finalize() propagate events to device contracts as well as
121 LDI callbacks registered against the exported minor nodes.
122
123
124 The LDI event framework has the following guarantees and requirements
125 with respect to these callbacks:
126
127 1. The notify() callback is invoked before an event (repre‐
128 sented by the event cookie) occurs on a device (represented
129 by the layered driver handle) and is invoked only for events
130 that can be blocked. If the callback returns LDI_EV_FAILURE,
131 the event is blocked. If the callback returns LDI_EV_SUC‐
132 CESS, the event is allowed to proceed. If any other value is
133 returned, it is an error. An error message is logged and the
134 event is blocked. An example of an event that can be blocked
135 and for which notify callbacks may be invoked is the offline
136 event LDI_EV_OFFLINE.
137
138 2. The finalize callback is invoked for all events (including
139 events that cannot be blocked) after the event has occurred.
140 It is invoked with either LDI_EV_SUCCESS indicating that the
141 event successfully happened or LDI_EV_FAILURE indicating
142 that the event did not occur. The finalize callback returns
143 no values. Good examples of events that cannot be blocked
144 are the degrade event (LDI_EV_DEGRADE) and events serviced
145 by the NDI event service framework.
146
147 3. Layered drivers may register one or both of these callbacks
148 (that is, only for a notify event or only for a finalize
149 event or for both) against any LDI handle that they may pos‐
150 sess. If a finalize or notify event is not being registered,
151 the corresponding pointer in the ldi_ev_callback_t structure
152 must be set to NULL. It is an error to attempt a registra‐
153 tion with both callbacks set to NULL.
154
155 4. A notify and/or finalize callback is invoked only if the
156 corresponding LDI handle is open. If an LDI handle against
157 which the callbacks are registered is closed, the corre‐
158 sponding finalize and notify callbacks is not invoked as it
159 is assumed that the layered driver is no longer interested
160 in the device. See number 5 below for the exception to this
161 rule.
162
163 5. A layered driver that closes it's LDI handle in it's notify
164 routine receives the corresponding finalize callback after
165 the event has occurred. Because the LDI handle has been
166 closed, the finalize callback is invoked with a NULL LDI
167 handle. It is the responsibility of the layered driver to
168 maintain state in it's private "arg" parameter so that it
169 can reopen the device (if desired) in it's finalize call‐
170 back.
171
172 One example where this may happen is with the LDI_EV_OFFLINE
173 event. A layered driver's notify callback may be invoked for
174 an offline event. The layered driver may choose to allow
175 this event to proceed. In that case, since it has a layered
176 open of the device, it must close the LDI handle so that the
177 offline event can succeed (an offline of a device does not
178 succeed if there is any open of the device, layered or oth‐
179 erwise). Since the layered driver has closed the LDI handle
180 in the notify routine, it's finalize callback (if any) is
181 invoked with a NULL LDI handle. It is the responsibility of
182 the layered driver to maintain state (such as the device
183 path or devid) in it's private "arg" parameter, so that in
184 the finalize routine, it can do a layered open of the device
185 if the device offline failed.
186
187 This is the only exception where the finalize callback is
188 invoked if the LDI handle has been closed. In all other
189 cases if the LDI handle has been closed, no corresponding
190 callbacks is invoked.
191
192 6. In order for the offline event to succeed (LDI_EV_OFFLINE),
193 it is imperative that there be no opens (including LDI han‐
194 dles) to the device. If a layered driver's notify callback
195 is invoked for an offline event and the driver intends to
196 allow the offline to proceed, the driver must close the cor‐
197 responding LDI handle.
198
199 7. The notify and finalize callbacks are not automatically
200 unregistered even if the corresponding LDI handle has been
201 closed. It is the responsibility of the layered driver to
202 unregister these callbacks when they are not required. It
203 may do so using the ldi_ev_remove_callbacks(9F) interface.
204 The LDI framework may panic if the entity registering the
205 callback (such as a dip, dev_t or module) no longer exists
206 on the system and the corresponding callbacks have not been
207 unregistered.
208
209 8. The LDI event framework guarantees that if a layered driver
210 receives a notify event, it also receives a finalize event
211 except if the layered consumer itself blocked the event
212 (that is, it returned LDI_EV_FAILURE from it's notify call‐
213 back. In this case, the layered driver knows that the event
214 has been blocked and therefore does not need the finalize
215 callback.
216
217 9. If a layered driver propagates notify events on minors it
218 imports to minors it exports, it must first propagate these
219 events up the software stack via ldi_eve_notify() in it's
220 notify callback. It must do so before attempting to check if
221 it blocks the event. This is required, because a layered
222 driver cannot release the device if consumers up the stack
223 are still using the device. If ldi_ev_notify() returns
224 LDI_EV_FAILURE, the callback must immediately return
225 LDI_EV_FAILURE from it's notify callback. If ldi_ev_notify()
226 returns LDI_EV_SUCCESS, then the state change is permissible
227 as far as consumers higher up in the software stack are con‐
228 cerned. The layered driver must then determine if it can
229 permit the state change. If the state change is to be
230 allowed, the layered driver must return LDI_EV_SUCCESS. If
231 the layered driver determines that the state change should
232 not be permitted, it must invoke ldi_ev_finalize() on
233 minors it exports with a result of LDI_EV_FAILURE (to inform
234 consumers up the stack) and then return LDI_EV_FAILURE from
235 it's notify callback.
236
237 10. The LDI event framework generates finalize events at the
238 earliest point where a failure is detected. If the failure
239 is detected in the framework (such as in ldi_ev_notify())
240 the framework generates the finalize events. In the event
241 that a failure is first detected in a layered driver (that
242 is, in the notify callback of a layered driver) the layered
243 driver must use ldi_ev_finalize() to send finalize events
244 up the software stack . See the examples for code snippets
245 describing this scenario.
246
247 11. The finalize callback must first reconfigure itself before
248 attempting to propagate the event up the software stack via
249 ldi_ev_finalize(9F). This is so that the minors it exports
250 are available and ready for use before the finalize event is
251 propagated up the software stack.
252
253 12. It may so happen that the event propagated up the software
254 stack is not the same as the event for which a layered
255 driver's notify/finalize callback is invoked. For example, a
256 layered driver's callback(s) may be invoked for an offline
257 event, but the driver may choose to only propagate the
258 degraded event to its consumers (since it may have a mir‐
259 ror/copy of the data on the device.) In that case, the lay‐
260 ered driver must generate a different event cookie (that is,
261 one corresponding to the degraded event via
262 ldi_ev_get_cookie(9F)) and use that cookie in its propaga‐
263 tion calls (that is, ldi_ev_notify(9F) and ldi_ev_final‐
264 ize(9F)).
265
266
267 Once the registration of the callback(s) is successful, an opaque
268 ldi_ev_callback_id_t structure is returned which may be used to unreg‐
269 ister the callback(s) later.
270
272 The return values for this function are:
273
274 LDI_EV_SUCCESS
275
276 Callback(s) added successfully.
277
278
279 LDI_EV_FAILURE
280
281 Failed to add callback(s).
282
283
285 This function can be called from user and kernel contexts only.
286
288 Example 1 Registration and Callbacks for the OFFLINE Event
289
290
291 The following example shows how the ldi_ev_register_callbacks() func‐
292 tion performs a registration and callback for the offline event:
293
294
295 static int
296 event_register(void)
297 {
298 ldi_handle_t lh;
299 ldi_ev_callback_t callb;
300 ldi_ev_cookie_t off_cookie;
301
302 if (ldi_ev_get_cookie(lh, LDI_EV_OFFLINE, &off_cookie)
303 == LDI_EV_FAILURE)
304 goto fail;
305
306
307 callb.cb_vers = LDI_EV_CB_VERS;
308 callb.cb_notify = off_notify;
309 callb.cb_finalize = off_finalize;
310
311 if (ldi_ev_register_callbacks(lh, off_cookie, &callb, arg, &id)
312 != LDI_EV_SUCCESS)
313 goto fail;
314 }
315
316 static void
317 event_unregister(ldi_ev_callback_id_t id)
318 {
319 ldi_ev_remove_callbacks(id);
320 }
321
322 static int
323 off_notify(ldi_handle_t lh, ldi_ev_cookie_t off_cookie, void *arg,
324 void *ev_data)
325 {
326
327 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_OFFLINE) == 0);
328
329 /* Map imported minors to exported minor */
330 widget_map(lh, &minor, &spec_type);
331
332 /*
333 * Call ldi_ev_notify() to propagate events to our consumers.
334 * This *must* happen before we check if offline should be blocked
335 */
336 if (ldi_ev_notify(dip, minor, spec_type, off_cookie, ev_data)
337 != LDI_EV_SUCCESS)
338 return (LDI_EV_FAILURE);
339
340 /*
341 * Next, check if we can allow the offline
342 */
343 if (widget_check(lh) == WIDGET_SUCCESS) {
344 widget_save_path(arg, lh);
345 widget_reconfigure(lh, RELEASE);
346 ldi_close(lh);
347 return (LDI_EV_SUCCESS)
348 }
349
350 /*
351 * We cannot permit the offline. The first layer that detects
352 * failure i.e. us, must generate finalize events for our
353 consumers
354 */
355 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_FAILURE, off_cookie,
356 ev_data);
357
358 return (LDI_EV_FAILURE);
359 }
360
361 /*
362 /*
363 * The finalize callback will only be called if we returned LDI_EV_SUCCESS
364 * in our notify callback. ldi_result passed in may be SUCCESS or FAILURE
365 */
366 static void
367 off_finalize(ldi_handle_t NULL_lh, ldi_ev_cookie_t off_cookie,
368 int ldi_result, void *arg, void *ev_data)
369 {
370 ldi_handle_t lh;
371
372 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_OFFLINE) == 0);
373
374 path = widget_get_path(arg);
375
376 widget_map_by_path(path, &minor, &spec_type);
377
378 if (ldi_result == LDI_EV_SUCCESS) {
379 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_SUCCESS,
380 off_cookie, ev_data);
381 return;
382 }
383
384 /* The offline failed. Reopen the device */
385 ldi_open_by_name(path, &lh);
386 widget_reconfigure(lh, REACQUIRE);
387
388 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_FAILURE, off_cookie,
389 ev_data);
390 }
391
392
393 Example 2 Registration and Callbacks for the DEGRADE Event
394
395
396 The following example shows how the ldi_ev_register_callbacks() func‐
397 tion performs a registration and callback for the degrade event:
398
399
400 static int
401 event_register(void)
402 {
403 ldi_handle_t lh;
404 ldi_ev_callback_t callb;
405 ldi_ev_cookie_t dgrd_cookie;
406
407 if (ldi_ev_get_cookie(lh, LDI_EV_DEGRADE, &dgrd_cookie)
408 == LDI_EV_FAILURE)
409 goto fail;
410
411 /* no notify callbacks allowed for degrade events */
412 callb.cb_vers = LDI_EV_CB_VERS;
413 callb.cb_notify = NULL; /* NULL, notify cannot be used for
414 DEGRADE */
415 callb.cb_finalize = dgrd_finalize;
416
417 if (ldi_ev_register_callbacks(lh, dgrd_cookie, &callb, arg, &id)
418 != LDI_EV_SUCCESS)
419 goto fail;
420 }
421
422 static void
423 event_unregister(ldi_ev_callback_id_t id)
424 {
425 ldi_ev_remove_callbacks(id);
426 }
427
428 /*
429 * For degrade events. ldi_result will always be LDI_EV_SUCCESS
430 */
431 static void
432 dgrd_finalize(ldi_handle_t lh, ldi_ev_cookie_t off_cookie,
433 int ldi_result, void *arg, void *ev_data)
434 {
435 ASSERT(ldi_result == LDI_EV_SUCCESS);
436 ASSERT(strcmp(ldi_ev_get_type(off_cookie), LDI_EV_DEGRADE) == 0);
437
438 widget_map(lh, &minor, &spec_type);
439
440 widget_reconfigure(lh, RELEASE);
441
442 ldi_ev_finalize(dip, minor, spec_type, LDI_EV_SUCCESS, d
443 grd_cookie, ev_data);
444 }
445
446
448 ldi_ev_finalize(9F), ldi_ev_get_cookie(9F), ldi_ev_notify(9F),
449 ldi_ev_remove_callbacks(9F)
450
451
452
453SunOS 5.11 21 Aug 2007 ldi_ev_register_callbacks(9F)