1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2022 Garrett D'Amore
25 * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
26 * Copyright 2023 MNX Cloud, Inc.
27 * Copyright 2026 Oxide Computer Company
28 */
29
30 #include <sys/note.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/buf.h>
35 #include <sys/uio.h>
36 #include <sys/cred.h>
37 #include <sys/poll.h>
38 #include <sys/mman.h>
39 #include <sys/kmem.h>
40 #include <sys/model.h>
41 #include <sys/file.h>
42 #include <sys/proc.h>
43 #include <sys/open.h>
44 #include <sys/user.h>
45 #include <sys/t_lock.h>
46 #include <sys/vm.h>
47 #include <sys/stat.h>
48 #include <vm/hat.h>
49 #include <vm/seg.h>
50 #include <vm/seg_vn.h>
51 #include <vm/seg_dev.h>
52 #include <vm/as.h>
53 #include <sys/cmn_err.h>
54 #include <sys/cpuvar.h>
55 #include <sys/debug.h>
56 #include <sys/autoconf.h>
57 #include <sys/sunddi.h>
58 #include <sys/esunddi.h>
59 #include <sys/sunndi.h>
60 #include <sys/kstat.h>
61 #include <sys/conf.h>
62 #include <sys/ddi_impldefs.h> /* include implementation structure defs */
63 #include <sys/ndi_impldefs.h> /* include prototypes */
64 #include <sys/ddi_periodic.h>
65 #include <sys/hwconf.h>
66 #include <sys/pathname.h>
67 #include <sys/modctl.h>
68 #include <sys/epm.h>
69 #include <sys/devctl.h>
70 #include <sys/callb.h>
71 #include <sys/cladm.h>
72 #include <sys/sysevent.h>
73 #include <sys/dacf_impl.h>
74 #include <sys/ddidevmap.h>
75 #include <sys/bootconf.h>
76 #include <sys/disp.h>
77 #include <sys/atomic.h>
78 #include <sys/promif.h>
79 #include <sys/instance.h>
80 #include <sys/sysevent/eventdefs.h>
81 #include <sys/task.h>
82 #include <sys/project.h>
83 #include <sys/taskq.h>
84 #include <sys/devpolicy.h>
85 #include <sys/ctype.h>
86 #include <net/if.h>
87 #include <sys/rctl.h>
88 #include <sys/zone.h>
89 #include <sys/clock_impl.h>
90 #include <sys/ddi.h>
91 #include <sys/modhash.h>
92 #include <sys/sunldi_impl.h>
93 #include <sys/fs/dv_node.h>
94 #include <sys/fs/snode.h>
95
96 extern pri_t minclsyspri;
97
98 extern rctl_hndl_t rc_project_locked_mem;
99 extern rctl_hndl_t rc_zone_locked_mem;
100
101 #ifdef DEBUG
102 static int sunddi_debug = 0;
103 #endif /* DEBUG */
104
105 /* ddi_umem_unlock miscellaneous */
106
107 static void i_ddi_umem_unlock_thread_start(void);
108
109 static kmutex_t ddi_umem_unlock_mutex; /* unlock list mutex */
110 static kcondvar_t ddi_umem_unlock_cv; /* unlock list block/unblock */
111 static kthread_t *ddi_umem_unlock_thread;
112 /*
113 * The ddi_umem_unlock FIFO list. NULL head pointer indicates empty list.
114 */
115 static struct ddi_umem_cookie *ddi_umem_unlock_head = NULL;
116 static struct ddi_umem_cookie *ddi_umem_unlock_tail = NULL;
117
118 /*
119 * DDI(Sun) Function and flag definitions:
120 */
121
122 #if defined(__x86)
123 /*
124 * Used to indicate which entries were chosen from a range.
125 */
126 char *chosen_reg = "chosen-reg";
127 #endif
128
129 /*
130 * Function used to ring system console bell
131 */
132 void (*ddi_console_bell_func)(clock_t duration);
133
134 /*
135 * Creating register mappings and handling interrupts:
136 */
137
138 /*
139 * Generic ddi_map: Call parent to fulfill request...
140 */
141
142 int
ddi_map(dev_info_t * dp,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * addrp)143 ddi_map(dev_info_t *dp, ddi_map_req_t *mp, off_t offset,
144 off_t len, caddr_t *addrp)
145 {
146 dev_info_t *pdip;
147
148 ASSERT(dp);
149 pdip = (dev_info_t *)DEVI(dp)->devi_parent;
150 return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip,
151 dp, mp, offset, len, addrp));
152 }
153
154 /*
155 * ddi_apply_range: (Called by nexi only.)
156 * Apply ranges in parent node dp, to child regspec rp...
157 */
158
159 int
ddi_apply_range(dev_info_t * dp,dev_info_t * rdip,struct regspec * rp)160 ddi_apply_range(dev_info_t *dp, dev_info_t *rdip, struct regspec *rp)
161 {
162 return (i_ddi_apply_range(dp, rdip, rp));
163 }
164
165 int
ddi_map_regs(dev_info_t * dip,uint_t rnumber,caddr_t * kaddrp,off_t offset,off_t len)166 ddi_map_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
167 off_t len)
168 {
169 ddi_map_req_t mr;
170 #if defined(__x86)
171 struct {
172 int bus;
173 int addr;
174 int size;
175 } reg, *reglist;
176 uint_t length;
177 int rc;
178
179 /*
180 * get the 'registers' or the 'reg' property.
181 * We look up the reg property as an array of
182 * int's.
183 */
184 rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
185 DDI_PROP_DONTPASS, "registers", (int **)®list, &length);
186 if (rc != DDI_PROP_SUCCESS)
187 rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
188 DDI_PROP_DONTPASS, "reg", (int **)®list, &length);
189 if (rc == DDI_PROP_SUCCESS) {
190 /*
191 * point to the required entry.
192 */
193 reg = reglist[rnumber];
194 reg.addr += offset;
195 if (len != 0)
196 reg.size = len;
197 /*
198 * make a new property containing ONLY the required tuple.
199 */
200 if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
201 chosen_reg, (int *)®, (sizeof (reg)/sizeof (int)))
202 != DDI_PROP_SUCCESS) {
203 cmn_err(CE_WARN, "%s%d: cannot create '%s' "
204 "property", DEVI(dip)->devi_name,
205 DEVI(dip)->devi_instance, chosen_reg);
206 }
207 /*
208 * free the memory allocated by
209 * ddi_prop_lookup_int_array ().
210 */
211 ddi_prop_free((void *)reglist);
212 }
213 #endif
214 mr.map_op = DDI_MO_MAP_LOCKED;
215 mr.map_type = DDI_MT_RNUMBER;
216 mr.map_obj.rnumber = rnumber;
217 mr.map_prot = PROT_READ | PROT_WRITE;
218 mr.map_flags = DDI_MF_KERNEL_MAPPING;
219 mr.map_handlep = NULL;
220 mr.map_vers = DDI_MAP_VERSION;
221
222 /*
223 * Call my parent to map in my regs.
224 */
225
226 return (ddi_map(dip, &mr, offset, len, kaddrp));
227 }
228
229 void
ddi_unmap_regs(dev_info_t * dip,uint_t rnumber,caddr_t * kaddrp,off_t offset,off_t len)230 ddi_unmap_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
231 off_t len)
232 {
233 ddi_map_req_t mr;
234
235 mr.map_op = DDI_MO_UNMAP;
236 mr.map_type = DDI_MT_RNUMBER;
237 mr.map_flags = DDI_MF_KERNEL_MAPPING;
238 mr.map_prot = PROT_READ | PROT_WRITE; /* who cares? */
239 mr.map_obj.rnumber = rnumber;
240 mr.map_handlep = NULL;
241 mr.map_vers = DDI_MAP_VERSION;
242
243 /*
244 * Call my parent to unmap my regs.
245 */
246
247 (void) ddi_map(dip, &mr, offset, len, kaddrp);
248 *kaddrp = (caddr_t)0;
249 #if defined(__x86)
250 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, chosen_reg);
251 #endif
252 }
253
254 int
ddi_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)255 ddi_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
256 off_t offset, off_t len, caddr_t *vaddrp)
257 {
258 return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
259 }
260
261 /*
262 * nullbusmap: The/DDI default bus_map entry point for nexi
263 * not conforming to the reg/range paradigm (i.e. scsi, etc.)
264 * with no HAT/MMU layer to be programmed at this level.
265 *
266 * If the call is to map by rnumber, return an error,
267 * otherwise pass anything else up the tree to my parent.
268 */
269 int
nullbusmap(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)270 nullbusmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
271 off_t offset, off_t len, caddr_t *vaddrp)
272 {
273 _NOTE(ARGUNUSED(rdip))
274 if (mp->map_type == DDI_MT_RNUMBER)
275 return (DDI_ME_UNSUPPORTED);
276
277 return (ddi_map(dip, mp, offset, len, vaddrp));
278 }
279
280 /*
281 * ddi_rnumber_to_regspec: Not for use by leaf drivers.
282 * Only for use by nexi using the reg/range paradigm.
283 */
284 struct regspec *
ddi_rnumber_to_regspec(dev_info_t * dip,int rnumber)285 ddi_rnumber_to_regspec(dev_info_t *dip, int rnumber)
286 {
287 return (i_ddi_rnumber_to_regspec(dip, rnumber));
288 }
289
290
291 /*
292 * Note that we allow the dip to be nil because we may be called
293 * prior even to the instantiation of the devinfo tree itself - all
294 * regular leaf and nexus drivers should always use a non-nil dip!
295 *
296 * We treat peek in a somewhat cavalier fashion .. assuming that we'll
297 * simply get a synchronous fault as soon as we touch a missing address.
298 *
299 * Poke is rather more carefully handled because we might poke to a write
300 * buffer, "succeed", then only find some time later that we got an
301 * asynchronous fault that indicated that the address we were writing to
302 * was not really backed by hardware.
303 */
304
305 static int
i_ddi_peekpoke(dev_info_t * devi,ddi_ctl_enum_t cmd,size_t size,void * addr,void * value_p)306 i_ddi_peekpoke(dev_info_t *devi, ddi_ctl_enum_t cmd, size_t size,
307 void *addr, void *value_p)
308 {
309 union {
310 uint64_t u64;
311 uint32_t u32;
312 uint16_t u16;
313 uint8_t u8;
314 } peekpoke_value;
315
316 peekpoke_ctlops_t peekpoke_args;
317 uint64_t dummy_result;
318 int rval;
319
320 /* Note: size is assumed to be correct; it is not checked. */
321 peekpoke_args.size = size;
322 peekpoke_args.dev_addr = (uintptr_t)addr;
323 peekpoke_args.handle = NULL;
324 peekpoke_args.repcount = 1;
325 peekpoke_args.flags = 0;
326
327 if (cmd == DDI_CTLOPS_POKE) {
328 switch (size) {
329 case sizeof (uint8_t):
330 peekpoke_value.u8 = *(uint8_t *)value_p;
331 break;
332 case sizeof (uint16_t):
333 peekpoke_value.u16 = *(uint16_t *)value_p;
334 break;
335 case sizeof (uint32_t):
336 peekpoke_value.u32 = *(uint32_t *)value_p;
337 break;
338 case sizeof (uint64_t):
339 peekpoke_value.u64 = *(uint64_t *)value_p;
340 break;
341 }
342 }
343
344 peekpoke_args.host_addr = (uintptr_t)&peekpoke_value.u64;
345
346 if (devi != NULL)
347 rval = ddi_ctlops(devi, devi, cmd, &peekpoke_args,
348 &dummy_result);
349 else
350 rval = peekpoke_mem(cmd, &peekpoke_args);
351
352 /*
353 * A NULL value_p is permitted by ddi_peek(9F); discard the result.
354 */
355 if ((cmd == DDI_CTLOPS_PEEK) & (value_p != NULL)) {
356 switch (size) {
357 case sizeof (uint8_t):
358 *(uint8_t *)value_p = peekpoke_value.u8;
359 break;
360 case sizeof (uint16_t):
361 *(uint16_t *)value_p = peekpoke_value.u16;
362 break;
363 case sizeof (uint32_t):
364 *(uint32_t *)value_p = peekpoke_value.u32;
365 break;
366 case sizeof (uint64_t):
367 *(uint64_t *)value_p = peekpoke_value.u64;
368 break;
369 }
370 }
371
372 return (rval);
373 }
374
375 /*
376 * Keep ddi_peek() and ddi_poke() in case 3rd parties are calling this.
377 * they shouldn't be, but the 9f manpage kind of pseudo exposes it.
378 */
379 int
ddi_peek(dev_info_t * devi,size_t size,void * addr,void * value_p)380 ddi_peek(dev_info_t *devi, size_t size, void *addr, void *value_p)
381 {
382 switch (size) {
383 case sizeof (uint8_t):
384 case sizeof (uint16_t):
385 case sizeof (uint32_t):
386 case sizeof (uint64_t):
387 break;
388 default:
389 return (DDI_FAILURE);
390 }
391
392 return (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, size, addr, value_p));
393 }
394
395 int
ddi_poke(dev_info_t * devi,size_t size,void * addr,void * value_p)396 ddi_poke(dev_info_t *devi, size_t size, void *addr, void *value_p)
397 {
398 switch (size) {
399 case sizeof (uint8_t):
400 case sizeof (uint16_t):
401 case sizeof (uint32_t):
402 case sizeof (uint64_t):
403 break;
404 default:
405 return (DDI_FAILURE);
406 }
407
408 return (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, size, addr, value_p));
409 }
410
411 int
ddi_peek8(dev_info_t * dip,int8_t * addr,int8_t * val_p)412 ddi_peek8(dev_info_t *dip, int8_t *addr, int8_t *val_p)
413 {
414 return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
415 val_p));
416 }
417
418 int
ddi_peek16(dev_info_t * dip,int16_t * addr,int16_t * val_p)419 ddi_peek16(dev_info_t *dip, int16_t *addr, int16_t *val_p)
420 {
421 return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
422 val_p));
423 }
424
425 int
ddi_peek32(dev_info_t * dip,int32_t * addr,int32_t * val_p)426 ddi_peek32(dev_info_t *dip, int32_t *addr, int32_t *val_p)
427 {
428 return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
429 val_p));
430 }
431
432 int
ddi_peek64(dev_info_t * dip,int64_t * addr,int64_t * val_p)433 ddi_peek64(dev_info_t *dip, int64_t *addr, int64_t *val_p)
434 {
435 return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
436 val_p));
437 }
438
439 int
ddi_poke8(dev_info_t * dip,int8_t * addr,int8_t val)440 ddi_poke8(dev_info_t *dip, int8_t *addr, int8_t val)
441 {
442 return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
443 }
444
445 int
ddi_poke16(dev_info_t * dip,int16_t * addr,int16_t val)446 ddi_poke16(dev_info_t *dip, int16_t *addr, int16_t val)
447 {
448 return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
449 }
450
451 int
ddi_poke32(dev_info_t * dip,int32_t * addr,int32_t val)452 ddi_poke32(dev_info_t *dip, int32_t *addr, int32_t val)
453 {
454 return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
455 }
456
457 int
ddi_poke64(dev_info_t * dip,int64_t * addr,int64_t val)458 ddi_poke64(dev_info_t *dip, int64_t *addr, int64_t val)
459 {
460 return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
461 }
462
463 /*
464 * ddi_peekpokeio() is used primarily by the mem drivers for moving
465 * data to and from uio structures via peek and poke. Note that we
466 * use "internal" routines ddi_peek and ddi_poke to make this go
467 * slightly faster, avoiding the call overhead ..
468 */
469 int
ddi_peekpokeio(dev_info_t * devi,struct uio * uio,enum uio_rw rw,caddr_t addr,size_t len,uint_t xfersize)470 ddi_peekpokeio(dev_info_t *devi, struct uio *uio, enum uio_rw rw,
471 caddr_t addr, size_t len, uint_t xfersize)
472 {
473 int64_t ibuffer;
474 int8_t w8;
475 size_t sz;
476 int o;
477
478 if (xfersize > sizeof (long))
479 xfersize = sizeof (long);
480
481 while (len != 0) {
482 if ((len | (uintptr_t)addr) & 1) {
483 sz = sizeof (int8_t);
484 if (rw == UIO_WRITE) {
485 if ((o = uwritec(uio)) == -1)
486 return (DDI_FAILURE);
487 if (ddi_poke8(devi, (int8_t *)addr,
488 (int8_t)o) != DDI_SUCCESS)
489 return (DDI_FAILURE);
490 } else {
491 if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
492 (int8_t *)addr, &w8) != DDI_SUCCESS)
493 return (DDI_FAILURE);
494 if (ureadc(w8, uio))
495 return (DDI_FAILURE);
496 }
497 } else {
498 switch (xfersize) {
499 case sizeof (int64_t):
500 if (((len | (uintptr_t)addr) &
501 (sizeof (int64_t) - 1)) == 0) {
502 sz = xfersize;
503 break;
504 }
505 /*FALLTHROUGH*/
506 case sizeof (int32_t):
507 if (((len | (uintptr_t)addr) &
508 (sizeof (int32_t) - 1)) == 0) {
509 sz = xfersize;
510 break;
511 }
512 /*FALLTHROUGH*/
513 default:
514 /*
515 * This still assumes that we might have an
516 * I/O bus out there that permits 16-bit
517 * transfers (and that it would be upset by
518 * 32-bit transfers from such locations).
519 */
520 sz = sizeof (int16_t);
521 break;
522 }
523
524 if (rw == UIO_READ) {
525 if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
526 addr, &ibuffer) != DDI_SUCCESS)
527 return (DDI_FAILURE);
528 }
529
530 if (uiomove(&ibuffer, sz, rw, uio))
531 return (DDI_FAILURE);
532
533 if (rw == UIO_WRITE) {
534 if (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, sz,
535 addr, &ibuffer) != DDI_SUCCESS)
536 return (DDI_FAILURE);
537 }
538 }
539 addr += sz;
540 len -= sz;
541 }
542 return (DDI_SUCCESS);
543 }
544
545 /*
546 * These routines are used by drivers that do layered ioctls
547 * On sparc, they're implemented in assembler to avoid spilling
548 * register windows in the common (copyin) case ..
549 */
550 #if !defined(__sparc)
551 int
ddi_copyin(const void * buf,void * kernbuf,size_t size,int flags)552 ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
553 {
554 if (flags & FKIOCTL)
555 return (kcopy(buf, kernbuf, size) ? -1 : 0);
556 return (copyin(buf, kernbuf, size));
557 }
558
559 int
ddi_copyout(const void * buf,void * kernbuf,size_t size,int flags)560 ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
561 {
562 if (flags & FKIOCTL)
563 return (kcopy(buf, kernbuf, size) ? -1 : 0);
564 return (copyout(buf, kernbuf, size));
565 }
566 #endif /* !__sparc */
567
568 /*
569 * Conversions in nexus pagesize units. We don't duplicate the
570 * 'nil dip' semantics of peek/poke because btopr/btop/ptob are DDI/DKI
571 * routines anyway.
572 */
573 unsigned long
ddi_btop(dev_info_t * dip,unsigned long bytes)574 ddi_btop(dev_info_t *dip, unsigned long bytes)
575 {
576 unsigned long pages;
577
578 (void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOP, &bytes, &pages);
579 return (pages);
580 }
581
582 unsigned long
ddi_btopr(dev_info_t * dip,unsigned long bytes)583 ddi_btopr(dev_info_t *dip, unsigned long bytes)
584 {
585 unsigned long pages;
586
587 (void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOPR, &bytes, &pages);
588 return (pages);
589 }
590
591 unsigned long
ddi_ptob(dev_info_t * dip,unsigned long pages)592 ddi_ptob(dev_info_t *dip, unsigned long pages)
593 {
594 unsigned long bytes;
595
596 (void) ddi_ctlops(dip, dip, DDI_CTLOPS_PTOB, &pages, &bytes);
597 return (bytes);
598 }
599
600 unsigned int
ddi_enter_critical(void)601 ddi_enter_critical(void)
602 {
603 return ((uint_t)spl7());
604 }
605
606 void
ddi_exit_critical(unsigned int spl)607 ddi_exit_critical(unsigned int spl)
608 {
609 splx((int)spl);
610 }
611
612 /*
613 * Nexus ctlops punter
614 */
615
616 #if !defined(__sparc)
617 /*
618 * Request bus_ctl parent to handle a bus_ctl request
619 *
620 * (The sparc version is in sparc_ddi.s)
621 */
622 int
ddi_ctlops(dev_info_t * d,dev_info_t * r,ddi_ctl_enum_t op,void * a,void * v)623 ddi_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t op, void *a, void *v)
624 {
625 int (*fp)();
626
627 if (!d || !r)
628 return (DDI_FAILURE);
629
630 if ((d = (dev_info_t *)DEVI(d)->devi_bus_ctl) == NULL)
631 return (DDI_FAILURE);
632
633 fp = DEVI(d)->devi_ops->devo_bus_ops->bus_ctl;
634 return ((*fp)(d, r, op, a, v));
635 }
636
637 #endif
638
639 /*
640 * DMA/DVMA setup
641 */
642
643 #if !defined(__sparc)
644 /*
645 * Request bus_dma_ctl parent to fiddle with a dma request.
646 *
647 * (The sparc version is in sparc_subr.s)
648 */
649 int
ddi_dma_mctl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,enum ddi_dma_ctlops request,off_t * offp,size_t * lenp,caddr_t * objp,uint_t flags)650 ddi_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
651 ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
652 off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
653 {
654 int (*fp)();
655
656 if (dip != ddi_root_node())
657 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
658 fp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_ctl;
659 return ((*fp) (dip, rdip, handle, request, offp, lenp, objp, flags));
660 }
661 #endif
662
663 /*
664 * For all DMA control functions, call the DMA control
665 * routine and return status.
666 *
667 * Just plain assume that the parent is to be called.
668 * If a nexus driver or a thread outside the framework
669 * of a nexus driver or a leaf driver calls these functions,
670 * it is up to them to deal with the fact that the parent's
671 * bus_dma_ctl function will be the first one called.
672 */
673
674 #define HD ((ddi_dma_impl_t *)h)->dmai_rdip
675
676 /*
677 * This routine is left in place to satisfy link dependencies
678 * for any 3rd party nexus drivers that rely on it. It is never
679 * called, though.
680 */
681 /*ARGSUSED*/
682 int
ddi_dma_map(dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)683 ddi_dma_map(dev_info_t *dip, dev_info_t *rdip,
684 struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
685 {
686 return (DDI_FAILURE);
687 }
688
689 #if !defined(__sparc)
690
691 /*
692 * The SPARC versions of these routines are done in assembler to
693 * save register windows, so they're in sparc_subr.s.
694 */
695
696 int
ddi_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)697 ddi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
698 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
699 {
700 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
701 int (*)(caddr_t), caddr_t, ddi_dma_handle_t *);
702
703 if (dip != ddi_root_node())
704 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
705
706 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_allochdl;
707 return ((*funcp)(dip, rdip, attr, waitfp, arg, handlep));
708 }
709
710 int
ddi_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handlep)711 ddi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handlep)
712 {
713 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
714
715 if (dip != ddi_root_node())
716 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
717
718 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_freehdl;
719 return ((*funcp)(dip, rdip, handlep));
720 }
721
722 int
ddi_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cp,uint_t * ccountp)723 ddi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
724 ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
725 ddi_dma_cookie_t *cp, uint_t *ccountp)
726 {
727 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
728 struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *);
729
730 if (dip != ddi_root_node())
731 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
732
733 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_bindhdl;
734 return ((*funcp)(dip, rdip, handle, dmareq, cp, ccountp));
735 }
736
737 int
ddi_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)738 ddi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
739 ddi_dma_handle_t handle)
740 {
741 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
742
743 if (dip != ddi_root_node())
744 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
745
746 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl;
747 return ((*funcp)(dip, rdip, handle));
748 }
749
750
751 int
ddi_dma_flush(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,off_t off,size_t len,uint_t cache_flags)752 ddi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
753 ddi_dma_handle_t handle, off_t off, size_t len,
754 uint_t cache_flags)
755 {
756 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
757 off_t, size_t, uint_t);
758
759 if (dip != ddi_root_node())
760 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
761
762 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
763 return ((*funcp)(dip, rdip, handle, off, len, cache_flags));
764 }
765
766 int
ddi_dma_win(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)767 ddi_dma_win(dev_info_t *dip, dev_info_t *rdip,
768 ddi_dma_handle_t handle, uint_t win, off_t *offp,
769 size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
770 {
771 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
772 uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
773
774 if (dip != ddi_root_node())
775 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
776
777 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_win;
778 return ((*funcp)(dip, rdip, handle, win, offp, lenp,
779 cookiep, ccountp));
780 }
781
782 int
ddi_dma_sync(ddi_dma_handle_t h,off_t o,size_t l,uint_t whom)783 ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, uint_t whom)
784 {
785 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
786 dev_info_t *dip, *rdip;
787 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t, off_t,
788 size_t, uint_t);
789
790 /*
791 * the DMA nexus driver will set DMP_NOSYNC if the
792 * platform does not require any sync operation. For
793 * example if the memory is uncached or consistent
794 * and without any I/O write buffers involved.
795 */
796 if ((hp->dmai_rflags & DMP_NOSYNC) == DMP_NOSYNC)
797 return (DDI_SUCCESS);
798
799 dip = rdip = hp->dmai_rdip;
800 if (dip != ddi_root_node())
801 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
802 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
803 return ((*funcp)(dip, rdip, h, o, l, whom));
804 }
805
806 int
ddi_dma_unbind_handle(ddi_dma_handle_t h)807 ddi_dma_unbind_handle(ddi_dma_handle_t h)
808 {
809 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
810 dev_info_t *dip, *rdip;
811 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
812
813 dip = rdip = hp->dmai_rdip;
814 if (dip != ddi_root_node())
815 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
816 funcp = DEVI(rdip)->devi_bus_dma_unbindfunc;
817 return ((*funcp)(dip, rdip, h));
818 }
819
820 #endif /* !__sparc */
821
822 /*
823 * DMA burst sizes, and transfer minimums
824 */
825
826 int
ddi_dma_burstsizes(ddi_dma_handle_t handle)827 ddi_dma_burstsizes(ddi_dma_handle_t handle)
828 {
829 ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
830
831 if (!dimp)
832 return (0);
833 else
834 return (dimp->dmai_burstsizes);
835 }
836
837 /*
838 * Given two DMA attribute structures, apply the attributes
839 * of one to the other, following the rules of attributes
840 * and the wishes of the caller.
841 *
842 * The rules of DMA attribute structures are that you cannot
843 * make things *less* restrictive as you apply one set
844 * of attributes to another.
845 *
846 */
847 void
ddi_dma_attr_merge(ddi_dma_attr_t * attr,const ddi_dma_attr_t * mod)848 ddi_dma_attr_merge(ddi_dma_attr_t *attr, const ddi_dma_attr_t *mod)
849 {
850 attr->dma_attr_addr_lo =
851 MAX(attr->dma_attr_addr_lo, mod->dma_attr_addr_lo);
852 attr->dma_attr_addr_hi =
853 MIN(attr->dma_attr_addr_hi, mod->dma_attr_addr_hi);
854 attr->dma_attr_count_max =
855 MIN(attr->dma_attr_count_max, mod->dma_attr_count_max);
856 attr->dma_attr_align =
857 MAX(attr->dma_attr_align, mod->dma_attr_align);
858 attr->dma_attr_burstsizes =
859 (uint_t)(attr->dma_attr_burstsizes & mod->dma_attr_burstsizes);
860 attr->dma_attr_minxfer =
861 maxbit(attr->dma_attr_minxfer, mod->dma_attr_minxfer);
862 attr->dma_attr_maxxfer =
863 MIN(attr->dma_attr_maxxfer, mod->dma_attr_maxxfer);
864 attr->dma_attr_seg = MIN(attr->dma_attr_seg, mod->dma_attr_seg);
865 attr->dma_attr_sgllen = MIN((uint_t)attr->dma_attr_sgllen,
866 (uint_t)mod->dma_attr_sgllen);
867 attr->dma_attr_granular =
868 MAX(attr->dma_attr_granular, mod->dma_attr_granular);
869 }
870
871 /*
872 * mmap/segmap interface:
873 */
874
875 /*
876 * ddi_segmap: setup the default segment driver. Calls the drivers
877 * XXmmap routine to validate the range to be mapped.
878 * Return ENXIO of the range is not valid. Create
879 * a seg_dev segment that contains all of the
880 * necessary information and will reference the
881 * default segment driver routines. It returns zero
882 * on success or non-zero on failure.
883 */
884 int
ddi_segmap(dev_t dev,off_t offset,struct as * asp,caddr_t * addrp,off_t len,uint_t prot,uint_t maxprot,uint_t flags,cred_t * credp)885 ddi_segmap(dev_t dev, off_t offset, struct as *asp, caddr_t *addrp, off_t len,
886 uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp)
887 {
888 extern int spec_segmap(dev_t, off_t, struct as *, caddr_t *,
889 off_t, uint_t, uint_t, uint_t, struct cred *);
890
891 return (spec_segmap(dev, offset, asp, addrp, len,
892 prot, maxprot, flags, credp));
893 }
894
895 /*
896 * ddi_map_fault: Resolve mappings at fault time. Used by segment
897 * drivers. Allows each successive parent to resolve
898 * address translations and add its mappings to the
899 * mapping list supplied in the page structure. It
900 * returns zero on success or non-zero on failure.
901 */
902
903 int
ddi_map_fault(dev_info_t * dip,struct hat * hat,struct seg * seg,caddr_t addr,struct devpage * dp,pfn_t pfn,uint_t prot,uint_t lock)904 ddi_map_fault(dev_info_t *dip, struct hat *hat, struct seg *seg,
905 caddr_t addr, struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock)
906 {
907 return (i_ddi_map_fault(dip, dip, hat, seg, addr, dp, pfn, prot, lock));
908 }
909
910 /*
911 * ddi_device_mapping_check: Called from ddi_segmap_setup.
912 * Invokes platform specific DDI to determine whether attributes specified
913 * in attr(9s) are valid for the region of memory that will be made
914 * available for direct access to user process via the mmap(2) system call.
915 */
916 int
ddi_device_mapping_check(dev_t dev,const ddi_device_acc_attr_t * accattrp,uint_t rnumber,uint_t * hat_flags)917 ddi_device_mapping_check(dev_t dev, const ddi_device_acc_attr_t *accattrp,
918 uint_t rnumber, uint_t *hat_flags)
919 {
920 ddi_acc_handle_t handle;
921 ddi_map_req_t mr;
922 ddi_acc_hdl_t *hp;
923 int result;
924 dev_info_t *dip;
925
926 /*
927 * we use e_ddi_hold_devi_by_dev to search for the devi. We
928 * release it immediately since it should already be held by
929 * a devfs vnode.
930 */
931 if ((dip =
932 e_ddi_hold_devi_by_dev(dev, E_DDI_HOLD_DEVI_NOATTACH)) == NULL)
933 return (-1);
934 ddi_release_devi(dip); /* for e_ddi_hold_devi_by_dev() */
935
936 /*
937 * Allocate and initialize the common elements of data
938 * access handle.
939 */
940 handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
941 if (handle == NULL)
942 return (-1);
943
944 hp = impl_acc_hdl_get(handle);
945 hp->ah_vers = VERS_ACCHDL;
946 hp->ah_dip = dip;
947 hp->ah_rnumber = rnumber;
948 hp->ah_offset = 0;
949 hp->ah_len = 0;
950 hp->ah_acc = *accattrp;
951
952 /*
953 * Set up the mapping request and call to parent.
954 */
955 mr.map_op = DDI_MO_MAP_HANDLE;
956 mr.map_type = DDI_MT_RNUMBER;
957 mr.map_obj.rnumber = rnumber;
958 mr.map_prot = PROT_READ | PROT_WRITE;
959 mr.map_flags = DDI_MF_KERNEL_MAPPING;
960 mr.map_handlep = hp;
961 mr.map_vers = DDI_MAP_VERSION;
962 result = ddi_map(dip, &mr, 0, 0, NULL);
963
964 /*
965 * Region must be mappable, pick up flags from the framework.
966 */
967 *hat_flags = hp->ah_hat_flags;
968
969 impl_acc_hdl_free(handle);
970
971 /*
972 * check for end result.
973 */
974 if (result != DDI_SUCCESS)
975 return (-1);
976 return (0);
977 }
978
979
980 /*
981 * Property functions: See also, ddipropdefs.h.
982 *
983 * These functions are the framework for the property functions,
984 * i.e. they support software defined properties. All implementation
985 * specific property handling (i.e.: self-identifying devices and
986 * PROM defined properties are handled in the implementation specific
987 * functions (defined in ddi_implfuncs.h).
988 */
989
990 /*
991 * nopropop: Shouldn't be called, right?
992 */
993 int
nopropop(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)994 nopropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
995 char *name, caddr_t valuep, int *lengthp)
996 {
997 _NOTE(ARGUNUSED(dev, dip, prop_op, mod_flags, name, valuep, lengthp))
998 return (DDI_PROP_NOT_FOUND);
999 }
1000
1001 #ifdef DDI_PROP_DEBUG
1002 int ddi_prop_debug_flag = 0;
1003
1004 int
ddi_prop_debug(int enable)1005 ddi_prop_debug(int enable)
1006 {
1007 int prev = ddi_prop_debug_flag;
1008
1009 if ((enable != 0) || (prev != 0))
1010 printf("ddi_prop_debug: debugging %s\n",
1011 enable ? "enabled" : "disabled");
1012 ddi_prop_debug_flag = enable;
1013 return (prev);
1014 }
1015
1016 #endif /* DDI_PROP_DEBUG */
1017
1018 /*
1019 * Search a property list for a match, if found return pointer
1020 * to matching prop struct, else return NULL.
1021 */
1022
1023 ddi_prop_t *
i_ddi_prop_search(dev_t dev,char * name,uint_t flags,ddi_prop_t ** list_head)1024 i_ddi_prop_search(dev_t dev, char *name, uint_t flags, ddi_prop_t **list_head)
1025 {
1026 ddi_prop_t *propp;
1027
1028 /*
1029 * find the property in child's devinfo:
1030 * Search order defined by this search function is first matching
1031 * property with input dev == DDI_DEV_T_ANY matching any dev or
1032 * dev == propp->prop_dev, name == propp->name, and the correct
1033 * data type as specified in the flags. If a DDI_DEV_T_NONE dev
1034 * value made it this far then it implies a DDI_DEV_T_ANY search.
1035 */
1036 if (dev == DDI_DEV_T_NONE)
1037 dev = DDI_DEV_T_ANY;
1038
1039 for (propp = *list_head; propp != NULL; propp = propp->prop_next) {
1040
1041 if (!DDI_STRSAME(propp->prop_name, name))
1042 continue;
1043
1044 if ((dev != DDI_DEV_T_ANY) && (propp->prop_dev != dev))
1045 continue;
1046
1047 if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
1048 continue;
1049
1050 return (propp);
1051 }
1052
1053 return ((ddi_prop_t *)0);
1054 }
1055
1056 /*
1057 * Search for property within devnames structures
1058 */
1059 ddi_prop_t *
i_ddi_search_global_prop(dev_t dev,char * name,uint_t flags)1060 i_ddi_search_global_prop(dev_t dev, char *name, uint_t flags)
1061 {
1062 major_t major;
1063 struct devnames *dnp;
1064 ddi_prop_t *propp;
1065
1066 /*
1067 * Valid dev_t value is needed to index into the
1068 * correct devnames entry, therefore a dev_t
1069 * value of DDI_DEV_T_ANY is not appropriate.
1070 */
1071 ASSERT(dev != DDI_DEV_T_ANY);
1072 if (dev == DDI_DEV_T_ANY) {
1073 return ((ddi_prop_t *)0);
1074 }
1075
1076 major = getmajor(dev);
1077 dnp = &(devnamesp[major]);
1078
1079 if (dnp->dn_global_prop_ptr == NULL)
1080 return ((ddi_prop_t *)0);
1081
1082 LOCK_DEV_OPS(&dnp->dn_lock);
1083
1084 for (propp = dnp->dn_global_prop_ptr->prop_list;
1085 propp != NULL;
1086 propp = (ddi_prop_t *)propp->prop_next) {
1087
1088 if (!DDI_STRSAME(propp->prop_name, name))
1089 continue;
1090
1091 if ((!(flags & DDI_PROP_ROOTNEX_GLOBAL)) &&
1092 (!(flags & LDI_DEV_T_ANY)) && (propp->prop_dev != dev))
1093 continue;
1094
1095 if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
1096 continue;
1097
1098 /* Property found, return it */
1099 UNLOCK_DEV_OPS(&dnp->dn_lock);
1100 return (propp);
1101 }
1102
1103 UNLOCK_DEV_OPS(&dnp->dn_lock);
1104 return ((ddi_prop_t *)0);
1105 }
1106
1107 static char prop_no_mem_msg[] = "can't allocate memory for ddi property <%s>";
1108
1109 /*
1110 * ddi_prop_search_global:
1111 * Search the global property list within devnames
1112 * for the named property. Return the encoded value.
1113 */
1114 static int
i_ddi_prop_search_global(dev_t dev,uint_t flags,char * name,void * valuep,uint_t * lengthp)1115 i_ddi_prop_search_global(dev_t dev, uint_t flags, char *name,
1116 void *valuep, uint_t *lengthp)
1117 {
1118 ddi_prop_t *propp;
1119 caddr_t buffer;
1120
1121 propp = i_ddi_search_global_prop(dev, name, flags);
1122
1123 /* Property NOT found, bail */
1124 if (propp == (ddi_prop_t *)0)
1125 return (DDI_PROP_NOT_FOUND);
1126
1127 if (propp->prop_flags & DDI_PROP_UNDEF_IT)
1128 return (DDI_PROP_UNDEFINED);
1129
1130 if ((buffer = kmem_alloc(propp->prop_len,
1131 (flags & DDI_PROP_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP)) == NULL) {
1132 cmn_err(CE_CONT, prop_no_mem_msg, name);
1133 return (DDI_PROP_NO_MEMORY);
1134 }
1135
1136 /*
1137 * Return the encoded data
1138 */
1139 *(caddr_t *)valuep = buffer;
1140 *lengthp = propp->prop_len;
1141 bcopy(propp->prop_val, buffer, propp->prop_len);
1142
1143 return (DDI_PROP_SUCCESS);
1144 }
1145
1146 /*
1147 * ddi_prop_search_common: Lookup and return the encoded value
1148 */
1149 int
ddi_prop_search_common(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,uint_t flags,char * name,void * valuep,uint_t * lengthp)1150 ddi_prop_search_common(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1151 uint_t flags, char *name, void *valuep, uint_t *lengthp)
1152 {
1153 ddi_prop_t *propp;
1154 int i;
1155 caddr_t buffer = NULL;
1156 caddr_t prealloc = NULL;
1157 int plength = 0;
1158 dev_info_t *pdip;
1159 int (*bop)();
1160
1161 /*CONSTANTCONDITION*/
1162 while (1) {
1163
1164 mutex_enter(&(DEVI(dip)->devi_lock));
1165
1166
1167 /*
1168 * find the property in child's devinfo:
1169 * Search order is:
1170 * 1. driver defined properties
1171 * 2. system defined properties
1172 * 3. driver global properties
1173 * 4. boot defined properties
1174 */
1175
1176 propp = i_ddi_prop_search(dev, name, flags,
1177 &(DEVI(dip)->devi_drv_prop_ptr));
1178 if (propp == NULL) {
1179 propp = i_ddi_prop_search(dev, name, flags,
1180 &(DEVI(dip)->devi_sys_prop_ptr));
1181 }
1182 if ((propp == NULL) && DEVI(dip)->devi_global_prop_list) {
1183 propp = i_ddi_prop_search(dev, name, flags,
1184 &DEVI(dip)->devi_global_prop_list->prop_list);
1185 }
1186
1187 if (propp == NULL) {
1188 propp = i_ddi_prop_search(dev, name, flags,
1189 &(DEVI(dip)->devi_hw_prop_ptr));
1190 }
1191
1192 /*
1193 * Software property found?
1194 */
1195 if (propp != (ddi_prop_t *)0) {
1196
1197 /*
1198 * If explicit undefine, return now.
1199 */
1200 if (propp->prop_flags & DDI_PROP_UNDEF_IT) {
1201 mutex_exit(&(DEVI(dip)->devi_lock));
1202 if (prealloc)
1203 kmem_free(prealloc, plength);
1204 return (DDI_PROP_UNDEFINED);
1205 }
1206
1207 /*
1208 * If we only want to know if it exists, return now
1209 */
1210 if (prop_op == PROP_EXISTS) {
1211 mutex_exit(&(DEVI(dip)->devi_lock));
1212 ASSERT(prealloc == NULL);
1213 return (DDI_PROP_SUCCESS);
1214 }
1215
1216 /*
1217 * If length only request or prop length == 0,
1218 * service request and return now.
1219 */
1220 if ((prop_op == PROP_LEN) ||(propp->prop_len == 0)) {
1221 *lengthp = propp->prop_len;
1222
1223 /*
1224 * if prop_op is PROP_LEN_AND_VAL_ALLOC
1225 * that means prop_len is 0, so set valuep
1226 * also to NULL
1227 */
1228 if (prop_op == PROP_LEN_AND_VAL_ALLOC)
1229 *(caddr_t *)valuep = NULL;
1230
1231 mutex_exit(&(DEVI(dip)->devi_lock));
1232 if (prealloc)
1233 kmem_free(prealloc, plength);
1234 return (DDI_PROP_SUCCESS);
1235 }
1236
1237 /*
1238 * If LEN_AND_VAL_ALLOC and the request can sleep,
1239 * drop the mutex, allocate the buffer, and go
1240 * through the loop again. If we already allocated
1241 * the buffer, and the size of the property changed,
1242 * keep trying...
1243 */
1244 if ((prop_op == PROP_LEN_AND_VAL_ALLOC) &&
1245 (flags & DDI_PROP_CANSLEEP)) {
1246 if (prealloc && (propp->prop_len != plength)) {
1247 kmem_free(prealloc, plength);
1248 prealloc = NULL;
1249 }
1250 if (prealloc == NULL) {
1251 plength = propp->prop_len;
1252 mutex_exit(&(DEVI(dip)->devi_lock));
1253 prealloc = kmem_alloc(plength,
1254 KM_SLEEP);
1255 continue;
1256 }
1257 }
1258
1259 /*
1260 * Allocate buffer, if required. Either way,
1261 * set `buffer' variable.
1262 */
1263 i = *lengthp; /* Get callers length */
1264 *lengthp = propp->prop_len; /* Set callers length */
1265
1266 switch (prop_op) {
1267
1268 case PROP_LEN_AND_VAL_ALLOC:
1269
1270 if (prealloc == NULL) {
1271 buffer = kmem_alloc(propp->prop_len,
1272 KM_NOSLEEP);
1273 } else {
1274 buffer = prealloc;
1275 }
1276
1277 if (buffer == NULL) {
1278 mutex_exit(&(DEVI(dip)->devi_lock));
1279 cmn_err(CE_CONT, prop_no_mem_msg, name);
1280 return (DDI_PROP_NO_MEMORY);
1281 }
1282 /* Set callers buf ptr */
1283 *(caddr_t *)valuep = buffer;
1284 break;
1285
1286 case PROP_LEN_AND_VAL_BUF:
1287
1288 if (propp->prop_len > (i)) {
1289 mutex_exit(&(DEVI(dip)->devi_lock));
1290 return (DDI_PROP_BUF_TOO_SMALL);
1291 }
1292
1293 buffer = valuep; /* Get callers buf ptr */
1294 break;
1295
1296 default:
1297 break;
1298 }
1299
1300 /*
1301 * Do the copy.
1302 */
1303 if (buffer != NULL)
1304 bcopy(propp->prop_val, buffer, propp->prop_len);
1305 mutex_exit(&(DEVI(dip)->devi_lock));
1306 return (DDI_PROP_SUCCESS);
1307 }
1308
1309 mutex_exit(&(DEVI(dip)->devi_lock));
1310 if (prealloc)
1311 kmem_free(prealloc, plength);
1312 prealloc = NULL;
1313
1314 /*
1315 * Prop not found, call parent bus_ops to deal with possible
1316 * h/w layer (possible PROM defined props, etc.) and to
1317 * possibly ascend the hierarchy, if allowed by flags.
1318 */
1319 pdip = (dev_info_t *)DEVI(dip)->devi_parent;
1320
1321 /*
1322 * One last call for the root driver PROM props?
1323 */
1324 if (dip == ddi_root_node()) {
1325 return (ddi_bus_prop_op(dev, dip, dip, prop_op,
1326 flags, name, valuep, (int *)lengthp));
1327 }
1328
1329 /*
1330 * We may have been called to check for properties
1331 * within a single devinfo node that has no parent -
1332 * see make_prop()
1333 */
1334 if (pdip == NULL) {
1335 ASSERT((flags &
1336 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM)) ==
1337 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM));
1338 return (DDI_PROP_NOT_FOUND);
1339 }
1340
1341 /*
1342 * Instead of recursing, we do iterative calls up the tree.
1343 * As a bit of optimization, skip the bus_op level if the
1344 * node is a s/w node and if the parent's bus_prop_op function
1345 * is `ddi_bus_prop_op', because we know that in this case,
1346 * this function does nothing.
1347 *
1348 * 4225415: If the parent isn't attached, or the child
1349 * hasn't been named by the parent yet, use the default
1350 * ddi_bus_prop_op as a proxy for the parent. This
1351 * allows property lookups in any child/parent state to
1352 * include 'prom' and inherited properties, even when
1353 * there are no drivers attached to the child or parent.
1354 */
1355
1356 bop = ddi_bus_prop_op;
1357 if (i_ddi_devi_attached(pdip) &&
1358 (i_ddi_node_state(dip) >= DS_INITIALIZED))
1359 bop = DEVI(pdip)->devi_ops->devo_bus_ops->bus_prop_op;
1360
1361 i = DDI_PROP_NOT_FOUND;
1362
1363 if ((bop != ddi_bus_prop_op) || ndi_dev_is_prom_node(dip)) {
1364 i = (*bop)(dev, pdip, dip, prop_op,
1365 flags | DDI_PROP_DONTPASS,
1366 name, valuep, lengthp);
1367 }
1368
1369 if ((flags & DDI_PROP_DONTPASS) ||
1370 (i != DDI_PROP_NOT_FOUND))
1371 return (i);
1372
1373 dip = pdip;
1374 }
1375 /*NOTREACHED*/
1376 }
1377
1378
1379 /*
1380 * ddi_prop_op: The basic property operator for drivers.
1381 *
1382 * In ddi_prop_op, the type of valuep is interpreted based on prop_op:
1383 *
1384 * prop_op valuep
1385 * ------ ------
1386 *
1387 * PROP_LEN <unused>
1388 *
1389 * PROP_LEN_AND_VAL_BUF Pointer to callers buffer
1390 *
1391 * PROP_LEN_AND_VAL_ALLOC Address of callers pointer (will be set to
1392 * address of allocated buffer, if successful)
1393 */
1394 int
ddi_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)1395 ddi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1396 char *name, caddr_t valuep, int *lengthp)
1397 {
1398 int i;
1399
1400 ASSERT((mod_flags & DDI_PROP_TYPE_MASK) == 0);
1401
1402 /*
1403 * If this was originally an LDI prop lookup then we bail here.
1404 * The reason is that the LDI property lookup interfaces first call
1405 * a drivers prop_op() entry point to allow it to override
1406 * properties. But if we've made it here, then the driver hasn't
1407 * overriden any properties. We don't want to continue with the
1408 * property search here because we don't have any type inforamtion.
1409 * When we return failure, the LDI interfaces will then proceed to
1410 * call the typed property interfaces to look up the property.
1411 */
1412 if (mod_flags & DDI_PROP_DYNAMIC)
1413 return (DDI_PROP_NOT_FOUND);
1414
1415 /*
1416 * check for pre-typed property consumer asking for typed property:
1417 * see e_ddi_getprop_int64.
1418 */
1419 if (mod_flags & DDI_PROP_CONSUMER_TYPED)
1420 mod_flags |= DDI_PROP_TYPE_INT64;
1421 mod_flags |= DDI_PROP_TYPE_ANY;
1422
1423 i = ddi_prop_search_common(dev, dip, prop_op,
1424 mod_flags, name, valuep, (uint_t *)lengthp);
1425 if (i == DDI_PROP_FOUND_1275)
1426 return (DDI_PROP_SUCCESS);
1427 return (i);
1428 }
1429
1430 /*
1431 * ddi_prop_op_nblocks_blksize: The basic property operator for drivers that
1432 * maintain size in number of blksize blocks. Provides a dynamic property
1433 * implementation for size oriented properties based on nblocks64 and blksize
1434 * values passed in by the driver. Fallback to ddi_prop_op if the nblocks64
1435 * is too large. This interface should not be used with a nblocks64 that
1436 * represents the driver's idea of how to represent unknown, if nblocks is
1437 * unknown use ddi_prop_op.
1438 */
1439 int
ddi_prop_op_nblocks_blksize(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t nblocks64,uint_t blksize)1440 ddi_prop_op_nblocks_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1441 int mod_flags, char *name, caddr_t valuep, int *lengthp,
1442 uint64_t nblocks64, uint_t blksize)
1443 {
1444 uint64_t size64;
1445 int blkshift;
1446
1447 /* convert block size to shift value */
1448 ASSERT(BIT_ONLYONESET(blksize));
1449 blkshift = highbit(blksize) - 1;
1450
1451 /*
1452 * There is no point in supporting nblocks64 values that don't have
1453 * an accurate uint64_t byte count representation.
1454 */
1455 if (nblocks64 >= (UINT64_MAX >> blkshift))
1456 return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1457 name, valuep, lengthp));
1458
1459 size64 = nblocks64 << blkshift;
1460 return (ddi_prop_op_size_blksize(dev, dip, prop_op, mod_flags,
1461 name, valuep, lengthp, size64, blksize));
1462 }
1463
1464 /*
1465 * ddi_prop_op_nblocks: ddi_prop_op_nblocks_blksize with DEV_BSIZE blksize.
1466 */
1467 int
ddi_prop_op_nblocks(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t nblocks64)1468 ddi_prop_op_nblocks(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1469 int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t nblocks64)
1470 {
1471 return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op,
1472 mod_flags, name, valuep, lengthp, nblocks64, DEV_BSIZE));
1473 }
1474
1475 /*
1476 * ddi_prop_op_size_blksize: The basic property operator for block drivers that
1477 * maintain size in bytes. Provides a of dynamic property implementation for
1478 * size oriented properties based on size64 value and blksize passed in by the
1479 * driver. Fallback to ddi_prop_op if the size64 is too large. This interface
1480 * should not be used with a size64 that represents the driver's idea of how
1481 * to represent unknown, if size is unknown use ddi_prop_op.
1482 *
1483 * NOTE: the legacy "nblocks"/"size" properties are treated as 32-bit unsigned
1484 * integers. While the most likely interface to request them ([bc]devi_size)
1485 * is declared int (signed) there is no enforcement of this, which means we
1486 * can't enforce limitations here without risking regression.
1487 */
1488 int
ddi_prop_op_size_blksize(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t size64,uint_t blksize)1489 ddi_prop_op_size_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1490 int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64,
1491 uint_t blksize)
1492 {
1493 uint64_t nblocks64;
1494 int callers_length;
1495 caddr_t buffer;
1496 int blkshift;
1497
1498 /*
1499 * This is a kludge to support capture of size(9P) pure dynamic
1500 * properties in snapshots for non-cmlb code (without exposing
1501 * i_ddi_prop_dyn changes). When everyone uses cmlb, this code
1502 * should be removed.
1503 */
1504 if (i_ddi_prop_dyn_driver_get(dip) == NULL) {
1505 static i_ddi_prop_dyn_t prop_dyn_size[] = {
1506 {"Size", DDI_PROP_TYPE_INT64, S_IFCHR},
1507 {"Nblocks", DDI_PROP_TYPE_INT64, S_IFBLK},
1508 {NULL}
1509 };
1510 i_ddi_prop_dyn_driver_set(dip, prop_dyn_size);
1511 }
1512
1513 /* convert block size to shift value */
1514 ASSERT(BIT_ONLYONESET(blksize));
1515 blkshift = highbit(blksize) - 1;
1516
1517 /* compute DEV_BSIZE nblocks value */
1518 nblocks64 = size64 >> blkshift;
1519
1520 /* get callers length, establish length of our dynamic properties */
1521 callers_length = *lengthp;
1522
1523 if (strcmp(name, "Nblocks") == 0)
1524 *lengthp = sizeof (uint64_t);
1525 else if (strcmp(name, "Size") == 0)
1526 *lengthp = sizeof (uint64_t);
1527 else if ((strcmp(name, "nblocks") == 0) && (nblocks64 < UINT_MAX))
1528 *lengthp = sizeof (uint32_t);
1529 else if ((strcmp(name, "size") == 0) && (size64 < UINT_MAX))
1530 *lengthp = sizeof (uint32_t);
1531 else if ((strcmp(name, "blksize") == 0) && (blksize < UINT_MAX))
1532 *lengthp = sizeof (uint32_t);
1533 else {
1534 /* fallback to ddi_prop_op */
1535 return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1536 name, valuep, lengthp));
1537 }
1538
1539 /* service request for the length of the property */
1540 if (prop_op == PROP_LEN)
1541 return (DDI_PROP_SUCCESS);
1542
1543 switch (prop_op) {
1544 case PROP_LEN_AND_VAL_ALLOC:
1545 if ((buffer = kmem_alloc(*lengthp,
1546 (mod_flags & DDI_PROP_CANSLEEP) ?
1547 KM_SLEEP : KM_NOSLEEP)) == NULL)
1548 return (DDI_PROP_NO_MEMORY);
1549
1550 *(caddr_t *)valuep = buffer; /* set callers buf ptr */
1551 break;
1552
1553 case PROP_LEN_AND_VAL_BUF:
1554 /* the length of the property and the request must match */
1555 if (callers_length != *lengthp)
1556 return (DDI_PROP_INVAL_ARG);
1557
1558 buffer = valuep; /* get callers buf ptr */
1559 break;
1560
1561 default:
1562 return (DDI_PROP_INVAL_ARG);
1563 }
1564
1565 /* transfer the value into the buffer */
1566 if (strcmp(name, "Nblocks") == 0)
1567 *((uint64_t *)buffer) = nblocks64;
1568 else if (strcmp(name, "Size") == 0)
1569 *((uint64_t *)buffer) = size64;
1570 else if (strcmp(name, "nblocks") == 0)
1571 *((uint32_t *)buffer) = (uint32_t)nblocks64;
1572 else if (strcmp(name, "size") == 0)
1573 *((uint32_t *)buffer) = (uint32_t)size64;
1574 else if (strcmp(name, "blksize") == 0)
1575 *((uint32_t *)buffer) = (uint32_t)blksize;
1576 return (DDI_PROP_SUCCESS);
1577 }
1578
1579 /*
1580 * ddi_prop_op_size: ddi_prop_op_size_blksize with DEV_BSIZE block size.
1581 */
1582 int
ddi_prop_op_size(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t size64)1583 ddi_prop_op_size(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1584 int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64)
1585 {
1586 return (ddi_prop_op_size_blksize(dev, dip, prop_op,
1587 mod_flags, name, valuep, lengthp, size64, DEV_BSIZE));
1588 }
1589
1590 /*
1591 * Variable length props...
1592 */
1593
1594 /*
1595 * ddi_getlongprop: Get variable length property len+val into a buffer
1596 * allocated by property provider via kmem_alloc. Requester
1597 * is responsible for freeing returned property via kmem_free.
1598 *
1599 * Arguments:
1600 *
1601 * dev_t: Input: dev_t of property.
1602 * dip: Input: dev_info_t pointer of child.
1603 * flags: Input: Possible flag modifiers are:
1604 * DDI_PROP_DONTPASS: Don't pass to parent if prop not found.
1605 * DDI_PROP_CANSLEEP: Memory allocation may sleep.
1606 * name: Input: name of property.
1607 * valuep: Output: Addr of callers buffer pointer.
1608 * lengthp:Output: *lengthp will contain prop length on exit.
1609 *
1610 * Possible Returns:
1611 *
1612 * DDI_PROP_SUCCESS: Prop found and returned.
1613 * DDI_PROP_NOT_FOUND: Prop not found
1614 * DDI_PROP_UNDEFINED: Prop explicitly undefined.
1615 * DDI_PROP_NO_MEMORY: Prop found, but unable to alloc mem.
1616 */
1617
1618 int
ddi_getlongprop(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t valuep,int * lengthp)1619 ddi_getlongprop(dev_t dev, dev_info_t *dip, int flags,
1620 char *name, caddr_t valuep, int *lengthp)
1621 {
1622 return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_ALLOC,
1623 flags, name, valuep, lengthp));
1624 }
1625
1626 /*
1627 *
1628 * ddi_getlongprop_buf: Get long prop into pre-allocated callers
1629 * buffer. (no memory allocation by provider).
1630 *
1631 * dev_t: Input: dev_t of property.
1632 * dip: Input: dev_info_t pointer of child.
1633 * flags: Input: DDI_PROP_DONTPASS or NULL
1634 * name: Input: name of property
1635 * valuep: Input: ptr to callers buffer.
1636 * lengthp:I/O: ptr to length of callers buffer on entry,
1637 * actual length of property on exit.
1638 *
1639 * Possible returns:
1640 *
1641 * DDI_PROP_SUCCESS Prop found and returned
1642 * DDI_PROP_NOT_FOUND Prop not found
1643 * DDI_PROP_UNDEFINED Prop explicitly undefined.
1644 * DDI_PROP_BUF_TOO_SMALL Prop found, callers buf too small,
1645 * no value returned, but actual prop
1646 * length returned in *lengthp
1647 *
1648 */
1649
1650 int
ddi_getlongprop_buf(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t valuep,int * lengthp)1651 ddi_getlongprop_buf(dev_t dev, dev_info_t *dip, int flags,
1652 char *name, caddr_t valuep, int *lengthp)
1653 {
1654 return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
1655 flags, name, valuep, lengthp));
1656 }
1657
1658 /*
1659 * Integer/boolean sized props.
1660 *
1661 * Call is value only... returns found boolean or int sized prop value or
1662 * defvalue if prop not found or is wrong length or is explicitly undefined.
1663 * Only flag is DDI_PROP_DONTPASS...
1664 *
1665 * By convention, this interface returns boolean (0) sized properties
1666 * as value (int)1.
1667 *
1668 * This never returns an error, if property not found or specifically
1669 * undefined, the input `defvalue' is returned.
1670 */
1671
1672 int
ddi_getprop(dev_t dev,dev_info_t * dip,int flags,char * name,int defvalue)1673 ddi_getprop(dev_t dev, dev_info_t *dip, int flags, char *name, int defvalue)
1674 {
1675 int propvalue = defvalue;
1676 int proplength = sizeof (int);
1677 int error;
1678
1679 error = ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
1680 flags, name, (caddr_t)&propvalue, &proplength);
1681
1682 if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
1683 propvalue = 1;
1684
1685 return (propvalue);
1686 }
1687
1688 /*
1689 * Get prop length interface: flags are 0 or DDI_PROP_DONTPASS
1690 * if returns DDI_PROP_SUCCESS, length returned in *lengthp.
1691 */
1692
1693 int
ddi_getproplen(dev_t dev,dev_info_t * dip,int flags,char * name,int * lengthp)1694 ddi_getproplen(dev_t dev, dev_info_t *dip, int flags, char *name, int *lengthp)
1695 {
1696 return (ddi_prop_op(dev, dip, PROP_LEN, flags, name, NULL, lengthp));
1697 }
1698
1699 /*
1700 * Allocate a struct prop_driver_data, along with 'size' bytes
1701 * for decoded property data. This structure is freed by
1702 * calling ddi_prop_free(9F).
1703 */
1704 static void *
ddi_prop_decode_alloc(size_t size,void (* prop_free)(struct prop_driver_data *))1705 ddi_prop_decode_alloc(size_t size, void (*prop_free)(struct prop_driver_data *))
1706 {
1707 struct prop_driver_data *pdd;
1708
1709 /*
1710 * Allocate a structure with enough memory to store the decoded data.
1711 */
1712 pdd = kmem_zalloc(sizeof (struct prop_driver_data) + size, KM_SLEEP);
1713 pdd->pdd_size = (sizeof (struct prop_driver_data) + size);
1714 pdd->pdd_prop_free = prop_free;
1715
1716 /*
1717 * Return a pointer to the location to put the decoded data.
1718 */
1719 return ((void *)((caddr_t)pdd + sizeof (struct prop_driver_data)));
1720 }
1721
1722 /*
1723 * Allocated the memory needed to store the encoded data in the property
1724 * handle.
1725 */
1726 static int
ddi_prop_encode_alloc(prop_handle_t * ph,size_t size)1727 ddi_prop_encode_alloc(prop_handle_t *ph, size_t size)
1728 {
1729 /*
1730 * If size is zero, then set data to NULL and size to 0. This
1731 * is a boolean property.
1732 */
1733 if (size == 0) {
1734 ph->ph_size = 0;
1735 ph->ph_data = NULL;
1736 ph->ph_cur_pos = NULL;
1737 ph->ph_save_pos = NULL;
1738 } else {
1739 if (ph->ph_flags == DDI_PROP_DONTSLEEP) {
1740 ph->ph_data = kmem_zalloc(size, KM_NOSLEEP);
1741 if (ph->ph_data == NULL)
1742 return (DDI_PROP_NO_MEMORY);
1743 } else
1744 ph->ph_data = kmem_zalloc(size, KM_SLEEP);
1745 ph->ph_size = size;
1746 ph->ph_cur_pos = ph->ph_data;
1747 ph->ph_save_pos = ph->ph_data;
1748 }
1749 return (DDI_PROP_SUCCESS);
1750 }
1751
1752 /*
1753 * Free the space allocated by the lookup routines. Each lookup routine
1754 * returns a pointer to the decoded data to the driver. The driver then
1755 * passes this pointer back to us. This data actually lives in a struct
1756 * prop_driver_data. We use negative indexing to find the beginning of
1757 * the structure and then free the entire structure using the size and
1758 * the free routine stored in the structure.
1759 */
1760 void
ddi_prop_free(void * datap)1761 ddi_prop_free(void *datap)
1762 {
1763 struct prop_driver_data *pdd;
1764
1765 /*
1766 * Get the structure
1767 */
1768 pdd = (struct prop_driver_data *)
1769 ((caddr_t)datap - sizeof (struct prop_driver_data));
1770 /*
1771 * Call the free routine to free it
1772 */
1773 (*pdd->pdd_prop_free)(pdd);
1774 }
1775
1776 /*
1777 * Free the data associated with an array of ints,
1778 * allocated with ddi_prop_decode_alloc().
1779 */
1780 static void
ddi_prop_free_ints(struct prop_driver_data * pdd)1781 ddi_prop_free_ints(struct prop_driver_data *pdd)
1782 {
1783 kmem_free(pdd, pdd->pdd_size);
1784 }
1785
1786 /*
1787 * Free a single string property or a single string contained within
1788 * the argv style return value of an array of strings.
1789 */
1790 static void
ddi_prop_free_string(struct prop_driver_data * pdd)1791 ddi_prop_free_string(struct prop_driver_data *pdd)
1792 {
1793 kmem_free(pdd, pdd->pdd_size);
1794
1795 }
1796
1797 /*
1798 * Free an array of strings.
1799 */
1800 static void
ddi_prop_free_strings(struct prop_driver_data * pdd)1801 ddi_prop_free_strings(struct prop_driver_data *pdd)
1802 {
1803 kmem_free(pdd, pdd->pdd_size);
1804 }
1805
1806 /*
1807 * Free the data associated with an array of bytes.
1808 */
1809 static void
ddi_prop_free_bytes(struct prop_driver_data * pdd)1810 ddi_prop_free_bytes(struct prop_driver_data *pdd)
1811 {
1812 kmem_free(pdd, pdd->pdd_size);
1813 }
1814
1815 /*
1816 * Reset the current location pointer in the property handle to the
1817 * beginning of the data.
1818 */
1819 void
ddi_prop_reset_pos(prop_handle_t * ph)1820 ddi_prop_reset_pos(prop_handle_t *ph)
1821 {
1822 ph->ph_cur_pos = ph->ph_data;
1823 ph->ph_save_pos = ph->ph_data;
1824 }
1825
1826 /*
1827 * Restore the current location pointer in the property handle to the
1828 * saved position.
1829 */
1830 void
ddi_prop_save_pos(prop_handle_t * ph)1831 ddi_prop_save_pos(prop_handle_t *ph)
1832 {
1833 ph->ph_save_pos = ph->ph_cur_pos;
1834 }
1835
1836 /*
1837 * Save the location that the current location pointer is pointing to..
1838 */
1839 void
ddi_prop_restore_pos(prop_handle_t * ph)1840 ddi_prop_restore_pos(prop_handle_t *ph)
1841 {
1842 ph->ph_cur_pos = ph->ph_save_pos;
1843 }
1844
1845 /*
1846 * Property encode/decode functions
1847 */
1848
1849 /*
1850 * Decode a single integer property
1851 */
1852 static int
ddi_prop_fm_decode_int(prop_handle_t * ph,void * data,uint_t * nelements)1853 ddi_prop_fm_decode_int(prop_handle_t *ph, void *data, uint_t *nelements)
1854 {
1855 int i;
1856 int tmp;
1857
1858 /*
1859 * If there is nothing to decode return an error
1860 */
1861 if (ph->ph_size == 0)
1862 return (DDI_PROP_END_OF_DATA);
1863
1864 /*
1865 * Decode the property as a single integer and return it
1866 * in data if we were able to decode it.
1867 */
1868 i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, &tmp);
1869 if (i < DDI_PROP_RESULT_OK) {
1870 switch (i) {
1871 case DDI_PROP_RESULT_EOF:
1872 return (DDI_PROP_END_OF_DATA);
1873
1874 case DDI_PROP_RESULT_ERROR:
1875 return (DDI_PROP_CANNOT_DECODE);
1876 }
1877 }
1878
1879 *(int *)data = tmp;
1880 *nelements = 1;
1881 return (DDI_PROP_SUCCESS);
1882 }
1883
1884 /*
1885 * Decode a single 64 bit integer property
1886 */
1887 static int
ddi_prop_fm_decode_int64(prop_handle_t * ph,void * data,uint_t * nelements)1888 ddi_prop_fm_decode_int64(prop_handle_t *ph, void *data, uint_t *nelements)
1889 {
1890 int i;
1891 int64_t tmp;
1892
1893 /*
1894 * If there is nothing to decode return an error
1895 */
1896 if (ph->ph_size == 0)
1897 return (DDI_PROP_END_OF_DATA);
1898
1899 /*
1900 * Decode the property as a single integer and return it
1901 * in data if we were able to decode it.
1902 */
1903 i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, &tmp);
1904 if (i < DDI_PROP_RESULT_OK) {
1905 switch (i) {
1906 case DDI_PROP_RESULT_EOF:
1907 return (DDI_PROP_END_OF_DATA);
1908
1909 case DDI_PROP_RESULT_ERROR:
1910 return (DDI_PROP_CANNOT_DECODE);
1911 }
1912 }
1913
1914 *(int64_t *)data = tmp;
1915 *nelements = 1;
1916 return (DDI_PROP_SUCCESS);
1917 }
1918
1919 /*
1920 * Decode an array of integers property
1921 */
1922 static int
ddi_prop_fm_decode_ints(prop_handle_t * ph,void * data,uint_t * nelements)1923 ddi_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
1924 {
1925 int i;
1926 int cnt = 0;
1927 int *tmp;
1928 int *intp;
1929 int n;
1930
1931 /*
1932 * Figure out how many array elements there are by going through the
1933 * data without decoding it first and counting.
1934 */
1935 for (;;) {
1936 i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
1937 if (i < 0)
1938 break;
1939 cnt++;
1940 }
1941
1942 /*
1943 * If there are no elements return an error
1944 */
1945 if (cnt == 0)
1946 return (DDI_PROP_END_OF_DATA);
1947
1948 /*
1949 * If we cannot skip through the data, we cannot decode it
1950 */
1951 if (i == DDI_PROP_RESULT_ERROR)
1952 return (DDI_PROP_CANNOT_DECODE);
1953
1954 /*
1955 * Reset the data pointer to the beginning of the encoded data
1956 */
1957 ddi_prop_reset_pos(ph);
1958
1959 /*
1960 * Allocated memory to store the decoded value in.
1961 */
1962 intp = ddi_prop_decode_alloc((cnt * sizeof (int)),
1963 ddi_prop_free_ints);
1964
1965 /*
1966 * Decode each element and place it in the space we just allocated
1967 */
1968 tmp = intp;
1969 for (n = 0; n < cnt; n++, tmp++) {
1970 i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
1971 if (i < DDI_PROP_RESULT_OK) {
1972 /*
1973 * Free the space we just allocated
1974 * and return an error.
1975 */
1976 ddi_prop_free(intp);
1977 switch (i) {
1978 case DDI_PROP_RESULT_EOF:
1979 return (DDI_PROP_END_OF_DATA);
1980
1981 case DDI_PROP_RESULT_ERROR:
1982 return (DDI_PROP_CANNOT_DECODE);
1983 }
1984 }
1985 }
1986
1987 *nelements = cnt;
1988 *(int **)data = intp;
1989
1990 return (DDI_PROP_SUCCESS);
1991 }
1992
1993 /*
1994 * Decode a 64 bit integer array property
1995 */
1996 static int
ddi_prop_fm_decode_int64_array(prop_handle_t * ph,void * data,uint_t * nelements)1997 ddi_prop_fm_decode_int64_array(prop_handle_t *ph, void *data, uint_t *nelements)
1998 {
1999 int i;
2000 int n;
2001 int cnt = 0;
2002 int64_t *tmp;
2003 int64_t *intp;
2004
2005 /*
2006 * Count the number of array elements by going
2007 * through the data without decoding it.
2008 */
2009 for (;;) {
2010 i = DDI_PROP_INT64(ph, DDI_PROP_CMD_SKIP, NULL);
2011 if (i < 0)
2012 break;
2013 cnt++;
2014 }
2015
2016 /*
2017 * If there are no elements return an error
2018 */
2019 if (cnt == 0)
2020 return (DDI_PROP_END_OF_DATA);
2021
2022 /*
2023 * If we cannot skip through the data, we cannot decode it
2024 */
2025 if (i == DDI_PROP_RESULT_ERROR)
2026 return (DDI_PROP_CANNOT_DECODE);
2027
2028 /*
2029 * Reset the data pointer to the beginning of the encoded data
2030 */
2031 ddi_prop_reset_pos(ph);
2032
2033 /*
2034 * Allocate memory to store the decoded value.
2035 */
2036 intp = ddi_prop_decode_alloc((cnt * sizeof (int64_t)),
2037 ddi_prop_free_ints);
2038
2039 /*
2040 * Decode each element and place it in the space allocated
2041 */
2042 tmp = intp;
2043 for (n = 0; n < cnt; n++, tmp++) {
2044 i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, tmp);
2045 if (i < DDI_PROP_RESULT_OK) {
2046 /*
2047 * Free the space we just allocated
2048 * and return an error.
2049 */
2050 ddi_prop_free(intp);
2051 switch (i) {
2052 case DDI_PROP_RESULT_EOF:
2053 return (DDI_PROP_END_OF_DATA);
2054
2055 case DDI_PROP_RESULT_ERROR:
2056 return (DDI_PROP_CANNOT_DECODE);
2057 }
2058 }
2059 }
2060
2061 *nelements = cnt;
2062 *(int64_t **)data = intp;
2063
2064 return (DDI_PROP_SUCCESS);
2065 }
2066
2067 /*
2068 * Encode an array of integers property (Can be one element)
2069 */
2070 int
ddi_prop_fm_encode_ints(prop_handle_t * ph,void * data,uint_t nelements)2071 ddi_prop_fm_encode_ints(prop_handle_t *ph, void *data, uint_t nelements)
2072 {
2073 int i;
2074 int *tmp;
2075 int cnt;
2076 int size;
2077
2078 /*
2079 * If there is no data, we cannot do anything
2080 */
2081 if (nelements == 0)
2082 return (DDI_PROP_CANNOT_ENCODE);
2083
2084 /*
2085 * Get the size of an encoded int.
2086 */
2087 size = DDI_PROP_INT(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
2088
2089 if (size < DDI_PROP_RESULT_OK) {
2090 switch (size) {
2091 case DDI_PROP_RESULT_EOF:
2092 return (DDI_PROP_END_OF_DATA);
2093
2094 case DDI_PROP_RESULT_ERROR:
2095 return (DDI_PROP_CANNOT_ENCODE);
2096 }
2097 }
2098
2099 /*
2100 * Allocate space in the handle to store the encoded int.
2101 */
2102 if (ddi_prop_encode_alloc(ph, size * nelements) !=
2103 DDI_PROP_SUCCESS)
2104 return (DDI_PROP_NO_MEMORY);
2105
2106 /*
2107 * Encode the array of ints.
2108 */
2109 tmp = (int *)data;
2110 for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2111 i = DDI_PROP_INT(ph, DDI_PROP_CMD_ENCODE, tmp);
2112 if (i < DDI_PROP_RESULT_OK) {
2113 switch (i) {
2114 case DDI_PROP_RESULT_EOF:
2115 return (DDI_PROP_END_OF_DATA);
2116
2117 case DDI_PROP_RESULT_ERROR:
2118 return (DDI_PROP_CANNOT_ENCODE);
2119 }
2120 }
2121 }
2122
2123 return (DDI_PROP_SUCCESS);
2124 }
2125
2126
2127 /*
2128 * Encode a 64 bit integer array property
2129 */
2130 int
ddi_prop_fm_encode_int64(prop_handle_t * ph,void * data,uint_t nelements)2131 ddi_prop_fm_encode_int64(prop_handle_t *ph, void *data, uint_t nelements)
2132 {
2133 int i;
2134 int cnt;
2135 int size;
2136 int64_t *tmp;
2137
2138 /*
2139 * If there is no data, we cannot do anything
2140 */
2141 if (nelements == 0)
2142 return (DDI_PROP_CANNOT_ENCODE);
2143
2144 /*
2145 * Get the size of an encoded 64 bit int.
2146 */
2147 size = DDI_PROP_INT64(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
2148
2149 if (size < DDI_PROP_RESULT_OK) {
2150 switch (size) {
2151 case DDI_PROP_RESULT_EOF:
2152 return (DDI_PROP_END_OF_DATA);
2153
2154 case DDI_PROP_RESULT_ERROR:
2155 return (DDI_PROP_CANNOT_ENCODE);
2156 }
2157 }
2158
2159 /*
2160 * Allocate space in the handle to store the encoded int.
2161 */
2162 if (ddi_prop_encode_alloc(ph, size * nelements) !=
2163 DDI_PROP_SUCCESS)
2164 return (DDI_PROP_NO_MEMORY);
2165
2166 /*
2167 * Encode the array of ints.
2168 */
2169 tmp = (int64_t *)data;
2170 for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2171 i = DDI_PROP_INT64(ph, DDI_PROP_CMD_ENCODE, tmp);
2172 if (i < DDI_PROP_RESULT_OK) {
2173 switch (i) {
2174 case DDI_PROP_RESULT_EOF:
2175 return (DDI_PROP_END_OF_DATA);
2176
2177 case DDI_PROP_RESULT_ERROR:
2178 return (DDI_PROP_CANNOT_ENCODE);
2179 }
2180 }
2181 }
2182
2183 return (DDI_PROP_SUCCESS);
2184 }
2185
2186 /*
2187 * Decode a single string property
2188 */
2189 static int
ddi_prop_fm_decode_string(prop_handle_t * ph,void * data,uint_t * nelements)2190 ddi_prop_fm_decode_string(prop_handle_t *ph, void *data, uint_t *nelements)
2191 {
2192 char *tmp;
2193 char *str;
2194 int i;
2195 int size;
2196
2197 /*
2198 * If there is nothing to decode return an error
2199 */
2200 if (ph->ph_size == 0)
2201 return (DDI_PROP_END_OF_DATA);
2202
2203 /*
2204 * Get the decoded size of the encoded string.
2205 */
2206 size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2207 if (size < DDI_PROP_RESULT_OK) {
2208 switch (size) {
2209 case DDI_PROP_RESULT_EOF:
2210 return (DDI_PROP_END_OF_DATA);
2211
2212 case DDI_PROP_RESULT_ERROR:
2213 return (DDI_PROP_CANNOT_DECODE);
2214 }
2215 }
2216
2217 /*
2218 * Allocated memory to store the decoded value in.
2219 */
2220 str = ddi_prop_decode_alloc((size_t)size, ddi_prop_free_string);
2221
2222 ddi_prop_reset_pos(ph);
2223
2224 /*
2225 * Decode the str and place it in the space we just allocated
2226 */
2227 tmp = str;
2228 i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
2229 if (i < DDI_PROP_RESULT_OK) {
2230 /*
2231 * Free the space we just allocated
2232 * and return an error.
2233 */
2234 ddi_prop_free(str);
2235 switch (i) {
2236 case DDI_PROP_RESULT_EOF:
2237 return (DDI_PROP_END_OF_DATA);
2238
2239 case DDI_PROP_RESULT_ERROR:
2240 return (DDI_PROP_CANNOT_DECODE);
2241 }
2242 }
2243
2244 *(char **)data = str;
2245 *nelements = 1;
2246
2247 return (DDI_PROP_SUCCESS);
2248 }
2249
2250 /*
2251 * Decode an array of strings.
2252 */
2253 int
ddi_prop_fm_decode_strings(prop_handle_t * ph,void * data,uint_t * nelements)2254 ddi_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
2255 {
2256 int cnt = 0;
2257 char **strs;
2258 char **tmp;
2259 char *ptr;
2260 int i;
2261 int n;
2262 int size;
2263 size_t nbytes;
2264
2265 /*
2266 * Figure out how many array elements there are by going through the
2267 * data without decoding it first and counting.
2268 */
2269 for (;;) {
2270 i = DDI_PROP_STR(ph, DDI_PROP_CMD_SKIP, NULL);
2271 if (i < 0)
2272 break;
2273 cnt++;
2274 }
2275
2276 /*
2277 * If there are no elements return an error
2278 */
2279 if (cnt == 0)
2280 return (DDI_PROP_END_OF_DATA);
2281
2282 /*
2283 * If we cannot skip through the data, we cannot decode it
2284 */
2285 if (i == DDI_PROP_RESULT_ERROR)
2286 return (DDI_PROP_CANNOT_DECODE);
2287
2288 /*
2289 * Reset the data pointer to the beginning of the encoded data
2290 */
2291 ddi_prop_reset_pos(ph);
2292
2293 /*
2294 * Figure out how much memory we need for the sum total
2295 */
2296 nbytes = (cnt + 1) * sizeof (char *);
2297
2298 for (n = 0; n < cnt; n++) {
2299 /*
2300 * Get the decoded size of the current encoded string.
2301 */
2302 size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2303 if (size < DDI_PROP_RESULT_OK) {
2304 switch (size) {
2305 case DDI_PROP_RESULT_EOF:
2306 return (DDI_PROP_END_OF_DATA);
2307
2308 case DDI_PROP_RESULT_ERROR:
2309 return (DDI_PROP_CANNOT_DECODE);
2310 }
2311 }
2312
2313 nbytes += size;
2314 }
2315
2316 /*
2317 * Allocate memory in which to store the decoded strings.
2318 */
2319 strs = ddi_prop_decode_alloc(nbytes, ddi_prop_free_strings);
2320
2321 /*
2322 * Set up pointers for each string by figuring out yet
2323 * again how long each string is.
2324 */
2325 ddi_prop_reset_pos(ph);
2326 ptr = (caddr_t)strs + ((cnt + 1) * sizeof (char *));
2327 for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
2328 /*
2329 * Get the decoded size of the current encoded string.
2330 */
2331 size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2332 if (size < DDI_PROP_RESULT_OK) {
2333 ddi_prop_free(strs);
2334 switch (size) {
2335 case DDI_PROP_RESULT_EOF:
2336 return (DDI_PROP_END_OF_DATA);
2337
2338 case DDI_PROP_RESULT_ERROR:
2339 return (DDI_PROP_CANNOT_DECODE);
2340 }
2341 }
2342
2343 *tmp = ptr;
2344 ptr += size;
2345 }
2346
2347 /*
2348 * String array is terminated by a NULL
2349 */
2350 *tmp = NULL;
2351
2352 /*
2353 * Finally, we can decode each string
2354 */
2355 ddi_prop_reset_pos(ph);
2356 for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
2357 i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, *tmp);
2358 if (i < DDI_PROP_RESULT_OK) {
2359 /*
2360 * Free the space we just allocated
2361 * and return an error
2362 */
2363 ddi_prop_free(strs);
2364 switch (i) {
2365 case DDI_PROP_RESULT_EOF:
2366 return (DDI_PROP_END_OF_DATA);
2367
2368 case DDI_PROP_RESULT_ERROR:
2369 return (DDI_PROP_CANNOT_DECODE);
2370 }
2371 }
2372 }
2373
2374 *(char ***)data = strs;
2375 *nelements = cnt;
2376
2377 return (DDI_PROP_SUCCESS);
2378 }
2379
2380 /*
2381 * Encode a string.
2382 */
2383 int
ddi_prop_fm_encode_string(prop_handle_t * ph,void * data,uint_t nelements)2384 ddi_prop_fm_encode_string(prop_handle_t *ph, void *data, uint_t nelements)
2385 {
2386 char **tmp;
2387 int size;
2388 int i;
2389
2390 /*
2391 * If there is no data, we cannot do anything
2392 */
2393 if (nelements == 0)
2394 return (DDI_PROP_CANNOT_ENCODE);
2395
2396 /*
2397 * Get the size of the encoded string.
2398 */
2399 tmp = (char **)data;
2400 size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
2401 if (size < DDI_PROP_RESULT_OK) {
2402 switch (size) {
2403 case DDI_PROP_RESULT_EOF:
2404 return (DDI_PROP_END_OF_DATA);
2405
2406 case DDI_PROP_RESULT_ERROR:
2407 return (DDI_PROP_CANNOT_ENCODE);
2408 }
2409 }
2410
2411 /*
2412 * Allocate space in the handle to store the encoded string.
2413 */
2414 if (ddi_prop_encode_alloc(ph, size) != DDI_PROP_SUCCESS)
2415 return (DDI_PROP_NO_MEMORY);
2416
2417 ddi_prop_reset_pos(ph);
2418
2419 /*
2420 * Encode the string.
2421 */
2422 tmp = (char **)data;
2423 i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
2424 if (i < DDI_PROP_RESULT_OK) {
2425 switch (i) {
2426 case DDI_PROP_RESULT_EOF:
2427 return (DDI_PROP_END_OF_DATA);
2428
2429 case DDI_PROP_RESULT_ERROR:
2430 return (DDI_PROP_CANNOT_ENCODE);
2431 }
2432 }
2433
2434 return (DDI_PROP_SUCCESS);
2435 }
2436
2437
2438 /*
2439 * Encode an array of strings.
2440 */
2441 int
ddi_prop_fm_encode_strings(prop_handle_t * ph,void * data,uint_t nelements)2442 ddi_prop_fm_encode_strings(prop_handle_t *ph, void *data, uint_t nelements)
2443 {
2444 int cnt = 0;
2445 char **tmp;
2446 int size;
2447 uint_t total_size;
2448 int i;
2449
2450 /*
2451 * If there is no data, we cannot do anything
2452 */
2453 if (nelements == 0)
2454 return (DDI_PROP_CANNOT_ENCODE);
2455
2456 /*
2457 * Get the total size required to encode all the strings.
2458 */
2459 total_size = 0;
2460 tmp = (char **)data;
2461 for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2462 size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
2463 if (size < DDI_PROP_RESULT_OK) {
2464 switch (size) {
2465 case DDI_PROP_RESULT_EOF:
2466 return (DDI_PROP_END_OF_DATA);
2467
2468 case DDI_PROP_RESULT_ERROR:
2469 return (DDI_PROP_CANNOT_ENCODE);
2470 }
2471 }
2472 total_size += (uint_t)size;
2473 }
2474
2475 /*
2476 * Allocate space in the handle to store the encoded strings.
2477 */
2478 if (ddi_prop_encode_alloc(ph, total_size) != DDI_PROP_SUCCESS)
2479 return (DDI_PROP_NO_MEMORY);
2480
2481 ddi_prop_reset_pos(ph);
2482
2483 /*
2484 * Encode the array of strings.
2485 */
2486 tmp = (char **)data;
2487 for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2488 i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
2489 if (i < DDI_PROP_RESULT_OK) {
2490 switch (i) {
2491 case DDI_PROP_RESULT_EOF:
2492 return (DDI_PROP_END_OF_DATA);
2493
2494 case DDI_PROP_RESULT_ERROR:
2495 return (DDI_PROP_CANNOT_ENCODE);
2496 }
2497 }
2498 }
2499
2500 return (DDI_PROP_SUCCESS);
2501 }
2502
2503
2504 /*
2505 * Decode an array of bytes.
2506 */
2507 static int
ddi_prop_fm_decode_bytes(prop_handle_t * ph,void * data,uint_t * nelements)2508 ddi_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
2509 {
2510 uchar_t *tmp;
2511 int nbytes;
2512 int i;
2513
2514 /*
2515 * If there are no elements return an error
2516 */
2517 if (ph->ph_size == 0)
2518 return (DDI_PROP_END_OF_DATA);
2519
2520 /*
2521 * Get the size of the encoded array of bytes.
2522 */
2523 nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
2524 data, ph->ph_size);
2525 if (nbytes < DDI_PROP_RESULT_OK) {
2526 switch (nbytes) {
2527 case DDI_PROP_RESULT_EOF:
2528 return (DDI_PROP_END_OF_DATA);
2529
2530 case DDI_PROP_RESULT_ERROR:
2531 return (DDI_PROP_CANNOT_DECODE);
2532 }
2533 }
2534
2535 /*
2536 * Allocated memory to store the decoded value in.
2537 */
2538 tmp = ddi_prop_decode_alloc(nbytes, ddi_prop_free_bytes);
2539
2540 /*
2541 * Decode each element and place it in the space we just allocated
2542 */
2543 i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
2544 if (i < DDI_PROP_RESULT_OK) {
2545 /*
2546 * Free the space we just allocated
2547 * and return an error
2548 */
2549 ddi_prop_free(tmp);
2550 switch (i) {
2551 case DDI_PROP_RESULT_EOF:
2552 return (DDI_PROP_END_OF_DATA);
2553
2554 case DDI_PROP_RESULT_ERROR:
2555 return (DDI_PROP_CANNOT_DECODE);
2556 }
2557 }
2558
2559 *(uchar_t **)data = tmp;
2560 *nelements = nbytes;
2561
2562 return (DDI_PROP_SUCCESS);
2563 }
2564
2565 /*
2566 * Encode an array of bytes.
2567 */
2568 int
ddi_prop_fm_encode_bytes(prop_handle_t * ph,void * data,uint_t nelements)2569 ddi_prop_fm_encode_bytes(prop_handle_t *ph, void *data, uint_t nelements)
2570 {
2571 int size;
2572 int i;
2573
2574 /*
2575 * If there are no elements, then this is a boolean property,
2576 * so just create a property handle with no data and return.
2577 */
2578 if (nelements == 0) {
2579 (void) ddi_prop_encode_alloc(ph, 0);
2580 return (DDI_PROP_SUCCESS);
2581 }
2582
2583 /*
2584 * Get the size of the encoded array of bytes.
2585 */
2586 size = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_ESIZE, (uchar_t *)data,
2587 nelements);
2588 if (size < DDI_PROP_RESULT_OK) {
2589 switch (size) {
2590 case DDI_PROP_RESULT_EOF:
2591 return (DDI_PROP_END_OF_DATA);
2592
2593 case DDI_PROP_RESULT_ERROR:
2594 return (DDI_PROP_CANNOT_DECODE);
2595 }
2596 }
2597
2598 /*
2599 * Allocate space in the handle to store the encoded bytes.
2600 */
2601 if (ddi_prop_encode_alloc(ph, (uint_t)size) != DDI_PROP_SUCCESS)
2602 return (DDI_PROP_NO_MEMORY);
2603
2604 /*
2605 * Encode the array of bytes.
2606 */
2607 i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_ENCODE, (uchar_t *)data,
2608 nelements);
2609 if (i < DDI_PROP_RESULT_OK) {
2610 switch (i) {
2611 case DDI_PROP_RESULT_EOF:
2612 return (DDI_PROP_END_OF_DATA);
2613
2614 case DDI_PROP_RESULT_ERROR:
2615 return (DDI_PROP_CANNOT_ENCODE);
2616 }
2617 }
2618
2619 return (DDI_PROP_SUCCESS);
2620 }
2621
2622 /*
2623 * OBP 1275 integer, string and byte operators.
2624 *
2625 * DDI_PROP_CMD_DECODE:
2626 *
2627 * DDI_PROP_RESULT_ERROR: cannot decode the data
2628 * DDI_PROP_RESULT_EOF: end of data
2629 * DDI_PROP_OK: data was decoded
2630 *
2631 * DDI_PROP_CMD_ENCODE:
2632 *
2633 * DDI_PROP_RESULT_ERROR: cannot encode the data
2634 * DDI_PROP_RESULT_EOF: end of data
2635 * DDI_PROP_OK: data was encoded
2636 *
2637 * DDI_PROP_CMD_SKIP:
2638 *
2639 * DDI_PROP_RESULT_ERROR: cannot skip the data
2640 * DDI_PROP_RESULT_EOF: end of data
2641 * DDI_PROP_OK: data was skipped
2642 *
2643 * DDI_PROP_CMD_GET_ESIZE:
2644 *
2645 * DDI_PROP_RESULT_ERROR: cannot get encoded size
2646 * DDI_PROP_RESULT_EOF: end of data
2647 * > 0: the encoded size
2648 *
2649 * DDI_PROP_CMD_GET_DSIZE:
2650 *
2651 * DDI_PROP_RESULT_ERROR: cannot get decoded size
2652 * DDI_PROP_RESULT_EOF: end of data
2653 * > 0: the decoded size
2654 */
2655
2656 /*
2657 * OBP 1275 integer operator
2658 *
2659 * OBP properties are a byte stream of data, so integers may not be
2660 * properly aligned. Therefore we need to copy them one byte at a time.
2661 */
2662 int
ddi_prop_1275_int(prop_handle_t * ph,uint_t cmd,int * data)2663 ddi_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
2664 {
2665 int i;
2666
2667 switch (cmd) {
2668 case DDI_PROP_CMD_DECODE:
2669 /*
2670 * Check that there is encoded data
2671 */
2672 if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
2673 return (DDI_PROP_RESULT_ERROR);
2674 if (ph->ph_flags & PH_FROM_PROM) {
2675 i = MIN(ph->ph_size, PROP_1275_INT_SIZE);
2676 if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
2677 ph->ph_size - i))
2678 return (DDI_PROP_RESULT_ERROR);
2679 } else {
2680 if (ph->ph_size < sizeof (int) ||
2681 ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
2682 ph->ph_size - sizeof (int))))
2683 return (DDI_PROP_RESULT_ERROR);
2684 }
2685
2686 /*
2687 * Copy the integer, using the implementation-specific
2688 * copy function if the property is coming from the PROM.
2689 */
2690 if (ph->ph_flags & PH_FROM_PROM) {
2691 *data = impl_ddi_prop_int_from_prom(
2692 (uchar_t *)ph->ph_cur_pos,
2693 (ph->ph_size < PROP_1275_INT_SIZE) ?
2694 ph->ph_size : PROP_1275_INT_SIZE);
2695 } else {
2696 bcopy(ph->ph_cur_pos, data, sizeof (int));
2697 }
2698
2699 /*
2700 * Move the current location to the start of the next
2701 * bit of undecoded data.
2702 */
2703 ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
2704 PROP_1275_INT_SIZE;
2705 return (DDI_PROP_RESULT_OK);
2706
2707 case DDI_PROP_CMD_ENCODE:
2708 /*
2709 * Check that there is room to encoded the data
2710 */
2711 if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
2712 ph->ph_size < PROP_1275_INT_SIZE ||
2713 ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
2714 ph->ph_size - sizeof (int))))
2715 return (DDI_PROP_RESULT_ERROR);
2716
2717 /*
2718 * Encode the integer into the byte stream one byte at a
2719 * time.
2720 */
2721 bcopy(data, ph->ph_cur_pos, sizeof (int));
2722
2723 /*
2724 * Move the current location to the start of the next bit of
2725 * space where we can store encoded data.
2726 */
2727 ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
2728 return (DDI_PROP_RESULT_OK);
2729
2730 case DDI_PROP_CMD_SKIP:
2731 /*
2732 * Check that there is encoded data
2733 */
2734 if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
2735 ph->ph_size < PROP_1275_INT_SIZE)
2736 return (DDI_PROP_RESULT_ERROR);
2737
2738
2739 if ((caddr_t)ph->ph_cur_pos ==
2740 (caddr_t)ph->ph_data + ph->ph_size) {
2741 return (DDI_PROP_RESULT_EOF);
2742 } else if ((caddr_t)ph->ph_cur_pos >
2743 (caddr_t)ph->ph_data + ph->ph_size) {
2744 return (DDI_PROP_RESULT_EOF);
2745 }
2746
2747 /*
2748 * Move the current location to the start of the next bit of
2749 * undecoded data.
2750 */
2751 ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
2752 return (DDI_PROP_RESULT_OK);
2753
2754 case DDI_PROP_CMD_GET_ESIZE:
2755 /*
2756 * Return the size of an encoded integer on OBP
2757 */
2758 return (PROP_1275_INT_SIZE);
2759
2760 case DDI_PROP_CMD_GET_DSIZE:
2761 /*
2762 * Return the size of a decoded integer on the system.
2763 */
2764 return (sizeof (int));
2765
2766 default:
2767 #ifdef DEBUG
2768 panic("ddi_prop_1275_int: %x impossible", cmd);
2769 /*NOTREACHED*/
2770 #else
2771 return (DDI_PROP_RESULT_ERROR);
2772 #endif /* DEBUG */
2773 }
2774 }
2775
2776 /*
2777 * 64 bit integer operator.
2778 *
2779 * This is an extension, defined by Sun, to the 1275 integer
2780 * operator. This routine handles the encoding/decoding of
2781 * 64 bit integer properties.
2782 */
2783 int
ddi_prop_int64_op(prop_handle_t * ph,uint_t cmd,int64_t * data)2784 ddi_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
2785 {
2786
2787 switch (cmd) {
2788 case DDI_PROP_CMD_DECODE:
2789 /*
2790 * Check that there is encoded data
2791 */
2792 if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
2793 return (DDI_PROP_RESULT_ERROR);
2794 if (ph->ph_flags & PH_FROM_PROM) {
2795 return (DDI_PROP_RESULT_ERROR);
2796 } else {
2797 if (ph->ph_size < sizeof (int64_t) ||
2798 ((int64_t *)ph->ph_cur_pos >
2799 ((int64_t *)ph->ph_data +
2800 ph->ph_size - sizeof (int64_t))))
2801 return (DDI_PROP_RESULT_ERROR);
2802 }
2803 /*
2804 * Copy the integer, using the implementation-specific
2805 * copy function if the property is coming from the PROM.
2806 */
2807 if (ph->ph_flags & PH_FROM_PROM) {
2808 return (DDI_PROP_RESULT_ERROR);
2809 } else {
2810 bcopy(ph->ph_cur_pos, data, sizeof (int64_t));
2811 }
2812
2813 /*
2814 * Move the current location to the start of the next
2815 * bit of undecoded data.
2816 */
2817 ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
2818 sizeof (int64_t);
2819 return (DDI_PROP_RESULT_OK);
2820
2821 case DDI_PROP_CMD_ENCODE:
2822 /*
2823 * Check that there is room to encoded the data
2824 */
2825 if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
2826 ph->ph_size < sizeof (int64_t) ||
2827 ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
2828 ph->ph_size - sizeof (int64_t))))
2829 return (DDI_PROP_RESULT_ERROR);
2830
2831 /*
2832 * Encode the integer into the byte stream one byte at a
2833 * time.
2834 */
2835 bcopy(data, ph->ph_cur_pos, sizeof (int64_t));
2836
2837 /*
2838 * Move the current location to the start of the next bit of
2839 * space where we can store encoded data.
2840 */
2841 ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
2842 sizeof (int64_t);
2843 return (DDI_PROP_RESULT_OK);
2844
2845 case DDI_PROP_CMD_SKIP:
2846 /*
2847 * Check that there is encoded data
2848 */
2849 if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
2850 ph->ph_size < sizeof (int64_t))
2851 return (DDI_PROP_RESULT_ERROR);
2852
2853 if ((caddr_t)ph->ph_cur_pos ==
2854 (caddr_t)ph->ph_data + ph->ph_size) {
2855 return (DDI_PROP_RESULT_EOF);
2856 } else if ((caddr_t)ph->ph_cur_pos >
2857 (caddr_t)ph->ph_data + ph->ph_size) {
2858 return (DDI_PROP_RESULT_EOF);
2859 }
2860
2861 /*
2862 * Move the current location to the start of
2863 * the next bit of undecoded data.
2864 */
2865 ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
2866 sizeof (int64_t);
2867 return (DDI_PROP_RESULT_OK);
2868
2869 case DDI_PROP_CMD_GET_ESIZE:
2870 /*
2871 * Return the size of an encoded integer on OBP
2872 */
2873 return (sizeof (int64_t));
2874
2875 case DDI_PROP_CMD_GET_DSIZE:
2876 /*
2877 * Return the size of a decoded integer on the system.
2878 */
2879 return (sizeof (int64_t));
2880
2881 default:
2882 #ifdef DEBUG
2883 panic("ddi_prop_int64_op: %x impossible", cmd);
2884 /*NOTREACHED*/
2885 #else
2886 return (DDI_PROP_RESULT_ERROR);
2887 #endif /* DEBUG */
2888 }
2889 }
2890
2891 /*
2892 * OBP 1275 string operator.
2893 *
2894 * OBP strings are NULL terminated.
2895 */
2896 int
ddi_prop_1275_string(prop_handle_t * ph,uint_t cmd,char * data)2897 ddi_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
2898 {
2899 int n;
2900 char *p;
2901 char *end;
2902
2903 switch (cmd) {
2904 case DDI_PROP_CMD_DECODE:
2905 /*
2906 * Check that there is encoded data
2907 */
2908 if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
2909 return (DDI_PROP_RESULT_ERROR);
2910 }
2911
2912 /*
2913 * Match DDI_PROP_CMD_GET_DSIZE logic for when to stop and
2914 * how to NULL terminate result.
2915 */
2916 p = (char *)ph->ph_cur_pos;
2917 end = (char *)ph->ph_data + ph->ph_size;
2918 if (p >= end)
2919 return (DDI_PROP_RESULT_EOF);
2920
2921 while (p < end) {
2922 *data++ = *p;
2923 if (*p++ == 0) { /* NULL from OBP */
2924 ph->ph_cur_pos = p;
2925 return (DDI_PROP_RESULT_OK);
2926 }
2927 }
2928
2929 /*
2930 * If OBP did not NULL terminate string, which happens
2931 * (at least) for 'true'/'false' boolean values, account for
2932 * the space and store null termination on decode.
2933 */
2934 ph->ph_cur_pos = p;
2935 *data = 0;
2936 return (DDI_PROP_RESULT_OK);
2937
2938 case DDI_PROP_CMD_ENCODE:
2939 /*
2940 * Check that there is room to encoded the data
2941 */
2942 if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
2943 return (DDI_PROP_RESULT_ERROR);
2944 }
2945
2946 n = strlen(data) + 1;
2947 if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
2948 ph->ph_size - n)) {
2949 return (DDI_PROP_RESULT_ERROR);
2950 }
2951
2952 /*
2953 * Copy the NULL terminated string
2954 */
2955 bcopy(data, ph->ph_cur_pos, n);
2956
2957 /*
2958 * Move the current location to the start of the next bit of
2959 * space where we can store encoded data.
2960 */
2961 ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
2962 return (DDI_PROP_RESULT_OK);
2963
2964 case DDI_PROP_CMD_SKIP:
2965 /*
2966 * Check that there is encoded data
2967 */
2968 if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
2969 return (DDI_PROP_RESULT_ERROR);
2970 }
2971
2972 /*
2973 * Return the string length plus one for the NULL
2974 * We know the size of the property, we need to
2975 * ensure that the string is properly formatted,
2976 * since we may be looking up random OBP data.
2977 */
2978 p = (char *)ph->ph_cur_pos;
2979 end = (char *)ph->ph_data + ph->ph_size;
2980 if (p >= end)
2981 return (DDI_PROP_RESULT_EOF);
2982
2983 while (p < end) {
2984 if (*p++ == 0) { /* NULL from OBP */
2985 ph->ph_cur_pos = p;
2986 return (DDI_PROP_RESULT_OK);
2987 }
2988 }
2989
2990 /*
2991 * Accommodate the fact that OBP does not always NULL
2992 * terminate strings.
2993 */
2994 ph->ph_cur_pos = p;
2995 return (DDI_PROP_RESULT_OK);
2996
2997 case DDI_PROP_CMD_GET_ESIZE:
2998 /*
2999 * Return the size of the encoded string on OBP.
3000 */
3001 return (strlen(data) + 1);
3002
3003 case DDI_PROP_CMD_GET_DSIZE:
3004 /*
3005 * Return the string length plus one for the NULL.
3006 * We know the size of the property, we need to
3007 * ensure that the string is properly formatted,
3008 * since we may be looking up random OBP data.
3009 */
3010 p = (char *)ph->ph_cur_pos;
3011 end = (char *)ph->ph_data + ph->ph_size;
3012 if (p >= end)
3013 return (DDI_PROP_RESULT_EOF);
3014
3015 for (n = 0; p < end; n++) {
3016 if (*p++ == 0) { /* NULL from OBP */
3017 ph->ph_cur_pos = p;
3018 return (n + 1);
3019 }
3020 }
3021
3022 /*
3023 * If OBP did not NULL terminate string, which happens for
3024 * 'true'/'false' boolean values, account for the space
3025 * to store null termination here.
3026 */
3027 ph->ph_cur_pos = p;
3028 return (n + 1);
3029
3030 default:
3031 #ifdef DEBUG
3032 panic("ddi_prop_1275_string: %x impossible", cmd);
3033 /*NOTREACHED*/
3034 #else
3035 return (DDI_PROP_RESULT_ERROR);
3036 #endif /* DEBUG */
3037 }
3038 }
3039
3040 /*
3041 * OBP 1275 byte operator
3042 *
3043 * Caller must specify the number of bytes to get. OBP encodes bytes
3044 * as a byte so there is a 1-to-1 translation.
3045 */
3046 int
ddi_prop_1275_bytes(prop_handle_t * ph,uint_t cmd,uchar_t * data,uint_t nelements)3047 ddi_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
3048 uint_t nelements)
3049 {
3050 switch (cmd) {
3051 case DDI_PROP_CMD_DECODE:
3052 /*
3053 * Check that there is encoded data
3054 */
3055 if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3056 ph->ph_size < nelements ||
3057 ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3058 ph->ph_size - nelements)))
3059 return (DDI_PROP_RESULT_ERROR);
3060
3061 /*
3062 * Copy out the bytes
3063 */
3064 bcopy(ph->ph_cur_pos, data, nelements);
3065
3066 /*
3067 * Move the current location
3068 */
3069 ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3070 return (DDI_PROP_RESULT_OK);
3071
3072 case DDI_PROP_CMD_ENCODE:
3073 /*
3074 * Check that there is room to encode the data
3075 */
3076 if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3077 ph->ph_size < nelements ||
3078 ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3079 ph->ph_size - nelements)))
3080 return (DDI_PROP_RESULT_ERROR);
3081
3082 /*
3083 * Copy in the bytes
3084 */
3085 bcopy(data, ph->ph_cur_pos, nelements);
3086
3087 /*
3088 * Move the current location to the start of the next bit of
3089 * space where we can store encoded data.
3090 */
3091 ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3092 return (DDI_PROP_RESULT_OK);
3093
3094 case DDI_PROP_CMD_SKIP:
3095 /*
3096 * Check that there is encoded data
3097 */
3098 if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3099 ph->ph_size < nelements)
3100 return (DDI_PROP_RESULT_ERROR);
3101
3102 if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3103 ph->ph_size - nelements))
3104 return (DDI_PROP_RESULT_EOF);
3105
3106 /*
3107 * Move the current location
3108 */
3109 ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3110 return (DDI_PROP_RESULT_OK);
3111
3112 case DDI_PROP_CMD_GET_ESIZE:
3113 /*
3114 * The size in bytes of the encoded size is the
3115 * same as the decoded size provided by the caller.
3116 */
3117 return (nelements);
3118
3119 case DDI_PROP_CMD_GET_DSIZE:
3120 /*
3121 * Just return the number of bytes specified by the caller.
3122 */
3123 return (nelements);
3124
3125 default:
3126 #ifdef DEBUG
3127 panic("ddi_prop_1275_bytes: %x impossible", cmd);
3128 /*NOTREACHED*/
3129 #else
3130 return (DDI_PROP_RESULT_ERROR);
3131 #endif /* DEBUG */
3132 }
3133 }
3134
3135 /*
3136 * Used for properties that come from the OBP, hardware configuration files,
3137 * or that are created by calls to ddi_prop_update(9F).
3138 */
3139 static struct prop_handle_ops prop_1275_ops = {
3140 ddi_prop_1275_int,
3141 ddi_prop_1275_string,
3142 ddi_prop_1275_bytes,
3143 ddi_prop_int64_op
3144 };
3145
3146
3147 /*
3148 * Interface to create/modify a managed property on child's behalf...
3149 * Flags interpreted are:
3150 * DDI_PROP_CANSLEEP: Allow memory allocation to sleep.
3151 * DDI_PROP_SYSTEM_DEF: Manipulate system list rather than driver list.
3152 *
3153 * Use same dev_t when modifying or undefining a property.
3154 * Search for properties with DDI_DEV_T_ANY to match first named
3155 * property on the list.
3156 *
3157 * Properties are stored LIFO and subsequently will match the first
3158 * `matching' instance.
3159 */
3160
3161 /*
3162 * ddi_prop_add: Add a software defined property
3163 */
3164
3165 /*
3166 * define to get a new ddi_prop_t.
3167 * km_flags are KM_SLEEP or KM_NOSLEEP.
3168 */
3169
3170 #define DDI_NEW_PROP_T(km_flags) \
3171 (kmem_zalloc(sizeof (ddi_prop_t), km_flags))
3172
3173 static int
ddi_prop_add(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t value,int length)3174 ddi_prop_add(dev_t dev, dev_info_t *dip, int flags,
3175 char *name, caddr_t value, int length)
3176 {
3177 ddi_prop_t *new_propp, *propp;
3178 ddi_prop_t **list_head = &(DEVI(dip)->devi_drv_prop_ptr);
3179 int km_flags = KM_NOSLEEP;
3180 int name_buf_len;
3181
3182 /*
3183 * If dev_t is DDI_DEV_T_ANY or name's length is zero return error.
3184 */
3185
3186 if (dev == DDI_DEV_T_ANY || name == (char *)0 || strlen(name) == 0)
3187 return (DDI_PROP_INVAL_ARG);
3188
3189 if (flags & DDI_PROP_CANSLEEP)
3190 km_flags = KM_SLEEP;
3191
3192 if (flags & DDI_PROP_SYSTEM_DEF)
3193 list_head = &(DEVI(dip)->devi_sys_prop_ptr);
3194 else if (flags & DDI_PROP_HW_DEF)
3195 list_head = &(DEVI(dip)->devi_hw_prop_ptr);
3196
3197 if ((new_propp = DDI_NEW_PROP_T(km_flags)) == NULL) {
3198 cmn_err(CE_CONT, prop_no_mem_msg, name);
3199 return (DDI_PROP_NO_MEMORY);
3200 }
3201
3202 /*
3203 * If dev is major number 0, then we need to do a ddi_name_to_major
3204 * to get the real major number for the device. This needs to be
3205 * done because some drivers need to call ddi_prop_create in their
3206 * attach routines but they don't have a dev. By creating the dev
3207 * ourself if the major number is 0, drivers will not have to know what
3208 * their major number. They can just create a dev with major number
3209 * 0 and pass it in. For device 0, we will be doing a little extra
3210 * work by recreating the same dev that we already have, but its the
3211 * price you pay :-).
3212 *
3213 * This fixes bug #1098060.
3214 */
3215 if (getmajor(dev) == DDI_MAJOR_T_UNKNOWN) {
3216 new_propp->prop_dev =
3217 makedevice(ddi_name_to_major(DEVI(dip)->devi_binding_name),
3218 getminor(dev));
3219 } else
3220 new_propp->prop_dev = dev;
3221
3222 /*
3223 * Allocate space for property name and copy it in...
3224 */
3225
3226 name_buf_len = strlen(name) + 1;
3227 new_propp->prop_name = kmem_alloc(name_buf_len, km_flags);
3228 if (new_propp->prop_name == 0) {
3229 kmem_free(new_propp, sizeof (ddi_prop_t));
3230 cmn_err(CE_CONT, prop_no_mem_msg, name);
3231 return (DDI_PROP_NO_MEMORY);
3232 }
3233 bcopy(name, new_propp->prop_name, name_buf_len);
3234
3235 /*
3236 * Set the property type
3237 */
3238 new_propp->prop_flags = flags & DDI_PROP_TYPE_MASK;
3239
3240 /*
3241 * Set length and value ONLY if not an explicit property undefine:
3242 * NOTE: value and length are zero for explicit undefines.
3243 */
3244
3245 if (flags & DDI_PROP_UNDEF_IT) {
3246 new_propp->prop_flags |= DDI_PROP_UNDEF_IT;
3247 } else {
3248 if ((new_propp->prop_len = length) != 0) {
3249 new_propp->prop_val = kmem_alloc(length, km_flags);
3250 if (new_propp->prop_val == 0) {
3251 kmem_free(new_propp->prop_name, name_buf_len);
3252 kmem_free(new_propp, sizeof (ddi_prop_t));
3253 cmn_err(CE_CONT, prop_no_mem_msg, name);
3254 return (DDI_PROP_NO_MEMORY);
3255 }
3256 bcopy(value, new_propp->prop_val, length);
3257 }
3258 }
3259
3260 /*
3261 * Link property into beginning of list. (Properties are LIFO order.)
3262 */
3263
3264 mutex_enter(&(DEVI(dip)->devi_lock));
3265 propp = *list_head;
3266 new_propp->prop_next = propp;
3267 *list_head = new_propp;
3268 mutex_exit(&(DEVI(dip)->devi_lock));
3269 return (DDI_PROP_SUCCESS);
3270 }
3271
3272
3273 /*
3274 * ddi_prop_change: Modify a software managed property value
3275 *
3276 * Set new length and value if found.
3277 * returns DDI_PROP_INVAL_ARG if dev is DDI_DEV_T_ANY or
3278 * input name is the NULL string.
3279 * returns DDI_PROP_NO_MEMORY if unable to allocate memory
3280 *
3281 * Note: an undef can be modified to be a define,
3282 * (you can't go the other way.)
3283 */
3284
3285 static int
ddi_prop_change(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t value,int length)3286 ddi_prop_change(dev_t dev, dev_info_t *dip, int flags,
3287 char *name, caddr_t value, int length)
3288 {
3289 ddi_prop_t *propp;
3290 ddi_prop_t **ppropp;
3291 caddr_t p = NULL;
3292
3293 if ((dev == DDI_DEV_T_ANY) || (name == NULL) || (strlen(name) == 0))
3294 return (DDI_PROP_INVAL_ARG);
3295
3296 /*
3297 * Preallocate buffer, even if we don't need it...
3298 */
3299 if (length != 0) {
3300 p = kmem_alloc(length, (flags & DDI_PROP_CANSLEEP) ?
3301 KM_SLEEP : KM_NOSLEEP);
3302 if (p == NULL) {
3303 cmn_err(CE_CONT, prop_no_mem_msg, name);
3304 return (DDI_PROP_NO_MEMORY);
3305 }
3306 }
3307
3308 /*
3309 * If the dev_t value contains DDI_MAJOR_T_UNKNOWN for the major
3310 * number, a real dev_t value should be created based upon the dip's
3311 * binding driver. See ddi_prop_add...
3312 */
3313 if (getmajor(dev) == DDI_MAJOR_T_UNKNOWN)
3314 dev = makedevice(
3315 ddi_name_to_major(DEVI(dip)->devi_binding_name),
3316 getminor(dev));
3317
3318 /*
3319 * Check to see if the property exists. If so we modify it.
3320 * Else we create it by calling ddi_prop_add().
3321 */
3322 mutex_enter(&(DEVI(dip)->devi_lock));
3323 ppropp = &DEVI(dip)->devi_drv_prop_ptr;
3324 if (flags & DDI_PROP_SYSTEM_DEF)
3325 ppropp = &DEVI(dip)->devi_sys_prop_ptr;
3326 else if (flags & DDI_PROP_HW_DEF)
3327 ppropp = &DEVI(dip)->devi_hw_prop_ptr;
3328
3329 if ((propp = i_ddi_prop_search(dev, name, flags, ppropp)) != NULL) {
3330 /*
3331 * Need to reallocate buffer? If so, do it
3332 * carefully (reuse same space if new prop
3333 * is same size and non-NULL sized).
3334 */
3335 if (length != 0)
3336 bcopy(value, p, length);
3337
3338 if (propp->prop_len != 0)
3339 kmem_free(propp->prop_val, propp->prop_len);
3340
3341 propp->prop_len = length;
3342 propp->prop_val = p;
3343 propp->prop_flags &= ~DDI_PROP_UNDEF_IT;
3344 mutex_exit(&(DEVI(dip)->devi_lock));
3345 return (DDI_PROP_SUCCESS);
3346 }
3347
3348 mutex_exit(&(DEVI(dip)->devi_lock));
3349 if (length != 0)
3350 kmem_free(p, length);
3351
3352 return (ddi_prop_add(dev, dip, flags, name, value, length));
3353 }
3354
3355 /*
3356 * Common update routine used to update and encode a property. Creates
3357 * a property handle, calls the property encode routine, figures out if
3358 * the property already exists and updates if it does. Otherwise it
3359 * creates if it does not exist.
3360 */
3361 int
ddi_prop_update_common(dev_t match_dev,dev_info_t * dip,int flags,char * name,void * data,uint_t nelements,int (* prop_create)(prop_handle_t *,void * data,uint_t nelements))3362 ddi_prop_update_common(dev_t match_dev, dev_info_t *dip, int flags,
3363 char *name, void *data, uint_t nelements,
3364 int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
3365 {
3366 prop_handle_t ph;
3367 int rval;
3368 uint_t ourflags;
3369
3370 /*
3371 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3372 * return error.
3373 */
3374 if (match_dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3375 return (DDI_PROP_INVAL_ARG);
3376
3377 /*
3378 * Create the handle
3379 */
3380 ph.ph_data = NULL;
3381 ph.ph_cur_pos = NULL;
3382 ph.ph_save_pos = NULL;
3383 ph.ph_size = 0;
3384 ph.ph_ops = &prop_1275_ops;
3385
3386 /*
3387 * ourflags:
3388 * For compatibility with the old interfaces. The old interfaces
3389 * didn't sleep by default and slept when the flag was set. These
3390 * interfaces to the opposite. So the old interfaces now set the
3391 * DDI_PROP_DONTSLEEP flag by default which tells us not to sleep.
3392 *
3393 * ph.ph_flags:
3394 * Blocked data or unblocked data allocation
3395 * for ph.ph_data in ddi_prop_encode_alloc()
3396 */
3397 if (flags & DDI_PROP_DONTSLEEP) {
3398 ourflags = flags;
3399 ph.ph_flags = DDI_PROP_DONTSLEEP;
3400 } else {
3401 ourflags = flags | DDI_PROP_CANSLEEP;
3402 ph.ph_flags = DDI_PROP_CANSLEEP;
3403 }
3404
3405 /*
3406 * Encode the data and store it in the property handle by
3407 * calling the prop_encode routine.
3408 */
3409 if ((rval = (*prop_create)(&ph, data, nelements)) !=
3410 DDI_PROP_SUCCESS) {
3411 if (rval == DDI_PROP_NO_MEMORY)
3412 cmn_err(CE_CONT, prop_no_mem_msg, name);
3413 if (ph.ph_size != 0)
3414 kmem_free(ph.ph_data, ph.ph_size);
3415 return (rval);
3416 }
3417
3418 /*
3419 * The old interfaces use a stacking approach to creating
3420 * properties. If we are being called from the old interfaces,
3421 * the DDI_PROP_STACK_CREATE flag will be set, so we just do a
3422 * create without checking.
3423 */
3424 if (flags & DDI_PROP_STACK_CREATE) {
3425 rval = ddi_prop_add(match_dev, dip,
3426 ourflags, name, ph.ph_data, ph.ph_size);
3427 } else {
3428 rval = ddi_prop_change(match_dev, dip,
3429 ourflags, name, ph.ph_data, ph.ph_size);
3430 }
3431
3432 /*
3433 * Free the encoded data allocated in the prop_encode routine.
3434 */
3435 if (ph.ph_size != 0)
3436 kmem_free(ph.ph_data, ph.ph_size);
3437
3438 return (rval);
3439 }
3440
3441
3442 /*
3443 * ddi_prop_create: Define a managed property:
3444 * See above for details.
3445 */
3446
3447 int
ddi_prop_create(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)3448 ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
3449 char *name, caddr_t value, int length)
3450 {
3451 if (!(flag & DDI_PROP_CANSLEEP)) {
3452 flag |= DDI_PROP_DONTSLEEP;
3453 #ifdef DDI_PROP_DEBUG
3454 if (length != 0)
3455 cmn_err(CE_NOTE, "!ddi_prop_create: interface obsolete,"
3456 "use ddi_prop_update (prop = %s, node = %s%d)",
3457 name, ddi_driver_name(dip), ddi_get_instance(dip));
3458 #endif /* DDI_PROP_DEBUG */
3459 }
3460 flag &= ~DDI_PROP_SYSTEM_DEF;
3461 flag |= DDI_PROP_STACK_CREATE | DDI_PROP_TYPE_ANY;
3462 return (ddi_prop_update_common(dev, dip, flag, name,
3463 value, length, ddi_prop_fm_encode_bytes));
3464 }
3465
3466 int
e_ddi_prop_create(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)3467 e_ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
3468 char *name, caddr_t value, int length)
3469 {
3470 if (!(flag & DDI_PROP_CANSLEEP))
3471 flag |= DDI_PROP_DONTSLEEP;
3472 flag |= DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE | DDI_PROP_TYPE_ANY;
3473 return (ddi_prop_update_common(dev, dip, flag,
3474 name, value, length, ddi_prop_fm_encode_bytes));
3475 }
3476
3477 int
ddi_prop_modify(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)3478 ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
3479 char *name, caddr_t value, int length)
3480 {
3481 ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
3482
3483 /*
3484 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3485 * return error.
3486 */
3487 if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3488 return (DDI_PROP_INVAL_ARG);
3489
3490 if (!(flag & DDI_PROP_CANSLEEP))
3491 flag |= DDI_PROP_DONTSLEEP;
3492 flag &= ~DDI_PROP_SYSTEM_DEF;
3493 if (ddi_prop_exists(dev, dip, (flag | DDI_PROP_NOTPROM), name) == 0)
3494 return (DDI_PROP_NOT_FOUND);
3495
3496 return (ddi_prop_update_common(dev, dip,
3497 (flag | DDI_PROP_TYPE_BYTE), name,
3498 value, length, ddi_prop_fm_encode_bytes));
3499 }
3500
3501 int
e_ddi_prop_modify(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)3502 e_ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
3503 char *name, caddr_t value, int length)
3504 {
3505 ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
3506
3507 /*
3508 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3509 * return error.
3510 */
3511 if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3512 return (DDI_PROP_INVAL_ARG);
3513
3514 if (ddi_prop_exists(dev, dip, (flag | DDI_PROP_SYSTEM_DEF), name) == 0)
3515 return (DDI_PROP_NOT_FOUND);
3516
3517 if (!(flag & DDI_PROP_CANSLEEP))
3518 flag |= DDI_PROP_DONTSLEEP;
3519 return (ddi_prop_update_common(dev, dip,
3520 (flag | DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE),
3521 name, value, length, ddi_prop_fm_encode_bytes));
3522 }
3523
3524
3525 /*
3526 * Common lookup routine used to lookup and decode a property.
3527 * Creates a property handle, searches for the raw encoded data,
3528 * fills in the handle, and calls the property decode functions
3529 * passed in.
3530 *
3531 * This routine is not static because ddi_bus_prop_op() which lives in
3532 * ddi_impl.c calls it. No driver should be calling this routine.
3533 */
3534 int
ddi_prop_lookup_common(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,void * data,uint_t * nelements,int (* prop_decoder)(prop_handle_t *,void * data,uint_t * nelements))3535 ddi_prop_lookup_common(dev_t match_dev, dev_info_t *dip,
3536 uint_t flags, char *name, void *data, uint_t *nelements,
3537 int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
3538 {
3539 int rval;
3540 uint_t ourflags;
3541 prop_handle_t ph;
3542
3543 if ((match_dev == DDI_DEV_T_NONE) ||
3544 (name == NULL) || (strlen(name) == 0))
3545 return (DDI_PROP_INVAL_ARG);
3546
3547 ourflags = (flags & DDI_PROP_DONTSLEEP) ? flags :
3548 flags | DDI_PROP_CANSLEEP;
3549
3550 /*
3551 * Get the encoded data
3552 */
3553 bzero(&ph, sizeof (prop_handle_t));
3554
3555 if ((flags & DDI_UNBND_DLPI2) || (flags & DDI_PROP_ROOTNEX_GLOBAL)) {
3556 /*
3557 * For rootnex and unbound dlpi style-2 devices, index into
3558 * the devnames' array and search the global
3559 * property list.
3560 */
3561 ourflags &= ~DDI_UNBND_DLPI2;
3562 rval = i_ddi_prop_search_global(match_dev,
3563 ourflags, name, &ph.ph_data, &ph.ph_size);
3564 } else {
3565 rval = ddi_prop_search_common(match_dev, dip,
3566 PROP_LEN_AND_VAL_ALLOC, ourflags, name,
3567 &ph.ph_data, &ph.ph_size);
3568
3569 }
3570
3571 if (rval != DDI_PROP_SUCCESS && rval != DDI_PROP_FOUND_1275) {
3572 ASSERT(ph.ph_data == NULL);
3573 ASSERT(ph.ph_size == 0);
3574 return (rval);
3575 }
3576
3577 /*
3578 * If the encoded data came from a OBP or software
3579 * use the 1275 OBP decode/encode routines.
3580 */
3581 ph.ph_cur_pos = ph.ph_data;
3582 ph.ph_save_pos = ph.ph_data;
3583 ph.ph_ops = &prop_1275_ops;
3584 ph.ph_flags = (rval == DDI_PROP_FOUND_1275) ? PH_FROM_PROM : 0;
3585
3586 rval = (*prop_decoder)(&ph, data, nelements);
3587
3588 /*
3589 * Free the encoded data
3590 */
3591 if (ph.ph_size != 0)
3592 kmem_free(ph.ph_data, ph.ph_size);
3593
3594 return (rval);
3595 }
3596
3597 /*
3598 * Lookup and return an array of composite properties. The driver must
3599 * provide the decode routine.
3600 */
3601 int
ddi_prop_lookup(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,void * data,uint_t * nelements,int (* prop_decoder)(prop_handle_t *,void * data,uint_t * nelements))3602 ddi_prop_lookup(dev_t match_dev, dev_info_t *dip,
3603 uint_t flags, char *name, void *data, uint_t *nelements,
3604 int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
3605 {
3606 return (ddi_prop_lookup_common(match_dev, dip,
3607 (flags | DDI_PROP_TYPE_COMPOSITE), name,
3608 data, nelements, prop_decoder));
3609 }
3610
3611 /*
3612 * Return 1 if a property exists (no type checking done).
3613 * Return 0 if it does not exist.
3614 */
3615 int
ddi_prop_exists(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name)3616 ddi_prop_exists(dev_t match_dev, dev_info_t *dip, uint_t flags, char *name)
3617 {
3618 int i;
3619 uint_t x = 0;
3620
3621 i = ddi_prop_search_common(match_dev, dip, PROP_EXISTS,
3622 flags | DDI_PROP_TYPE_MASK, name, NULL, &x);
3623 return (i == DDI_PROP_SUCCESS || i == DDI_PROP_FOUND_1275);
3624 }
3625
3626
3627 /*
3628 * Update an array of composite properties. The driver must
3629 * provide the encode routine.
3630 */
3631 int
ddi_prop_update(dev_t match_dev,dev_info_t * dip,char * name,void * data,uint_t nelements,int (* prop_create)(prop_handle_t *,void * data,uint_t nelements))3632 ddi_prop_update(dev_t match_dev, dev_info_t *dip,
3633 char *name, void *data, uint_t nelements,
3634 int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
3635 {
3636 return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_COMPOSITE,
3637 name, data, nelements, prop_create));
3638 }
3639
3640 /*
3641 * Get a single integer or boolean property and return it.
3642 * If the property does not exists, or cannot be decoded,
3643 * then return the defvalue passed in.
3644 *
3645 * This routine always succeeds.
3646 */
3647 int
ddi_prop_get_int(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int defvalue)3648 ddi_prop_get_int(dev_t match_dev, dev_info_t *dip, uint_t flags,
3649 char *name, int defvalue)
3650 {
3651 int data;
3652 uint_t nelements;
3653 int rval;
3654
3655 if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3656 LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
3657 #ifdef DEBUG
3658 if (dip != NULL) {
3659 cmn_err(CE_WARN, "ddi_prop_get_int: invalid flag"
3660 " 0x%x (prop = %s, node = %s%d)", flags,
3661 name, ddi_driver_name(dip), ddi_get_instance(dip));
3662 }
3663 #endif /* DEBUG */
3664 flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3665 LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
3666 }
3667
3668 if ((rval = ddi_prop_lookup_common(match_dev, dip,
3669 (flags | DDI_PROP_TYPE_INT), name, &data, &nelements,
3670 ddi_prop_fm_decode_int)) != DDI_PROP_SUCCESS) {
3671 if (rval == DDI_PROP_END_OF_DATA)
3672 data = 1;
3673 else
3674 data = defvalue;
3675 }
3676 return (data);
3677 }
3678
3679 /*
3680 * Get a single 64 bit integer or boolean property and return it.
3681 * If the property does not exists, or cannot be decoded,
3682 * then return the defvalue passed in.
3683 *
3684 * This routine always succeeds.
3685 */
3686 int64_t
ddi_prop_get_int64(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int64_t defvalue)3687 ddi_prop_get_int64(dev_t match_dev, dev_info_t *dip, uint_t flags,
3688 char *name, int64_t defvalue)
3689 {
3690 int64_t data;
3691 uint_t nelements;
3692 int rval;
3693
3694 if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3695 LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
3696 #ifdef DEBUG
3697 if (dip != NULL) {
3698 cmn_err(CE_WARN, "ddi_prop_get_int64: invalid flag"
3699 " 0x%x (prop = %s, node = %s%d)", flags,
3700 name, ddi_driver_name(dip), ddi_get_instance(dip));
3701 }
3702 #endif /* DEBUG */
3703 return (DDI_PROP_INVAL_ARG);
3704 }
3705
3706 if ((rval = ddi_prop_lookup_common(match_dev, dip,
3707 (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
3708 name, &data, &nelements, ddi_prop_fm_decode_int64))
3709 != DDI_PROP_SUCCESS) {
3710 if (rval == DDI_PROP_END_OF_DATA)
3711 data = 1;
3712 else
3713 data = defvalue;
3714 }
3715 return (data);
3716 }
3717
3718 /*
3719 * Get an array of integer property
3720 */
3721 int
ddi_prop_lookup_int_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int ** data,uint_t * nelements)3722 ddi_prop_lookup_int_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
3723 char *name, int **data, uint_t *nelements)
3724 {
3725 if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3726 LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
3727 #ifdef DEBUG
3728 if (dip != NULL) {
3729 cmn_err(CE_WARN, "ddi_prop_lookup_int_array: "
3730 "invalid flag 0x%x (prop = %s, node = %s%d)",
3731 flags, name, ddi_driver_name(dip),
3732 ddi_get_instance(dip));
3733 }
3734 #endif /* DEBUG */
3735 flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3736 LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
3737 }
3738
3739 return (ddi_prop_lookup_common(match_dev, dip,
3740 (flags | DDI_PROP_TYPE_INT), name, data,
3741 nelements, ddi_prop_fm_decode_ints));
3742 }
3743
3744 /*
3745 * Get an array of 64 bit integer properties
3746 */
3747 int
ddi_prop_lookup_int64_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int64_t ** data,uint_t * nelements)3748 ddi_prop_lookup_int64_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
3749 char *name, int64_t **data, uint_t *nelements)
3750 {
3751 if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3752 LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
3753 #ifdef DEBUG
3754 if (dip != NULL) {
3755 cmn_err(CE_WARN, "ddi_prop_lookup_int64_array: "
3756 "invalid flag 0x%x (prop = %s, node = %s%d)",
3757 flags, name, ddi_driver_name(dip),
3758 ddi_get_instance(dip));
3759 }
3760 #endif /* DEBUG */
3761 return (DDI_PROP_INVAL_ARG);
3762 }
3763
3764 return (ddi_prop_lookup_common(match_dev, dip,
3765 (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
3766 name, data, nelements, ddi_prop_fm_decode_int64_array));
3767 }
3768
3769 /*
3770 * Update a single integer property. If the property exists on the drivers
3771 * property list it updates, else it creates it.
3772 */
3773 int
ddi_prop_update_int(dev_t match_dev,dev_info_t * dip,char * name,int data)3774 ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
3775 char *name, int data)
3776 {
3777 return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
3778 name, &data, 1, ddi_prop_fm_encode_ints));
3779 }
3780
3781 /*
3782 * Update a single 64 bit integer property.
3783 * Update the driver property list if it exists, else create it.
3784 */
3785 int
ddi_prop_update_int64(dev_t match_dev,dev_info_t * dip,char * name,int64_t data)3786 ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
3787 char *name, int64_t data)
3788 {
3789 return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
3790 name, &data, 1, ddi_prop_fm_encode_int64));
3791 }
3792
3793 int
e_ddi_prop_update_int(dev_t match_dev,dev_info_t * dip,char * name,int data)3794 e_ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
3795 char *name, int data)
3796 {
3797 return (ddi_prop_update_common(match_dev, dip,
3798 DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
3799 name, &data, 1, ddi_prop_fm_encode_ints));
3800 }
3801
3802 int
e_ddi_prop_update_int64(dev_t match_dev,dev_info_t * dip,char * name,int64_t data)3803 e_ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
3804 char *name, int64_t data)
3805 {
3806 return (ddi_prop_update_common(match_dev, dip,
3807 DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
3808 name, &data, 1, ddi_prop_fm_encode_int64));
3809 }
3810
3811 /*
3812 * Update an array of integer property. If the property exists on the drivers
3813 * property list it updates, else it creates it.
3814 */
3815 int
ddi_prop_update_int_array(dev_t match_dev,dev_info_t * dip,char * name,int * data,uint_t nelements)3816 ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
3817 char *name, int *data, uint_t nelements)
3818 {
3819 return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
3820 name, data, nelements, ddi_prop_fm_encode_ints));
3821 }
3822
3823 /*
3824 * Update an array of 64 bit integer properties.
3825 * Update the driver property list if it exists, else create it.
3826 */
3827 int
ddi_prop_update_int64_array(dev_t match_dev,dev_info_t * dip,char * name,int64_t * data,uint_t nelements)3828 ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
3829 char *name, int64_t *data, uint_t nelements)
3830 {
3831 return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
3832 name, data, nelements, ddi_prop_fm_encode_int64));
3833 }
3834
3835 int
e_ddi_prop_update_int64_array(dev_t match_dev,dev_info_t * dip,char * name,int64_t * data,uint_t nelements)3836 e_ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
3837 char *name, int64_t *data, uint_t nelements)
3838 {
3839 return (ddi_prop_update_common(match_dev, dip,
3840 DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
3841 name, data, nelements, ddi_prop_fm_encode_int64));
3842 }
3843
3844 int
e_ddi_prop_update_int_array(dev_t match_dev,dev_info_t * dip,char * name,int * data,uint_t nelements)3845 e_ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
3846 char *name, int *data, uint_t nelements)
3847 {
3848 return (ddi_prop_update_common(match_dev, dip,
3849 DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
3850 name, data, nelements, ddi_prop_fm_encode_ints));
3851 }
3852
3853 /*
3854 * Get a single string property.
3855 */
3856 int
ddi_prop_lookup_string(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,char ** data)3857 ddi_prop_lookup_string(dev_t match_dev, dev_info_t *dip, uint_t flags,
3858 char *name, char **data)
3859 {
3860 uint_t x;
3861
3862 if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3863 LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
3864 #ifdef DEBUG
3865 if (dip != NULL) {
3866 cmn_err(CE_WARN, "%s: invalid flag 0x%x "
3867 "(prop = %s, node = %s%d); invalid bits ignored",
3868 "ddi_prop_lookup_string", flags, name,
3869 ddi_driver_name(dip), ddi_get_instance(dip));
3870 }
3871 #endif /* DEBUG */
3872 flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3873 LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
3874 }
3875
3876 return (ddi_prop_lookup_common(match_dev, dip,
3877 (flags | DDI_PROP_TYPE_STRING), name, data,
3878 &x, ddi_prop_fm_decode_string));
3879 }
3880
3881 /*
3882 * Get an array of strings property.
3883 */
3884 int
ddi_prop_lookup_string_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,char *** data,uint_t * nelements)3885 ddi_prop_lookup_string_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
3886 char *name, char ***data, uint_t *nelements)
3887 {
3888 if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3889 LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
3890 #ifdef DEBUG
3891 if (dip != NULL) {
3892 cmn_err(CE_WARN, "ddi_prop_lookup_string_array: "
3893 "invalid flag 0x%x (prop = %s, node = %s%d)",
3894 flags, name, ddi_driver_name(dip),
3895 ddi_get_instance(dip));
3896 }
3897 #endif /* DEBUG */
3898 flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3899 LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
3900 }
3901
3902 return (ddi_prop_lookup_common(match_dev, dip,
3903 (flags | DDI_PROP_TYPE_STRING), name, data,
3904 nelements, ddi_prop_fm_decode_strings));
3905 }
3906
3907 /*
3908 * Update a single string property.
3909 */
3910 int
ddi_prop_update_string(dev_t match_dev,dev_info_t * dip,char * name,char * data)3911 ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
3912 char *name, char *data)
3913 {
3914 return (ddi_prop_update_common(match_dev, dip,
3915 DDI_PROP_TYPE_STRING, name, &data, 1,
3916 ddi_prop_fm_encode_string));
3917 }
3918
3919 int
e_ddi_prop_update_string(dev_t match_dev,dev_info_t * dip,char * name,char * data)3920 e_ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
3921 char *name, char *data)
3922 {
3923 return (ddi_prop_update_common(match_dev, dip,
3924 DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
3925 name, &data, 1, ddi_prop_fm_encode_string));
3926 }
3927
3928
3929 /*
3930 * Update an array of strings property.
3931 */
3932 int
ddi_prop_update_string_array(dev_t match_dev,dev_info_t * dip,char * name,char ** data,uint_t nelements)3933 ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
3934 char *name, char **data, uint_t nelements)
3935 {
3936 return (ddi_prop_update_common(match_dev, dip,
3937 DDI_PROP_TYPE_STRING, name, data, nelements,
3938 ddi_prop_fm_encode_strings));
3939 }
3940
3941 int
e_ddi_prop_update_string_array(dev_t match_dev,dev_info_t * dip,char * name,char ** data,uint_t nelements)3942 e_ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
3943 char *name, char **data, uint_t nelements)
3944 {
3945 return (ddi_prop_update_common(match_dev, dip,
3946 DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
3947 name, data, nelements,
3948 ddi_prop_fm_encode_strings));
3949 }
3950
3951
3952 /*
3953 * Get an array of bytes property.
3954 */
3955 int
ddi_prop_lookup_byte_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,uchar_t ** data,uint_t * nelements)3956 ddi_prop_lookup_byte_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
3957 char *name, uchar_t **data, uint_t *nelements)
3958 {
3959 if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3960 LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
3961 #ifdef DEBUG
3962 if (dip != NULL) {
3963 cmn_err(CE_WARN, "ddi_prop_lookup_byte_array: "
3964 " invalid flag 0x%x (prop = %s, node = %s%d)",
3965 flags, name, ddi_driver_name(dip),
3966 ddi_get_instance(dip));
3967 }
3968 #endif /* DEBUG */
3969 flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
3970 LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
3971 }
3972
3973 return (ddi_prop_lookup_common(match_dev, dip,
3974 (flags | DDI_PROP_TYPE_BYTE), name, data,
3975 nelements, ddi_prop_fm_decode_bytes));
3976 }
3977
3978 /*
3979 * Update an array of bytes property.
3980 */
3981 int
ddi_prop_update_byte_array(dev_t match_dev,dev_info_t * dip,char * name,uchar_t * data,uint_t nelements)3982 ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
3983 char *name, uchar_t *data, uint_t nelements)
3984 {
3985 if (nelements == 0)
3986 return (DDI_PROP_INVAL_ARG);
3987
3988 return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_BYTE,
3989 name, data, nelements, ddi_prop_fm_encode_bytes));
3990 }
3991
3992
3993 int
e_ddi_prop_update_byte_array(dev_t match_dev,dev_info_t * dip,char * name,uchar_t * data,uint_t nelements)3994 e_ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
3995 char *name, uchar_t *data, uint_t nelements)
3996 {
3997 if (nelements == 0)
3998 return (DDI_PROP_INVAL_ARG);
3999
4000 return (ddi_prop_update_common(match_dev, dip,
4001 DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE,
4002 name, data, nelements, ddi_prop_fm_encode_bytes));
4003 }
4004
4005
4006 /*
4007 * ddi_prop_remove_common: Undefine a managed property:
4008 * Input dev_t must match dev_t when defined.
4009 * Returns DDI_PROP_NOT_FOUND, possibly.
4010 * DDI_PROP_INVAL_ARG is also possible if dev is
4011 * DDI_DEV_T_ANY or incoming name is the NULL string.
4012 */
4013 int
ddi_prop_remove_common(dev_t dev,dev_info_t * dip,char * name,int flag)4014 ddi_prop_remove_common(dev_t dev, dev_info_t *dip, char *name, int flag)
4015 {
4016 ddi_prop_t **list_head = &(DEVI(dip)->devi_drv_prop_ptr);
4017 ddi_prop_t *propp;
4018 ddi_prop_t *lastpropp = NULL;
4019
4020 if ((dev == DDI_DEV_T_ANY) || (name == (char *)0) ||
4021 (strlen(name) == 0)) {
4022 return (DDI_PROP_INVAL_ARG);
4023 }
4024
4025 if (flag & DDI_PROP_SYSTEM_DEF)
4026 list_head = &(DEVI(dip)->devi_sys_prop_ptr);
4027 else if (flag & DDI_PROP_HW_DEF)
4028 list_head = &(DEVI(dip)->devi_hw_prop_ptr);
4029
4030 mutex_enter(&(DEVI(dip)->devi_lock));
4031
4032 for (propp = *list_head; propp != NULL; propp = propp->prop_next) {
4033 if (DDI_STRSAME(propp->prop_name, name) &&
4034 (dev == propp->prop_dev)) {
4035 /*
4036 * Unlink this propp allowing for it to
4037 * be first in the list:
4038 */
4039
4040 if (lastpropp == NULL)
4041 *list_head = propp->prop_next;
4042 else
4043 lastpropp->prop_next = propp->prop_next;
4044
4045 mutex_exit(&(DEVI(dip)->devi_lock));
4046
4047 /*
4048 * Free memory and return...
4049 */
4050 kmem_free(propp->prop_name,
4051 strlen(propp->prop_name) + 1);
4052 if (propp->prop_len != 0)
4053 kmem_free(propp->prop_val, propp->prop_len);
4054 kmem_free(propp, sizeof (ddi_prop_t));
4055 return (DDI_PROP_SUCCESS);
4056 }
4057 lastpropp = propp;
4058 }
4059 mutex_exit(&(DEVI(dip)->devi_lock));
4060 return (DDI_PROP_NOT_FOUND);
4061 }
4062
4063 int
ddi_prop_remove(dev_t dev,dev_info_t * dip,char * name)4064 ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
4065 {
4066 return (ddi_prop_remove_common(dev, dip, name, 0));
4067 }
4068
4069 int
e_ddi_prop_remove(dev_t dev,dev_info_t * dip,char * name)4070 e_ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
4071 {
4072 return (ddi_prop_remove_common(dev, dip, name, DDI_PROP_SYSTEM_DEF));
4073 }
4074
4075 /*
4076 * e_ddi_prop_list_delete: remove a list of properties
4077 * Note that the caller needs to provide the required protection
4078 * (eg. devi_lock if these properties are still attached to a devi)
4079 */
4080 void
e_ddi_prop_list_delete(ddi_prop_t * props)4081 e_ddi_prop_list_delete(ddi_prop_t *props)
4082 {
4083 i_ddi_prop_list_delete(props);
4084 }
4085
4086 /*
4087 * ddi_prop_remove_all_common:
4088 * Used before unloading a driver to remove
4089 * all properties. (undefines all dev_t's props.)
4090 * Also removes `explicitly undefined' props.
4091 * No errors possible.
4092 */
4093 void
ddi_prop_remove_all_common(dev_info_t * dip,int flag)4094 ddi_prop_remove_all_common(dev_info_t *dip, int flag)
4095 {
4096 ddi_prop_t **list_head;
4097
4098 mutex_enter(&(DEVI(dip)->devi_lock));
4099 if (flag & DDI_PROP_SYSTEM_DEF) {
4100 list_head = &(DEVI(dip)->devi_sys_prop_ptr);
4101 } else if (flag & DDI_PROP_HW_DEF) {
4102 list_head = &(DEVI(dip)->devi_hw_prop_ptr);
4103 } else {
4104 list_head = &(DEVI(dip)->devi_drv_prop_ptr);
4105 }
4106 i_ddi_prop_list_delete(*list_head);
4107 *list_head = NULL;
4108 mutex_exit(&(DEVI(dip)->devi_lock));
4109 }
4110
4111
4112 /*
4113 * ddi_prop_remove_all: Remove all driver prop definitions.
4114 */
4115
4116 void
ddi_prop_remove_all(dev_info_t * dip)4117 ddi_prop_remove_all(dev_info_t *dip)
4118 {
4119 i_ddi_prop_dyn_driver_set(dip, NULL);
4120 ddi_prop_remove_all_common(dip, 0);
4121 }
4122
4123 /*
4124 * e_ddi_prop_remove_all: Remove all system prop definitions.
4125 */
4126
4127 void
e_ddi_prop_remove_all(dev_info_t * dip)4128 e_ddi_prop_remove_all(dev_info_t *dip)
4129 {
4130 ddi_prop_remove_all_common(dip, (int)DDI_PROP_SYSTEM_DEF);
4131 }
4132
4133
4134 /*
4135 * ddi_prop_undefine: Explicitly undefine a property. Property
4136 * searches which match this property return
4137 * the error code DDI_PROP_UNDEFINED.
4138 *
4139 * Use ddi_prop_remove to negate effect of
4140 * ddi_prop_undefine
4141 *
4142 * See above for error returns.
4143 */
4144
4145 int
ddi_prop_undefine(dev_t dev,dev_info_t * dip,int flag,char * name)4146 ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
4147 {
4148 if (!(flag & DDI_PROP_CANSLEEP))
4149 flag |= DDI_PROP_DONTSLEEP;
4150 flag |= DDI_PROP_STACK_CREATE | DDI_PROP_UNDEF_IT | DDI_PROP_TYPE_ANY;
4151 return (ddi_prop_update_common(dev, dip, flag,
4152 name, NULL, 0, ddi_prop_fm_encode_bytes));
4153 }
4154
4155 int
e_ddi_prop_undefine(dev_t dev,dev_info_t * dip,int flag,char * name)4156 e_ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
4157 {
4158 if (!(flag & DDI_PROP_CANSLEEP))
4159 flag |= DDI_PROP_DONTSLEEP;
4160 flag |= DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE |
4161 DDI_PROP_UNDEF_IT | DDI_PROP_TYPE_ANY;
4162 return (ddi_prop_update_common(dev, dip, flag,
4163 name, NULL, 0, ddi_prop_fm_encode_bytes));
4164 }
4165
4166 /*
4167 * Support for gathering dynamic properties in devinfo snapshot.
4168 */
4169 void
i_ddi_prop_dyn_driver_set(dev_info_t * dip,i_ddi_prop_dyn_t * dp)4170 i_ddi_prop_dyn_driver_set(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
4171 {
4172 DEVI(dip)->devi_prop_dyn_driver = dp;
4173 }
4174
4175 i_ddi_prop_dyn_t *
i_ddi_prop_dyn_driver_get(dev_info_t * dip)4176 i_ddi_prop_dyn_driver_get(dev_info_t *dip)
4177 {
4178 return (DEVI(dip)->devi_prop_dyn_driver);
4179 }
4180
4181 void
i_ddi_prop_dyn_parent_set(dev_info_t * dip,i_ddi_prop_dyn_t * dp)4182 i_ddi_prop_dyn_parent_set(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
4183 {
4184 DEVI(dip)->devi_prop_dyn_parent = dp;
4185 }
4186
4187 i_ddi_prop_dyn_t *
i_ddi_prop_dyn_parent_get(dev_info_t * dip)4188 i_ddi_prop_dyn_parent_get(dev_info_t *dip)
4189 {
4190 return (DEVI(dip)->devi_prop_dyn_parent);
4191 }
4192
4193 void
i_ddi_prop_dyn_cache_invalidate(dev_info_t * dip,i_ddi_prop_dyn_t * dp)4194 i_ddi_prop_dyn_cache_invalidate(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
4195 {
4196 /* for now we invalidate the entire cached snapshot */
4197 if (dip && dp)
4198 i_ddi_di_cache_invalidate();
4199 }
4200
4201 /* ARGSUSED */
4202 void
ddi_prop_cache_invalidate(dev_t dev,dev_info_t * dip,char * name,int flags)4203 ddi_prop_cache_invalidate(dev_t dev, dev_info_t *dip, char *name, int flags)
4204 {
4205 /* for now we invalidate the entire cached snapshot */
4206 i_ddi_di_cache_invalidate();
4207 }
4208
4209
4210 /*
4211 * Code to search hardware layer (PROM), if it exists, on behalf of child.
4212 *
4213 * if input dip != child_dip, then call is on behalf of child
4214 * to search PROM, do it via ddi_prop_search_common() and ascend only
4215 * if allowed.
4216 *
4217 * if input dip == ch_dip (child_dip), call is on behalf of root driver,
4218 * to search for PROM defined props only.
4219 *
4220 * Note that the PROM search is done only if the requested dev
4221 * is either DDI_DEV_T_ANY or DDI_DEV_T_NONE. PROM properties
4222 * have no associated dev, thus are automatically associated with
4223 * DDI_DEV_T_NONE.
4224 *
4225 * Modifying flag DDI_PROP_NOTPROM inhibits the search in the h/w layer.
4226 *
4227 * Returns DDI_PROP_FOUND_1275 if found to indicate to framework
4228 * that the property resides in the prom.
4229 */
4230 int
impl_ddi_bus_prop_op(dev_t dev,dev_info_t * dip,dev_info_t * ch_dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)4231 impl_ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
4232 ddi_prop_op_t prop_op, int mod_flags,
4233 char *name, caddr_t valuep, int *lengthp)
4234 {
4235 int len;
4236 caddr_t buffer = NULL;
4237
4238 /*
4239 * If requested dev is DDI_DEV_T_NONE or DDI_DEV_T_ANY, then
4240 * look in caller's PROM if it's a self identifying device...
4241 *
4242 * Note that this is very similar to ddi_prop_op, but we
4243 * search the PROM instead of the s/w defined properties,
4244 * and we are called on by the parent driver to do this for
4245 * the child.
4246 */
4247
4248 if (((dev == DDI_DEV_T_NONE) || (dev == DDI_DEV_T_ANY)) &&
4249 ndi_dev_is_prom_node(ch_dip) &&
4250 ((mod_flags & DDI_PROP_NOTPROM) == 0)) {
4251 len = prom_getproplen((pnode_t)DEVI(ch_dip)->devi_nodeid, name);
4252 if (len == -1) {
4253 return (DDI_PROP_NOT_FOUND);
4254 }
4255
4256 /*
4257 * If exists only request, we're done
4258 */
4259 if (prop_op == PROP_EXISTS) {
4260 return (DDI_PROP_FOUND_1275);
4261 }
4262
4263 /*
4264 * If length only request or prop length == 0, get out
4265 */
4266 if ((prop_op == PROP_LEN) || (len == 0)) {
4267 *lengthp = len;
4268 return (DDI_PROP_FOUND_1275);
4269 }
4270
4271 /*
4272 * Allocate buffer if required... (either way `buffer'
4273 * is receiving address).
4274 */
4275
4276 switch (prop_op) {
4277
4278 case PROP_LEN_AND_VAL_ALLOC:
4279
4280 buffer = kmem_alloc((size_t)len,
4281 mod_flags & DDI_PROP_CANSLEEP ?
4282 KM_SLEEP : KM_NOSLEEP);
4283 if (buffer == NULL) {
4284 return (DDI_PROP_NO_MEMORY);
4285 }
4286 *(caddr_t *)valuep = buffer;
4287 break;
4288
4289 case PROP_LEN_AND_VAL_BUF:
4290
4291 if (len > (*lengthp)) {
4292 *lengthp = len;
4293 return (DDI_PROP_BUF_TOO_SMALL);
4294 }
4295
4296 buffer = valuep;
4297 break;
4298
4299 default:
4300 break;
4301 }
4302
4303 /*
4304 * Call the PROM function to do the copy.
4305 */
4306 (void) prom_getprop((pnode_t)DEVI(ch_dip)->devi_nodeid,
4307 name, buffer);
4308
4309 *lengthp = len; /* return the actual length to the caller */
4310 (void) impl_fix_props(dip, ch_dip, name, len, buffer);
4311 return (DDI_PROP_FOUND_1275);
4312 }
4313
4314 return (DDI_PROP_NOT_FOUND);
4315 }
4316
4317 /*
4318 * The ddi_bus_prop_op default bus nexus prop op function.
4319 *
4320 * Code to search hardware layer (PROM), if it exists,
4321 * on behalf of child, then, if appropriate, ascend and check
4322 * my own software defined properties...
4323 */
4324 int
ddi_bus_prop_op(dev_t dev,dev_info_t * dip,dev_info_t * ch_dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)4325 ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
4326 ddi_prop_op_t prop_op, int mod_flags,
4327 char *name, caddr_t valuep, int *lengthp)
4328 {
4329 int error;
4330
4331 error = impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op, mod_flags,
4332 name, valuep, lengthp);
4333
4334 if (error == DDI_PROP_SUCCESS || error == DDI_PROP_FOUND_1275 ||
4335 error == DDI_PROP_BUF_TOO_SMALL)
4336 return (error);
4337
4338 if (error == DDI_PROP_NO_MEMORY) {
4339 cmn_err(CE_CONT, prop_no_mem_msg, name);
4340 return (DDI_PROP_NO_MEMORY);
4341 }
4342
4343 /*
4344 * Check the 'options' node as a last resort
4345 */
4346 if ((mod_flags & DDI_PROP_DONTPASS) != 0)
4347 return (DDI_PROP_NOT_FOUND);
4348
4349 if (ch_dip == ddi_root_node()) {
4350 /*
4351 * As a last resort, when we've reached
4352 * the top and still haven't found the
4353 * property, see if the desired property
4354 * is attached to the options node.
4355 *
4356 * The options dip is attached right after boot.
4357 */
4358 ASSERT(options_dip != NULL);
4359 /*
4360 * Force the "don't pass" flag to *just* see
4361 * what the options node has to offer.
4362 */
4363 return (ddi_prop_search_common(dev, options_dip, prop_op,
4364 mod_flags|DDI_PROP_DONTPASS, name, valuep,
4365 (uint_t *)lengthp));
4366 }
4367
4368 /*
4369 * Otherwise, continue search with parent's s/w defined properties...
4370 * NOTE: Using `dip' in following call increments the level.
4371 */
4372
4373 return (ddi_prop_search_common(dev, dip, prop_op, mod_flags,
4374 name, valuep, (uint_t *)lengthp));
4375 }
4376
4377 /*
4378 * External property functions used by other parts of the kernel...
4379 */
4380
4381 /*
4382 * e_ddi_getlongprop: See comments for ddi_get_longprop.
4383 */
4384
4385 int
e_ddi_getlongprop(dev_t dev,vtype_t type,char * name,int flags,caddr_t valuep,int * lengthp)4386 e_ddi_getlongprop(dev_t dev, vtype_t type, char *name, int flags,
4387 caddr_t valuep, int *lengthp)
4388 {
4389 _NOTE(ARGUNUSED(type))
4390 dev_info_t *devi;
4391 ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_ALLOC;
4392 int error;
4393
4394 if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4395 return (DDI_PROP_NOT_FOUND);
4396
4397 error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
4398 ddi_release_devi(devi);
4399 return (error);
4400 }
4401
4402 /*
4403 * e_ddi_getlongprop_buf: See comments for ddi_getlongprop_buf.
4404 */
4405
4406 int
e_ddi_getlongprop_buf(dev_t dev,vtype_t type,char * name,int flags,caddr_t valuep,int * lengthp)4407 e_ddi_getlongprop_buf(dev_t dev, vtype_t type, char *name, int flags,
4408 caddr_t valuep, int *lengthp)
4409 {
4410 _NOTE(ARGUNUSED(type))
4411 dev_info_t *devi;
4412 ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
4413 int error;
4414
4415 if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4416 return (DDI_PROP_NOT_FOUND);
4417
4418 error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
4419 ddi_release_devi(devi);
4420 return (error);
4421 }
4422
4423 /*
4424 * e_ddi_getprop: See comments for ddi_getprop.
4425 */
4426 int
e_ddi_getprop(dev_t dev,vtype_t type,char * name,int flags,int defvalue)4427 e_ddi_getprop(dev_t dev, vtype_t type, char *name, int flags, int defvalue)
4428 {
4429 _NOTE(ARGUNUSED(type))
4430 dev_info_t *devi;
4431 ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
4432 int propvalue = defvalue;
4433 int proplength = sizeof (int);
4434 int error;
4435
4436 if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4437 return (defvalue);
4438
4439 error = cdev_prop_op(dev, devi, prop_op,
4440 flags, name, (caddr_t)&propvalue, &proplength);
4441 ddi_release_devi(devi);
4442
4443 if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
4444 propvalue = 1;
4445
4446 return (propvalue);
4447 }
4448
4449 /*
4450 * e_ddi_getprop_int64:
4451 *
4452 * This is a typed interfaces, but predates typed properties. With the
4453 * introduction of typed properties the framework tries to ensure
4454 * consistent use of typed interfaces. This is why TYPE_INT64 is not
4455 * part of TYPE_ANY. E_ddi_getprop_int64 is a special case where a
4456 * typed interface invokes legacy (non-typed) interfaces:
4457 * cdev_prop_op(), prop_op(9E), ddi_prop_op(9F)). In this case the
4458 * fact that TYPE_INT64 is not part of TYPE_ANY matters. To support
4459 * this type of lookup as a single operation we invoke the legacy
4460 * non-typed interfaces with the special CONSUMER_TYPED bit set. The
4461 * framework ddi_prop_op(9F) implementation is expected to check for
4462 * CONSUMER_TYPED and, if set, expand type bits beyond TYPE_ANY
4463 * (currently TYPE_INT64).
4464 */
4465 int64_t
e_ddi_getprop_int64(dev_t dev,vtype_t type,char * name,int flags,int64_t defvalue)4466 e_ddi_getprop_int64(dev_t dev, vtype_t type, char *name,
4467 int flags, int64_t defvalue)
4468 {
4469 _NOTE(ARGUNUSED(type))
4470 dev_info_t *devi;
4471 ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
4472 int64_t propvalue = defvalue;
4473 int proplength = sizeof (propvalue);
4474 int error;
4475
4476 if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4477 return (defvalue);
4478
4479 error = cdev_prop_op(dev, devi, prop_op, flags |
4480 DDI_PROP_CONSUMER_TYPED, name, (caddr_t)&propvalue, &proplength);
4481 ddi_release_devi(devi);
4482
4483 if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
4484 propvalue = 1;
4485
4486 return (propvalue);
4487 }
4488
4489 /*
4490 * e_ddi_getproplen: See comments for ddi_getproplen.
4491 */
4492 int
e_ddi_getproplen(dev_t dev,vtype_t type,char * name,int flags,int * lengthp)4493 e_ddi_getproplen(dev_t dev, vtype_t type, char *name, int flags, int *lengthp)
4494 {
4495 _NOTE(ARGUNUSED(type))
4496 dev_info_t *devi;
4497 ddi_prop_op_t prop_op = PROP_LEN;
4498 int error;
4499
4500 if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4501 return (DDI_PROP_NOT_FOUND);
4502
4503 error = cdev_prop_op(dev, devi, prop_op, flags, name, NULL, lengthp);
4504 ddi_release_devi(devi);
4505 return (error);
4506 }
4507
4508 /*
4509 * Routines to get at elements of the dev_info structure
4510 */
4511
4512 /*
4513 * ddi_binding_name: Return the driver binding name of the devinfo node
4514 * This is the name the OS used to bind the node to a driver.
4515 */
4516 char *
ddi_binding_name(dev_info_t * dip)4517 ddi_binding_name(dev_info_t *dip)
4518 {
4519 return (DEVI(dip)->devi_binding_name);
4520 }
4521
4522 /*
4523 * ddi_driver_major: Return the major number of the driver that
4524 * the supplied devinfo is bound to. If not yet bound,
4525 * DDI_MAJOR_T_NONE.
4526 *
4527 * When used by the driver bound to 'devi', this
4528 * function will reliably return the driver major number.
4529 * Other ways of determining the driver major number, such as
4530 * major = ddi_name_to_major(ddi_get_name(devi));
4531 * major = ddi_name_to_major(ddi_binding_name(devi));
4532 * can return a different result as the driver/alias binding
4533 * can change dynamically, and thus should be avoided.
4534 */
4535 major_t
ddi_driver_major(dev_info_t * devi)4536 ddi_driver_major(dev_info_t *devi)
4537 {
4538 return (DEVI(devi)->devi_major);
4539 }
4540
4541 /*
4542 * ddi_driver_name: Return the normalized driver name. this is the
4543 * actual driver name
4544 */
4545 const char *
ddi_driver_name(dev_info_t * devi)4546 ddi_driver_name(dev_info_t *devi)
4547 {
4548 major_t major;
4549
4550 if ((major = ddi_driver_major(devi)) != DDI_MAJOR_T_NONE)
4551 return (ddi_major_to_name(major));
4552
4553 return (ddi_node_name(devi));
4554 }
4555
4556 /*
4557 * i_ddi_set_binding_name: Set binding name.
4558 *
4559 * Set the binding name to the given name.
4560 * This routine is for use by the ddi implementation, not by drivers.
4561 */
4562 void
i_ddi_set_binding_name(dev_info_t * dip,char * name)4563 i_ddi_set_binding_name(dev_info_t *dip, char *name)
4564 {
4565 DEVI(dip)->devi_binding_name = name;
4566
4567 }
4568
4569 /*
4570 * ddi_get_name: A synonym of ddi_binding_name() ... returns a name
4571 * the implementation has used to bind the node to a driver.
4572 */
4573 char *
ddi_get_name(dev_info_t * dip)4574 ddi_get_name(dev_info_t *dip)
4575 {
4576 return (DEVI(dip)->devi_binding_name);
4577 }
4578
4579 /*
4580 * ddi_node_name: Return the name property of the devinfo node
4581 * This may differ from ddi_binding_name if the node name
4582 * does not define a binding to a driver (i.e. generic names).
4583 */
4584 char *
ddi_node_name(dev_info_t * dip)4585 ddi_node_name(dev_info_t *dip)
4586 {
4587 return (DEVI(dip)->devi_node_name);
4588 }
4589
4590
4591 /*
4592 * ddi_get_nodeid: Get nodeid stored in dev_info structure.
4593 */
4594 int
ddi_get_nodeid(dev_info_t * dip)4595 ddi_get_nodeid(dev_info_t *dip)
4596 {
4597 return (DEVI(dip)->devi_nodeid);
4598 }
4599
4600 int
ddi_get_instance(dev_info_t * dip)4601 ddi_get_instance(dev_info_t *dip)
4602 {
4603 return (DEVI(dip)->devi_instance);
4604 }
4605
4606 struct dev_ops *
ddi_get_driver(dev_info_t * dip)4607 ddi_get_driver(dev_info_t *dip)
4608 {
4609 return (DEVI(dip)->devi_ops);
4610 }
4611
4612 void
ddi_set_driver(dev_info_t * dip,struct dev_ops * devo)4613 ddi_set_driver(dev_info_t *dip, struct dev_ops *devo)
4614 {
4615 DEVI(dip)->devi_ops = devo;
4616 }
4617
4618 /*
4619 * ddi_set_driver_private/ddi_get_driver_private:
4620 * Get/set device driver private data in devinfo.
4621 */
4622 void
ddi_set_driver_private(dev_info_t * dip,void * data)4623 ddi_set_driver_private(dev_info_t *dip, void *data)
4624 {
4625 DEVI(dip)->devi_driver_data = data;
4626 }
4627
4628 void *
ddi_get_driver_private(dev_info_t * dip)4629 ddi_get_driver_private(dev_info_t *dip)
4630 {
4631 return (DEVI(dip)->devi_driver_data);
4632 }
4633
4634 /*
4635 * ddi_get_parent, ddi_get_child, ddi_get_next_sibling
4636 */
4637
4638 dev_info_t *
ddi_get_parent(dev_info_t * dip)4639 ddi_get_parent(dev_info_t *dip)
4640 {
4641 return ((dev_info_t *)DEVI(dip)->devi_parent);
4642 }
4643
4644 dev_info_t *
ddi_get_child(dev_info_t * dip)4645 ddi_get_child(dev_info_t *dip)
4646 {
4647 return ((dev_info_t *)DEVI(dip)->devi_child);
4648 }
4649
4650 dev_info_t *
ddi_get_next_sibling(dev_info_t * dip)4651 ddi_get_next_sibling(dev_info_t *dip)
4652 {
4653 return ((dev_info_t *)DEVI(dip)->devi_sibling);
4654 }
4655
4656 dev_info_t *
ddi_get_next(dev_info_t * dip)4657 ddi_get_next(dev_info_t *dip)
4658 {
4659 return ((dev_info_t *)DEVI(dip)->devi_next);
4660 }
4661
4662 void
ddi_set_next(dev_info_t * dip,dev_info_t * nextdip)4663 ddi_set_next(dev_info_t *dip, dev_info_t *nextdip)
4664 {
4665 DEVI(dip)->devi_next = DEVI(nextdip);
4666 }
4667
4668 /*
4669 * ddi_root_node: Return root node of devinfo tree
4670 */
4671
4672 dev_info_t *
ddi_root_node(void)4673 ddi_root_node(void)
4674 {
4675 extern dev_info_t *top_devinfo;
4676
4677 return (top_devinfo);
4678 }
4679
4680 /*
4681 * Miscellaneous functions:
4682 */
4683
4684 /*
4685 * Implementation specific hooks
4686 */
4687
4688 void
ddi_report_dev(dev_info_t * d)4689 ddi_report_dev(dev_info_t *d)
4690 {
4691 char *b;
4692
4693 (void) ddi_ctlops(d, d, DDI_CTLOPS_REPORTDEV, (void *)0, (void *)0);
4694
4695 /*
4696 * If this devinfo node has cb_ops, it's implicitly accessible from
4697 * userland, so we print its full name together with the instance
4698 * number 'abbreviation' that the driver may use internally.
4699 */
4700 if (DEVI(d)->devi_ops->devo_cb_ops != (struct cb_ops *)0 &&
4701 (b = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP))) {
4702 cmn_err(CE_CONT, "?%s%d is %s\n",
4703 ddi_driver_name(d), ddi_get_instance(d),
4704 ddi_pathname(d, b));
4705 kmem_free(b, MAXPATHLEN);
4706 }
4707 }
4708
4709 /*
4710 * ddi_ctlops() is described in the assembler not to buy a new register
4711 * window when it's called and can reduce cost in climbing the device tree
4712 * without using the tail call optimization.
4713 */
4714 int
ddi_dev_regsize(dev_info_t * dev,uint_t rnumber,off_t * result)4715 ddi_dev_regsize(dev_info_t *dev, uint_t rnumber, off_t *result)
4716 {
4717 int ret;
4718
4719 ret = ddi_ctlops(dev, dev, DDI_CTLOPS_REGSIZE,
4720 (void *)&rnumber, (void *)result);
4721
4722 return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
4723 }
4724
4725 int
ddi_dev_nregs(dev_info_t * dev,int * result)4726 ddi_dev_nregs(dev_info_t *dev, int *result)
4727 {
4728 return (ddi_ctlops(dev, dev, DDI_CTLOPS_NREGS, 0, (void *)result));
4729 }
4730
4731 int
ddi_dev_is_sid(dev_info_t * d)4732 ddi_dev_is_sid(dev_info_t *d)
4733 {
4734 return (ddi_ctlops(d, d, DDI_CTLOPS_SIDDEV, (void *)0, (void *)0));
4735 }
4736
4737 int
ddi_slaveonly(dev_info_t * d)4738 ddi_slaveonly(dev_info_t *d)
4739 {
4740 return (ddi_ctlops(d, d, DDI_CTLOPS_SLAVEONLY, (void *)0, (void *)0));
4741 }
4742
4743 int
ddi_dev_affinity(dev_info_t * a,dev_info_t * b)4744 ddi_dev_affinity(dev_info_t *a, dev_info_t *b)
4745 {
4746 return (ddi_ctlops(a, a, DDI_CTLOPS_AFFINITY, (void *)b, (void *)0));
4747 }
4748
4749 int
ddi_streams_driver(dev_info_t * dip)4750 ddi_streams_driver(dev_info_t *dip)
4751 {
4752 if (i_ddi_devi_attached(dip) &&
4753 (DEVI(dip)->devi_ops->devo_cb_ops != NULL) &&
4754 (DEVI(dip)->devi_ops->devo_cb_ops->cb_str != NULL))
4755 return (DDI_SUCCESS);
4756 return (DDI_FAILURE);
4757 }
4758
4759 /*
4760 * callback free list
4761 */
4762
4763 static int ncallbacks;
4764 static int nc_low = 170;
4765 static int nc_med = 512;
4766 static int nc_high = 2048;
4767 static struct ddi_callback *callbackq;
4768 static struct ddi_callback *callbackqfree;
4769
4770 /*
4771 * set/run callback lists
4772 */
4773 struct cbstats {
4774 kstat_named_t cb_asked;
4775 kstat_named_t cb_new;
4776 kstat_named_t cb_run;
4777 kstat_named_t cb_delete;
4778 kstat_named_t cb_maxreq;
4779 kstat_named_t cb_maxlist;
4780 kstat_named_t cb_alloc;
4781 kstat_named_t cb_runouts;
4782 kstat_named_t cb_L2;
4783 kstat_named_t cb_grow;
4784 } cbstats = {
4785 {"asked", KSTAT_DATA_UINT32},
4786 {"new", KSTAT_DATA_UINT32},
4787 {"run", KSTAT_DATA_UINT32},
4788 {"delete", KSTAT_DATA_UINT32},
4789 {"maxreq", KSTAT_DATA_UINT32},
4790 {"maxlist", KSTAT_DATA_UINT32},
4791 {"alloc", KSTAT_DATA_UINT32},
4792 {"runouts", KSTAT_DATA_UINT32},
4793 {"L2", KSTAT_DATA_UINT32},
4794 {"grow", KSTAT_DATA_UINT32},
4795 };
4796
4797 #define nc_asked cb_asked.value.ui32
4798 #define nc_new cb_new.value.ui32
4799 #define nc_run cb_run.value.ui32
4800 #define nc_delete cb_delete.value.ui32
4801 #define nc_maxreq cb_maxreq.value.ui32
4802 #define nc_maxlist cb_maxlist.value.ui32
4803 #define nc_alloc cb_alloc.value.ui32
4804 #define nc_runouts cb_runouts.value.ui32
4805 #define nc_L2 cb_L2.value.ui32
4806 #define nc_grow cb_grow.value.ui32
4807
4808 static kmutex_t ddi_callback_mutex;
4809
4810 /*
4811 * callbacks are handled using a L1/L2 cache. The L1 cache
4812 * comes out of kmem_cache_alloc and can expand/shrink dynamically. If
4813 * we can't get callbacks from the L1 cache [because pageout is doing
4814 * I/O at the time freemem is 0], we allocate callbacks out of the
4815 * L2 cache. The L2 cache is static and depends on the memory size.
4816 * [We might also count the number of devices at probe time and
4817 * allocate one structure per device and adjust for deferred attach]
4818 */
4819 void
impl_ddi_callback_init(void)4820 impl_ddi_callback_init(void)
4821 {
4822 int i;
4823 uint_t physmegs;
4824 kstat_t *ksp;
4825
4826 physmegs = physmem >> (20 - PAGESHIFT);
4827 if (physmegs < 48) {
4828 ncallbacks = nc_low;
4829 } else if (physmegs < 128) {
4830 ncallbacks = nc_med;
4831 } else {
4832 ncallbacks = nc_high;
4833 }
4834
4835 /*
4836 * init free list
4837 */
4838 callbackq = kmem_zalloc(
4839 ncallbacks * sizeof (struct ddi_callback), KM_SLEEP);
4840 for (i = 0; i < ncallbacks-1; i++)
4841 callbackq[i].c_nfree = &callbackq[i+1];
4842 callbackqfree = callbackq;
4843
4844 /* init kstats */
4845 if (ksp = kstat_create("unix", 0, "cbstats", "misc", KSTAT_TYPE_NAMED,
4846 sizeof (cbstats) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL)) {
4847 ksp->ks_data = (void *) &cbstats;
4848 kstat_install(ksp);
4849 }
4850
4851 }
4852
4853 static void
callback_insert(int (* funcp)(caddr_t),caddr_t arg,uintptr_t * listid,int count)4854 callback_insert(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid,
4855 int count)
4856 {
4857 struct ddi_callback *list, *marker, *new;
4858 size_t size = sizeof (struct ddi_callback);
4859
4860 list = marker = (struct ddi_callback *)*listid;
4861 while (list != NULL) {
4862 if (list->c_call == funcp && list->c_arg == arg) {
4863 list->c_count += count;
4864 return;
4865 }
4866 marker = list;
4867 list = list->c_nlist;
4868 }
4869 new = kmem_alloc(size, KM_NOSLEEP);
4870 if (new == NULL) {
4871 new = callbackqfree;
4872 if (new == NULL) {
4873 new = kmem_alloc_tryhard(sizeof (struct ddi_callback),
4874 &size, KM_NOSLEEP | KM_PANIC);
4875 cbstats.nc_grow++;
4876 } else {
4877 callbackqfree = new->c_nfree;
4878 cbstats.nc_L2++;
4879 }
4880 }
4881 if (marker != NULL) {
4882 marker->c_nlist = new;
4883 } else {
4884 *listid = (uintptr_t)new;
4885 }
4886 new->c_size = size;
4887 new->c_nlist = NULL;
4888 new->c_call = funcp;
4889 new->c_arg = arg;
4890 new->c_count = count;
4891 cbstats.nc_new++;
4892 cbstats.nc_alloc++;
4893 if (cbstats.nc_alloc > cbstats.nc_maxlist)
4894 cbstats.nc_maxlist = cbstats.nc_alloc;
4895 }
4896
4897 void
ddi_set_callback(int (* funcp)(caddr_t),caddr_t arg,uintptr_t * listid)4898 ddi_set_callback(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid)
4899 {
4900 mutex_enter(&ddi_callback_mutex);
4901 cbstats.nc_asked++;
4902 if ((cbstats.nc_asked - cbstats.nc_run) > cbstats.nc_maxreq)
4903 cbstats.nc_maxreq = (cbstats.nc_asked - cbstats.nc_run);
4904 (void) callback_insert(funcp, arg, listid, 1);
4905 mutex_exit(&ddi_callback_mutex);
4906 }
4907
4908 static void
real_callback_run(void * Queue)4909 real_callback_run(void *Queue)
4910 {
4911 int (*funcp)(caddr_t);
4912 caddr_t arg;
4913 int count, rval;
4914 uintptr_t *listid;
4915 struct ddi_callback *list, *marker;
4916 int check_pending = 1;
4917 int pending = 0;
4918
4919 do {
4920 mutex_enter(&ddi_callback_mutex);
4921 listid = Queue;
4922 list = (struct ddi_callback *)*listid;
4923 if (list == NULL) {
4924 mutex_exit(&ddi_callback_mutex);
4925 return;
4926 }
4927 if (check_pending) {
4928 marker = list;
4929 while (marker != NULL) {
4930 pending += marker->c_count;
4931 marker = marker->c_nlist;
4932 }
4933 check_pending = 0;
4934 }
4935 ASSERT(pending > 0);
4936 ASSERT(list->c_count > 0);
4937 funcp = list->c_call;
4938 arg = list->c_arg;
4939 count = list->c_count;
4940 *(uintptr_t *)Queue = (uintptr_t)list->c_nlist;
4941 if (list >= &callbackq[0] &&
4942 list <= &callbackq[ncallbacks-1]) {
4943 list->c_nfree = callbackqfree;
4944 callbackqfree = list;
4945 } else
4946 kmem_free(list, list->c_size);
4947
4948 cbstats.nc_delete++;
4949 cbstats.nc_alloc--;
4950 mutex_exit(&ddi_callback_mutex);
4951
4952 do {
4953 if ((rval = (*funcp)(arg)) == 0) {
4954 pending -= count;
4955 mutex_enter(&ddi_callback_mutex);
4956 (void) callback_insert(funcp, arg, listid,
4957 count);
4958 cbstats.nc_runouts++;
4959 } else {
4960 pending--;
4961 mutex_enter(&ddi_callback_mutex);
4962 cbstats.nc_run++;
4963 }
4964 mutex_exit(&ddi_callback_mutex);
4965 } while (rval != 0 && (--count > 0));
4966 } while (pending > 0);
4967 }
4968
4969 void
ddi_run_callback(uintptr_t * listid)4970 ddi_run_callback(uintptr_t *listid)
4971 {
4972 softcall(real_callback_run, listid);
4973 }
4974
4975 /*
4976 * ddi_periodic_t
4977 * ddi_periodic_add(void (*func)(void *), void *arg, hrtime_t interval,
4978 * int level)
4979 *
4980 * INTERFACE LEVEL
4981 * Solaris DDI specific (Solaris DDI)
4982 *
4983 * PARAMETERS
4984 * func: the callback function
4985 *
4986 * The callback function will be invoked. The function is invoked
4987 * in kernel context if the argument level passed is the zero.
4988 * Otherwise it's invoked in interrupt context at the specified
4989 * level.
4990 *
4991 * arg: the argument passed to the callback function
4992 *
4993 * interval: interval time
4994 *
4995 * level : callback interrupt level
4996 *
4997 * If the value is the zero, the callback function is invoked
4998 * in kernel context. If the value is more than the zero, but
4999 * less than or equal to ten, the callback function is invoked in
5000 * interrupt context at the specified interrupt level, which may
5001 * be used for real time applications.
5002 *
5003 * This value must be in range of 0-10, which can be a numeric
5004 * number or a pre-defined macro (DDI_IPL_0, ... , DDI_IPL_10).
5005 *
5006 * DESCRIPTION
5007 * ddi_periodic_add(9F) schedules the specified function to be
5008 * periodically invoked in the interval time.
5009 *
5010 * As well as timeout(9F), the exact time interval over which the function
5011 * takes effect cannot be guaranteed, but the value given is a close
5012 * approximation.
5013 *
5014 * Drivers waiting on behalf of processes with real-time constraints must
5015 * pass non-zero value with the level argument to ddi_periodic_add(9F).
5016 *
5017 * RETURN VALUES
5018 * ddi_periodic_add(9F) returns a non-zero opaque value (ddi_periodic_t),
5019 * which must be used for ddi_periodic_delete(9F) to specify the request.
5020 *
5021 * CONTEXT
5022 * ddi_periodic_add(9F) can be called in user or kernel context, but
5023 * it cannot be called in interrupt context, which is different from
5024 * timeout(9F).
5025 */
5026 ddi_periodic_t
ddi_periodic_add(void (* func)(void *),void * arg,hrtime_t interval,int level)5027 ddi_periodic_add(void (*func)(void *), void *arg, hrtime_t interval, int level)
5028 {
5029 /*
5030 * Sanity check of the argument level.
5031 */
5032 if (level < DDI_IPL_0 || level > DDI_IPL_10)
5033 cmn_err(CE_PANIC,
5034 "ddi_periodic_add: invalid interrupt level (%d).", level);
5035
5036 /*
5037 * Sanity check of the context. ddi_periodic_add() cannot be
5038 * called in either interrupt context or high interrupt context.
5039 */
5040 if (servicing_interrupt())
5041 cmn_err(CE_PANIC,
5042 "ddi_periodic_add: called in (high) interrupt context.");
5043
5044 return ((ddi_periodic_t)i_timeout(func, arg, interval, level));
5045 }
5046
5047 /*
5048 * void
5049 * ddi_periodic_delete(ddi_periodic_t req)
5050 *
5051 * INTERFACE LEVEL
5052 * Solaris DDI specific (Solaris DDI)
5053 *
5054 * PARAMETERS
5055 * req: ddi_periodic_t opaque value ddi_periodic_add(9F) returned
5056 * previously.
5057 *
5058 * DESCRIPTION
5059 * ddi_periodic_delete(9F) cancels the ddi_periodic_add(9F) request
5060 * previously requested.
5061 *
5062 * ddi_periodic_delete(9F) will not return until the pending request
5063 * is canceled or executed.
5064 *
5065 * As well as untimeout(9F), calling ddi_periodic_delete(9F) for a
5066 * timeout which is either running on another CPU, or has already
5067 * completed causes no problems. However, unlike untimeout(9F), there is
5068 * no restrictions on the lock which might be held across the call to
5069 * ddi_periodic_delete(9F).
5070 *
5071 * Drivers should be structured with the understanding that the arrival of
5072 * both an interrupt and a timeout for that interrupt can occasionally
5073 * occur, in either order.
5074 *
5075 * CONTEXT
5076 * ddi_periodic_delete(9F) can be called in user or kernel context, but
5077 * it cannot be called in interrupt context, which is different from
5078 * untimeout(9F).
5079 */
5080 void
ddi_periodic_delete(ddi_periodic_t req)5081 ddi_periodic_delete(ddi_periodic_t req)
5082 {
5083 /*
5084 * Sanity check of the context. ddi_periodic_delete() cannot be
5085 * called in either interrupt context or high interrupt context.
5086 */
5087 if (servicing_interrupt())
5088 cmn_err(CE_PANIC,
5089 "ddi_periodic_delete: called in (high) interrupt context.");
5090
5091 i_untimeout((timeout_t)req);
5092 }
5093
5094 dev_info_t *
nodevinfo(dev_t dev,int otyp)5095 nodevinfo(dev_t dev, int otyp)
5096 {
5097 _NOTE(ARGUNUSED(dev, otyp))
5098 return ((dev_info_t *)0);
5099 }
5100
5101 /*
5102 * A driver should support its own getinfo(9E) entry point. This function
5103 * is provided as a convenience for ON drivers that don't expect their
5104 * getinfo(9E) entry point to be called. A driver that uses this must not
5105 * call ddi_create_minor_node.
5106 */
5107 int
ddi_no_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5108 ddi_no_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
5109 {
5110 _NOTE(ARGUNUSED(dip, infocmd, arg, result))
5111 return (DDI_FAILURE);
5112 }
5113
5114 /*
5115 * A driver should support its own getinfo(9E) entry point. This function
5116 * is provided as a convenience for ON drivers that where the minor number
5117 * is the instance. Drivers that do not have 1:1 mapping must implement
5118 * their own getinfo(9E) function.
5119 */
5120 int
ddi_getinfo_1to1(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5121 ddi_getinfo_1to1(dev_info_t *dip, ddi_info_cmd_t infocmd,
5122 void *arg, void **result)
5123 {
5124 _NOTE(ARGUNUSED(dip))
5125 int instance;
5126
5127 if (infocmd != DDI_INFO_DEVT2INSTANCE)
5128 return (DDI_FAILURE);
5129
5130 instance = getminor((dev_t)(uintptr_t)arg);
5131 *result = (void *)(uintptr_t)instance;
5132 return (DDI_SUCCESS);
5133 }
5134
5135 int
ddifail(dev_info_t * devi,ddi_attach_cmd_t cmd)5136 ddifail(dev_info_t *devi, ddi_attach_cmd_t cmd)
5137 {
5138 _NOTE(ARGUNUSED(devi, cmd))
5139 return (DDI_FAILURE);
5140 }
5141
5142 int
ddi_no_dma_map(dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)5143 ddi_no_dma_map(dev_info_t *dip, dev_info_t *rdip,
5144 struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
5145 {
5146 _NOTE(ARGUNUSED(dip, rdip, dmareqp, handlep))
5147 return (DDI_DMA_NOMAPPING);
5148 }
5149
5150 int
ddi_no_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)5151 ddi_no_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
5152 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
5153 {
5154 _NOTE(ARGUNUSED(dip, rdip, attr, waitfp, arg, handlep))
5155 return (DDI_DMA_BADATTR);
5156 }
5157
5158 int
ddi_no_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)5159 ddi_no_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
5160 ddi_dma_handle_t handle)
5161 {
5162 _NOTE(ARGUNUSED(dip, rdip, handle))
5163 return (DDI_FAILURE);
5164 }
5165
5166 int
ddi_no_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cp,uint_t * ccountp)5167 ddi_no_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
5168 ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
5169 ddi_dma_cookie_t *cp, uint_t *ccountp)
5170 {
5171 _NOTE(ARGUNUSED(dip, rdip, handle, dmareq, cp, ccountp))
5172 return (DDI_DMA_NOMAPPING);
5173 }
5174
5175 int
ddi_no_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)5176 ddi_no_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
5177 ddi_dma_handle_t handle)
5178 {
5179 _NOTE(ARGUNUSED(dip, rdip, handle))
5180 return (DDI_FAILURE);
5181 }
5182
5183 int
ddi_no_dma_flush(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,off_t off,size_t len,uint_t cache_flags)5184 ddi_no_dma_flush(dev_info_t *dip, dev_info_t *rdip,
5185 ddi_dma_handle_t handle, off_t off, size_t len,
5186 uint_t cache_flags)
5187 {
5188 _NOTE(ARGUNUSED(dip, rdip, handle, off, len, cache_flags))
5189 return (DDI_FAILURE);
5190 }
5191
5192 int
ddi_no_dma_win(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)5193 ddi_no_dma_win(dev_info_t *dip, dev_info_t *rdip,
5194 ddi_dma_handle_t handle, uint_t win, off_t *offp,
5195 size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
5196 {
5197 _NOTE(ARGUNUSED(dip, rdip, handle, win, offp, lenp, cookiep, ccountp))
5198 return (DDI_FAILURE);
5199 }
5200
5201 int
ddi_no_dma_mctl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,enum ddi_dma_ctlops request,off_t * offp,size_t * lenp,caddr_t * objp,uint_t flags)5202 ddi_no_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
5203 ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
5204 off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
5205 {
5206 _NOTE(ARGUNUSED(dip, rdip, handle, request, offp, lenp, objp, flags))
5207 return (DDI_FAILURE);
5208 }
5209
5210 void
ddivoid(void)5211 ddivoid(void)
5212 {}
5213
5214 int
nochpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** pollhdrp)5215 nochpoll(dev_t dev, short events, int anyyet, short *reventsp,
5216 struct pollhead **pollhdrp)
5217 {
5218 _NOTE(ARGUNUSED(dev, events, anyyet, reventsp, pollhdrp))
5219 return (ENXIO);
5220 }
5221
5222 cred_t *
ddi_get_cred(void)5223 ddi_get_cred(void)
5224 {
5225 return (CRED());
5226 }
5227
5228 clock_t
ddi_get_lbolt(void)5229 ddi_get_lbolt(void)
5230 {
5231 return ((clock_t)lbolt_hybrid());
5232 }
5233
5234 int64_t
ddi_get_lbolt64(void)5235 ddi_get_lbolt64(void)
5236 {
5237 return (lbolt_hybrid());
5238 }
5239
5240 /*
5241 * The number of CPUs that the system is expected to have once boot has
5242 * completed, for use when sizing per-CPU resources at any point in boot.
5243 * Early in boot only the boot processor is running, and "ncpus" does not
5244 * yet reflect the processors that have still to be started.
5245 *
5246 * The value counts processors that are present, whether online or not,
5247 * and so does not change as processors are taken offline and brought
5248 * back online. A processor that is physically added to, or removed from,
5249 * a running system does change the count, but a caller will usually not
5250 * observe that either, having sized its resources once at attach time.
5251 * That is acceptable for the intended use since the value is a sizing
5252 * estimate.
5253 */
5254 uint_t
ddi_ncpus_expected(void)5255 ddi_ncpus_expected(void)
5256 {
5257 if (ncpus >= 2)
5258 return ((uint_t)ncpus);
5259
5260 /*
5261 * Size for the number of processors that boot is expected to start,
5262 * where the platform has recorded that, and for the maximum number
5263 * that it could start otherwise.
5264 */
5265 return ((uint_t)((boot_max_ncpus == -1) ? max_ncpus : boot_max_ncpus));
5266 }
5267
5268 time_t
ddi_get_time(void)5269 ddi_get_time(void)
5270 {
5271 time_t now;
5272
5273 if ((now = gethrestime_sec()) == 0) {
5274 timestruc_t ts;
5275 mutex_enter(&tod_lock);
5276 ts = tod_get();
5277 mutex_exit(&tod_lock);
5278 return (ts.tv_sec);
5279 } else {
5280 return (now);
5281 }
5282 }
5283
5284 pid_t
ddi_get_pid(void)5285 ddi_get_pid(void)
5286 {
5287 return (ttoproc(curthread)->p_pid);
5288 }
5289
5290 kt_did_t
ddi_get_kt_did(void)5291 ddi_get_kt_did(void)
5292 {
5293 return (curthread->t_did);
5294 }
5295
5296 /*
5297 * This function returns B_TRUE if the caller can reasonably expect that a call
5298 * to cv_wait_sig(9F), cv_timedwait_sig(9F), or qwait_sig(9F) could be awakened
5299 * by user-level signal. If it returns B_FALSE, then the caller should use
5300 * other means to make certain that the wait will not hang "forever."
5301 *
5302 * It does not check the signal mask, nor for reception of any particular
5303 * signal.
5304 *
5305 * Currently, a thread can receive a signal if it's not a kernel thread and it
5306 * is not in the middle of exit(2) tear-down. Threads that are in that
5307 * tear-down effectively convert cv_wait_sig to cv_wait, cv_timedwait_sig to
5308 * cv_timedwait, and qwait_sig to qwait.
5309 */
5310 boolean_t
ddi_can_receive_sig(void)5311 ddi_can_receive_sig(void)
5312 {
5313 proc_t *pp;
5314
5315 if (curthread->t_proc_flag & TP_LWPEXIT)
5316 return (B_FALSE);
5317 if ((pp = ttoproc(curthread)) == NULL)
5318 return (B_FALSE);
5319 return (pp->p_as != &kas);
5320 }
5321
5322 /*
5323 * Swap bytes in 16-bit [half-]words
5324 */
5325 void
swab(void * src,void * dst,size_t nbytes)5326 swab(void *src, void *dst, size_t nbytes)
5327 {
5328 uchar_t *pf = (uchar_t *)src;
5329 uchar_t *pt = (uchar_t *)dst;
5330 uchar_t tmp;
5331 int nshorts;
5332
5333 nshorts = nbytes >> 1;
5334
5335 while (--nshorts >= 0) {
5336 tmp = *pf++;
5337 *pt++ = *pf++;
5338 *pt++ = tmp;
5339 }
5340 }
5341
5342 static void
ddi_append_minor_node(dev_info_t * ddip,struct ddi_minor_data * dmdp)5343 ddi_append_minor_node(dev_info_t *ddip, struct ddi_minor_data *dmdp)
5344 {
5345 struct ddi_minor_data *dp;
5346
5347 ndi_devi_enter(ddip);
5348 if ((dp = DEVI(ddip)->devi_minor) == (struct ddi_minor_data *)NULL) {
5349 DEVI(ddip)->devi_minor = dmdp;
5350 } else {
5351 while (dp->next != (struct ddi_minor_data *)NULL)
5352 dp = dp->next;
5353 dp->next = dmdp;
5354 }
5355 ndi_devi_exit(ddip);
5356 }
5357
5358 static int
i_log_devfs_minor_create(dev_info_t * dip,char * minor_name)5359 i_log_devfs_minor_create(dev_info_t *dip, char *minor_name)
5360 {
5361 int se_flag;
5362 int kmem_flag;
5363 int se_err;
5364 char *pathname, *class_name;
5365 sysevent_t *ev = NULL;
5366 sysevent_id_t eid;
5367 sysevent_value_t se_val;
5368 sysevent_attr_list_t *ev_attr_list = NULL;
5369
5370 /* determine interrupt context */
5371 se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP;
5372 kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
5373
5374 i_ddi_di_cache_invalidate();
5375
5376 #ifdef DEBUG
5377 if ((se_flag == SE_NOSLEEP) && sunddi_debug) {
5378 cmn_err(CE_CONT, "ddi_create_minor_node: called from "
5379 "interrupt level by driver %s",
5380 ddi_driver_name(dip));
5381 }
5382 #endif /* DEBUG */
5383
5384 ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_CREATE, EP_DDI, se_flag);
5385 if (ev == NULL) {
5386 goto fail;
5387 }
5388
5389 pathname = kmem_alloc(MAXPATHLEN, kmem_flag);
5390 if (pathname == NULL) {
5391 sysevent_free(ev);
5392 goto fail;
5393 }
5394
5395 (void) ddi_pathname(dip, pathname);
5396 ASSERT(strlen(pathname));
5397 se_val.value_type = SE_DATA_TYPE_STRING;
5398 se_val.value.sv_string = pathname;
5399 if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
5400 &se_val, se_flag) != 0) {
5401 kmem_free(pathname, MAXPATHLEN);
5402 sysevent_free(ev);
5403 goto fail;
5404 }
5405 kmem_free(pathname, MAXPATHLEN);
5406
5407 /* add the device class attribute */
5408 if ((class_name = i_ddi_devi_class(dip)) != NULL) {
5409 se_val.value_type = SE_DATA_TYPE_STRING;
5410 se_val.value.sv_string = class_name;
5411 if (sysevent_add_attr(&ev_attr_list,
5412 DEVFS_DEVI_CLASS, &se_val, SE_SLEEP) != 0) {
5413 sysevent_free_attr(ev_attr_list);
5414 goto fail;
5415 }
5416 }
5417
5418 /*
5419 * allow for NULL minor names
5420 */
5421 if (minor_name != NULL) {
5422 se_val.value.sv_string = minor_name;
5423 if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
5424 &se_val, se_flag) != 0) {
5425 sysevent_free_attr(ev_attr_list);
5426 sysevent_free(ev);
5427 goto fail;
5428 }
5429 }
5430
5431 if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
5432 sysevent_free_attr(ev_attr_list);
5433 sysevent_free(ev);
5434 goto fail;
5435 }
5436
5437 if ((se_err = log_sysevent(ev, se_flag, &eid)) != 0) {
5438 if (se_err == SE_NO_TRANSPORT) {
5439 cmn_err(CE_WARN, "/devices or /dev may not be current "
5440 "for driver %s (%s). Run devfsadm -i %s",
5441 ddi_driver_name(dip), "syseventd not responding",
5442 ddi_driver_name(dip));
5443 } else {
5444 sysevent_free(ev);
5445 goto fail;
5446 }
5447 }
5448
5449 sysevent_free(ev);
5450 return (DDI_SUCCESS);
5451 fail:
5452 cmn_err(CE_WARN, "/devices or /dev may not be current "
5453 "for driver %s. Run devfsadm -i %s",
5454 ddi_driver_name(dip), ddi_driver_name(dip));
5455 return (DDI_SUCCESS);
5456 }
5457
5458 /*
5459 * failing to remove a minor node is not of interest
5460 * therefore we do not generate an error message
5461 */
5462 static int
i_log_devfs_minor_remove(dev_info_t * dip,char * minor_name)5463 i_log_devfs_minor_remove(dev_info_t *dip, char *minor_name)
5464 {
5465 char *pathname, *class_name;
5466 sysevent_t *ev;
5467 sysevent_id_t eid;
5468 sysevent_value_t se_val;
5469 sysevent_attr_list_t *ev_attr_list = NULL;
5470
5471 /*
5472 * only log ddi_remove_minor_node() calls outside the scope
5473 * of attach/detach reconfigurations and when the dip is
5474 * still initialized.
5475 */
5476 if (DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip) ||
5477 (i_ddi_node_state(dip) < DS_INITIALIZED)) {
5478 return (DDI_SUCCESS);
5479 }
5480
5481 i_ddi_di_cache_invalidate();
5482
5483 ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_REMOVE, EP_DDI, SE_SLEEP);
5484 if (ev == NULL) {
5485 return (DDI_SUCCESS);
5486 }
5487
5488 pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
5489 if (pathname == NULL) {
5490 sysevent_free(ev);
5491 return (DDI_SUCCESS);
5492 }
5493
5494 (void) ddi_pathname(dip, pathname);
5495 ASSERT(strlen(pathname));
5496 se_val.value_type = SE_DATA_TYPE_STRING;
5497 se_val.value.sv_string = pathname;
5498 if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
5499 &se_val, SE_SLEEP) != 0) {
5500 kmem_free(pathname, MAXPATHLEN);
5501 sysevent_free(ev);
5502 return (DDI_SUCCESS);
5503 }
5504
5505 kmem_free(pathname, MAXPATHLEN);
5506
5507 /*
5508 * allow for NULL minor names
5509 */
5510 if (minor_name != NULL) {
5511 se_val.value.sv_string = minor_name;
5512 if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
5513 &se_val, SE_SLEEP) != 0) {
5514 sysevent_free_attr(ev_attr_list);
5515 goto fail;
5516 }
5517 }
5518
5519 if ((class_name = i_ddi_devi_class(dip)) != NULL) {
5520 /* add the device class, driver name and instance attributes */
5521
5522 se_val.value_type = SE_DATA_TYPE_STRING;
5523 se_val.value.sv_string = class_name;
5524 if (sysevent_add_attr(&ev_attr_list,
5525 DEVFS_DEVI_CLASS, &se_val, SE_SLEEP) != 0) {
5526 sysevent_free_attr(ev_attr_list);
5527 goto fail;
5528 }
5529
5530 se_val.value_type = SE_DATA_TYPE_STRING;
5531 se_val.value.sv_string = (char *)ddi_driver_name(dip);
5532 if (sysevent_add_attr(&ev_attr_list,
5533 DEVFS_DRIVER_NAME, &se_val, SE_SLEEP) != 0) {
5534 sysevent_free_attr(ev_attr_list);
5535 goto fail;
5536 }
5537
5538 se_val.value_type = SE_DATA_TYPE_INT32;
5539 se_val.value.sv_int32 = ddi_get_instance(dip);
5540 if (sysevent_add_attr(&ev_attr_list,
5541 DEVFS_INSTANCE, &se_val, SE_SLEEP) != 0) {
5542 sysevent_free_attr(ev_attr_list);
5543 goto fail;
5544 }
5545
5546 }
5547
5548 if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
5549 sysevent_free_attr(ev_attr_list);
5550 } else {
5551 (void) log_sysevent(ev, SE_SLEEP, &eid);
5552 }
5553 fail:
5554 sysevent_free(ev);
5555 return (DDI_SUCCESS);
5556 }
5557
5558 /*
5559 * Derive the device class of the node.
5560 * Device class names aren't defined yet. Until this is done we use
5561 * devfs event subclass names as device class names.
5562 */
5563 static int
derive_devi_class(dev_info_t * dip,const char * node_type,int flag)5564 derive_devi_class(dev_info_t *dip, const char *node_type, int flag)
5565 {
5566 int rv = DDI_SUCCESS;
5567
5568 if (i_ddi_devi_class(dip) == NULL) {
5569 if (strncmp(node_type, DDI_NT_BLOCK,
5570 sizeof (DDI_NT_BLOCK) - 1) == 0 &&
5571 (node_type[sizeof (DDI_NT_BLOCK) - 1] == '\0' ||
5572 node_type[sizeof (DDI_NT_BLOCK) - 1] == ':') &&
5573 strcmp(node_type, DDI_NT_FD) != 0) {
5574
5575 rv = i_ddi_set_devi_class(dip, ESC_DISK, flag);
5576
5577 } else if (strncmp(node_type, DDI_NT_NET,
5578 sizeof (DDI_NT_NET) - 1) == 0 &&
5579 (node_type[sizeof (DDI_NT_NET) - 1] == '\0' ||
5580 node_type[sizeof (DDI_NT_NET) - 1] == ':')) {
5581
5582 rv = i_ddi_set_devi_class(dip, ESC_NETWORK, flag);
5583
5584 } else if (strncmp(node_type, DDI_NT_PRINTER,
5585 sizeof (DDI_NT_PRINTER) - 1) == 0 &&
5586 (node_type[sizeof (DDI_NT_PRINTER) - 1] == '\0' ||
5587 node_type[sizeof (DDI_NT_PRINTER) - 1] == ':')) {
5588
5589 rv = i_ddi_set_devi_class(dip, ESC_PRINTER, flag);
5590
5591 } else if (strncmp(node_type, DDI_PSEUDO,
5592 sizeof (DDI_PSEUDO) -1) == 0 &&
5593 (strncmp(ESC_LOFI, ddi_node_name(dip),
5594 sizeof (ESC_LOFI) -1) == 0)) {
5595 rv = i_ddi_set_devi_class(dip, ESC_LOFI, flag);
5596 }
5597 }
5598
5599 return (rv);
5600 }
5601
5602 /*
5603 * Check compliance with PSARC 2003/375:
5604 *
5605 * The name must contain only characters a-z, A-Z, 0-9 or _ and it must not
5606 * exceed IFNAMSIZ (16) characters in length.
5607 */
5608 static boolean_t
verify_name(const char * name)5609 verify_name(const char *name)
5610 {
5611 size_t len = strlen(name);
5612 const char *cp;
5613
5614 if (len == 0 || len > IFNAMSIZ)
5615 return (B_FALSE);
5616
5617 for (cp = name; *cp != '\0'; cp++) {
5618 if (!isalnum(*cp) && *cp != '_')
5619 return (B_FALSE);
5620 }
5621
5622 return (B_TRUE);
5623 }
5624
5625 /*
5626 * ddi_create_minor_common: Create a ddi_minor_data structure and
5627 * attach it to the given devinfo node.
5628 */
5629
5630 static int
ddi_create_minor_common(dev_info_t * dip,const char * name,int spec_type,minor_t minor_num,const char * node_type,int flag,ddi_minor_type mtype,const char * read_priv,const char * write_priv,mode_t priv_mode)5631 ddi_create_minor_common(dev_info_t *dip, const char *name, int spec_type,
5632 minor_t minor_num, const char *node_type, int flag, ddi_minor_type mtype,
5633 const char *read_priv, const char *write_priv, mode_t priv_mode)
5634 {
5635 struct ddi_minor_data *dmdp;
5636 major_t major;
5637
5638 if (spec_type != S_IFCHR && spec_type != S_IFBLK)
5639 return (DDI_FAILURE);
5640
5641 if (name == NULL)
5642 return (DDI_FAILURE);
5643
5644 /*
5645 * Log a message if the minor number the driver is creating
5646 * is not expressible on the on-disk filesystem (currently
5647 * this is limited to 18 bits both by UFS). The device can
5648 * be opened via devfs, but not by device special files created
5649 * via mknod().
5650 */
5651 if (minor_num > L_MAXMIN32) {
5652 cmn_err(CE_WARN,
5653 "%s%d:%s minor 0x%x too big for 32-bit applications",
5654 ddi_driver_name(dip), ddi_get_instance(dip),
5655 name, minor_num);
5656 return (DDI_FAILURE);
5657 }
5658
5659 /* dip must be bound and attached */
5660 major = ddi_driver_major(dip);
5661 ASSERT(major != DDI_MAJOR_T_NONE);
5662
5663 /*
5664 * Default node_type to DDI_PSEUDO and issue notice in debug mode
5665 */
5666 if (node_type == NULL) {
5667 node_type = DDI_PSEUDO;
5668 NDI_CONFIG_DEBUG((CE_NOTE, "!illegal node_type NULL for %s%d "
5669 " minor node %s; default to DDI_PSEUDO",
5670 ddi_driver_name(dip), ddi_get_instance(dip), name));
5671 }
5672
5673 /*
5674 * If the driver is a network driver, ensure that the name falls within
5675 * the interface naming constraints specified by PSARC/2003/375.
5676 */
5677 if (strcmp(node_type, DDI_NT_NET) == 0) {
5678 if (!verify_name(name))
5679 return (DDI_FAILURE);
5680
5681 if (mtype == DDM_MINOR) {
5682 struct devnames *dnp = &devnamesp[major];
5683
5684 /* Mark driver as a network driver */
5685 LOCK_DEV_OPS(&dnp->dn_lock);
5686 dnp->dn_flags |= DN_NETWORK_DRIVER;
5687
5688 /*
5689 * If this minor node is created during the device
5690 * attachment, this is a physical network device.
5691 * Mark the driver as a physical network driver.
5692 */
5693 if (DEVI_IS_ATTACHING(dip))
5694 dnp->dn_flags |= DN_NETWORK_PHYSDRIVER;
5695 UNLOCK_DEV_OPS(&dnp->dn_lock);
5696 }
5697 }
5698
5699 if (mtype == DDM_MINOR) {
5700 if (derive_devi_class(dip, node_type, KM_NOSLEEP) !=
5701 DDI_SUCCESS)
5702 return (DDI_FAILURE);
5703 }
5704
5705 /*
5706 * Take care of minor number information for the node.
5707 */
5708
5709 if ((dmdp = kmem_zalloc(sizeof (struct ddi_minor_data),
5710 KM_NOSLEEP)) == NULL) {
5711 return (DDI_FAILURE);
5712 }
5713 if ((dmdp->ddm_name = i_ddi_strdup(name, KM_NOSLEEP)) == NULL) {
5714 kmem_free(dmdp, sizeof (struct ddi_minor_data));
5715 return (DDI_FAILURE);
5716 }
5717 dmdp->dip = dip;
5718 dmdp->ddm_dev = makedevice(major, minor_num);
5719 dmdp->ddm_spec_type = spec_type;
5720 dmdp->ddm_node_type = node_type;
5721 dmdp->type = mtype;
5722 if (flag & CLONE_DEV) {
5723 dmdp->type = DDM_ALIAS;
5724 dmdp->ddm_dev = makedevice(ddi_driver_major(clone_dip), major);
5725 }
5726 if (flag & PRIVONLY_DEV) {
5727 dmdp->ddm_flags |= DM_NO_FSPERM;
5728 }
5729 if (read_priv || write_priv) {
5730 dmdp->ddm_node_priv =
5731 devpolicy_priv_by_name(read_priv, write_priv);
5732 }
5733 dmdp->ddm_priv_mode = priv_mode;
5734
5735 ddi_append_minor_node(dip, dmdp);
5736
5737 /*
5738 * only log ddi_create_minor_node() calls which occur
5739 * outside the scope of attach(9e)/detach(9e) reconfigurations
5740 */
5741 if (!(DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip)) &&
5742 mtype != DDM_INTERNAL_PATH) {
5743 (void) i_log_devfs_minor_create(dip, dmdp->ddm_name);
5744 }
5745
5746 /*
5747 * Check if any dacf rules match the creation of this minor node
5748 */
5749 dacfc_match_create_minor(name, node_type, dip, dmdp, flag);
5750 return (DDI_SUCCESS);
5751 }
5752
5753 int
ddi_create_minor_node(dev_info_t * dip,const char * name,int spec_type,minor_t minor_num,const char * node_type,int flag)5754 ddi_create_minor_node(dev_info_t *dip, const char *name, int spec_type,
5755 minor_t minor_num, const char *node_type, int flag)
5756 {
5757 return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5758 node_type, flag, DDM_MINOR, NULL, NULL, 0));
5759 }
5760
5761 int
ddi_create_priv_minor_node(dev_info_t * dip,const char * name,int spec_type,minor_t minor_num,const char * node_type,int flag,const char * rdpriv,const char * wrpriv,mode_t priv_mode)5762 ddi_create_priv_minor_node(dev_info_t *dip, const char *name, int spec_type,
5763 minor_t minor_num, const char *node_type, int flag,
5764 const char *rdpriv, const char *wrpriv, mode_t priv_mode)
5765 {
5766 return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5767 node_type, flag, DDM_MINOR, rdpriv, wrpriv, priv_mode));
5768 }
5769
5770 int
ddi_create_default_minor_node(dev_info_t * dip,const char * name,int spec_type,minor_t minor_num,const char * node_type,int flag)5771 ddi_create_default_minor_node(dev_info_t *dip, const char *name, int spec_type,
5772 minor_t minor_num, const char *node_type, int flag)
5773 {
5774 return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5775 node_type, flag, DDM_DEFAULT, NULL, NULL, 0));
5776 }
5777
5778 /*
5779 * Internal (non-ddi) routine for drivers to export names known
5780 * to the kernel (especially ddi_pathname_to_dev_t and friends)
5781 * but not exported externally to /dev
5782 */
5783 int
ddi_create_internal_pathname(dev_info_t * dip,char * name,int spec_type,minor_t minor_num)5784 ddi_create_internal_pathname(dev_info_t *dip, char *name, int spec_type,
5785 minor_t minor_num)
5786 {
5787 return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5788 "internal", 0, DDM_INTERNAL_PATH, NULL, NULL, 0));
5789 }
5790
5791 void
ddi_remove_minor_node(dev_info_t * dip,const char * name)5792 ddi_remove_minor_node(dev_info_t *dip, const char *name)
5793 {
5794 struct ddi_minor_data *dmdp, *dmdp1;
5795 struct ddi_minor_data **dmdp_prev;
5796
5797 ndi_devi_enter(dip);
5798 dmdp_prev = &DEVI(dip)->devi_minor;
5799 dmdp = DEVI(dip)->devi_minor;
5800 while (dmdp != NULL) {
5801 dmdp1 = dmdp->next;
5802 if ((name == NULL || (dmdp->ddm_name != NULL &&
5803 strcmp(name, dmdp->ddm_name) == 0))) {
5804 if (dmdp->ddm_name != NULL) {
5805 if (dmdp->type != DDM_INTERNAL_PATH)
5806 (void) i_log_devfs_minor_remove(dip,
5807 dmdp->ddm_name);
5808 kmem_free(dmdp->ddm_name,
5809 strlen(dmdp->ddm_name) + 1);
5810 }
5811 /*
5812 * Release device privilege, if any.
5813 * Release dacf client data associated with this minor
5814 * node by storing NULL.
5815 */
5816 if (dmdp->ddm_node_priv)
5817 dpfree(dmdp->ddm_node_priv);
5818 dacf_store_info((dacf_infohdl_t)dmdp, NULL);
5819 kmem_free(dmdp, sizeof (struct ddi_minor_data));
5820 *dmdp_prev = dmdp1;
5821 /*
5822 * OK, we found it, so get out now -- if we drive on,
5823 * we will strcmp against garbage. See 1139209.
5824 */
5825 if (name != NULL)
5826 break;
5827 } else {
5828 dmdp_prev = &dmdp->next;
5829 }
5830 dmdp = dmdp1;
5831 }
5832 ndi_devi_exit(dip);
5833 }
5834
5835
5836 int
ddi_in_panic()5837 ddi_in_panic()
5838 {
5839 return (panicstr != NULL);
5840 }
5841
5842
5843 /*
5844 * Find first bit set in a mask (returned counting from 1 up)
5845 */
5846
5847 int
ddi_ffs(long mask)5848 ddi_ffs(long mask)
5849 {
5850 return (ffs(mask));
5851 }
5852
5853 /*
5854 * Find last bit set. Take mask and clear
5855 * all but the most significant bit, and
5856 * then let ffs do the rest of the work.
5857 *
5858 * Algorithm courtesy of Steve Chessin.
5859 */
5860
5861 int
ddi_fls(long mask)5862 ddi_fls(long mask)
5863 {
5864 while (mask) {
5865 long nx;
5866
5867 if ((nx = (mask & (mask - 1))) == 0)
5868 break;
5869 mask = nx;
5870 }
5871 return (ffs(mask));
5872 }
5873
5874 /*
5875 * The ddi_soft_state_* routines comprise generic storage management utilities
5876 * for driver soft state structures (in "the old days," this was done with
5877 * statically sized array - big systems and dynamic loading and unloading
5878 * make heap allocation more attractive).
5879 */
5880
5881 /*
5882 * Allocate a set of pointers to 'n_items' objects of size 'size'
5883 * bytes. Each pointer is initialized to nil.
5884 *
5885 * The 'size' and 'n_items' values are stashed in the opaque
5886 * handle returned to the caller.
5887 *
5888 * This implementation interprets 'set of pointers' to mean 'array
5889 * of pointers' but note that nothing in the interface definition
5890 * precludes an implementation that uses, for example, a linked list.
5891 * However there should be a small efficiency gain from using an array
5892 * at lookup time.
5893 *
5894 * NOTE As an optimization, we make our growable array allocations in
5895 * powers of two (bytes), since that's how much kmem_alloc (currently)
5896 * gives us anyway. It should save us some free/realloc's ..
5897 *
5898 * As a further optimization, we make the growable array start out
5899 * with MIN_N_ITEMS in it.
5900 */
5901
5902 #define MIN_N_ITEMS 8 /* 8 void *'s == 32 bytes */
5903
5904 int
ddi_soft_state_init(void ** state_p,size_t size,size_t n_items)5905 ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
5906 {
5907 i_ddi_soft_state *ss;
5908
5909 if (state_p == NULL || size == 0)
5910 return (EINVAL);
5911
5912 ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
5913 mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
5914 ss->size = size;
5915
5916 if (n_items < MIN_N_ITEMS)
5917 ss->n_items = MIN_N_ITEMS;
5918 else {
5919 int bitlog;
5920
5921 if ((bitlog = ddi_fls(n_items)) == ddi_ffs(n_items))
5922 bitlog--;
5923 ss->n_items = 1 << bitlog;
5924 }
5925
5926 ASSERT(ss->n_items >= n_items);
5927
5928 ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
5929
5930 *state_p = ss;
5931 return (0);
5932 }
5933
5934 /*
5935 * Allocate a state structure of size 'size' to be associated
5936 * with item 'item'.
5937 *
5938 * In this implementation, the array is extended to
5939 * allow the requested offset, if needed.
5940 */
5941 int
ddi_soft_state_zalloc(void * state,int item)5942 ddi_soft_state_zalloc(void *state, int item)
5943 {
5944 i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
5945 void **array;
5946 void *new_element;
5947
5948 if ((state == NULL) || (item < 0))
5949 return (DDI_FAILURE);
5950
5951 mutex_enter(&ss->lock);
5952 if (ss->size == 0) {
5953 mutex_exit(&ss->lock);
5954 cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle: %s",
5955 mod_containing_pc(caller()));
5956 return (DDI_FAILURE);
5957 }
5958
5959 array = ss->array; /* NULL if ss->n_items == 0 */
5960 ASSERT(ss->n_items != 0 && array != NULL);
5961
5962 /*
5963 * refuse to tread on an existing element
5964 */
5965 if (item < ss->n_items && array[item] != NULL) {
5966 mutex_exit(&ss->lock);
5967 return (DDI_FAILURE);
5968 }
5969
5970 /*
5971 * Allocate a new element to plug in
5972 */
5973 new_element = kmem_zalloc(ss->size, KM_SLEEP);
5974
5975 /*
5976 * Check if the array is big enough, if not, grow it.
5977 */
5978 if (item >= ss->n_items) {
5979 void **new_array;
5980 size_t new_n_items;
5981 struct i_ddi_soft_state *dirty;
5982
5983 /*
5984 * Allocate a new array of the right length, copy
5985 * all the old pointers to the new array, then
5986 * if it exists at all, put the old array on the
5987 * dirty list.
5988 *
5989 * Note that we can't kmem_free() the old array.
5990 *
5991 * Why -- well the 'get' operation is 'mutex-free', so we
5992 * can't easily catch a suspended thread that is just about
5993 * to dereference the array we just grew out of. So we
5994 * cons up a header and put it on a list of 'dirty'
5995 * pointer arrays. (Dirty in the sense that there may
5996 * be suspended threads somewhere that are in the middle
5997 * of referencing them). Fortunately, we -can- garbage
5998 * collect it all at ddi_soft_state_fini time.
5999 */
6000 new_n_items = ss->n_items;
6001 while (new_n_items < (1 + item))
6002 new_n_items <<= 1; /* double array size .. */
6003
6004 ASSERT(new_n_items >= (1 + item)); /* sanity check! */
6005
6006 new_array = kmem_zalloc(new_n_items * sizeof (void *),
6007 KM_SLEEP);
6008 /*
6009 * Copy the pointers into the new array
6010 */
6011 bcopy(array, new_array, ss->n_items * sizeof (void *));
6012
6013 /*
6014 * Save the old array on the dirty list
6015 */
6016 dirty = kmem_zalloc(sizeof (*dirty), KM_SLEEP);
6017 dirty->array = ss->array;
6018 dirty->n_items = ss->n_items;
6019 dirty->next = ss->next;
6020 ss->next = dirty;
6021
6022 ss->array = (array = new_array);
6023 ss->n_items = new_n_items;
6024 }
6025
6026 ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
6027
6028 array[item] = new_element;
6029
6030 mutex_exit(&ss->lock);
6031 return (DDI_SUCCESS);
6032 }
6033
6034 /*
6035 * Fetch a pointer to the allocated soft state structure.
6036 *
6037 * This is designed to be cheap.
6038 *
6039 * There's an argument that there should be more checking for
6040 * nil pointers and out of bounds on the array.. but we do a lot
6041 * of that in the alloc/free routines.
6042 *
6043 * An array has the convenience that we don't need to lock read-access
6044 * to it c.f. a linked list. However our "expanding array" strategy
6045 * means that we should hold a readers lock on the i_ddi_soft_state
6046 * structure.
6047 *
6048 * However, from a performance viewpoint, we need to do it without
6049 * any locks at all -- this also makes it a leaf routine. The algorithm
6050 * is 'lock-free' because we only discard the pointer arrays at
6051 * ddi_soft_state_fini() time.
6052 */
6053 void *
ddi_get_soft_state(void * state,int item)6054 ddi_get_soft_state(void *state, int item)
6055 {
6056 i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
6057
6058 ASSERT((ss != NULL) && (item >= 0));
6059
6060 if (item < ss->n_items && ss->array != NULL)
6061 return (ss->array[item]);
6062 return (NULL);
6063 }
6064
6065 /*
6066 * Free the state structure corresponding to 'item.' Freeing an
6067 * element that has either gone or was never allocated is not
6068 * considered an error. Note that we free the state structure, but
6069 * we don't shrink our pointer array, or discard 'dirty' arrays,
6070 * since even a few pointers don't really waste too much memory.
6071 *
6072 * Passing an item number that is out of bounds, or a null pointer will
6073 * provoke an error message.
6074 */
6075 void
ddi_soft_state_free(void * state,int item)6076 ddi_soft_state_free(void *state, int item)
6077 {
6078 i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
6079 void **array;
6080 void *element;
6081 static char msg[] = "ddi_soft_state_free:";
6082
6083 if (ss == NULL) {
6084 cmn_err(CE_WARN, "%s null handle: %s",
6085 msg, mod_containing_pc(caller()));
6086 return;
6087 }
6088
6089 element = NULL;
6090
6091 mutex_enter(&ss->lock);
6092
6093 if ((array = ss->array) == NULL || ss->size == 0) {
6094 cmn_err(CE_WARN, "%s bad handle: %s",
6095 msg, mod_containing_pc(caller()));
6096 } else if (item < 0 || item >= ss->n_items) {
6097 cmn_err(CE_WARN, "%s item %d not in range [0..%lu]: %s",
6098 msg, item, ss->n_items - 1, mod_containing_pc(caller()));
6099 } else if (array[item] != NULL) {
6100 element = array[item];
6101 array[item] = NULL;
6102 }
6103
6104 mutex_exit(&ss->lock);
6105
6106 if (element)
6107 kmem_free(element, ss->size);
6108 }
6109
6110 /*
6111 * Free the entire set of pointers, and any
6112 * soft state structures contained therein.
6113 *
6114 * Note that we don't grab the ss->lock mutex, even though
6115 * we're inspecting the various fields of the data structure.
6116 *
6117 * There is an implicit assumption that this routine will
6118 * never run concurrently with any of the above on this
6119 * particular state structure i.e. by the time the driver
6120 * calls this routine, there should be no other threads
6121 * running in the driver.
6122 */
6123 void
ddi_soft_state_fini(void ** state_p)6124 ddi_soft_state_fini(void **state_p)
6125 {
6126 i_ddi_soft_state *ss, *dirty;
6127 int item;
6128 static char msg[] = "ddi_soft_state_fini:";
6129
6130 if (state_p == NULL ||
6131 (ss = (i_ddi_soft_state *)(*state_p)) == NULL) {
6132 cmn_err(CE_WARN, "%s null handle: %s",
6133 msg, mod_containing_pc(caller()));
6134 return;
6135 }
6136
6137 if (ss->size == 0) {
6138 cmn_err(CE_WARN, "%s bad handle: %s",
6139 msg, mod_containing_pc(caller()));
6140 return;
6141 }
6142
6143 if (ss->n_items > 0) {
6144 for (item = 0; item < ss->n_items; item++)
6145 ddi_soft_state_free(ss, item);
6146 kmem_free(ss->array, ss->n_items * sizeof (void *));
6147 }
6148
6149 /*
6150 * Now delete any dirty arrays from previous 'grow' operations
6151 */
6152 for (dirty = ss->next; dirty; dirty = ss->next) {
6153 ss->next = dirty->next;
6154 kmem_free(dirty->array, dirty->n_items * sizeof (void *));
6155 kmem_free(dirty, sizeof (*dirty));
6156 }
6157
6158 mutex_destroy(&ss->lock);
6159 kmem_free(ss, sizeof (*ss));
6160
6161 *state_p = NULL;
6162 }
6163
6164 #define SS_N_ITEMS_PER_HASH 16
6165 #define SS_MIN_HASH_SZ 16
6166 #define SS_MAX_HASH_SZ 4096
6167
6168 int
ddi_soft_state_bystr_init(ddi_soft_state_bystr ** state_p,size_t size,int n_items)6169 ddi_soft_state_bystr_init(ddi_soft_state_bystr **state_p, size_t size,
6170 int n_items)
6171 {
6172 i_ddi_soft_state_bystr *sss;
6173 int hash_sz;
6174
6175 ASSERT(state_p && size && n_items);
6176 if ((state_p == NULL) || (size == 0) || (n_items == 0))
6177 return (EINVAL);
6178
6179 /* current implementation is based on hash, convert n_items to hash */
6180 hash_sz = n_items / SS_N_ITEMS_PER_HASH;
6181 if (hash_sz < SS_MIN_HASH_SZ)
6182 hash_sz = SS_MIN_HASH_SZ;
6183 else if (hash_sz > SS_MAX_HASH_SZ)
6184 hash_sz = SS_MAX_HASH_SZ;
6185
6186 /* allocate soft_state pool */
6187 sss = kmem_zalloc(sizeof (*sss), KM_SLEEP);
6188 sss->ss_size = size;
6189 sss->ss_mod_hash = mod_hash_create_strhash("soft_state_bystr",
6190 hash_sz, mod_hash_null_valdtor);
6191 *state_p = (ddi_soft_state_bystr *)sss;
6192 return (0);
6193 }
6194
6195 int
ddi_soft_state_bystr_zalloc(ddi_soft_state_bystr * state,const char * str)6196 ddi_soft_state_bystr_zalloc(ddi_soft_state_bystr *state, const char *str)
6197 {
6198 i_ddi_soft_state_bystr *sss = (i_ddi_soft_state_bystr *)state;
6199 void *sso;
6200 char *dup_str;
6201
6202 ASSERT(sss && str && sss->ss_mod_hash);
6203 if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
6204 return (DDI_FAILURE);
6205 sso = kmem_zalloc(sss->ss_size, KM_SLEEP);
6206 dup_str = i_ddi_strdup((char *)str, KM_SLEEP);
6207 if (mod_hash_insert(sss->ss_mod_hash,
6208 (mod_hash_key_t)dup_str, (mod_hash_val_t)sso) == 0)
6209 return (DDI_SUCCESS);
6210
6211 /*
6212 * The only error from an strhash insert is caused by a duplicate key.
6213 * We refuse to tread on an existing elements, so free and fail.
6214 */
6215 kmem_free(dup_str, strlen(dup_str) + 1);
6216 kmem_free(sso, sss->ss_size);
6217 return (DDI_FAILURE);
6218 }
6219
6220 void *
ddi_soft_state_bystr_get(ddi_soft_state_bystr * state,const char * str)6221 ddi_soft_state_bystr_get(ddi_soft_state_bystr *state, const char *str)
6222 {
6223 i_ddi_soft_state_bystr *sss = (i_ddi_soft_state_bystr *)state;
6224 void *sso;
6225
6226 ASSERT(sss && str && sss->ss_mod_hash);
6227 if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
6228 return (NULL);
6229
6230 if (mod_hash_find(sss->ss_mod_hash,
6231 (mod_hash_key_t)str, (mod_hash_val_t *)&sso) == 0)
6232 return (sso);
6233 return (NULL);
6234 }
6235
6236 void
ddi_soft_state_bystr_free(ddi_soft_state_bystr * state,const char * str)6237 ddi_soft_state_bystr_free(ddi_soft_state_bystr *state, const char *str)
6238 {
6239 i_ddi_soft_state_bystr *sss = (i_ddi_soft_state_bystr *)state;
6240 void *sso;
6241
6242 ASSERT(sss && str && sss->ss_mod_hash);
6243 if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
6244 return;
6245
6246 (void) mod_hash_remove(sss->ss_mod_hash,
6247 (mod_hash_key_t)str, (mod_hash_val_t *)&sso);
6248 kmem_free(sso, sss->ss_size);
6249 }
6250
6251 void
ddi_soft_state_bystr_fini(ddi_soft_state_bystr ** state_p)6252 ddi_soft_state_bystr_fini(ddi_soft_state_bystr **state_p)
6253 {
6254 i_ddi_soft_state_bystr *sss;
6255
6256 ASSERT(state_p);
6257 if (state_p == NULL)
6258 return;
6259
6260 sss = (i_ddi_soft_state_bystr *)(*state_p);
6261 if (sss == NULL)
6262 return;
6263
6264 ASSERT(sss->ss_mod_hash);
6265 if (sss->ss_mod_hash) {
6266 mod_hash_destroy_strhash(sss->ss_mod_hash);
6267 sss->ss_mod_hash = NULL;
6268 }
6269
6270 kmem_free(sss, sizeof (*sss));
6271 *state_p = NULL;
6272 }
6273
6274 /*
6275 * The ddi_strid_* routines provide string-to-index management utilities.
6276 */
6277 /* allocate and initialize an strid set */
6278 int
ddi_strid_init(ddi_strid ** strid_p,int n_items)6279 ddi_strid_init(ddi_strid **strid_p, int n_items)
6280 {
6281 i_ddi_strid *ss;
6282 int hash_sz;
6283
6284 if (strid_p == NULL)
6285 return (DDI_FAILURE);
6286
6287 /* current implementation is based on hash, convert n_items to hash */
6288 hash_sz = n_items / SS_N_ITEMS_PER_HASH;
6289 if (hash_sz < SS_MIN_HASH_SZ)
6290 hash_sz = SS_MIN_HASH_SZ;
6291 else if (hash_sz > SS_MAX_HASH_SZ)
6292 hash_sz = SS_MAX_HASH_SZ;
6293
6294 ss = kmem_alloc(sizeof (*ss), KM_SLEEP);
6295 ss->strid_chunksz = n_items;
6296 ss->strid_spacesz = n_items;
6297 ss->strid_space = id_space_create("strid", 1, n_items);
6298 ss->strid_bystr = mod_hash_create_strhash("strid_bystr", hash_sz,
6299 mod_hash_null_valdtor);
6300 ss->strid_byid = mod_hash_create_idhash("strid_byid", hash_sz,
6301 mod_hash_null_valdtor);
6302 *strid_p = (ddi_strid *)ss;
6303 return (DDI_SUCCESS);
6304 }
6305
6306 /* allocate an id mapping within the specified set for str, return id */
6307 static id_t
i_ddi_strid_alloc(ddi_strid * strid,char * str)6308 i_ddi_strid_alloc(ddi_strid *strid, char *str)
6309 {
6310 i_ddi_strid *ss = (i_ddi_strid *)strid;
6311 id_t id;
6312 char *s;
6313
6314 ASSERT(ss && str);
6315 if ((ss == NULL) || (str == NULL))
6316 return (0);
6317
6318 /*
6319 * Allocate an id using VM_FIRSTFIT in order to keep allocated id
6320 * range as compressed as possible. This is important to minimize
6321 * the amount of space used when the id is used as a ddi_soft_state
6322 * index by the caller.
6323 *
6324 * If the id list is exhausted, increase the size of the list
6325 * by the chuck size specified in ddi_strid_init and reattempt
6326 * the allocation
6327 */
6328 if ((id = id_allocff_nosleep(ss->strid_space)) == (id_t)-1) {
6329 id_space_extend(ss->strid_space, ss->strid_spacesz,
6330 ss->strid_spacesz + ss->strid_chunksz);
6331 ss->strid_spacesz += ss->strid_chunksz;
6332 if ((id = id_allocff_nosleep(ss->strid_space)) == (id_t)-1)
6333 return (0);
6334 }
6335
6336 /*
6337 * NOTE: since we create and destroy in unison we can save space by
6338 * using bystr key as the byid value. This means destroy must occur
6339 * in (byid, bystr) order.
6340 */
6341 s = i_ddi_strdup(str, KM_SLEEP);
6342 if (mod_hash_insert(ss->strid_bystr, (mod_hash_key_t)s,
6343 (mod_hash_val_t)(intptr_t)id) != 0) {
6344 ddi_strid_free(strid, id);
6345 return (0);
6346 }
6347 if (mod_hash_insert(ss->strid_byid, (mod_hash_key_t)(intptr_t)id,
6348 (mod_hash_val_t)s) != 0) {
6349 ddi_strid_free(strid, id);
6350 return (0);
6351 }
6352
6353 /* NOTE: s if freed on mod_hash_destroy by mod_hash_strval_dtor */
6354 return (id);
6355 }
6356
6357 /* allocate an id mapping within the specified set for str, return id */
6358 id_t
ddi_strid_alloc(ddi_strid * strid,char * str)6359 ddi_strid_alloc(ddi_strid *strid, char *str)
6360 {
6361 return (i_ddi_strid_alloc(strid, str));
6362 }
6363
6364 /* return the id within the specified strid given the str */
6365 id_t
ddi_strid_str2id(ddi_strid * strid,char * str)6366 ddi_strid_str2id(ddi_strid *strid, char *str)
6367 {
6368 i_ddi_strid *ss = (i_ddi_strid *)strid;
6369 id_t id = 0;
6370 mod_hash_val_t hv;
6371
6372 ASSERT(ss && str);
6373 if (ss && str && (mod_hash_find(ss->strid_bystr,
6374 (mod_hash_key_t)str, &hv) == 0))
6375 id = (int)(intptr_t)hv;
6376 return (id);
6377 }
6378
6379 /* return str within the specified strid given the id */
6380 char *
ddi_strid_id2str(ddi_strid * strid,id_t id)6381 ddi_strid_id2str(ddi_strid *strid, id_t id)
6382 {
6383 i_ddi_strid *ss = (i_ddi_strid *)strid;
6384 char *str = NULL;
6385 mod_hash_val_t hv;
6386
6387 ASSERT(ss && id > 0);
6388 if (ss && (id > 0) && (mod_hash_find(ss->strid_byid,
6389 (mod_hash_key_t)(uintptr_t)id, &hv) == 0))
6390 str = (char *)hv;
6391 return (str);
6392 }
6393
6394 /* free the id mapping within the specified strid */
6395 void
ddi_strid_free(ddi_strid * strid,id_t id)6396 ddi_strid_free(ddi_strid *strid, id_t id)
6397 {
6398 i_ddi_strid *ss = (i_ddi_strid *)strid;
6399 char *str;
6400
6401 ASSERT(ss && id > 0);
6402 if ((ss == NULL) || (id <= 0))
6403 return;
6404
6405 /* bystr key is byid value: destroy order must be (byid, bystr) */
6406 str = ddi_strid_id2str(strid, id);
6407 (void) mod_hash_destroy(ss->strid_byid, (mod_hash_key_t)(uintptr_t)id);
6408 id_free(ss->strid_space, id);
6409
6410 if (str)
6411 (void) mod_hash_destroy(ss->strid_bystr, (mod_hash_key_t)str);
6412 }
6413
6414 /* destroy the strid set */
6415 void
ddi_strid_fini(ddi_strid ** strid_p)6416 ddi_strid_fini(ddi_strid **strid_p)
6417 {
6418 i_ddi_strid *ss;
6419
6420 ASSERT(strid_p);
6421 if (strid_p == NULL)
6422 return;
6423
6424 ss = (i_ddi_strid *)(*strid_p);
6425 if (ss == NULL)
6426 return;
6427
6428 /* bystr key is byid value: destroy order must be (byid, bystr) */
6429 if (ss->strid_byid)
6430 mod_hash_destroy_hash(ss->strid_byid);
6431 if (ss->strid_byid)
6432 mod_hash_destroy_hash(ss->strid_bystr);
6433 if (ss->strid_space)
6434 id_space_destroy(ss->strid_space);
6435 kmem_free(ss, sizeof (*ss));
6436 *strid_p = NULL;
6437 }
6438
6439 /*
6440 * This sets the devi_addr entry in the dev_info structure 'dip' to 'name'.
6441 * Storage is double buffered to prevent updates during devi_addr use -
6442 * double buffering is adaquate for reliable ddi_deviname() consumption.
6443 * The double buffer is not freed until dev_info structure destruction
6444 * (by i_ddi_free_node).
6445 */
6446 void
ddi_set_name_addr(dev_info_t * dip,char * name)6447 ddi_set_name_addr(dev_info_t *dip, char *name)
6448 {
6449 char *buf = DEVI(dip)->devi_addr_buf;
6450 char *newaddr;
6451
6452 if (buf == NULL) {
6453 buf = kmem_zalloc(2 * MAXNAMELEN, KM_SLEEP);
6454 DEVI(dip)->devi_addr_buf = buf;
6455 }
6456
6457 if (name) {
6458 ASSERT(strlen(name) < MAXNAMELEN);
6459 newaddr = (DEVI(dip)->devi_addr == buf) ?
6460 (buf + MAXNAMELEN) : buf;
6461 (void) strlcpy(newaddr, name, MAXNAMELEN);
6462 } else
6463 newaddr = NULL;
6464
6465 DEVI(dip)->devi_addr = newaddr;
6466 }
6467
6468 char *
ddi_get_name_addr(dev_info_t * dip)6469 ddi_get_name_addr(dev_info_t *dip)
6470 {
6471 return (DEVI(dip)->devi_addr);
6472 }
6473
6474 void
ddi_set_parent_data(dev_info_t * dip,void * pd)6475 ddi_set_parent_data(dev_info_t *dip, void *pd)
6476 {
6477 DEVI(dip)->devi_parent_data = pd;
6478 }
6479
6480 void *
ddi_get_parent_data(dev_info_t * dip)6481 ddi_get_parent_data(dev_info_t *dip)
6482 {
6483 return (DEVI(dip)->devi_parent_data);
6484 }
6485
6486 /*
6487 * ddi_name_to_major: returns the major number of a named module,
6488 * derived from the current driver alias binding.
6489 *
6490 * Caveat: drivers should avoid the use of this function, in particular
6491 * together with ddi_get_name/ddi_binding name, as per
6492 * major = ddi_name_to_major(ddi_get_name(devi));
6493 * ddi_name_to_major() relies on the state of the device/alias binding,
6494 * which can and does change dynamically as aliases are administered
6495 * over time. An attached device instance cannot rely on the major
6496 * number returned by ddi_name_to_major() to match its own major number.
6497 *
6498 * For driver use, ddi_driver_major() reliably returns the major number
6499 * for the module to which the device was bound at attach time over
6500 * the life of the instance.
6501 * major = ddi_driver_major(dev_info_t *)
6502 */
6503 major_t
ddi_name_to_major(const char * name)6504 ddi_name_to_major(const char *name)
6505 {
6506 return (mod_name_to_major(name));
6507 }
6508
6509 /*
6510 * ddi_major_to_name: Returns the module name bound to a major number.
6511 */
6512 char *
ddi_major_to_name(major_t major)6513 ddi_major_to_name(major_t major)
6514 {
6515 return (mod_major_to_name(major));
6516 }
6517
6518 /*
6519 * Return the name of the devinfo node pointed at by 'dip' in the buffer
6520 * pointed at by 'name.' A devinfo node is named as a result of calling
6521 * ddi_initchild().
6522 *
6523 * Note: the driver must be held before calling this function!
6524 */
6525 char *
ddi_deviname(dev_info_t * dip,char * name)6526 ddi_deviname(dev_info_t *dip, char *name)
6527 {
6528 char *addrname;
6529 char none = '\0';
6530
6531 if (dip == ddi_root_node()) {
6532 *name = '\0';
6533 return (name);
6534 }
6535
6536 if (i_ddi_node_state(dip) < DS_BOUND) {
6537 addrname = &none;
6538 } else {
6539 /*
6540 * Use ddi_get_name_addr() without checking state so we get
6541 * a unit-address if we are called after ddi_set_name_addr()
6542 * by nexus DDI_CTL_INITCHILD code, but before completing
6543 * node promotion to DS_INITIALIZED. We currently have
6544 * two situations where we are called in this state:
6545 * o For framework processing of a path-oriented alias.
6546 * o If a SCSA nexus driver calls ddi_devid_register()
6547 * from it's tran_tgt_init(9E) implementation.
6548 */
6549 addrname = ddi_get_name_addr(dip);
6550 if (addrname == NULL)
6551 addrname = &none;
6552 }
6553
6554 if (*addrname == '\0') {
6555 (void) sprintf(name, "/%s", ddi_node_name(dip));
6556 } else {
6557 (void) sprintf(name, "/%s@%s", ddi_node_name(dip), addrname);
6558 }
6559
6560 return (name);
6561 }
6562
6563 /*
6564 * Spits out the name of device node, typically name@addr, for a given node,
6565 * using the driver name, not the nodename.
6566 *
6567 * Used by match_parent. Not to be used elsewhere.
6568 */
6569 char *
i_ddi_parname(dev_info_t * dip,char * name)6570 i_ddi_parname(dev_info_t *dip, char *name)
6571 {
6572 char *addrname;
6573
6574 if (dip == ddi_root_node()) {
6575 *name = '\0';
6576 return (name);
6577 }
6578
6579 ASSERT(i_ddi_node_state(dip) >= DS_INITIALIZED);
6580
6581 if (*(addrname = ddi_get_name_addr(dip)) == '\0')
6582 (void) sprintf(name, "%s", ddi_binding_name(dip));
6583 else
6584 (void) sprintf(name, "%s@%s", ddi_binding_name(dip), addrname);
6585 return (name);
6586 }
6587
6588 static char *
pathname_work(dev_info_t * dip,char * path)6589 pathname_work(dev_info_t *dip, char *path)
6590 {
6591 char *bp;
6592
6593 if (dip == ddi_root_node()) {
6594 *path = '\0';
6595 return (path);
6596 }
6597 (void) pathname_work(ddi_get_parent(dip), path);
6598 bp = path + strlen(path);
6599 (void) ddi_deviname(dip, bp);
6600 return (path);
6601 }
6602
6603 char *
ddi_pathname(dev_info_t * dip,char * path)6604 ddi_pathname(dev_info_t *dip, char *path)
6605 {
6606 return (pathname_work(dip, path));
6607 }
6608
6609 char *
ddi_pathname_minor(struct ddi_minor_data * dmdp,char * path)6610 ddi_pathname_minor(struct ddi_minor_data *dmdp, char *path)
6611 {
6612 if (dmdp->dip == NULL)
6613 *path = '\0';
6614 else {
6615 (void) ddi_pathname(dmdp->dip, path);
6616 if (dmdp->ddm_name) {
6617 (void) strcat(path, ":");
6618 (void) strcat(path, dmdp->ddm_name);
6619 }
6620 }
6621 return (path);
6622 }
6623
6624 static char *
pathname_work_obp(dev_info_t * dip,char * path)6625 pathname_work_obp(dev_info_t *dip, char *path)
6626 {
6627 char *bp;
6628 char *obp_path;
6629
6630 /*
6631 * look up the "obp-path" property, return the path if it exists
6632 */
6633 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
6634 "obp-path", &obp_path) == DDI_PROP_SUCCESS) {
6635 (void) strcpy(path, obp_path);
6636 ddi_prop_free(obp_path);
6637 return (path);
6638 }
6639
6640 /*
6641 * stop at root, no obp path
6642 */
6643 if (dip == ddi_root_node()) {
6644 return (NULL);
6645 }
6646
6647 obp_path = pathname_work_obp(ddi_get_parent(dip), path);
6648 if (obp_path == NULL)
6649 return (NULL);
6650
6651 /*
6652 * append our component to parent's obp path
6653 */
6654 bp = path + strlen(path);
6655 if (*(bp - 1) != '/')
6656 (void) strcat(bp++, "/");
6657 (void) ddi_deviname(dip, bp);
6658 return (path);
6659 }
6660
6661 /*
6662 * return the 'obp-path' based path for the given node, or NULL if the node
6663 * does not have a different obp path. NOTE: Unlike ddi_pathname, this
6664 * function can't be called from interrupt context (since we need to
6665 * lookup a string property).
6666 */
6667 char *
ddi_pathname_obp(dev_info_t * dip,char * path)6668 ddi_pathname_obp(dev_info_t *dip, char *path)
6669 {
6670 ASSERT(!servicing_interrupt());
6671 if (dip == NULL || path == NULL)
6672 return (NULL);
6673
6674 /* split work into a separate function to aid debugging */
6675 return (pathname_work_obp(dip, path));
6676 }
6677
6678 int
ddi_pathname_obp_set(dev_info_t * dip,char * component)6679 ddi_pathname_obp_set(dev_info_t *dip, char *component)
6680 {
6681 dev_info_t *pdip;
6682 char *obp_path = NULL;
6683 int rc = DDI_FAILURE;
6684
6685 if (dip == NULL)
6686 return (DDI_FAILURE);
6687
6688 obp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
6689
6690 pdip = ddi_get_parent(dip);
6691
6692 if (ddi_pathname_obp(pdip, obp_path) == NULL) {
6693 (void) ddi_pathname(pdip, obp_path);
6694 }
6695
6696 if (component) {
6697 (void) strncat(obp_path, "/", MAXPATHLEN);
6698 (void) strncat(obp_path, component, MAXPATHLEN);
6699 }
6700 rc = ndi_prop_update_string(DDI_DEV_T_NONE, dip, "obp-path",
6701 obp_path);
6702
6703 if (obp_path)
6704 kmem_free(obp_path, MAXPATHLEN);
6705
6706 return (rc);
6707 }
6708
6709 /*
6710 * Given a dev_t, return the pathname of the corresponding device in the
6711 * buffer pointed at by "path." The buffer is assumed to be large enough
6712 * to hold the pathname of the device (MAXPATHLEN).
6713 *
6714 * The pathname of a device is the pathname of the devinfo node to which
6715 * the device "belongs," concatenated with the character ':' and the name
6716 * of the minor node corresponding to the dev_t. If spec_type is 0 then
6717 * just the pathname of the devinfo node is returned without driving attach
6718 * of that node. For a non-zero spec_type, an attach is performed and a
6719 * search of the minor list occurs.
6720 *
6721 * It is possible that the path associated with the dev_t is not
6722 * currently available in the devinfo tree. In order to have a
6723 * dev_t, a device must have been discovered before, which means
6724 * that the path is always in the instance tree. The one exception
6725 * to this is if the dev_t is associated with a pseudo driver, in
6726 * which case the device must exist on the pseudo branch of the
6727 * devinfo tree as a result of parsing .conf files.
6728 */
6729 int
ddi_dev_pathname(dev_t devt,int spec_type,char * path)6730 ddi_dev_pathname(dev_t devt, int spec_type, char *path)
6731 {
6732 major_t major = getmajor(devt);
6733 int instance;
6734 dev_info_t *dip;
6735 char *minorname;
6736 char *drvname;
6737
6738 if (major >= devcnt)
6739 goto fail;
6740 if (major == clone_major) {
6741 /* clone has no minor nodes, manufacture the path here */
6742 if ((drvname = ddi_major_to_name(getminor(devt))) == NULL)
6743 goto fail;
6744
6745 (void) snprintf(path, MAXPATHLEN, "%s:%s", CLONE_PATH, drvname);
6746 return (DDI_SUCCESS);
6747 }
6748
6749 /* extract instance from devt (getinfo(9E) DDI_INFO_DEVT2INSTANCE). */
6750 if ((instance = dev_to_instance(devt)) == -1)
6751 goto fail;
6752
6753 /* reconstruct the path given the major/instance */
6754 if (e_ddi_majorinstance_to_path(major, instance, path) != DDI_SUCCESS)
6755 goto fail;
6756
6757 /* if spec_type given we must drive attach and search minor nodes */
6758 if ((spec_type == S_IFCHR) || (spec_type == S_IFBLK)) {
6759 /* attach the path so we can search minors */
6760 if ((dip = e_ddi_hold_devi_by_path(path, 0)) == NULL)
6761 goto fail;
6762
6763 /* Add minorname to path. */
6764 ndi_devi_enter(dip);
6765 minorname = i_ddi_devtspectype_to_minorname(dip,
6766 devt, spec_type);
6767 if (minorname) {
6768 (void) strcat(path, ":");
6769 (void) strcat(path, minorname);
6770 }
6771 ndi_devi_exit(dip);
6772 ddi_release_devi(dip);
6773 if (minorname == NULL)
6774 goto fail;
6775 }
6776 ASSERT(strlen(path) < MAXPATHLEN);
6777 return (DDI_SUCCESS);
6778
6779 fail: *path = 0;
6780 return (DDI_FAILURE);
6781 }
6782
6783 /*
6784 * Given a major number and an instance, return the path.
6785 * This interface does NOT drive attach.
6786 */
6787 int
e_ddi_majorinstance_to_path(major_t major,int instance,char * path)6788 e_ddi_majorinstance_to_path(major_t major, int instance, char *path)
6789 {
6790 struct devnames *dnp;
6791 dev_info_t *dip;
6792
6793 if ((major >= devcnt) || (instance == -1)) {
6794 *path = 0;
6795 return (DDI_FAILURE);
6796 }
6797
6798 /* look for the major/instance in the instance tree */
6799 if (e_ddi_instance_majorinstance_to_path(major, instance,
6800 path) == DDI_SUCCESS) {
6801 ASSERT(strlen(path) < MAXPATHLEN);
6802 return (DDI_SUCCESS);
6803 }
6804
6805 /*
6806 * Not in instance tree, find the instance on the per driver list and
6807 * construct path to instance via ddi_pathname(). This is how paths
6808 * down the 'pseudo' branch are constructed.
6809 */
6810 dnp = &(devnamesp[major]);
6811 LOCK_DEV_OPS(&(dnp->dn_lock));
6812 for (dip = dnp->dn_head; dip;
6813 dip = (dev_info_t *)DEVI(dip)->devi_next) {
6814 /* Skip if instance does not match. */
6815 if (DEVI(dip)->devi_instance != instance)
6816 continue;
6817
6818 /*
6819 * An ndi_hold_devi() does not prevent DS_INITIALIZED->DS_BOUND
6820 * node demotion, so it is not an effective way of ensuring
6821 * that the ddi_pathname result has a unit-address. Instead,
6822 * we reverify the node state after calling ddi_pathname().
6823 */
6824 if (i_ddi_node_state(dip) >= DS_INITIALIZED) {
6825 (void) ddi_pathname(dip, path);
6826 if (i_ddi_node_state(dip) < DS_INITIALIZED)
6827 continue;
6828 UNLOCK_DEV_OPS(&(dnp->dn_lock));
6829 ASSERT(strlen(path) < MAXPATHLEN);
6830 return (DDI_SUCCESS);
6831 }
6832 }
6833 UNLOCK_DEV_OPS(&(dnp->dn_lock));
6834
6835 /* can't reconstruct the path */
6836 *path = 0;
6837 return (DDI_FAILURE);
6838 }
6839
6840 #define GLD_DRIVER_PPA "SUNW,gld_v0_ppa"
6841
6842 /*
6843 * Given the dip for a network interface return the ppa for that interface.
6844 *
6845 * In all cases except GLD v0 drivers, the ppa == instance.
6846 * In the case of GLD v0 drivers, the ppa is equal to the attach order.
6847 * So for these drivers when the attach routine calls gld_register(),
6848 * the GLD framework creates an integer property called "gld_driver_ppa"
6849 * that can be queried here.
6850 *
6851 * The only time this function is used is when a system is booting over nfs.
6852 * In this case the system has to resolve the pathname of the boot device
6853 * to it's ppa.
6854 */
6855 int
i_ddi_devi_get_ppa(dev_info_t * dip)6856 i_ddi_devi_get_ppa(dev_info_t *dip)
6857 {
6858 return (ddi_prop_get_int(DDI_DEV_T_ANY, dip,
6859 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
6860 GLD_DRIVER_PPA, ddi_get_instance(dip)));
6861 }
6862
6863 /*
6864 * i_ddi_devi_set_ppa() should only be called from gld_register()
6865 * and only for GLD v0 drivers
6866 */
6867 void
i_ddi_devi_set_ppa(dev_info_t * dip,int ppa)6868 i_ddi_devi_set_ppa(dev_info_t *dip, int ppa)
6869 {
6870 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, dip, GLD_DRIVER_PPA, ppa);
6871 }
6872
6873
6874 /*
6875 * Private DDI Console bell functions.
6876 */
6877 void
ddi_ring_console_bell(clock_t duration)6878 ddi_ring_console_bell(clock_t duration)
6879 {
6880 if (ddi_console_bell_func != NULL)
6881 (*ddi_console_bell_func)(duration);
6882 }
6883
6884 void
ddi_set_console_bell(void (* bellfunc)(clock_t duration))6885 ddi_set_console_bell(void (*bellfunc)(clock_t duration))
6886 {
6887 ddi_console_bell_func = bellfunc;
6888 }
6889
6890 int
ddi_dma_alloc_handle(dev_info_t * dip,const ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)6891 ddi_dma_alloc_handle(dev_info_t *dip, const ddi_dma_attr_t *attr,
6892 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
6893 {
6894 int (*funcp)() = ddi_dma_allochdl;
6895 ddi_dma_attr_t dma_attr;
6896 struct bus_ops *bop;
6897
6898 if (attr == NULL)
6899 return (DDI_DMA_BADATTR);
6900
6901 dma_attr = *attr;
6902
6903 bop = DEVI(dip)->devi_ops->devo_bus_ops;
6904 if (bop && bop->bus_dma_allochdl)
6905 funcp = bop->bus_dma_allochdl;
6906
6907 return ((*funcp)(dip, dip, &dma_attr, waitfp, arg, handlep));
6908 }
6909
6910 void
ddi_dma_free_handle(ddi_dma_handle_t * handlep)6911 ddi_dma_free_handle(ddi_dma_handle_t *handlep)
6912 {
6913 ddi_dma_handle_t h = *handlep;
6914 (void) ddi_dma_freehdl(HD, HD, h);
6915 }
6916
6917 static uintptr_t dma_mem_list_id = 0;
6918
6919
6920 int
ddi_dma_mem_alloc(ddi_dma_handle_t handle,size_t length,const ddi_device_acc_attr_t * accattrp,uint_t flags,int (* waitfp)(caddr_t),caddr_t arg,caddr_t * kaddrp,size_t * real_length,ddi_acc_handle_t * handlep)6921 ddi_dma_mem_alloc(ddi_dma_handle_t handle, size_t length,
6922 const ddi_device_acc_attr_t *accattrp, uint_t flags,
6923 int (*waitfp)(caddr_t), caddr_t arg, caddr_t *kaddrp,
6924 size_t *real_length, ddi_acc_handle_t *handlep)
6925 {
6926 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6927 dev_info_t *dip = hp->dmai_rdip;
6928 ddi_acc_hdl_t *ap;
6929 ddi_dma_attr_t *attrp = &hp->dmai_attr;
6930 uint_t sleepflag, xfermodes;
6931 int (*fp)(caddr_t);
6932 int rval;
6933
6934 if (waitfp == DDI_DMA_SLEEP)
6935 fp = (int (*)())KM_SLEEP;
6936 else if (waitfp == DDI_DMA_DONTWAIT)
6937 fp = (int (*)())KM_NOSLEEP;
6938 else
6939 fp = waitfp;
6940 *handlep = impl_acc_hdl_alloc(fp, arg);
6941 if (*handlep == NULL)
6942 return (DDI_FAILURE);
6943
6944 /* check if the cache attributes are supported */
6945 if (i_ddi_check_cache_attr(flags) == B_FALSE)
6946 return (DDI_FAILURE);
6947
6948 /*
6949 * Transfer the meaningful bits to xfermodes.
6950 * Double-check if the 3rd party driver correctly sets the bits.
6951 * If not, set DDI_DMA_STREAMING to keep compatibility.
6952 */
6953 xfermodes = flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING);
6954 if (xfermodes == 0) {
6955 xfermodes = DDI_DMA_STREAMING;
6956 }
6957
6958 /*
6959 * initialize the common elements of data access handle
6960 */
6961 ap = impl_acc_hdl_get(*handlep);
6962 ap->ah_vers = VERS_ACCHDL;
6963 ap->ah_dip = dip;
6964 ap->ah_offset = 0;
6965 ap->ah_len = 0;
6966 ap->ah_xfermodes = flags;
6967 ap->ah_acc = *accattrp;
6968
6969 sleepflag = ((waitfp == DDI_DMA_SLEEP) ? 1 : 0);
6970 if (xfermodes == DDI_DMA_CONSISTENT) {
6971 rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag,
6972 flags, accattrp, kaddrp, NULL, ap);
6973 *real_length = length;
6974 } else {
6975 rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag,
6976 flags, accattrp, kaddrp, real_length, ap);
6977 }
6978 if (rval == DDI_SUCCESS) {
6979 ap->ah_len = (off_t)(*real_length);
6980 ap->ah_addr = *kaddrp;
6981 } else {
6982 impl_acc_hdl_free(*handlep);
6983 *handlep = (ddi_acc_handle_t)NULL;
6984 if (waitfp != DDI_DMA_SLEEP && waitfp != DDI_DMA_DONTWAIT) {
6985 ddi_set_callback(waitfp, arg, &dma_mem_list_id);
6986 }
6987 rval = DDI_FAILURE;
6988 }
6989 return (rval);
6990 }
6991
6992 void
ddi_dma_mem_free(ddi_acc_handle_t * handlep)6993 ddi_dma_mem_free(ddi_acc_handle_t *handlep)
6994 {
6995 ddi_acc_hdl_t *ap;
6996
6997 ap = impl_acc_hdl_get(*handlep);
6998 ASSERT(ap);
6999
7000 i_ddi_mem_free((caddr_t)ap->ah_addr, ap);
7001
7002 /*
7003 * free the handle
7004 */
7005 impl_acc_hdl_free(*handlep);
7006 *handlep = (ddi_acc_handle_t)NULL;
7007
7008 if (dma_mem_list_id != 0) {
7009 ddi_run_callback(&dma_mem_list_id);
7010 }
7011 }
7012
7013 int
ddi_dma_buf_bind_handle(ddi_dma_handle_t handle,struct buf * bp,uint_t flags,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_cookie_t * cookiep,uint_t * ccountp)7014 ddi_dma_buf_bind_handle(ddi_dma_handle_t handle, struct buf *bp,
7015 uint_t flags, int (*waitfp)(caddr_t), caddr_t arg,
7016 ddi_dma_cookie_t *cookiep, uint_t *ccountp)
7017 {
7018 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7019 dev_info_t *dip, *rdip;
7020 struct ddi_dma_req dmareq;
7021 int (*funcp)();
7022 ddi_dma_cookie_t cookie;
7023 uint_t count;
7024
7025 if (cookiep == NULL)
7026 cookiep = &cookie;
7027
7028 if (ccountp == NULL)
7029 ccountp = &count;
7030
7031 dmareq.dmar_flags = flags;
7032 dmareq.dmar_fp = waitfp;
7033 dmareq.dmar_arg = arg;
7034 dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount;
7035
7036 if (bp->b_flags & B_PAGEIO) {
7037 dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES;
7038 dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages;
7039 dmareq.dmar_object.dmao_obj.pp_obj.pp_offset =
7040 (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET);
7041 } else {
7042 dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr;
7043 if (bp->b_flags & B_SHADOW) {
7044 dmareq.dmar_object.dmao_obj.virt_obj.v_priv =
7045 bp->b_shadow;
7046 dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR;
7047 } else {
7048 dmareq.dmar_object.dmao_type =
7049 (bp->b_flags & (B_PHYS | B_REMAPPED)) ?
7050 DMA_OTYP_BUFVADDR : DMA_OTYP_VADDR;
7051 dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
7052 }
7053
7054 /*
7055 * If the buffer has no proc pointer, or the proc
7056 * struct has the kernel address space, or the buffer has
7057 * been marked B_REMAPPED (meaning that it is now
7058 * mapped into the kernel's address space), then
7059 * the address space is kas (kernel address space).
7060 */
7061 if ((bp->b_proc == NULL) || (bp->b_proc->p_as == &kas) ||
7062 (bp->b_flags & B_REMAPPED)) {
7063 dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0;
7064 } else {
7065 dmareq.dmar_object.dmao_obj.virt_obj.v_as =
7066 bp->b_proc->p_as;
7067 }
7068 }
7069
7070 dip = rdip = hp->dmai_rdip;
7071 if (dip != ddi_root_node())
7072 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
7073 funcp = DEVI(rdip)->devi_bus_dma_bindfunc;
7074 return ((*funcp)(dip, rdip, handle, &dmareq, cookiep, ccountp));
7075 }
7076
7077 int
ddi_dma_addr_bind_handle(ddi_dma_handle_t handle,struct as * as,caddr_t addr,size_t len,uint_t flags,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_cookie_t * cookiep,uint_t * ccountp)7078 ddi_dma_addr_bind_handle(ddi_dma_handle_t handle, struct as *as,
7079 caddr_t addr, size_t len, uint_t flags, int (*waitfp)(caddr_t),
7080 caddr_t arg, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
7081 {
7082 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7083 dev_info_t *dip, *rdip;
7084 struct ddi_dma_req dmareq;
7085 int (*funcp)();
7086 ddi_dma_cookie_t cookie;
7087 uint_t count;
7088
7089 if (len == (uint_t)0) {
7090 return (DDI_DMA_NOMAPPING);
7091 }
7092
7093 if (cookiep == NULL)
7094 cookiep = &cookie;
7095
7096 if (ccountp == NULL)
7097 ccountp = &count;
7098
7099 dmareq.dmar_flags = flags;
7100 dmareq.dmar_fp = waitfp;
7101 dmareq.dmar_arg = arg;
7102 dmareq.dmar_object.dmao_size = len;
7103 dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
7104 dmareq.dmar_object.dmao_obj.virt_obj.v_as = as;
7105 dmareq.dmar_object.dmao_obj.virt_obj.v_addr = addr;
7106 dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
7107
7108 dip = rdip = hp->dmai_rdip;
7109 if (dip != ddi_root_node())
7110 dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
7111 funcp = DEVI(rdip)->devi_bus_dma_bindfunc;
7112 return ((*funcp)(dip, rdip, handle, &dmareq, cookiep, ccountp));
7113 }
7114
7115 void
ddi_dma_nextcookie(ddi_dma_handle_t handle,ddi_dma_cookie_t * cookiep)7116 ddi_dma_nextcookie(ddi_dma_handle_t handle, ddi_dma_cookie_t *cookiep)
7117 {
7118 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7119 ddi_dma_cookie_t *cp;
7120
7121 if (hp->dmai_curcookie >= hp->dmai_ncookies) {
7122 panic("ddi_dma_nextcookie() called too many times on handle %p",
7123 hp);
7124 }
7125
7126 cp = hp->dmai_cookie;
7127 ASSERT(cp);
7128
7129 cookiep->dmac_notused = cp->dmac_notused;
7130 cookiep->dmac_type = cp->dmac_type;
7131 cookiep->dmac_address = cp->dmac_address;
7132 cookiep->dmac_size = cp->dmac_size;
7133 hp->dmai_cookie++;
7134 hp->dmai_curcookie++;
7135 }
7136
7137 int
ddi_dma_ncookies(ddi_dma_handle_t handle)7138 ddi_dma_ncookies(ddi_dma_handle_t handle)
7139 {
7140 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7141
7142 return (hp->dmai_ncookies);
7143 }
7144
7145 const ddi_dma_cookie_t *
ddi_dma_cookie_iter(ddi_dma_handle_t handle,const ddi_dma_cookie_t * iter)7146 ddi_dma_cookie_iter(ddi_dma_handle_t handle, const ddi_dma_cookie_t *iter)
7147 {
7148 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7149 const ddi_dma_cookie_t *base, *end;
7150
7151 if (hp->dmai_ncookies == 0) {
7152 return (NULL);
7153 }
7154
7155 base = hp->dmai_cookie - hp->dmai_curcookie;
7156 end = base + hp->dmai_ncookies;
7157 if (iter == NULL) {
7158 return (base);
7159 }
7160
7161 if ((uintptr_t)iter < (uintptr_t)base ||
7162 (uintptr_t)iter >= (uintptr_t)end) {
7163 return (NULL);
7164 }
7165
7166 iter++;
7167 if (iter == end) {
7168 return (NULL);
7169 }
7170
7171 return (iter);
7172 }
7173
7174 const ddi_dma_cookie_t *
ddi_dma_cookie_get(ddi_dma_handle_t handle,uint_t index)7175 ddi_dma_cookie_get(ddi_dma_handle_t handle, uint_t index)
7176 {
7177 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7178 const ddi_dma_cookie_t *base;
7179
7180 if (index >= hp->dmai_ncookies) {
7181 return (NULL);
7182 }
7183
7184 base = hp->dmai_cookie - hp->dmai_curcookie;
7185 return (base + index);
7186 }
7187
7188 const ddi_dma_cookie_t *
ddi_dma_cookie_one(ddi_dma_handle_t handle)7189 ddi_dma_cookie_one(ddi_dma_handle_t handle)
7190 {
7191 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7192 const ddi_dma_cookie_t *base;
7193
7194 if (hp->dmai_ncookies != 1) {
7195 panic("ddi_dma_cookie_one() called with improper handle %p",
7196 hp);
7197 }
7198 ASSERT3P(hp->dmai_cookie, !=, NULL);
7199
7200 base = hp->dmai_cookie - hp->dmai_curcookie;
7201 return (base);
7202 }
7203
7204 int
ddi_dma_numwin(ddi_dma_handle_t handle,uint_t * nwinp)7205 ddi_dma_numwin(ddi_dma_handle_t handle, uint_t *nwinp)
7206 {
7207 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7208 if ((hp->dmai_rflags & DDI_DMA_PARTIAL) == 0) {
7209 return (DDI_FAILURE);
7210 } else {
7211 *nwinp = hp->dmai_nwin;
7212 return (DDI_SUCCESS);
7213 }
7214 }
7215
7216 int
ddi_dma_getwin(ddi_dma_handle_t h,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)7217 ddi_dma_getwin(ddi_dma_handle_t h, uint_t win, off_t *offp,
7218 size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
7219 {
7220 int (*funcp)() = ddi_dma_win;
7221 struct bus_ops *bop;
7222 ddi_dma_cookie_t cookie;
7223 uint_t count;
7224
7225 bop = DEVI(HD)->devi_ops->devo_bus_ops;
7226 if (bop && bop->bus_dma_win)
7227 funcp = bop->bus_dma_win;
7228
7229 if (cookiep == NULL)
7230 cookiep = &cookie;
7231
7232 if (ccountp == NULL)
7233 ccountp = &count;
7234
7235 return ((*funcp)(HD, HD, h, win, offp, lenp, cookiep, ccountp));
7236 }
7237
7238 int
ddi_dma_set_sbus64(ddi_dma_handle_t h,ulong_t burstsizes)7239 ddi_dma_set_sbus64(ddi_dma_handle_t h, ulong_t burstsizes)
7240 {
7241 return (ddi_dma_mctl(HD, HD, h, DDI_DMA_SET_SBUS64, 0,
7242 &burstsizes, 0, 0));
7243 }
7244
7245 int
i_ddi_dma_fault_check(ddi_dma_impl_t * hp)7246 i_ddi_dma_fault_check(ddi_dma_impl_t *hp)
7247 {
7248 return (hp->dmai_fault);
7249 }
7250
7251 int
ddi_check_dma_handle(ddi_dma_handle_t handle)7252 ddi_check_dma_handle(ddi_dma_handle_t handle)
7253 {
7254 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7255 int (*check)(ddi_dma_impl_t *);
7256
7257 if ((check = hp->dmai_fault_check) == NULL)
7258 check = i_ddi_dma_fault_check;
7259
7260 return (((*check)(hp) == DDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
7261 }
7262
7263 void
i_ddi_dma_set_fault(ddi_dma_handle_t handle)7264 i_ddi_dma_set_fault(ddi_dma_handle_t handle)
7265 {
7266 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7267 void (*notify)(ddi_dma_impl_t *);
7268
7269 if (!hp->dmai_fault) {
7270 hp->dmai_fault = 1;
7271 if ((notify = hp->dmai_fault_notify) != NULL)
7272 (*notify)(hp);
7273 }
7274 }
7275
7276 void
i_ddi_dma_clr_fault(ddi_dma_handle_t handle)7277 i_ddi_dma_clr_fault(ddi_dma_handle_t handle)
7278 {
7279 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7280 void (*notify)(ddi_dma_impl_t *);
7281
7282 if (hp->dmai_fault) {
7283 hp->dmai_fault = 0;
7284 if ((notify = hp->dmai_fault_notify) != NULL)
7285 (*notify)(hp);
7286 }
7287 }
7288
7289 /*
7290 * register mapping routines.
7291 */
7292 int
ddi_regs_map_setup(dev_info_t * dip,uint_t rnumber,caddr_t * addrp,offset_t offset,offset_t len,const ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handle)7293 ddi_regs_map_setup(dev_info_t *dip, uint_t rnumber, caddr_t *addrp,
7294 offset_t offset, offset_t len, const ddi_device_acc_attr_t *accattrp,
7295 ddi_acc_handle_t *handle)
7296 {
7297 ddi_map_req_t mr;
7298 ddi_acc_hdl_t *hp;
7299 int result;
7300
7301 /*
7302 * Allocate and initialize the common elements of data access handle.
7303 */
7304 *handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
7305 hp = impl_acc_hdl_get(*handle);
7306 hp->ah_vers = VERS_ACCHDL;
7307 hp->ah_dip = dip;
7308 hp->ah_rnumber = rnumber;
7309 hp->ah_offset = offset;
7310 hp->ah_len = len;
7311 hp->ah_acc = *accattrp;
7312
7313 /*
7314 * Set up the mapping request and call to parent.
7315 */
7316 mr.map_op = DDI_MO_MAP_LOCKED;
7317 mr.map_type = DDI_MT_RNUMBER;
7318 mr.map_obj.rnumber = rnumber;
7319 mr.map_prot = PROT_READ | PROT_WRITE;
7320 mr.map_flags = DDI_MF_KERNEL_MAPPING;
7321 mr.map_handlep = hp;
7322 mr.map_vers = DDI_MAP_VERSION;
7323 result = ddi_map(dip, &mr, offset, len, addrp);
7324
7325 /*
7326 * check for end result
7327 */
7328 if (result != DDI_SUCCESS) {
7329 impl_acc_hdl_free(*handle);
7330 *handle = (ddi_acc_handle_t)NULL;
7331 } else {
7332 hp->ah_addr = *addrp;
7333 }
7334
7335 return (result);
7336 }
7337
7338 void
ddi_regs_map_free(ddi_acc_handle_t * handlep)7339 ddi_regs_map_free(ddi_acc_handle_t *handlep)
7340 {
7341 ddi_map_req_t mr;
7342 ddi_acc_hdl_t *hp;
7343
7344 hp = impl_acc_hdl_get(*handlep);
7345 ASSERT(hp);
7346
7347 mr.map_op = DDI_MO_UNMAP;
7348 mr.map_type = DDI_MT_RNUMBER;
7349 mr.map_obj.rnumber = hp->ah_rnumber;
7350 mr.map_prot = PROT_READ | PROT_WRITE;
7351 mr.map_flags = DDI_MF_KERNEL_MAPPING;
7352 mr.map_handlep = hp;
7353 mr.map_vers = DDI_MAP_VERSION;
7354
7355 /*
7356 * Call my parent to unmap my regs.
7357 */
7358 (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
7359 hp->ah_len, &hp->ah_addr);
7360 /*
7361 * free the handle
7362 */
7363 impl_acc_hdl_free(*handlep);
7364 *handlep = (ddi_acc_handle_t)NULL;
7365 }
7366
7367 int
ddi_device_zero(ddi_acc_handle_t handle,caddr_t dev_addr,size_t bytecount,ssize_t dev_advcnt,uint_t dev_datasz)7368 ddi_device_zero(ddi_acc_handle_t handle, caddr_t dev_addr, size_t bytecount,
7369 ssize_t dev_advcnt, uint_t dev_datasz)
7370 {
7371 uint8_t *b;
7372 uint16_t *w;
7373 uint32_t *l;
7374 uint64_t *ll;
7375
7376 /* check for total byte count is multiple of data transfer size */
7377 if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
7378 return (DDI_FAILURE);
7379
7380 switch (dev_datasz) {
7381 case DDI_DATA_SZ01_ACC:
7382 for (b = (uint8_t *)dev_addr;
7383 bytecount != 0; bytecount -= 1, b += dev_advcnt)
7384 ddi_put8(handle, b, 0);
7385 break;
7386 case DDI_DATA_SZ02_ACC:
7387 for (w = (uint16_t *)dev_addr;
7388 bytecount != 0; bytecount -= 2, w += dev_advcnt)
7389 ddi_put16(handle, w, 0);
7390 break;
7391 case DDI_DATA_SZ04_ACC:
7392 for (l = (uint32_t *)dev_addr;
7393 bytecount != 0; bytecount -= 4, l += dev_advcnt)
7394 ddi_put32(handle, l, 0);
7395 break;
7396 case DDI_DATA_SZ08_ACC:
7397 for (ll = (uint64_t *)dev_addr;
7398 bytecount != 0; bytecount -= 8, ll += dev_advcnt)
7399 ddi_put64(handle, ll, 0x0ll);
7400 break;
7401 default:
7402 return (DDI_FAILURE);
7403 }
7404 return (DDI_SUCCESS);
7405 }
7406
7407 int
ddi_device_copy(ddi_acc_handle_t src_handle,caddr_t src_addr,ssize_t src_advcnt,ddi_acc_handle_t dest_handle,caddr_t dest_addr,ssize_t dest_advcnt,size_t bytecount,uint_t dev_datasz)7408 ddi_device_copy(
7409 ddi_acc_handle_t src_handle, caddr_t src_addr, ssize_t src_advcnt,
7410 ddi_acc_handle_t dest_handle, caddr_t dest_addr, ssize_t dest_advcnt,
7411 size_t bytecount, uint_t dev_datasz)
7412 {
7413 uint8_t *b_src, *b_dst;
7414 uint16_t *w_src, *w_dst;
7415 uint32_t *l_src, *l_dst;
7416 uint64_t *ll_src, *ll_dst;
7417
7418 /* check for total byte count is multiple of data transfer size */
7419 if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
7420 return (DDI_FAILURE);
7421
7422 switch (dev_datasz) {
7423 case DDI_DATA_SZ01_ACC:
7424 b_src = (uint8_t *)src_addr;
7425 b_dst = (uint8_t *)dest_addr;
7426
7427 for (; bytecount != 0; bytecount -= 1) {
7428 ddi_put8(dest_handle, b_dst,
7429 ddi_get8(src_handle, b_src));
7430 b_dst += dest_advcnt;
7431 b_src += src_advcnt;
7432 }
7433 break;
7434 case DDI_DATA_SZ02_ACC:
7435 w_src = (uint16_t *)src_addr;
7436 w_dst = (uint16_t *)dest_addr;
7437
7438 for (; bytecount != 0; bytecount -= 2) {
7439 ddi_put16(dest_handle, w_dst,
7440 ddi_get16(src_handle, w_src));
7441 w_dst += dest_advcnt;
7442 w_src += src_advcnt;
7443 }
7444 break;
7445 case DDI_DATA_SZ04_ACC:
7446 l_src = (uint32_t *)src_addr;
7447 l_dst = (uint32_t *)dest_addr;
7448
7449 for (; bytecount != 0; bytecount -= 4) {
7450 ddi_put32(dest_handle, l_dst,
7451 ddi_get32(src_handle, l_src));
7452 l_dst += dest_advcnt;
7453 l_src += src_advcnt;
7454 }
7455 break;
7456 case DDI_DATA_SZ08_ACC:
7457 ll_src = (uint64_t *)src_addr;
7458 ll_dst = (uint64_t *)dest_addr;
7459
7460 for (; bytecount != 0; bytecount -= 8) {
7461 ddi_put64(dest_handle, ll_dst,
7462 ddi_get64(src_handle, ll_src));
7463 ll_dst += dest_advcnt;
7464 ll_src += src_advcnt;
7465 }
7466 break;
7467 default:
7468 return (DDI_FAILURE);
7469 }
7470 return (DDI_SUCCESS);
7471 }
7472
7473 #define swap16(value) \
7474 ((((value) & 0xff) << 8) | ((value) >> 8))
7475
7476 #define swap32(value) \
7477 (((uint32_t)swap16((uint16_t)((value) & 0xffff)) << 16) | \
7478 (uint32_t)swap16((uint16_t)((value) >> 16)))
7479
7480 #define swap64(value) \
7481 (((uint64_t)swap32((uint32_t)((value) & 0xffffffff)) \
7482 << 32) | \
7483 (uint64_t)swap32((uint32_t)((value) >> 32)))
7484
7485 uint16_t
ddi_swap16(uint16_t value)7486 ddi_swap16(uint16_t value)
7487 {
7488 return (swap16(value));
7489 }
7490
7491 uint32_t
ddi_swap32(uint32_t value)7492 ddi_swap32(uint32_t value)
7493 {
7494 return (swap32(value));
7495 }
7496
7497 uint64_t
ddi_swap64(uint64_t value)7498 ddi_swap64(uint64_t value)
7499 {
7500 return (swap64(value));
7501 }
7502
7503 /*
7504 * Convert a binding name to a driver name.
7505 * A binding name is the name used to determine the driver for a
7506 * device - it may be either an alias for the driver or the name
7507 * of the driver itself.
7508 */
7509 char *
i_binding_to_drv_name(char * bname)7510 i_binding_to_drv_name(char *bname)
7511 {
7512 major_t major_no;
7513
7514 ASSERT(bname != NULL);
7515
7516 if ((major_no = ddi_name_to_major(bname)) == -1)
7517 return (NULL);
7518 return (ddi_major_to_name(major_no));
7519 }
7520
7521 /*
7522 * Search for minor name that has specified dev_t and spec_type.
7523 * If spec_type is zero then any dev_t match works. Since we
7524 * are returning a pointer to the minor name string, we require the
7525 * caller to do the locking.
7526 */
7527 char *
i_ddi_devtspectype_to_minorname(dev_info_t * dip,dev_t dev,int spec_type)7528 i_ddi_devtspectype_to_minorname(dev_info_t *dip, dev_t dev, int spec_type)
7529 {
7530 struct ddi_minor_data *dmdp;
7531
7532 /*
7533 * The did layered driver currently intentionally returns a
7534 * devinfo ptr for an underlying sd instance based on a did
7535 * dev_t. In this case it is not an error.
7536 *
7537 * The did layered driver is associated with Sun Cluster.
7538 */
7539 ASSERT((ddi_driver_major(dip) == getmajor(dev)) ||
7540 (strcmp(ddi_major_to_name(getmajor(dev)), "did") == 0));
7541
7542 ASSERT(DEVI_BUSY_OWNED(dip));
7543 for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
7544 if (((dmdp->type == DDM_MINOR) ||
7545 (dmdp->type == DDM_INTERNAL_PATH) ||
7546 (dmdp->type == DDM_DEFAULT)) &&
7547 (dmdp->ddm_dev == dev) &&
7548 ((((spec_type & (S_IFCHR|S_IFBLK))) == 0) ||
7549 (dmdp->ddm_spec_type == spec_type)))
7550 return (dmdp->ddm_name);
7551 }
7552
7553 return (NULL);
7554 }
7555
7556 /*
7557 * Find the devt and spectype of the specified minor_name.
7558 * Return DDI_FAILURE if minor_name not found. Since we are
7559 * returning everything via arguments we can do the locking.
7560 */
7561 int
i_ddi_minorname_to_devtspectype(dev_info_t * dip,const char * minor_name,dev_t * devtp,int * spectypep)7562 i_ddi_minorname_to_devtspectype(dev_info_t *dip, const char *minor_name,
7563 dev_t *devtp, int *spectypep)
7564 {
7565 struct ddi_minor_data *dmdp;
7566
7567 /* deal with clone minor nodes */
7568 if (dip == clone_dip) {
7569 major_t major;
7570 /*
7571 * Make sure minor_name is a STREAMS driver.
7572 * We load the driver but don't attach to any instances.
7573 */
7574
7575 major = ddi_name_to_major(minor_name);
7576 if (major == DDI_MAJOR_T_NONE)
7577 return (DDI_FAILURE);
7578
7579 if (ddi_hold_driver(major) == NULL)
7580 return (DDI_FAILURE);
7581
7582 if (STREAMSTAB(major) == NULL) {
7583 ddi_rele_driver(major);
7584 return (DDI_FAILURE);
7585 }
7586 ddi_rele_driver(major);
7587
7588 if (devtp)
7589 *devtp = makedevice(clone_major, (minor_t)major);
7590
7591 if (spectypep)
7592 *spectypep = S_IFCHR;
7593
7594 return (DDI_SUCCESS);
7595 }
7596
7597 ndi_devi_enter(dip);
7598 for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
7599 if (((dmdp->type != DDM_MINOR) &&
7600 (dmdp->type != DDM_INTERNAL_PATH) &&
7601 (dmdp->type != DDM_DEFAULT)) ||
7602 strcmp(minor_name, dmdp->ddm_name))
7603 continue;
7604
7605 if (devtp)
7606 *devtp = dmdp->ddm_dev;
7607
7608 if (spectypep)
7609 *spectypep = dmdp->ddm_spec_type;
7610
7611 ndi_devi_exit(dip);
7612 return (DDI_SUCCESS);
7613 }
7614 ndi_devi_exit(dip);
7615
7616 return (DDI_FAILURE);
7617 }
7618
7619 static kmutex_t devid_gen_mutex;
7620 static short devid_gen_number;
7621
7622 #ifdef DEBUG
7623
7624 static int devid_register_corrupt = 0;
7625 static int devid_register_corrupt_major = 0;
7626 static int devid_register_corrupt_hint = 0;
7627 static int devid_register_corrupt_hint_major = 0;
7628
7629 static int devid_lyr_debug = 0;
7630
7631 #define DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs) \
7632 if (devid_lyr_debug) \
7633 ddi_debug_devid_devts(msg, ndevs, devs)
7634
7635 #else
7636
7637 #define DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs)
7638
7639 #endif /* DEBUG */
7640
7641
7642 #ifdef DEBUG
7643
7644 static void
ddi_debug_devid_devts(char * msg,int ndevs,dev_t * devs)7645 ddi_debug_devid_devts(char *msg, int ndevs, dev_t *devs)
7646 {
7647 int i;
7648
7649 cmn_err(CE_CONT, "%s:\n", msg);
7650 for (i = 0; i < ndevs; i++) {
7651 cmn_err(CE_CONT, " 0x%lx\n", devs[i]);
7652 }
7653 }
7654
7655 static void
ddi_debug_devid_paths(char * msg,int npaths,char ** paths)7656 ddi_debug_devid_paths(char *msg, int npaths, char **paths)
7657 {
7658 int i;
7659
7660 cmn_err(CE_CONT, "%s:\n", msg);
7661 for (i = 0; i < npaths; i++) {
7662 cmn_err(CE_CONT, " %s\n", paths[i]);
7663 }
7664 }
7665
7666 static void
ddi_debug_devid_devts_per_path(char * path,int ndevs,dev_t * devs)7667 ddi_debug_devid_devts_per_path(char *path, int ndevs, dev_t *devs)
7668 {
7669 int i;
7670
7671 cmn_err(CE_CONT, "dev_ts per path %s\n", path);
7672 for (i = 0; i < ndevs; i++) {
7673 cmn_err(CE_CONT, " 0x%lx\n", devs[i]);
7674 }
7675 }
7676
7677 #endif /* DEBUG */
7678
7679 /*
7680 * Register device id into DDI framework.
7681 * Must be called when the driver is bound.
7682 */
7683 static int
i_ddi_devid_register(dev_info_t * dip,ddi_devid_t devid)7684 i_ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
7685 {
7686 impl_devid_t *i_devid = (impl_devid_t *)devid;
7687 size_t driver_len;
7688 const char *driver_name;
7689 char *devid_str;
7690 major_t major;
7691
7692 if ((dip == NULL) ||
7693 ((major = ddi_driver_major(dip)) == DDI_MAJOR_T_NONE))
7694 return (DDI_FAILURE);
7695
7696 /* verify that the devid is valid */
7697 if (ddi_devid_valid(devid) != DDI_SUCCESS)
7698 return (DDI_FAILURE);
7699
7700 /* Updating driver name hint in devid */
7701 driver_name = ddi_driver_name(dip);
7702 driver_len = strlen(driver_name);
7703 if (driver_len > DEVID_HINT_SIZE) {
7704 /* Pick up last four characters of driver name */
7705 driver_name += driver_len - DEVID_HINT_SIZE;
7706 driver_len = DEVID_HINT_SIZE;
7707 }
7708 bzero(i_devid->did_driver, DEVID_HINT_SIZE);
7709 bcopy(driver_name, i_devid->did_driver, driver_len);
7710
7711 #ifdef DEBUG
7712 /* Corrupt the devid for testing. */
7713 if (devid_register_corrupt)
7714 i_devid->did_id[0] += devid_register_corrupt;
7715 if (devid_register_corrupt_major &&
7716 (major == devid_register_corrupt_major))
7717 i_devid->did_id[0] += 1;
7718 if (devid_register_corrupt_hint)
7719 i_devid->did_driver[0] += devid_register_corrupt_hint;
7720 if (devid_register_corrupt_hint_major &&
7721 (major == devid_register_corrupt_hint_major))
7722 i_devid->did_driver[0] += 1;
7723 #endif /* DEBUG */
7724
7725 /* encode the devid as a string */
7726 if ((devid_str = ddi_devid_str_encode(devid, NULL)) == NULL)
7727 return (DDI_FAILURE);
7728
7729 /* add string as a string property */
7730 if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
7731 DEVID_PROP_NAME, devid_str) != DDI_SUCCESS) {
7732 cmn_err(CE_WARN, "%s%d: devid property update failed",
7733 ddi_driver_name(dip), ddi_get_instance(dip));
7734 ddi_devid_str_free(devid_str);
7735 return (DDI_FAILURE);
7736 }
7737
7738 /* keep pointer to devid string for interrupt context fma code */
7739 if (DEVI(dip)->devi_devid_str)
7740 ddi_devid_str_free(DEVI(dip)->devi_devid_str);
7741 DEVI(dip)->devi_devid_str = devid_str;
7742 return (DDI_SUCCESS);
7743 }
7744
7745 int
ddi_devid_register(dev_info_t * dip,ddi_devid_t devid)7746 ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
7747 {
7748 int rval;
7749
7750 rval = i_ddi_devid_register(dip, devid);
7751 if (rval == DDI_SUCCESS) {
7752 /*
7753 * Register devid in devid-to-path cache
7754 */
7755 if (e_devid_cache_register(dip, devid) == DDI_SUCCESS) {
7756 mutex_enter(&DEVI(dip)->devi_lock);
7757 DEVI(dip)->devi_flags |= DEVI_CACHED_DEVID;
7758 mutex_exit(&DEVI(dip)->devi_lock);
7759 } else if (ddi_get_name_addr(dip)) {
7760 /*
7761 * We only expect cache_register DDI_FAILURE when we
7762 * can't form the full path because of NULL devi_addr.
7763 */
7764 cmn_err(CE_WARN, "%s%d: failed to cache devid",
7765 ddi_driver_name(dip), ddi_get_instance(dip));
7766 }
7767 } else {
7768 cmn_err(CE_WARN, "%s%d: failed to register devid",
7769 ddi_driver_name(dip), ddi_get_instance(dip));
7770 }
7771 return (rval);
7772 }
7773
7774 /*
7775 * Remove (unregister) device id from DDI framework.
7776 * Must be called when device is detached.
7777 */
7778 static void
i_ddi_devid_unregister(dev_info_t * dip)7779 i_ddi_devid_unregister(dev_info_t *dip)
7780 {
7781 if (DEVI(dip)->devi_devid_str) {
7782 ddi_devid_str_free(DEVI(dip)->devi_devid_str);
7783 DEVI(dip)->devi_devid_str = NULL;
7784 }
7785
7786 /* remove the devid property */
7787 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, DEVID_PROP_NAME);
7788 }
7789
7790 void
ddi_devid_unregister(dev_info_t * dip)7791 ddi_devid_unregister(dev_info_t *dip)
7792 {
7793 mutex_enter(&DEVI(dip)->devi_lock);
7794 DEVI(dip)->devi_flags &= ~DEVI_CACHED_DEVID;
7795 mutex_exit(&DEVI(dip)->devi_lock);
7796 e_devid_cache_unregister(dip);
7797 i_ddi_devid_unregister(dip);
7798 }
7799
7800 /*
7801 * Allocate and initialize a device id.
7802 */
7803 int
ddi_devid_init(dev_info_t * dip,ushort_t devid_type,ushort_t nbytes,void * id,ddi_devid_t * ret_devid)7804 ddi_devid_init(
7805 dev_info_t *dip,
7806 ushort_t devid_type,
7807 ushort_t nbytes,
7808 void *id,
7809 ddi_devid_t *ret_devid)
7810 {
7811 impl_devid_t *i_devid;
7812 int sz = sizeof (*i_devid) + nbytes - sizeof (char);
7813 int driver_len;
7814 const char *driver_name;
7815
7816 switch (devid_type) {
7817 case DEVID_SCSI3_WWN:
7818 /*FALLTHRU*/
7819 case DEVID_SCSI_SERIAL:
7820 /*FALLTHRU*/
7821 case DEVID_ATA_SERIAL:
7822 /*FALLTHRU*/
7823 case DEVID_NVME_NSID:
7824 /*FALLTHRU*/
7825 case DEVID_NVME_EUI64:
7826 /*FALLTHRU*/
7827 case DEVID_NVME_NGUID:
7828 /*FALLTHRU*/
7829 case DEVID_ENCAP:
7830 if (nbytes == 0)
7831 return (DDI_FAILURE);
7832 if (id == NULL)
7833 return (DDI_FAILURE);
7834 break;
7835 case DEVID_FAB:
7836 if (nbytes != 0)
7837 return (DDI_FAILURE);
7838 if (id != NULL)
7839 return (DDI_FAILURE);
7840 nbytes = sizeof (int) +
7841 sizeof (struct timeval32) + sizeof (short);
7842 sz += nbytes;
7843 break;
7844 default:
7845 return (DDI_FAILURE);
7846 }
7847
7848 if ((i_devid = kmem_zalloc(sz, KM_SLEEP)) == NULL)
7849 return (DDI_FAILURE);
7850
7851 i_devid->did_magic_hi = DEVID_MAGIC_MSB;
7852 i_devid->did_magic_lo = DEVID_MAGIC_LSB;
7853 i_devid->did_rev_hi = DEVID_REV_MSB;
7854 i_devid->did_rev_lo = DEVID_REV_LSB;
7855 DEVID_FORMTYPE(i_devid, devid_type);
7856 DEVID_FORMLEN(i_devid, nbytes);
7857
7858 /* Fill in driver name hint */
7859 driver_name = ddi_driver_name(dip);
7860 driver_len = strlen(driver_name);
7861 if (driver_len > DEVID_HINT_SIZE) {
7862 /* Pick up last four characters of driver name */
7863 driver_name += driver_len - DEVID_HINT_SIZE;
7864 driver_len = DEVID_HINT_SIZE;
7865 }
7866
7867 bcopy(driver_name, i_devid->did_driver, driver_len);
7868
7869 /* Fill in id field */
7870 if (devid_type == DEVID_FAB) {
7871 char *cp;
7872 uint32_t hostid;
7873 struct timeval32 timestamp32;
7874 int i;
7875 int *ip;
7876 short gen;
7877
7878 /* increase the generation number */
7879 mutex_enter(&devid_gen_mutex);
7880 gen = devid_gen_number++;
7881 mutex_exit(&devid_gen_mutex);
7882
7883 cp = i_devid->did_id;
7884
7885 /* Fill in host id (big-endian byte ordering) */
7886 hostid = zone_get_hostid(NULL);
7887 *cp++ = hibyte(hiword(hostid));
7888 *cp++ = lobyte(hiword(hostid));
7889 *cp++ = hibyte(loword(hostid));
7890 *cp++ = lobyte(loword(hostid));
7891
7892 /*
7893 * Fill in timestamp (big-endian byte ordering)
7894 *
7895 * (Note that the format may have to be changed
7896 * before 2038 comes around, though it's arguably
7897 * unique enough as it is..)
7898 */
7899 uniqtime32(×tamp32);
7900 ip = (int *)×tamp32;
7901 for (i = 0;
7902 i < sizeof (timestamp32) / sizeof (int); i++, ip++) {
7903 int val;
7904 val = *ip;
7905 *cp++ = hibyte(hiword(val));
7906 *cp++ = lobyte(hiword(val));
7907 *cp++ = hibyte(loword(val));
7908 *cp++ = lobyte(loword(val));
7909 }
7910
7911 /* fill in the generation number */
7912 *cp++ = hibyte(gen);
7913 *cp++ = lobyte(gen);
7914 } else
7915 bcopy(id, i_devid->did_id, nbytes);
7916
7917 /* return device id */
7918 *ret_devid = (ddi_devid_t)i_devid;
7919 return (DDI_SUCCESS);
7920 }
7921
7922 int
ddi_devid_get(dev_info_t * dip,ddi_devid_t * ret_devid)7923 ddi_devid_get(dev_info_t *dip, ddi_devid_t *ret_devid)
7924 {
7925 return (i_ddi_devi_get_devid(DDI_DEV_T_ANY, dip, ret_devid));
7926 }
7927
7928 int
i_ddi_devi_get_devid(dev_t dev,dev_info_t * dip,ddi_devid_t * ret_devid)7929 i_ddi_devi_get_devid(dev_t dev, dev_info_t *dip, ddi_devid_t *ret_devid)
7930 {
7931 char *devidstr;
7932
7933 ASSERT(dev != DDI_DEV_T_NONE);
7934
7935 /* look up the property, devt specific first */
7936 if (ddi_prop_lookup_string(dev, dip, DDI_PROP_DONTPASS,
7937 DEVID_PROP_NAME, &devidstr) != DDI_PROP_SUCCESS) {
7938 if ((dev == DDI_DEV_T_ANY) ||
7939 (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
7940 DDI_PROP_DONTPASS, DEVID_PROP_NAME, &devidstr) !=
7941 DDI_PROP_SUCCESS)) {
7942 return (DDI_FAILURE);
7943 }
7944 }
7945
7946 /* convert to binary form */
7947 if (ddi_devid_str_decode(devidstr, ret_devid, NULL) == -1) {
7948 ddi_prop_free(devidstr);
7949 return (DDI_FAILURE);
7950 }
7951 ddi_prop_free(devidstr);
7952 return (DDI_SUCCESS);
7953 }
7954
7955 /*
7956 * Return a copy of the device id for dev_t
7957 */
7958 int
ddi_lyr_get_devid(dev_t dev,ddi_devid_t * ret_devid)7959 ddi_lyr_get_devid(dev_t dev, ddi_devid_t *ret_devid)
7960 {
7961 dev_info_t *dip;
7962 int rval;
7963
7964 /* get the dip */
7965 if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
7966 return (DDI_FAILURE);
7967
7968 rval = i_ddi_devi_get_devid(dev, dip, ret_devid);
7969
7970 ddi_release_devi(dip); /* e_ddi_hold_devi_by_dev() */
7971 return (rval);
7972 }
7973
7974 /*
7975 * Return a copy of the minor name for dev_t and spec_type
7976 */
7977 int
ddi_lyr_get_minor_name(dev_t dev,int spec_type,char ** minor_name)7978 ddi_lyr_get_minor_name(dev_t dev, int spec_type, char **minor_name)
7979 {
7980 char *buf;
7981 dev_info_t *dip;
7982 char *nm;
7983 int rval;
7984
7985 if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL) {
7986 *minor_name = NULL;
7987 return (DDI_FAILURE);
7988 }
7989
7990 /* Find the minor name and copy into max size buf */
7991 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
7992 ndi_devi_enter(dip);
7993 nm = i_ddi_devtspectype_to_minorname(dip, dev, spec_type);
7994 if (nm)
7995 (void) strcpy(buf, nm);
7996 ndi_devi_exit(dip);
7997 ddi_release_devi(dip); /* e_ddi_hold_devi_by_dev() */
7998
7999 if (nm) {
8000 /* duplicate into min size buf for return result */
8001 *minor_name = i_ddi_strdup(buf, KM_SLEEP);
8002 rval = DDI_SUCCESS;
8003 } else {
8004 *minor_name = NULL;
8005 rval = DDI_FAILURE;
8006 }
8007
8008 /* free max size buf and return */
8009 kmem_free(buf, MAXNAMELEN);
8010 return (rval);
8011 }
8012
8013 int
ddi_lyr_devid_to_devlist(ddi_devid_t devid,const char * minor_name,int * retndevs,dev_t ** retdevs)8014 ddi_lyr_devid_to_devlist(
8015 ddi_devid_t devid,
8016 const char *minor_name,
8017 int *retndevs,
8018 dev_t **retdevs)
8019 {
8020 ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
8021
8022 if (e_devid_cache_to_devt_list(devid, minor_name,
8023 retndevs, retdevs) == DDI_SUCCESS) {
8024 ASSERT(*retndevs > 0);
8025 DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
8026 *retndevs, *retdevs);
8027 return (DDI_SUCCESS);
8028 }
8029
8030 if (e_ddi_devid_discovery(devid) == DDI_FAILURE) {
8031 return (DDI_FAILURE);
8032 }
8033
8034 if (e_devid_cache_to_devt_list(devid, minor_name,
8035 retndevs, retdevs) == DDI_SUCCESS) {
8036 ASSERT(*retndevs > 0);
8037 DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
8038 *retndevs, *retdevs);
8039 return (DDI_SUCCESS);
8040 }
8041
8042 return (DDI_FAILURE);
8043 }
8044
8045 void
ddi_lyr_free_devlist(dev_t * devlist,int ndevs)8046 ddi_lyr_free_devlist(dev_t *devlist, int ndevs)
8047 {
8048 kmem_free(devlist, sizeof (dev_t) * ndevs);
8049 }
8050
8051 /*
8052 * Note: This will need to be fixed if we ever allow processes to
8053 * have more than one data model per exec.
8054 */
8055 model_t
ddi_mmap_get_model(void)8056 ddi_mmap_get_model(void)
8057 {
8058 return (get_udatamodel());
8059 }
8060
8061 model_t
ddi_model_convert_from(model_t model)8062 ddi_model_convert_from(model_t model)
8063 {
8064 return ((model & DDI_MODEL_MASK) & ~DDI_MODEL_NATIVE);
8065 }
8066
8067 /*
8068 * ddi interfaces managing storage and retrieval of eventcookies.
8069 */
8070
8071 /*
8072 * Invoke bus nexus driver's implementation of the
8073 * (*bus_remove_eventcall)() interface to remove a registered
8074 * callback handler for "event".
8075 */
8076 int
ddi_remove_event_handler(ddi_callback_id_t id)8077 ddi_remove_event_handler(ddi_callback_id_t id)
8078 {
8079 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)id;
8080 dev_info_t *ddip;
8081
8082 ASSERT(cb);
8083 if (!cb) {
8084 return (DDI_FAILURE);
8085 }
8086
8087 ddip = NDI_EVENT_DDIP(cb->ndi_evtcb_cookie);
8088 return (ndi_busop_remove_eventcall(ddip, id));
8089 }
8090
8091 /*
8092 * Invoke bus nexus driver's implementation of the
8093 * (*bus_add_eventcall)() interface to register a callback handler
8094 * for "event".
8095 */
8096 int
ddi_add_event_handler(dev_info_t * dip,ddi_eventcookie_t event,void (* handler)(dev_info_t *,ddi_eventcookie_t,void *,void *),void * arg,ddi_callback_id_t * id)8097 ddi_add_event_handler(dev_info_t *dip, ddi_eventcookie_t event,
8098 void (*handler)(dev_info_t *, ddi_eventcookie_t, void *, void *),
8099 void *arg, ddi_callback_id_t *id)
8100 {
8101 return (ndi_busop_add_eventcall(dip, dip, event, handler, arg, id));
8102 }
8103
8104
8105 /*
8106 * Return a handle for event "name" by calling up the device tree
8107 * hierarchy via (*bus_get_eventcookie)() interface until claimed
8108 * by a bus nexus or top of dev_info tree is reached.
8109 */
8110 int
ddi_get_eventcookie(dev_info_t * dip,char * name,ddi_eventcookie_t * event_cookiep)8111 ddi_get_eventcookie(dev_info_t *dip, char *name,
8112 ddi_eventcookie_t *event_cookiep)
8113 {
8114 return (ndi_busop_get_eventcookie(dip, dip,
8115 name, event_cookiep));
8116 }
8117
8118 /*
8119 * This procedure is provided as the general callback function when
8120 * umem_lockmemory calls as_add_callback for long term memory locking.
8121 * When as_unmap, as_setprot, or as_free encounter segments which have
8122 * locked memory, this callback will be invoked.
8123 */
8124 void
umem_lock_undo(struct as * as,void * arg,uint_t event)8125 umem_lock_undo(struct as *as, void *arg, uint_t event)
8126 {
8127 _NOTE(ARGUNUSED(as, event))
8128 struct ddi_umem_cookie *cp = (struct ddi_umem_cookie *)arg;
8129
8130 /*
8131 * Call the cleanup function. Decrement the cookie reference
8132 * count, if it goes to zero, return the memory for the cookie.
8133 * The i_ddi_umem_unlock for this cookie may or may not have been
8134 * called already. It is the responsibility of the caller of
8135 * umem_lockmemory to handle the case of the cleanup routine
8136 * being called after a ddi_umem_unlock for the cookie
8137 * was called.
8138 */
8139
8140 (*cp->callbacks.cbo_umem_lock_cleanup)((ddi_umem_cookie_t)cp);
8141
8142 /* remove the cookie if reference goes to zero */
8143 if (atomic_dec_ulong_nv((ulong_t *)(&(cp->cook_refcnt))) == 0) {
8144 kmem_free(cp, sizeof (struct ddi_umem_cookie));
8145 }
8146 }
8147
8148 /*
8149 * The following two Consolidation Private routines provide generic
8150 * interfaces to increase/decrease the amount of device-locked memory.
8151 *
8152 * To keep project_rele and project_hold consistent, i_ddi_decr_locked_memory()
8153 * must be called every time i_ddi_incr_locked_memory() is called.
8154 */
8155 int
8156 /* ARGSUSED */
i_ddi_incr_locked_memory(proc_t * procp,rctl_qty_t inc)8157 i_ddi_incr_locked_memory(proc_t *procp, rctl_qty_t inc)
8158 {
8159 ASSERT(procp != NULL);
8160 mutex_enter(&procp->p_lock);
8161 if (rctl_incr_locked_mem(procp, NULL, inc, 1)) {
8162 mutex_exit(&procp->p_lock);
8163 return (ENOMEM);
8164 }
8165 mutex_exit(&procp->p_lock);
8166 return (0);
8167 }
8168
8169 /*
8170 * To keep project_rele and project_hold consistent, i_ddi_incr_locked_memory()
8171 * must be called every time i_ddi_decr_locked_memory() is called.
8172 */
8173 /* ARGSUSED */
8174 void
i_ddi_decr_locked_memory(proc_t * procp,rctl_qty_t dec)8175 i_ddi_decr_locked_memory(proc_t *procp, rctl_qty_t dec)
8176 {
8177 ASSERT(procp != NULL);
8178 mutex_enter(&procp->p_lock);
8179 rctl_decr_locked_mem(procp, NULL, dec, 1);
8180 mutex_exit(&procp->p_lock);
8181 }
8182
8183 /*
8184 * The cookie->upd_max_lock_rctl flag is used to determine if we should
8185 * charge device locked memory to the max-locked-memory rctl. Tracking
8186 * device locked memory causes the rctl locks to get hot under high-speed
8187 * I/O such as RDSv3 over IB. If there is no max-locked-memory rctl limit,
8188 * we bypass charging the locked memory to the rctl altogether. The cookie's
8189 * flag tells us if the rctl value should be updated when unlocking the memory,
8190 * in case the rctl gets changed after the memory was locked. Any device
8191 * locked memory in that rare case will not be counted toward the rctl limit.
8192 *
8193 * When tracking the locked memory, the kproject_t parameter is always NULL
8194 * in the code paths:
8195 * i_ddi_incr_locked_memory -> rctl_incr_locked_mem
8196 * i_ddi_decr_locked_memory -> rctl_decr_locked_mem
8197 * Thus, we always use the tk_proj member to check the projp setting.
8198 */
8199 static void
init_lockedmem_rctl_flag(struct ddi_umem_cookie * cookie)8200 init_lockedmem_rctl_flag(struct ddi_umem_cookie *cookie)
8201 {
8202 proc_t *p;
8203 kproject_t *projp;
8204 zone_t *zonep;
8205
8206 ASSERT(cookie);
8207 p = cookie->procp;
8208 ASSERT(p);
8209
8210 zonep = p->p_zone;
8211 projp = p->p_task->tk_proj;
8212
8213 ASSERT(zonep);
8214 ASSERT(projp);
8215
8216 if (zonep->zone_locked_mem_ctl == UINT64_MAX &&
8217 projp->kpj_data.kpd_locked_mem_ctl == UINT64_MAX)
8218 cookie->upd_max_lock_rctl = 0;
8219 else
8220 cookie->upd_max_lock_rctl = 1;
8221 }
8222
8223 /*
8224 * This routine checks if the max-locked-memory resource ctl is
8225 * exceeded, if not increments it, grabs a hold on the project.
8226 * Returns 0 if successful otherwise returns error code
8227 */
8228 static int
umem_incr_devlockmem(struct ddi_umem_cookie * cookie)8229 umem_incr_devlockmem(struct ddi_umem_cookie *cookie)
8230 {
8231 proc_t *procp;
8232 int ret;
8233
8234 ASSERT(cookie);
8235 if (cookie->upd_max_lock_rctl == 0)
8236 return (0);
8237
8238 procp = cookie->procp;
8239 ASSERT(procp);
8240
8241 if ((ret = i_ddi_incr_locked_memory(procp,
8242 cookie->size)) != 0) {
8243 return (ret);
8244 }
8245 return (0);
8246 }
8247
8248 /*
8249 * Decrements the max-locked-memory resource ctl and releases
8250 * the hold on the project that was acquired during umem_incr_devlockmem
8251 */
8252 static void
umem_decr_devlockmem(struct ddi_umem_cookie * cookie)8253 umem_decr_devlockmem(struct ddi_umem_cookie *cookie)
8254 {
8255 proc_t *proc;
8256
8257 if (cookie->upd_max_lock_rctl == 0)
8258 return;
8259
8260 proc = (proc_t *)cookie->procp;
8261 if (!proc)
8262 return;
8263
8264 i_ddi_decr_locked_memory(proc, cookie->size);
8265 }
8266
8267 /*
8268 * A consolidation private function which is essentially equivalent to
8269 * ddi_umem_lock but with the addition of arguments ops_vector and procp.
8270 * A call to as_add_callback is done if DDI_UMEMLOCK_LONGTERM is set, and
8271 * the ops_vector is valid.
8272 *
8273 * Lock the virtual address range in the current process and create a
8274 * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
8275 * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
8276 * to user space.
8277 *
8278 * Note: The resource control accounting currently uses a full charge model
8279 * in other words attempts to lock the same/overlapping areas of memory
8280 * will deduct the full size of the buffer from the projects running
8281 * counter for the device locked memory.
8282 *
8283 * addr, size should be PAGESIZE aligned
8284 *
8285 * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
8286 * identifies whether the locked memory will be read or written or both
8287 * DDI_UMEMLOCK_LONGTERM must be set when the locking will
8288 * be maintained for an indefinitely long period (essentially permanent),
8289 * rather than for what would be required for a typical I/O completion.
8290 * When DDI_UMEMLOCK_LONGTERM is set, umem_lockmemory will return EFAULT
8291 * if the memory pertains to a regular file which is mapped MAP_SHARED.
8292 * This is to prevent a deadlock if a file truncation is attempted after
8293 * after the locking is done.
8294 *
8295 * Returns 0 on success
8296 * EINVAL - for invalid parameters
8297 * EPERM, ENOMEM and other error codes returned by as_pagelock
8298 * ENOMEM - is returned if the current request to lock memory exceeds
8299 * *.max-locked-memory resource control value.
8300 * EFAULT - memory pertains to a regular file mapped shared and
8301 * and DDI_UMEMLOCK_LONGTERM flag is set
8302 * EAGAIN - could not start the ddi_umem_unlock list processing thread
8303 */
8304 int
umem_lockmemory(caddr_t addr,size_t len,int flags,ddi_umem_cookie_t * cookie,struct umem_callback_ops * ops_vector,proc_t * procp)8305 umem_lockmemory(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie,
8306 struct umem_callback_ops *ops_vector,
8307 proc_t *procp)
8308 {
8309 int error;
8310 struct ddi_umem_cookie *p;
8311 void (*driver_callback)() = NULL;
8312 struct as *as;
8313 struct seg *seg;
8314 vnode_t *vp;
8315
8316 /* Allow device drivers to not have to reference "curproc" */
8317 if (procp == NULL)
8318 procp = curproc;
8319 as = procp->p_as;
8320 *cookie = NULL; /* in case of any error return */
8321
8322 /* These are the only three valid flags */
8323 if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE |
8324 DDI_UMEMLOCK_LONGTERM)) != 0)
8325 return (EINVAL);
8326
8327 /* At least one (can be both) of the two access flags must be set */
8328 if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0)
8329 return (EINVAL);
8330
8331 /* addr and len must be page-aligned */
8332 if (((uintptr_t)addr & PAGEOFFSET) != 0)
8333 return (EINVAL);
8334
8335 if ((len & PAGEOFFSET) != 0)
8336 return (EINVAL);
8337
8338 /*
8339 * For longterm locking a driver callback must be specified; if
8340 * not longterm then a callback is optional.
8341 */
8342 if (ops_vector != NULL) {
8343 if (ops_vector->cbo_umem_callback_version !=
8344 UMEM_CALLBACK_VERSION)
8345 return (EINVAL);
8346 else
8347 driver_callback = ops_vector->cbo_umem_lock_cleanup;
8348 }
8349 if ((driver_callback == NULL) && (flags & DDI_UMEMLOCK_LONGTERM))
8350 return (EINVAL);
8351
8352 /*
8353 * Call i_ddi_umem_unlock_thread_start if necessary. It will
8354 * be called on first ddi_umem_lock or umem_lockmemory call.
8355 */
8356 if (ddi_umem_unlock_thread == NULL)
8357 i_ddi_umem_unlock_thread_start();
8358
8359 /* Allocate memory for the cookie */
8360 p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
8361
8362 /* Convert the flags to seg_rw type */
8363 if (flags & DDI_UMEMLOCK_WRITE) {
8364 p->s_flags = S_WRITE;
8365 } else {
8366 p->s_flags = S_READ;
8367 }
8368
8369 /* Store procp in cookie for later iosetup/unlock */
8370 p->procp = (void *)procp;
8371
8372 /*
8373 * Store the struct as pointer in cookie for later use by
8374 * ddi_umem_unlock. The proc->p_as will be stale if ddi_umem_unlock
8375 * is called after relvm is called.
8376 */
8377 p->asp = as;
8378
8379 /*
8380 * The size field is needed for lockmem accounting.
8381 */
8382 p->size = len;
8383 init_lockedmem_rctl_flag(p);
8384
8385 if (umem_incr_devlockmem(p) != 0) {
8386 /*
8387 * The requested memory cannot be locked
8388 */
8389 kmem_free(p, sizeof (struct ddi_umem_cookie));
8390 *cookie = (ddi_umem_cookie_t)NULL;
8391 return (ENOMEM);
8392 }
8393
8394 /* Lock the pages corresponding to addr, len in memory */
8395 error = as_pagelock(as, &(p->pparray), addr, len, p->s_flags);
8396 if (error != 0) {
8397 umem_decr_devlockmem(p);
8398 kmem_free(p, sizeof (struct ddi_umem_cookie));
8399 *cookie = (ddi_umem_cookie_t)NULL;
8400 return (error);
8401 }
8402
8403 /*
8404 * For longterm locking the addr must pertain to a seg_vn segment or
8405 * or a seg_spt segment.
8406 * If the segment pertains to a regular file, it cannot be
8407 * mapped MAP_SHARED.
8408 * This is to prevent a deadlock if a file truncation is attempted
8409 * after the locking is done.
8410 * Doing this after as_pagelock guarantees persistence of the as; if
8411 * an unacceptable segment is found, the cleanup includes calling
8412 * as_pageunlock before returning EFAULT.
8413 *
8414 * segdev is allowed here as it is already locked. This allows
8415 * for memory exported by drivers through mmap() (which is already
8416 * locked) to be allowed for LONGTERM.
8417 */
8418 if (flags & DDI_UMEMLOCK_LONGTERM) {
8419 extern struct seg_ops segspt_shmops;
8420 extern struct seg_ops segdev_ops;
8421 AS_LOCK_ENTER(as, RW_READER);
8422 for (seg = as_segat(as, addr); ; seg = AS_SEGNEXT(as, seg)) {
8423 if (seg == NULL || seg->s_base > addr + len)
8424 break;
8425 if (seg->s_ops == &segdev_ops)
8426 continue;
8427 if (((seg->s_ops != &segvn_ops) &&
8428 (seg->s_ops != &segspt_shmops)) ||
8429 ((SEGOP_GETVP(seg, addr, &vp) == 0 &&
8430 vp != NULL && vp->v_type == VREG) &&
8431 (SEGOP_GETTYPE(seg, addr) & MAP_SHARED))) {
8432 as_pageunlock(as, p->pparray,
8433 addr, len, p->s_flags);
8434 AS_LOCK_EXIT(as);
8435 umem_decr_devlockmem(p);
8436 kmem_free(p, sizeof (struct ddi_umem_cookie));
8437 *cookie = (ddi_umem_cookie_t)NULL;
8438 return (EFAULT);
8439 }
8440 }
8441 AS_LOCK_EXIT(as);
8442 }
8443
8444
8445 /* Initialize the fields in the ddi_umem_cookie */
8446 p->cvaddr = addr;
8447 p->type = UMEM_LOCKED;
8448 if (driver_callback != NULL) {
8449 /* i_ddi_umem_unlock and umem_lock_undo may need the cookie */
8450 p->cook_refcnt = 2;
8451 p->callbacks = *ops_vector;
8452 } else {
8453 /* only i_ddi_umme_unlock needs the cookie */
8454 p->cook_refcnt = 1;
8455 }
8456
8457 *cookie = (ddi_umem_cookie_t)p;
8458
8459 /*
8460 * If a driver callback was specified, add an entry to the
8461 * as struct callback list. The as_pagelock above guarantees
8462 * the persistence of as.
8463 */
8464 if (driver_callback) {
8465 error = as_add_callback(as, umem_lock_undo, p, AS_ALL_EVENT,
8466 addr, len, KM_SLEEP);
8467 if (error != 0) {
8468 as_pageunlock(as, p->pparray,
8469 addr, len, p->s_flags);
8470 umem_decr_devlockmem(p);
8471 kmem_free(p, sizeof (struct ddi_umem_cookie));
8472 *cookie = (ddi_umem_cookie_t)NULL;
8473 }
8474 }
8475 return (error);
8476 }
8477
8478 /*
8479 * Unlock the pages locked by ddi_umem_lock or umem_lockmemory and free
8480 * the cookie. Called from i_ddi_umem_unlock_thread.
8481 */
8482
8483 static void
i_ddi_umem_unlock(struct ddi_umem_cookie * p)8484 i_ddi_umem_unlock(struct ddi_umem_cookie *p)
8485 {
8486 uint_t rc;
8487
8488 /*
8489 * There is no way to determine whether a callback to
8490 * umem_lock_undo was registered via as_add_callback.
8491 * (i.e. umem_lockmemory was called with DDI_MEMLOCK_LONGTERM and
8492 * a valid callback function structure.) as_delete_callback
8493 * is called to delete a possible registered callback. If the
8494 * return from as_delete_callbacks is AS_CALLBACK_DELETED, it
8495 * indicates that there was a callback registered, and that is was
8496 * successfully deleted. Thus, the cookie reference count
8497 * will never be decremented by umem_lock_undo. Just return the
8498 * memory for the cookie, since both users of the cookie are done.
8499 * A return of AS_CALLBACK_NOTFOUND indicates a callback was
8500 * never registered. A return of AS_CALLBACK_DELETE_DEFERRED
8501 * indicates that callback processing is taking place and, and
8502 * umem_lock_undo is, or will be, executing, and thus decrementing
8503 * the cookie reference count when it is complete.
8504 *
8505 * This needs to be done before as_pageunlock so that the
8506 * persistence of as is guaranteed because of the locked pages.
8507 *
8508 */
8509 rc = as_delete_callback(p->asp, p);
8510
8511
8512 /*
8513 * The proc->p_as will be stale if i_ddi_umem_unlock is called
8514 * after relvm is called so use p->asp.
8515 */
8516 as_pageunlock(p->asp, p->pparray, p->cvaddr, p->size, p->s_flags);
8517
8518 /*
8519 * Now that we have unlocked the memory decrement the
8520 * *.max-locked-memory rctl
8521 */
8522 umem_decr_devlockmem(p);
8523
8524 if (rc == AS_CALLBACK_DELETED) {
8525 /* umem_lock_undo will not happen, return the cookie memory */
8526 ASSERT(p->cook_refcnt == 2);
8527 kmem_free(p, sizeof (struct ddi_umem_cookie));
8528 } else {
8529 /*
8530 * umem_undo_lock may happen if as_delete_callback returned
8531 * AS_CALLBACK_DELETE_DEFERRED. In that case, decrement the
8532 * reference count, atomically, and return the cookie
8533 * memory if the reference count goes to zero. The only
8534 * other value for rc is AS_CALLBACK_NOTFOUND. In that
8535 * case, just return the cookie memory.
8536 */
8537 if ((rc != AS_CALLBACK_DELETE_DEFERRED) ||
8538 (atomic_dec_ulong_nv((ulong_t *)(&(p->cook_refcnt)))
8539 == 0)) {
8540 kmem_free(p, sizeof (struct ddi_umem_cookie));
8541 }
8542 }
8543 }
8544
8545 /*
8546 * i_ddi_umem_unlock_thread - deferred ddi_umem_unlock list handler.
8547 *
8548 * Call i_ddi_umem_unlock for entries in the ddi_umem_unlock list
8549 * until it is empty. Then, wait for more to be added. This thread is awoken
8550 * via calls to ddi_umem_unlock.
8551 */
8552
8553 static void
i_ddi_umem_unlock_thread(void)8554 i_ddi_umem_unlock_thread(void)
8555 {
8556 struct ddi_umem_cookie *ret_cookie;
8557 callb_cpr_t cprinfo;
8558
8559 /* process the ddi_umem_unlock list */
8560 CALLB_CPR_INIT(&cprinfo, &ddi_umem_unlock_mutex,
8561 callb_generic_cpr, "unlock_thread");
8562 for (;;) {
8563 mutex_enter(&ddi_umem_unlock_mutex);
8564 if (ddi_umem_unlock_head != NULL) { /* list not empty */
8565 ret_cookie = ddi_umem_unlock_head;
8566 /* take if off the list */
8567 if ((ddi_umem_unlock_head =
8568 ddi_umem_unlock_head->unl_forw) == NULL) {
8569 ddi_umem_unlock_tail = NULL;
8570 }
8571 mutex_exit(&ddi_umem_unlock_mutex);
8572 /* unlock the pages in this cookie */
8573 (void) i_ddi_umem_unlock(ret_cookie);
8574 } else { /* list is empty, wait for next ddi_umem_unlock */
8575 CALLB_CPR_SAFE_BEGIN(&cprinfo);
8576 cv_wait(&ddi_umem_unlock_cv, &ddi_umem_unlock_mutex);
8577 CALLB_CPR_SAFE_END(&cprinfo, &ddi_umem_unlock_mutex);
8578 mutex_exit(&ddi_umem_unlock_mutex);
8579 }
8580 }
8581 /* ddi_umem_unlock_thread does not exit */
8582 /* NOTREACHED */
8583 }
8584
8585 /*
8586 * Start the thread that will process the ddi_umem_unlock list if it is
8587 * not already started (i_ddi_umem_unlock_thread).
8588 */
8589 static void
i_ddi_umem_unlock_thread_start(void)8590 i_ddi_umem_unlock_thread_start(void)
8591 {
8592 mutex_enter(&ddi_umem_unlock_mutex);
8593 if (ddi_umem_unlock_thread == NULL) {
8594 ddi_umem_unlock_thread = thread_create(NULL, 0,
8595 i_ddi_umem_unlock_thread, NULL, 0, &p0,
8596 TS_RUN, minclsyspri);
8597 }
8598 mutex_exit(&ddi_umem_unlock_mutex);
8599 }
8600
8601 /*
8602 * Lock the virtual address range in the current process and create a
8603 * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
8604 * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
8605 * to user space.
8606 *
8607 * Note: The resource control accounting currently uses a full charge model
8608 * in other words attempts to lock the same/overlapping areas of memory
8609 * will deduct the full size of the buffer from the projects running
8610 * counter for the device locked memory. This applies to umem_lockmemory too.
8611 *
8612 * addr, size should be PAGESIZE aligned
8613 * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
8614 * identifies whether the locked memory will be read or written or both
8615 *
8616 * Returns 0 on success
8617 * EINVAL - for invalid parameters
8618 * EPERM, ENOMEM and other error codes returned by as_pagelock
8619 * ENOMEM - is returned if the current request to lock memory exceeds
8620 * *.max-locked-memory resource control value.
8621 * EAGAIN - could not start the ddi_umem_unlock list processing thread
8622 */
8623 int
ddi_umem_lock(caddr_t addr,size_t len,int flags,ddi_umem_cookie_t * cookie)8624 ddi_umem_lock(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie)
8625 {
8626 int error;
8627 struct ddi_umem_cookie *p;
8628
8629 *cookie = NULL; /* in case of any error return */
8630
8631 /* These are the only two valid flags */
8632 if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) != 0) {
8633 return (EINVAL);
8634 }
8635
8636 /* At least one of the two flags (or both) must be set */
8637 if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0) {
8638 return (EINVAL);
8639 }
8640
8641 /* addr and len must be page-aligned */
8642 if (((uintptr_t)addr & PAGEOFFSET) != 0) {
8643 return (EINVAL);
8644 }
8645
8646 if ((len & PAGEOFFSET) != 0) {
8647 return (EINVAL);
8648 }
8649
8650 /*
8651 * Call i_ddi_umem_unlock_thread_start if necessary. It will
8652 * be called on first ddi_umem_lock or umem_lockmemory call.
8653 */
8654 if (ddi_umem_unlock_thread == NULL)
8655 i_ddi_umem_unlock_thread_start();
8656
8657 /* Allocate memory for the cookie */
8658 p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
8659
8660 /* Convert the flags to seg_rw type */
8661 if (flags & DDI_UMEMLOCK_WRITE) {
8662 p->s_flags = S_WRITE;
8663 } else {
8664 p->s_flags = S_READ;
8665 }
8666
8667 /* Store curproc in cookie for later iosetup/unlock */
8668 p->procp = (void *)curproc;
8669
8670 /*
8671 * Store the struct as pointer in cookie for later use by
8672 * ddi_umem_unlock. The proc->p_as will be stale if ddi_umem_unlock
8673 * is called after relvm is called.
8674 */
8675 p->asp = curproc->p_as;
8676 /*
8677 * The size field is needed for lockmem accounting.
8678 */
8679 p->size = len;
8680 init_lockedmem_rctl_flag(p);
8681
8682 if (umem_incr_devlockmem(p) != 0) {
8683 /*
8684 * The requested memory cannot be locked
8685 */
8686 kmem_free(p, sizeof (struct ddi_umem_cookie));
8687 *cookie = (ddi_umem_cookie_t)NULL;
8688 return (ENOMEM);
8689 }
8690
8691 /* Lock the pages corresponding to addr, len in memory */
8692 error = as_pagelock(((proc_t *)p->procp)->p_as, &(p->pparray),
8693 addr, len, p->s_flags);
8694 if (error != 0) {
8695 umem_decr_devlockmem(p);
8696 kmem_free(p, sizeof (struct ddi_umem_cookie));
8697 *cookie = (ddi_umem_cookie_t)NULL;
8698 return (error);
8699 }
8700
8701 /* Initialize the fields in the ddi_umem_cookie */
8702 p->cvaddr = addr;
8703 p->type = UMEM_LOCKED;
8704 p->cook_refcnt = 1;
8705
8706 *cookie = (ddi_umem_cookie_t)p;
8707 return (error);
8708 }
8709
8710 /*
8711 * Add the cookie to the ddi_umem_unlock list. Pages will be
8712 * unlocked by i_ddi_umem_unlock_thread.
8713 */
8714
8715 void
ddi_umem_unlock(ddi_umem_cookie_t cookie)8716 ddi_umem_unlock(ddi_umem_cookie_t cookie)
8717 {
8718 struct ddi_umem_cookie *p = (struct ddi_umem_cookie *)cookie;
8719
8720 ASSERT(p->type == UMEM_LOCKED);
8721 ASSERT(CPU_ON_INTR(CPU) == 0); /* cannot be high level */
8722 ASSERT(ddi_umem_unlock_thread != NULL);
8723
8724 p->unl_forw = (struct ddi_umem_cookie *)NULL; /* end of list */
8725 /*
8726 * Queue the unlock request and notify i_ddi_umem_unlock thread
8727 * if it's called in the interrupt context. Otherwise, unlock pages
8728 * immediately.
8729 */
8730 if (servicing_interrupt()) {
8731 /* queue the unlock request and notify the thread */
8732 mutex_enter(&ddi_umem_unlock_mutex);
8733 if (ddi_umem_unlock_head == NULL) {
8734 ddi_umem_unlock_head = ddi_umem_unlock_tail = p;
8735 cv_broadcast(&ddi_umem_unlock_cv);
8736 } else {
8737 ddi_umem_unlock_tail->unl_forw = p;
8738 ddi_umem_unlock_tail = p;
8739 }
8740 mutex_exit(&ddi_umem_unlock_mutex);
8741 } else {
8742 /* unlock the pages right away */
8743 (void) i_ddi_umem_unlock(p);
8744 }
8745 }
8746
8747 /*
8748 * Create a buf structure from a ddi_umem_cookie
8749 * cookie - is a ddi_umem_cookie for from ddi_umem_lock and ddi_umem_alloc
8750 * (only UMEM_LOCKED & KMEM_NON_PAGEABLE types supported)
8751 * off, len - identifies the portion of the memory represented by the cookie
8752 * that the buf points to.
8753 * NOTE: off, len need to follow the alignment/size restrictions of the
8754 * device (dev) that this buf will be passed to. Some devices
8755 * will accept unrestricted alignment/size, whereas others (such as
8756 * st) require some block-size alignment/size. It is the caller's
8757 * responsibility to ensure that the alignment/size restrictions
8758 * are met (we cannot assert as we do not know the restrictions)
8759 *
8760 * direction - is one of B_READ or B_WRITE and needs to be compatible with
8761 * the flags used in ddi_umem_lock
8762 *
8763 * The following three arguments are used to initialize fields in the
8764 * buf structure and are uninterpreted by this routine.
8765 *
8766 * dev
8767 * blkno
8768 * iodone
8769 *
8770 * sleepflag - is one of DDI_UMEM_SLEEP or DDI_UMEM_NOSLEEP
8771 *
8772 * Returns a buf structure pointer on success (to be freed by freerbuf)
8773 * NULL on any parameter error or memory alloc failure
8774 *
8775 */
8776 struct buf *
ddi_umem_iosetup(ddi_umem_cookie_t cookie,off_t off,size_t len,int direction,dev_t dev,daddr_t blkno,int (* iodone)(struct buf *),int sleepflag)8777 ddi_umem_iosetup(ddi_umem_cookie_t cookie, off_t off, size_t len,
8778 int direction, dev_t dev, daddr_t blkno,
8779 int (*iodone)(struct buf *), int sleepflag)
8780 {
8781 struct ddi_umem_cookie *p = (struct ddi_umem_cookie *)cookie;
8782 struct buf *bp;
8783
8784 /*
8785 * check for valid cookie offset, len
8786 */
8787 if ((off + len) > p->size) {
8788 return (NULL);
8789 }
8790
8791 if (len > p->size) {
8792 return (NULL);
8793 }
8794
8795 /* direction has to be one of B_READ or B_WRITE */
8796 if ((direction != B_READ) && (direction != B_WRITE)) {
8797 return (NULL);
8798 }
8799
8800 /* These are the only two valid sleepflags */
8801 if ((sleepflag != DDI_UMEM_SLEEP) && (sleepflag != DDI_UMEM_NOSLEEP)) {
8802 return (NULL);
8803 }
8804
8805 /*
8806 * Only cookies of type UMEM_LOCKED and KMEM_NON_PAGEABLE are supported
8807 */
8808 if ((p->type != UMEM_LOCKED) && (p->type != KMEM_NON_PAGEABLE)) {
8809 return (NULL);
8810 }
8811
8812 /* If type is KMEM_NON_PAGEABLE procp is NULL */
8813 ASSERT((p->type == KMEM_NON_PAGEABLE) ?
8814 (p->procp == NULL) : (p->procp != NULL));
8815
8816 bp = kmem_alloc(sizeof (struct buf), sleepflag);
8817 if (bp == NULL) {
8818 return (NULL);
8819 }
8820 bioinit(bp);
8821
8822 bp->b_flags = B_BUSY | B_PHYS | direction;
8823 bp->b_edev = dev;
8824 bp->b_lblkno = blkno;
8825 bp->b_iodone = iodone;
8826 bp->b_bcount = len;
8827 bp->b_proc = (proc_t *)p->procp;
8828 ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
8829 bp->b_un.b_addr = (caddr_t)((uintptr_t)(p->cvaddr) + off);
8830 if (p->pparray != NULL) {
8831 bp->b_flags |= B_SHADOW;
8832 ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
8833 bp->b_shadow = p->pparray + btop(off);
8834 }
8835 return (bp);
8836 }
8837
8838 /*
8839 * Fault-handling and related routines
8840 */
8841
8842 ddi_devstate_t
ddi_get_devstate(dev_info_t * dip)8843 ddi_get_devstate(dev_info_t *dip)
8844 {
8845 if (DEVI_IS_DEVICE_OFFLINE(dip))
8846 return (DDI_DEVSTATE_OFFLINE);
8847 else if (DEVI_IS_DEVICE_DOWN(dip) || DEVI_IS_BUS_DOWN(dip))
8848 return (DDI_DEVSTATE_DOWN);
8849 else if (DEVI_IS_BUS_QUIESCED(dip))
8850 return (DDI_DEVSTATE_QUIESCED);
8851 else if (DEVI_IS_DEVICE_DEGRADED(dip))
8852 return (DDI_DEVSTATE_DEGRADED);
8853 else
8854 return (DDI_DEVSTATE_UP);
8855 }
8856
8857 void
ddi_dev_report_fault(dev_info_t * dip,ddi_fault_impact_t impact,ddi_fault_location_t location,const char * message)8858 ddi_dev_report_fault(dev_info_t *dip, ddi_fault_impact_t impact,
8859 ddi_fault_location_t location, const char *message)
8860 {
8861 struct ddi_fault_event_data fd;
8862 ddi_eventcookie_t ec;
8863
8864 /*
8865 * Assemble all the information into a fault-event-data structure
8866 */
8867 fd.f_dip = dip;
8868 fd.f_impact = impact;
8869 fd.f_location = location;
8870 fd.f_message = message;
8871 fd.f_oldstate = ddi_get_devstate(dip);
8872
8873 /*
8874 * Get eventcookie from defining parent.
8875 */
8876 if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) !=
8877 DDI_SUCCESS)
8878 return;
8879
8880 (void) ndi_post_event(dip, dip, ec, &fd);
8881 }
8882
8883 char *
i_ddi_devi_class(dev_info_t * dip)8884 i_ddi_devi_class(dev_info_t *dip)
8885 {
8886 return (DEVI(dip)->devi_device_class);
8887 }
8888
8889 int
i_ddi_set_devi_class(dev_info_t * dip,const char * devi_class,int flag)8890 i_ddi_set_devi_class(dev_info_t *dip, const char *devi_class, int flag)
8891 {
8892 struct dev_info *devi = DEVI(dip);
8893
8894 mutex_enter(&devi->devi_lock);
8895
8896 if (devi->devi_device_class)
8897 kmem_free(devi->devi_device_class,
8898 strlen(devi->devi_device_class) + 1);
8899
8900 if ((devi->devi_device_class = i_ddi_strdup(devi_class, flag))
8901 != NULL) {
8902 mutex_exit(&devi->devi_lock);
8903 return (DDI_SUCCESS);
8904 }
8905
8906 mutex_exit(&devi->devi_lock);
8907
8908 return (DDI_FAILURE);
8909 }
8910
8911
8912 /*
8913 * Task Queues DDI interfaces.
8914 */
8915
8916 /* ARGSUSED */
8917 ddi_taskq_t *
ddi_taskq_create(dev_info_t * dip,const char * name,int nthreads,pri_t pri,uint_t cflags)8918 ddi_taskq_create(dev_info_t *dip, const char *name, int nthreads,
8919 pri_t pri, uint_t cflags)
8920 {
8921 char full_name[TASKQ_NAMELEN];
8922 const char *tq_name;
8923 int nodeid = 0;
8924
8925 if (dip == NULL)
8926 tq_name = name;
8927 else {
8928 nodeid = ddi_get_instance(dip);
8929
8930 if (name == NULL)
8931 name = "tq";
8932
8933 (void) snprintf(full_name, sizeof (full_name), "%s_%s",
8934 ddi_driver_name(dip), name);
8935
8936 tq_name = full_name;
8937 }
8938
8939 return ((ddi_taskq_t *)taskq_create_instance(tq_name, nodeid, nthreads,
8940 pri == TASKQ_DEFAULTPRI ? minclsyspri : pri,
8941 nthreads, INT_MAX, TASKQ_PREPOPULATE));
8942 }
8943
8944 void
ddi_taskq_destroy(ddi_taskq_t * tq)8945 ddi_taskq_destroy(ddi_taskq_t *tq)
8946 {
8947 taskq_destroy((taskq_t *)tq);
8948 }
8949
8950 int
ddi_taskq_dispatch(ddi_taskq_t * tq,void (* func)(void *),void * arg,uint_t dflags)8951 ddi_taskq_dispatch(ddi_taskq_t *tq, void (* func)(void *),
8952 void *arg, uint_t dflags)
8953 {
8954 taskqid_t id = taskq_dispatch((taskq_t *)tq, func, arg,
8955 dflags == DDI_SLEEP ? TQ_SLEEP : TQ_NOSLEEP);
8956
8957 return (id != TASKQID_INVALID ? DDI_SUCCESS : DDI_FAILURE);
8958 }
8959
8960 void
ddi_taskq_wait(ddi_taskq_t * tq)8961 ddi_taskq_wait(ddi_taskq_t *tq)
8962 {
8963 taskq_wait((taskq_t *)tq);
8964 }
8965
8966 void
ddi_taskq_suspend(ddi_taskq_t * tq)8967 ddi_taskq_suspend(ddi_taskq_t *tq)
8968 {
8969 taskq_suspend((taskq_t *)tq);
8970 }
8971
8972 boolean_t
ddi_taskq_suspended(ddi_taskq_t * tq)8973 ddi_taskq_suspended(ddi_taskq_t *tq)
8974 {
8975 return (taskq_suspended((taskq_t *)tq));
8976 }
8977
8978 void
ddi_taskq_resume(ddi_taskq_t * tq)8979 ddi_taskq_resume(ddi_taskq_t *tq)
8980 {
8981 taskq_resume((taskq_t *)tq);
8982 }
8983
8984 int
ddi_parse(const char * ifname,char * alnum,uint_t * nump)8985 ddi_parse(const char *ifname, char *alnum, uint_t *nump)
8986 {
8987 /*
8988 * Cap "alnum" size at LIFNAMSIZ, as callers use that in most/all
8989 * cases.
8990 */
8991 return (ddi_parse_dlen(ifname, alnum, LIFNAMSIZ, nump));
8992 }
8993
8994 int
ddi_parse_dlen(const char * ifname,char * alnum,size_t alnumsize,uint_t * nump)8995 ddi_parse_dlen(const char *ifname, char *alnum, size_t alnumsize, uint_t *nump)
8996 {
8997 const char *p;
8998 int copy_len;
8999 ulong_t num;
9000 boolean_t nonum = B_TRUE;
9001 char c;
9002
9003 copy_len = strlen(ifname);
9004 for (p = ifname + copy_len; p != ifname; copy_len--) {
9005 c = *--p;
9006 if (!isdigit(c)) {
9007 /*
9008 * At this point, copy_len is the length of ifname
9009 * WITHOUT the PPA number. For "e1000g10" copy_len is 6.
9010 *
9011 * We must first make sure we HAVE a PPA, and we
9012 * aren't exceeding alnumsize with copy_len and a '\0'
9013 * terminator...
9014 */
9015 int copy_len_nul = copy_len + 1;
9016
9017 if (nonum || alnumsize < copy_len_nul)
9018 return (DDI_FAILURE);
9019
9020 /*
9021 * ... then we abuse strlcpy() to copy over the
9022 * driver name portion AND '\0'-terminate it.
9023 */
9024 (void) strlcpy(alnum, ifname, copy_len_nul);
9025 if (ddi_strtoul(p + 1, NULL, 10, &num) != 0)
9026 return (DDI_FAILURE);
9027 break;
9028 }
9029 nonum = B_FALSE;
9030 }
9031
9032 if (copy_len == 0)
9033 return (DDI_FAILURE);
9034
9035 *nump = num;
9036 return (DDI_SUCCESS);
9037 }
9038
9039 /*
9040 * Default initialization function for drivers that don't need to quiesce.
9041 */
9042 /* ARGSUSED */
9043 int
ddi_quiesce_not_needed(dev_info_t * dip)9044 ddi_quiesce_not_needed(dev_info_t *dip)
9045 {
9046 return (DDI_SUCCESS);
9047 }
9048
9049 /*
9050 * Initialization function for drivers that should implement quiesce()
9051 * but haven't yet.
9052 */
9053 /* ARGSUSED */
9054 int
ddi_quiesce_not_supported(dev_info_t * dip)9055 ddi_quiesce_not_supported(dev_info_t *dip)
9056 {
9057 return (DDI_FAILURE);
9058 }
9059
9060 char *
ddi_strdup(const char * str,int flag)9061 ddi_strdup(const char *str, int flag)
9062 {
9063 int n;
9064 char *ptr;
9065
9066 ASSERT(str != NULL);
9067 ASSERT((flag == KM_SLEEP) || (flag == KM_NOSLEEP));
9068
9069 n = strlen(str);
9070 if ((ptr = kmem_alloc(n + 1, flag)) == NULL)
9071 return (NULL);
9072 bcopy(str, ptr, n + 1);
9073 return (ptr);
9074 }
9075
9076 char *
strdup(const char * str)9077 strdup(const char *str)
9078 {
9079 return (ddi_strdup(str, KM_SLEEP));
9080 }
9081
9082 void
strfree(char * str)9083 strfree(char *str)
9084 {
9085 ASSERT(str != NULL);
9086 kmem_free(str, strlen(str) + 1);
9087 }
9088
9089 /*
9090 * Generic DDI callback interfaces.
9091 */
9092
9093 int
ddi_cb_register(dev_info_t * dip,ddi_cb_flags_t flags,ddi_cb_func_t cbfunc,void * arg1,void * arg2,ddi_cb_handle_t * ret_hdlp)9094 ddi_cb_register(dev_info_t *dip, ddi_cb_flags_t flags, ddi_cb_func_t cbfunc,
9095 void *arg1, void *arg2, ddi_cb_handle_t *ret_hdlp)
9096 {
9097 ddi_cb_t *cbp;
9098
9099 ASSERT(dip != NULL);
9100 ASSERT(DDI_CB_FLAG_VALID(flags));
9101 ASSERT(cbfunc != NULL);
9102 ASSERT(ret_hdlp != NULL);
9103
9104 /* Sanity check the context */
9105 ASSERT(!servicing_interrupt());
9106 if (servicing_interrupt())
9107 return (DDI_FAILURE);
9108
9109 /* Validate parameters */
9110 if ((dip == NULL) || !DDI_CB_FLAG_VALID(flags) ||
9111 (cbfunc == NULL) || (ret_hdlp == NULL))
9112 return (DDI_EINVAL);
9113
9114 /* Check for previous registration */
9115 if (DEVI(dip)->devi_cb_p != NULL)
9116 return (DDI_EALREADY);
9117
9118 /* Allocate and initialize callback */
9119 cbp = kmem_zalloc(sizeof (ddi_cb_t), KM_SLEEP);
9120 cbp->cb_dip = dip;
9121 cbp->cb_func = cbfunc;
9122 cbp->cb_arg1 = arg1;
9123 cbp->cb_arg2 = arg2;
9124 cbp->cb_flags = flags;
9125 DEVI(dip)->devi_cb_p = cbp;
9126
9127 /* If adding an IRM callback, notify IRM */
9128 if (flags & DDI_CB_FLAG_INTR)
9129 i_ddi_irm_set_cb(dip, B_TRUE);
9130
9131 *ret_hdlp = (ddi_cb_handle_t)&(DEVI(dip)->devi_cb_p);
9132 return (DDI_SUCCESS);
9133 }
9134
9135 int
ddi_cb_unregister(ddi_cb_handle_t hdl)9136 ddi_cb_unregister(ddi_cb_handle_t hdl)
9137 {
9138 ddi_cb_t *cbp;
9139 dev_info_t *dip;
9140
9141 ASSERT(hdl != NULL);
9142
9143 /* Sanity check the context */
9144 ASSERT(!servicing_interrupt());
9145 if (servicing_interrupt())
9146 return (DDI_FAILURE);
9147
9148 /* Validate parameters */
9149 if ((hdl == NULL) || ((cbp = *(ddi_cb_t **)hdl) == NULL) ||
9150 ((dip = cbp->cb_dip) == NULL))
9151 return (DDI_EINVAL);
9152
9153 /* If removing an IRM callback, notify IRM */
9154 if (cbp->cb_flags & DDI_CB_FLAG_INTR)
9155 i_ddi_irm_set_cb(dip, B_FALSE);
9156
9157 /* Destroy the callback */
9158 kmem_free(cbp, sizeof (ddi_cb_t));
9159 DEVI(dip)->devi_cb_p = NULL;
9160
9161 return (DDI_SUCCESS);
9162 }
9163
9164 /*
9165 * Platform independent DR routines
9166 */
9167
9168 static int
ndi2errno(int n)9169 ndi2errno(int n)
9170 {
9171 int err = 0;
9172
9173 switch (n) {
9174 case NDI_NOMEM:
9175 err = ENOMEM;
9176 break;
9177 case NDI_BUSY:
9178 err = EBUSY;
9179 break;
9180 case NDI_FAULT:
9181 err = EFAULT;
9182 break;
9183 case NDI_FAILURE:
9184 err = EIO;
9185 break;
9186 case NDI_SUCCESS:
9187 break;
9188 case NDI_BADHANDLE:
9189 default:
9190 err = EINVAL;
9191 break;
9192 }
9193 return (err);
9194 }
9195
9196 /*
9197 * Prom tree node list
9198 */
9199 struct ptnode {
9200 pnode_t nodeid;
9201 struct ptnode *next;
9202 };
9203
9204 /*
9205 * Prom tree walk arg
9206 */
9207 struct pta {
9208 dev_info_t *pdip;
9209 devi_branch_t *bp;
9210 uint_t flags;
9211 dev_info_t *fdip;
9212 struct ptnode *head;
9213 };
9214
9215 static void
visit_node(pnode_t nodeid,struct pta * ap)9216 visit_node(pnode_t nodeid, struct pta *ap)
9217 {
9218 struct ptnode **nextp;
9219 int (*select)(pnode_t, void *, uint_t);
9220
9221 ASSERT(nodeid != OBP_NONODE && nodeid != OBP_BADNODE);
9222
9223 select = ap->bp->create.prom_branch_select;
9224
9225 ASSERT(select);
9226
9227 if (select(nodeid, ap->bp->arg, 0) == DDI_SUCCESS) {
9228
9229 for (nextp = &ap->head; *nextp; nextp = &(*nextp)->next)
9230 ;
9231
9232 *nextp = kmem_zalloc(sizeof (struct ptnode), KM_SLEEP);
9233
9234 (*nextp)->nodeid = nodeid;
9235 }
9236
9237 if ((ap->flags & DEVI_BRANCH_CHILD) == DEVI_BRANCH_CHILD)
9238 return;
9239
9240 nodeid = prom_childnode(nodeid);
9241 while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) {
9242 visit_node(nodeid, ap);
9243 nodeid = prom_nextnode(nodeid);
9244 }
9245 }
9246
9247 /*
9248 * NOTE: The caller of this function must check for device contracts
9249 * or LDI callbacks against this dip before setting the dip offline.
9250 */
9251 static int
set_infant_dip_offline(dev_info_t * dip,void * arg)9252 set_infant_dip_offline(dev_info_t *dip, void *arg)
9253 {
9254 char *path = (char *)arg;
9255
9256 ASSERT(dip);
9257 ASSERT(arg);
9258
9259 if (i_ddi_node_state(dip) >= DS_ATTACHED) {
9260 (void) ddi_pathname(dip, path);
9261 cmn_err(CE_WARN, "Attempt to set offline flag on attached "
9262 "node: %s", path);
9263 return (DDI_FAILURE);
9264 }
9265
9266 mutex_enter(&(DEVI(dip)->devi_lock));
9267 if (!DEVI_IS_DEVICE_OFFLINE(dip))
9268 DEVI_SET_DEVICE_OFFLINE(dip);
9269 mutex_exit(&(DEVI(dip)->devi_lock));
9270
9271 return (DDI_SUCCESS);
9272 }
9273
9274 typedef struct result {
9275 char *path;
9276 int result;
9277 } result_t;
9278
9279 static int
dip_set_offline(dev_info_t * dip,void * arg)9280 dip_set_offline(dev_info_t *dip, void *arg)
9281 {
9282 int end;
9283 result_t *resp = (result_t *)arg;
9284
9285 ASSERT(dip);
9286 ASSERT(resp);
9287
9288 /*
9289 * We stop the walk if e_ddi_offline_notify() returns
9290 * failure, because this implies that one or more consumers
9291 * (either LDI or contract based) has blocked the offline.
9292 * So there is no point in conitnuing the walk
9293 */
9294 if (e_ddi_offline_notify(dip) == DDI_FAILURE) {
9295 resp->result = DDI_FAILURE;
9296 return (DDI_WALK_TERMINATE);
9297 }
9298
9299 /*
9300 * If set_infant_dip_offline() returns failure, it implies
9301 * that we failed to set a particular dip offline. This
9302 * does not imply that the offline as a whole should fail.
9303 * We want to do the best we can, so we continue the walk.
9304 */
9305 if (set_infant_dip_offline(dip, resp->path) == DDI_SUCCESS)
9306 end = DDI_SUCCESS;
9307 else
9308 end = DDI_FAILURE;
9309
9310 e_ddi_offline_finalize(dip, end);
9311
9312 return (DDI_WALK_CONTINUE);
9313 }
9314
9315 /*
9316 * The call to e_ddi_offline_notify() exists for the
9317 * unlikely error case that a branch we are trying to
9318 * create already exists and has device contracts or LDI
9319 * event callbacks against it.
9320 *
9321 * We allow create to succeed for such branches only if
9322 * no constraints block the offline.
9323 */
9324 static int
branch_set_offline(dev_info_t * dip,char * path)9325 branch_set_offline(dev_info_t *dip, char *path)
9326 {
9327 int end;
9328 result_t res;
9329
9330
9331 if (e_ddi_offline_notify(dip) == DDI_FAILURE) {
9332 return (DDI_FAILURE);
9333 }
9334
9335 if (set_infant_dip_offline(dip, path) == DDI_SUCCESS)
9336 end = DDI_SUCCESS;
9337 else
9338 end = DDI_FAILURE;
9339
9340 e_ddi_offline_finalize(dip, end);
9341
9342 if (end == DDI_FAILURE)
9343 return (DDI_FAILURE);
9344
9345 res.result = DDI_SUCCESS;
9346 res.path = path;
9347
9348 ndi_devi_enter(dip);
9349 ddi_walk_devs(ddi_get_child(dip), dip_set_offline, &res);
9350 ndi_devi_exit(dip);
9351
9352 return (res.result);
9353 }
9354
9355 /*ARGSUSED*/
9356 static int
create_prom_branch(void * arg,int has_changed)9357 create_prom_branch(void *arg, int has_changed)
9358 {
9359 int exists, rv;
9360 pnode_t nodeid;
9361 struct ptnode *tnp;
9362 dev_info_t *dip;
9363 struct pta *ap = arg;
9364 devi_branch_t *bp;
9365 char *path;
9366
9367 ASSERT(ap);
9368 ASSERT(ap->fdip == NULL);
9369 ASSERT(ap->pdip && ndi_dev_is_prom_node(ap->pdip));
9370
9371 bp = ap->bp;
9372
9373 nodeid = ddi_get_nodeid(ap->pdip);
9374 if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) {
9375 cmn_err(CE_WARN, "create_prom_branch: invalid "
9376 "nodeid: 0x%x", nodeid);
9377 return (EINVAL);
9378 }
9379
9380 ap->head = NULL;
9381
9382 nodeid = prom_childnode(nodeid);
9383 while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) {
9384 visit_node(nodeid, ap);
9385 nodeid = prom_nextnode(nodeid);
9386 }
9387
9388 if (ap->head == NULL)
9389 return (ENODEV);
9390
9391 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
9392 rv = 0;
9393 while ((tnp = ap->head) != NULL) {
9394 ap->head = tnp->next;
9395
9396 ndi_devi_enter(ap->pdip);
9397
9398 /*
9399 * Check if the branch already exists.
9400 */
9401 exists = 0;
9402 dip = e_ddi_nodeid_to_dip(tnp->nodeid);
9403 if (dip != NULL) {
9404 exists = 1;
9405
9406 /* Parent is held busy, so release hold */
9407 ndi_rele_devi(dip);
9408 #ifdef DEBUG
9409 cmn_err(CE_WARN, "create_prom_branch: dip(%p) exists"
9410 " for nodeid 0x%x", (void *)dip, tnp->nodeid);
9411 #endif
9412 } else {
9413 dip = i_ddi_create_branch(ap->pdip, tnp->nodeid);
9414 }
9415
9416 kmem_free(tnp, sizeof (struct ptnode));
9417
9418 /*
9419 * Hold the branch if it is not already held
9420 */
9421 if (dip && !exists) {
9422 e_ddi_branch_hold(dip);
9423 }
9424
9425 ASSERT(dip == NULL || e_ddi_branch_held(dip));
9426
9427 /*
9428 * Set all dips in the newly created branch offline so that
9429 * only a "configure" operation can attach
9430 * the branch
9431 */
9432 if (dip == NULL || branch_set_offline(dip, path)
9433 == DDI_FAILURE) {
9434 ndi_devi_exit(ap->pdip);
9435 rv = EIO;
9436 continue;
9437 }
9438
9439 ASSERT(ddi_get_parent(dip) == ap->pdip);
9440
9441 ndi_devi_exit(ap->pdip);
9442
9443 if (ap->flags & DEVI_BRANCH_CONFIGURE) {
9444 int error = e_ddi_branch_configure(dip, &ap->fdip, 0);
9445 if (error && rv == 0)
9446 rv = error;
9447 }
9448
9449 /*
9450 * Invoke devi_branch_callback() (if it exists) only for
9451 * newly created branches
9452 */
9453 if (bp->devi_branch_callback && !exists)
9454 bp->devi_branch_callback(dip, bp->arg, 0);
9455 }
9456
9457 kmem_free(path, MAXPATHLEN);
9458
9459 return (rv);
9460 }
9461
9462 static int
sid_node_create(dev_info_t * pdip,devi_branch_t * bp,dev_info_t ** rdipp)9463 sid_node_create(dev_info_t *pdip, devi_branch_t *bp, dev_info_t **rdipp)
9464 {
9465 int rv, len;
9466 int i, flags, ret;
9467 dev_info_t *dip;
9468 char *nbuf;
9469 char *path;
9470 static const char *noname = "<none>";
9471
9472 ASSERT(pdip);
9473 ASSERT(DEVI_BUSY_OWNED(pdip));
9474
9475 flags = 0;
9476
9477 /*
9478 * Creating the root of a branch ?
9479 */
9480 if (rdipp) {
9481 *rdipp = NULL;
9482 flags = DEVI_BRANCH_ROOT;
9483 }
9484
9485 ndi_devi_alloc_sleep(pdip, (char *)noname, DEVI_SID_NODEID, &dip);
9486 rv = bp->create.sid_branch_create(dip, bp->arg, flags);
9487
9488 nbuf = kmem_alloc(OBP_MAXDRVNAME, KM_SLEEP);
9489
9490 if (rv == DDI_WALK_ERROR) {
9491 cmn_err(CE_WARN, "e_ddi_branch_create: Error setting"
9492 " properties on devinfo node %p", (void *)dip);
9493 goto fail;
9494 }
9495
9496 len = OBP_MAXDRVNAME;
9497 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
9498 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "name", nbuf, &len)
9499 != DDI_PROP_SUCCESS) {
9500 cmn_err(CE_WARN, "e_ddi_branch_create: devinfo node %p has"
9501 "no name property", (void *)dip);
9502 goto fail;
9503 }
9504
9505 ASSERT(i_ddi_node_state(dip) == DS_PROTO);
9506 if (ndi_devi_set_nodename(dip, nbuf, 0) != NDI_SUCCESS) {
9507 cmn_err(CE_WARN, "e_ddi_branch_create: cannot set name (%s)"
9508 " for devinfo node %p", nbuf, (void *)dip);
9509 goto fail;
9510 }
9511
9512 kmem_free(nbuf, OBP_MAXDRVNAME);
9513
9514 /*
9515 * Ignore bind failures just like boot does
9516 */
9517 (void) ndi_devi_bind_driver(dip, 0);
9518
9519 switch (rv) {
9520 case DDI_WALK_CONTINUE:
9521 case DDI_WALK_PRUNESIB:
9522 ndi_devi_enter(dip);
9523
9524 i = DDI_WALK_CONTINUE;
9525 for (; i == DDI_WALK_CONTINUE; ) {
9526 i = sid_node_create(dip, bp, NULL);
9527 }
9528
9529 ASSERT(i == DDI_WALK_ERROR || i == DDI_WALK_PRUNESIB);
9530 if (i == DDI_WALK_ERROR)
9531 rv = i;
9532 /*
9533 * If PRUNESIB stop creating siblings
9534 * of dip's child. Subsequent walk behavior
9535 * is determined by rv returned by dip.
9536 */
9537
9538 ndi_devi_exit(dip);
9539 break;
9540 case DDI_WALK_TERMINATE:
9541 /*
9542 * Don't create children and ask our parent
9543 * to not create siblings either.
9544 */
9545 rv = DDI_WALK_PRUNESIB;
9546 break;
9547 case DDI_WALK_PRUNECHILD:
9548 /*
9549 * Don't create children, but ask parent to continue
9550 * with siblings.
9551 */
9552 rv = DDI_WALK_CONTINUE;
9553 break;
9554 default:
9555 ASSERT(0);
9556 break;
9557 }
9558
9559 if (rdipp)
9560 *rdipp = dip;
9561
9562 /*
9563 * Set device offline - only the "configure" op should cause an attach.
9564 * Note that it is safe to set the dip offline without checking
9565 * for either device contract or layered driver (LDI) based constraints
9566 * since there cannot be any contracts or LDI opens of this device.
9567 * This is because this node is a newly created dip with the parent busy
9568 * held, so no other thread can come in and attach this dip. A dip that
9569 * has never been attached cannot have contracts since by definition
9570 * a device contract (an agreement between a process and a device minor
9571 * node) can only be created against a device that has minor nodes
9572 * i.e is attached. Similarly an LDI open will only succeed if the
9573 * dip is attached. We assert below that the dip is not attached.
9574 */
9575 ASSERT(i_ddi_node_state(dip) < DS_ATTACHED);
9576 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
9577 ret = set_infant_dip_offline(dip, path);
9578 ASSERT(ret == DDI_SUCCESS);
9579 kmem_free(path, MAXPATHLEN);
9580
9581 return (rv);
9582 fail:
9583 (void) ndi_devi_free(dip);
9584 kmem_free(nbuf, OBP_MAXDRVNAME);
9585 return (DDI_WALK_ERROR);
9586 }
9587
9588 static int
create_sid_branch(dev_info_t * pdip,devi_branch_t * bp,dev_info_t ** dipp,uint_t flags)9589 create_sid_branch(
9590 dev_info_t *pdip,
9591 devi_branch_t *bp,
9592 dev_info_t **dipp,
9593 uint_t flags)
9594 {
9595 int rv = 0, state = DDI_WALK_CONTINUE;
9596 dev_info_t *rdip;
9597
9598 while (state == DDI_WALK_CONTINUE) {
9599 ndi_devi_enter(pdip);
9600
9601 state = sid_node_create(pdip, bp, &rdip);
9602 if (rdip == NULL) {
9603 ndi_devi_exit(pdip);
9604 ASSERT(state == DDI_WALK_ERROR);
9605 break;
9606 }
9607
9608 e_ddi_branch_hold(rdip);
9609
9610 ndi_devi_exit(pdip);
9611
9612 if (flags & DEVI_BRANCH_CONFIGURE) {
9613 int error = e_ddi_branch_configure(rdip, dipp, 0);
9614 if (error && rv == 0)
9615 rv = error;
9616 }
9617
9618 /*
9619 * devi_branch_callback() is optional
9620 */
9621 if (bp->devi_branch_callback)
9622 bp->devi_branch_callback(rdip, bp->arg, 0);
9623 }
9624
9625 ASSERT(state == DDI_WALK_ERROR || state == DDI_WALK_PRUNESIB);
9626
9627 return (state == DDI_WALK_ERROR ? EIO : rv);
9628 }
9629
9630 int
e_ddi_branch_create(dev_info_t * pdip,devi_branch_t * bp,dev_info_t ** dipp,uint_t flags)9631 e_ddi_branch_create(
9632 dev_info_t *pdip,
9633 devi_branch_t *bp,
9634 dev_info_t **dipp,
9635 uint_t flags)
9636 {
9637 int prom_devi, sid_devi, error;
9638
9639 if (pdip == NULL || bp == NULL || bp->type == 0)
9640 return (EINVAL);
9641
9642 prom_devi = (bp->type == DEVI_BRANCH_PROM) ? 1 : 0;
9643 sid_devi = (bp->type == DEVI_BRANCH_SID) ? 1 : 0;
9644
9645 if (prom_devi && bp->create.prom_branch_select == NULL)
9646 return (EINVAL);
9647 else if (sid_devi && bp->create.sid_branch_create == NULL)
9648 return (EINVAL);
9649 else if (!prom_devi && !sid_devi)
9650 return (EINVAL);
9651
9652 if (flags & DEVI_BRANCH_EVENT)
9653 return (EINVAL);
9654
9655 if (prom_devi) {
9656 struct pta pta = {0};
9657
9658 pta.pdip = pdip;
9659 pta.bp = bp;
9660 pta.flags = flags;
9661
9662 error = prom_tree_access(create_prom_branch, &pta, NULL);
9663
9664 if (dipp)
9665 *dipp = pta.fdip;
9666 else if (pta.fdip)
9667 ndi_rele_devi(pta.fdip);
9668 } else {
9669 error = create_sid_branch(pdip, bp, dipp, flags);
9670 }
9671
9672 return (error);
9673 }
9674
9675 int
e_ddi_branch_configure(dev_info_t * rdip,dev_info_t ** dipp,uint_t flags)9676 e_ddi_branch_configure(dev_info_t *rdip, dev_info_t **dipp, uint_t flags)
9677 {
9678 int rv;
9679 char *devnm;
9680 dev_info_t *pdip;
9681
9682 if (dipp)
9683 *dipp = NULL;
9684
9685 if (rdip == NULL || flags != 0 || (flags & DEVI_BRANCH_EVENT))
9686 return (EINVAL);
9687
9688 pdip = ddi_get_parent(rdip);
9689
9690 ndi_hold_devi(pdip);
9691
9692 if (!e_ddi_branch_held(rdip)) {
9693 ndi_rele_devi(pdip);
9694 cmn_err(CE_WARN, "e_ddi_branch_configure: "
9695 "dip(%p) not held", (void *)rdip);
9696 return (EINVAL);
9697 }
9698
9699 if (i_ddi_node_state(rdip) < DS_INITIALIZED) {
9700 /*
9701 * First attempt to bind a driver. If we fail, return
9702 * success (On some platforms, dips for some device
9703 * types (CPUs) may not have a driver)
9704 */
9705 if (ndi_devi_bind_driver(rdip, 0) != NDI_SUCCESS) {
9706 ndi_rele_devi(pdip);
9707 return (0);
9708 }
9709
9710 if (ddi_initchild(pdip, rdip) != DDI_SUCCESS) {
9711 rv = NDI_FAILURE;
9712 goto out;
9713 }
9714 }
9715
9716 ASSERT(i_ddi_node_state(rdip) >= DS_INITIALIZED);
9717
9718 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
9719
9720 (void) ddi_deviname(rdip, devnm);
9721
9722 if ((rv = ndi_devi_config_one(pdip, devnm+1, &rdip,
9723 NDI_DEVI_ONLINE | NDI_CONFIG)) == NDI_SUCCESS) {
9724 /* release hold from ndi_devi_config_one() */
9725 ndi_rele_devi(rdip);
9726 }
9727
9728 kmem_free(devnm, MAXNAMELEN + 1);
9729 out:
9730 if (rv != NDI_SUCCESS && dipp && rdip) {
9731 ndi_hold_devi(rdip);
9732 *dipp = rdip;
9733 }
9734 ndi_rele_devi(pdip);
9735 return (ndi2errno(rv));
9736 }
9737
9738 void
e_ddi_branch_hold(dev_info_t * rdip)9739 e_ddi_branch_hold(dev_info_t *rdip)
9740 {
9741 if (e_ddi_branch_held(rdip)) {
9742 cmn_err(CE_WARN, "e_ddi_branch_hold: branch already held");
9743 return;
9744 }
9745
9746 mutex_enter(&DEVI(rdip)->devi_lock);
9747 if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) == 0) {
9748 DEVI(rdip)->devi_flags |= DEVI_BRANCH_HELD;
9749 DEVI(rdip)->devi_ref++;
9750 }
9751 ASSERT(DEVI(rdip)->devi_ref > 0);
9752 mutex_exit(&DEVI(rdip)->devi_lock);
9753 }
9754
9755 int
e_ddi_branch_held(dev_info_t * rdip)9756 e_ddi_branch_held(dev_info_t *rdip)
9757 {
9758 int rv = 0;
9759
9760 mutex_enter(&DEVI(rdip)->devi_lock);
9761 if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) &&
9762 DEVI(rdip)->devi_ref > 0) {
9763 rv = 1;
9764 }
9765 mutex_exit(&DEVI(rdip)->devi_lock);
9766
9767 return (rv);
9768 }
9769
9770 void
e_ddi_branch_rele(dev_info_t * rdip)9771 e_ddi_branch_rele(dev_info_t *rdip)
9772 {
9773 mutex_enter(&DEVI(rdip)->devi_lock);
9774 DEVI(rdip)->devi_flags &= ~DEVI_BRANCH_HELD;
9775 DEVI(rdip)->devi_ref--;
9776 mutex_exit(&DEVI(rdip)->devi_lock);
9777 }
9778
9779 int
e_ddi_branch_unconfigure(dev_info_t * rdip,dev_info_t ** dipp,uint_t flags)9780 e_ddi_branch_unconfigure(
9781 dev_info_t *rdip,
9782 dev_info_t **dipp,
9783 uint_t flags)
9784 {
9785 int rv;
9786 int destroy;
9787 char *devnm;
9788 uint_t nflags;
9789 dev_info_t *pdip;
9790
9791 if (dipp)
9792 *dipp = NULL;
9793
9794 if (rdip == NULL)
9795 return (EINVAL);
9796
9797 pdip = ddi_get_parent(rdip);
9798
9799 ASSERT(pdip);
9800
9801 /*
9802 * Check if caller holds pdip busy - can cause deadlocks during
9803 * devfs_clean()
9804 */
9805 if (DEVI_BUSY_OWNED(pdip)) {
9806 cmn_err(CE_WARN, "e_ddi_branch_unconfigure: failed: parent"
9807 " devinfo node(%p) is busy held", (void *)pdip);
9808 return (EINVAL);
9809 }
9810
9811 destroy = (flags & DEVI_BRANCH_DESTROY) ? 1 : 0;
9812
9813 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
9814
9815 ndi_devi_enter(pdip);
9816 (void) ddi_deviname(rdip, devnm);
9817 ndi_devi_exit(pdip);
9818
9819 /*
9820 * ddi_deviname() returns a component name with / prepended.
9821 */
9822 (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
9823
9824 ndi_devi_enter(pdip);
9825
9826 /*
9827 * Recreate device name as it may have changed state (init/uninit)
9828 * when parent busy lock was dropped for devfs_clean()
9829 */
9830 (void) ddi_deviname(rdip, devnm);
9831
9832 if (!e_ddi_branch_held(rdip)) {
9833 kmem_free(devnm, MAXNAMELEN + 1);
9834 ndi_devi_exit(pdip);
9835 cmn_err(CE_WARN, "e_ddi_%s_branch: dip(%p) not held",
9836 destroy ? "destroy" : "unconfigure", (void *)rdip);
9837 return (EINVAL);
9838 }
9839
9840 /*
9841 * Release hold on the branch. This is ok since we are holding the
9842 * parent busy. If rdip is not removed, we must do a hold on the
9843 * branch before returning.
9844 */
9845 e_ddi_branch_rele(rdip);
9846
9847 nflags = NDI_DEVI_OFFLINE;
9848 if (destroy || (flags & DEVI_BRANCH_DESTROY)) {
9849 nflags |= NDI_DEVI_REMOVE;
9850 destroy = 1;
9851 } else {
9852 nflags |= NDI_UNCONFIG; /* uninit but don't remove */
9853 }
9854
9855 if (flags & DEVI_BRANCH_EVENT)
9856 nflags |= NDI_POST_EVENT;
9857
9858 if (i_ddi_devi_attached(pdip) &&
9859 (i_ddi_node_state(rdip) >= DS_INITIALIZED)) {
9860 rv = ndi_devi_unconfig_one(pdip, devnm+1, dipp, nflags);
9861 } else {
9862 rv = e_ddi_devi_unconfig(rdip, dipp, nflags);
9863 if (rv == NDI_SUCCESS) {
9864 ASSERT(!destroy || ddi_get_child(rdip) == NULL);
9865 rv = ndi_devi_offline(rdip, nflags);
9866 }
9867 }
9868
9869 if (!destroy || rv != NDI_SUCCESS) {
9870 /* The dip still exists, so do a hold */
9871 e_ddi_branch_hold(rdip);
9872 }
9873
9874 kmem_free(devnm, MAXNAMELEN + 1);
9875 ndi_devi_exit(pdip);
9876 return (ndi2errno(rv));
9877 }
9878
9879 int
e_ddi_branch_destroy(dev_info_t * rdip,dev_info_t ** dipp,uint_t flag)9880 e_ddi_branch_destroy(dev_info_t *rdip, dev_info_t **dipp, uint_t flag)
9881 {
9882 return (e_ddi_branch_unconfigure(rdip, dipp,
9883 flag|DEVI_BRANCH_DESTROY));
9884 }
9885
9886 /*
9887 * Number of chains for hash table
9888 */
9889 #define NUMCHAINS 17
9890
9891 /*
9892 * Devinfo busy arg
9893 */
9894 struct devi_busy {
9895 int dv_total;
9896 int s_total;
9897 mod_hash_t *dv_hash;
9898 mod_hash_t *s_hash;
9899 int (*callback)(dev_info_t *, void *, uint_t);
9900 void *arg;
9901 };
9902
9903 static int
visit_dip(dev_info_t * dip,void * arg)9904 visit_dip(dev_info_t *dip, void *arg)
9905 {
9906 uintptr_t sbusy, dvbusy, ref;
9907 struct devi_busy *bsp = arg;
9908
9909 ASSERT(bsp->callback);
9910
9911 /*
9912 * A dip cannot be busy if its reference count is 0
9913 */
9914 if ((ref = e_ddi_devi_holdcnt(dip)) == 0) {
9915 return (bsp->callback(dip, bsp->arg, 0));
9916 }
9917
9918 if (mod_hash_find(bsp->dv_hash, dip, (mod_hash_val_t *)&dvbusy))
9919 dvbusy = 0;
9920
9921 /*
9922 * To catch device opens currently maintained on specfs common snodes.
9923 */
9924 if (mod_hash_find(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy))
9925 sbusy = 0;
9926
9927 #ifdef DEBUG
9928 if (ref < sbusy || ref < dvbusy) {
9929 cmn_err(CE_WARN, "dip(%p): sopen = %lu, dvopen = %lu "
9930 "dip ref = %lu\n", (void *)dip, sbusy, dvbusy, ref);
9931 }
9932 #endif
9933
9934 dvbusy = (sbusy > dvbusy) ? sbusy : dvbusy;
9935
9936 return (bsp->callback(dip, bsp->arg, dvbusy));
9937 }
9938
9939 static int
visit_snode(struct snode * sp,void * arg)9940 visit_snode(struct snode *sp, void *arg)
9941 {
9942 uintptr_t sbusy;
9943 dev_info_t *dip;
9944 int count;
9945 struct devi_busy *bsp = arg;
9946
9947 ASSERT(sp);
9948
9949 /*
9950 * The stable lock is held. This prevents
9951 * the snode and its associated dip from
9952 * going away.
9953 */
9954 dip = NULL;
9955 count = spec_devi_open_count(sp, &dip);
9956
9957 if (count <= 0)
9958 return (DDI_WALK_CONTINUE);
9959
9960 ASSERT(dip);
9961
9962 if (mod_hash_remove(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy))
9963 sbusy = count;
9964 else
9965 sbusy += count;
9966
9967 if (mod_hash_insert(bsp->s_hash, dip, (mod_hash_val_t)sbusy)) {
9968 cmn_err(CE_WARN, "%s: s_hash insert failed: dip=0x%p, "
9969 "sbusy = %lu", "e_ddi_branch_referenced",
9970 (void *)dip, sbusy);
9971 }
9972
9973 bsp->s_total += count;
9974
9975 return (DDI_WALK_CONTINUE);
9976 }
9977
9978 static void
visit_dvnode(struct dv_node * dv,void * arg)9979 visit_dvnode(struct dv_node *dv, void *arg)
9980 {
9981 uintptr_t dvbusy;
9982 uint_t count;
9983 struct vnode *vp;
9984 struct devi_busy *bsp = arg;
9985
9986 ASSERT(dv && dv->dv_devi);
9987
9988 vp = DVTOV(dv);
9989
9990 mutex_enter(&vp->v_lock);
9991 count = vp->v_count;
9992 mutex_exit(&vp->v_lock);
9993
9994 if (!count)
9995 return;
9996
9997 if (mod_hash_remove(bsp->dv_hash, dv->dv_devi,
9998 (mod_hash_val_t *)&dvbusy))
9999 dvbusy = count;
10000 else
10001 dvbusy += count;
10002
10003 if (mod_hash_insert(bsp->dv_hash, dv->dv_devi,
10004 (mod_hash_val_t)dvbusy)) {
10005 cmn_err(CE_WARN, "%s: dv_hash insert failed: dip=0x%p, "
10006 "dvbusy=%lu", "e_ddi_branch_referenced",
10007 (void *)dv->dv_devi, dvbusy);
10008 }
10009
10010 bsp->dv_total += count;
10011 }
10012
10013 /*
10014 * Returns reference count on success or -1 on failure.
10015 */
10016 int
e_ddi_branch_referenced(dev_info_t * rdip,int (* callback)(dev_info_t * dip,void * arg,uint_t ref),void * arg)10017 e_ddi_branch_referenced(
10018 dev_info_t *rdip,
10019 int (*callback)(dev_info_t *dip, void *arg, uint_t ref),
10020 void *arg)
10021 {
10022 char *path;
10023 dev_info_t *pdip;
10024 struct devi_busy bsa = {0};
10025
10026 ASSERT(rdip);
10027
10028 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
10029
10030 ndi_hold_devi(rdip);
10031
10032 pdip = ddi_get_parent(rdip);
10033
10034 ASSERT(pdip);
10035
10036 /*
10037 * Check if caller holds pdip busy - can cause deadlocks during
10038 * devfs_walk()
10039 */
10040 if (!e_ddi_branch_held(rdip) || DEVI_BUSY_OWNED(pdip)) {
10041 cmn_err(CE_WARN, "e_ddi_branch_referenced: failed: "
10042 "devinfo branch(%p) not held or parent busy held",
10043 (void *)rdip);
10044 ndi_rele_devi(rdip);
10045 kmem_free(path, MAXPATHLEN);
10046 return (-1);
10047 }
10048
10049 ndi_devi_enter(pdip);
10050 (void) ddi_pathname(rdip, path);
10051 ndi_devi_exit(pdip);
10052
10053 bsa.dv_hash = mod_hash_create_ptrhash("dv_node busy hash", NUMCHAINS,
10054 mod_hash_null_valdtor, sizeof (struct dev_info));
10055
10056 bsa.s_hash = mod_hash_create_ptrhash("snode busy hash", NUMCHAINS,
10057 mod_hash_null_valdtor, sizeof (struct snode));
10058
10059 if (devfs_walk(path, visit_dvnode, &bsa)) {
10060 cmn_err(CE_WARN, "e_ddi_branch_referenced: "
10061 "devfs walk failed for: %s", path);
10062 kmem_free(path, MAXPATHLEN);
10063 bsa.s_total = bsa.dv_total = -1;
10064 goto out;
10065 }
10066
10067 kmem_free(path, MAXPATHLEN);
10068
10069 /*
10070 * Walk the snode table to detect device opens, which are currently
10071 * maintained on specfs common snodes.
10072 */
10073 spec_snode_walk(visit_snode, &bsa);
10074
10075 if (callback == NULL)
10076 goto out;
10077
10078 bsa.callback = callback;
10079 bsa.arg = arg;
10080
10081 if (visit_dip(rdip, &bsa) == DDI_WALK_CONTINUE) {
10082 ndi_devi_enter(rdip);
10083 ddi_walk_devs(ddi_get_child(rdip), visit_dip, &bsa);
10084 ndi_devi_exit(rdip);
10085 }
10086
10087 out:
10088 ndi_rele_devi(rdip);
10089 mod_hash_destroy_ptrhash(bsa.s_hash);
10090 mod_hash_destroy_ptrhash(bsa.dv_hash);
10091 return (bsa.s_total > bsa.dv_total ? bsa.s_total : bsa.dv_total);
10092 }
10093