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