1ldi_ev_register_callbacks(K9eFr)nel Functions for Drivledris_ev_register_callbacks(9F)
2
3
4

NAME

6       ldi_ev_register_callbacks - add a notify and/or finalize callback
7

SYNOPSIS

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

INTERFACE LEVEL

16       Solaris DDI specific (Solaris DDI)
17

PARAMETERS

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

DESCRIPTION

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

RETURN VALUES

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

CONTEXT

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

EXAMPLES

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

SEE ALSO

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)
Impressum