Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/pshot.c
+++ new/usr/src/uts/common/io/pshot.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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27 27 */
28 28
29 29 /*
30 30 * pseudo bus nexus driver
31 31 * hotplug framework test facility
32 32 */
33 33
34 34 /*
35 35 * The pshot driver can be used to exercise the i/o framework together
36 36 * with devfs by configuring an arbitrarily complex device tree.
37 37 *
38 38 * The pshot driver is rooted at /devices/pshot. The following commands
39 39 * illustrate the operation of devfs together with pshot's bus_config.
40 40 * The first command demonstrates that, like the magician showing there's
41 41 * nothing up his sleeve, /devices/pshot is empty. The second command
42 42 * conjures up a branch of pshot nodes. Note that pshot's bus_config is
43 43 * called sequentially by devfs for each node, as part of the pathname
44 44 * resolution, and that each pshot node is fully configured and
45 45 * attached before that node's bus_config is called to configure the
46 46 * next child down the tree. The final result is a "disk" node configured
47 47 * at the bottom of the named hierarchy of pshot nodes.
48 48 *
49 49 * #
50 50 * # ls /devices/pshot
51 51 * #
52 52 * # ls -ld /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
53 53 * drwxr-xr-x 2 root sys 512 Feb 6 15:10
54 54 * /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
55 55 *
56 56 * pshot supports some unique behaviors as aids for test error cases.
57 57 *
58 58 * Match these special address formats to behavior:
59 59 *
60 60 * err.* - induce bus_config error
61 61 * delay - induce 1 second of bus_config delay time
62 62 * delay,n - induce n seconds of bus_config delay time
63 63 * wait - induce 1 second of bus_config wait time
64 64 * wait,n - induce n seconds of bus_config wait time
65 65 * failinit.* - induce error at INITCHILD
66 66 * failprobe.* - induce error at probe
67 67 * failattach.* - induce error at attach
68 68 */
69 69
70 70 #if defined(lint) && !defined(DEBUG)
71 71 #define DEBUG 1
72 72 #endif
73 73
74 74 #include <sys/types.h>
75 75 #include <sys/cmn_err.h>
76 76 #include <sys/conf.h>
77 77 #include <sys/ddi_impldefs.h>
78 78 #include <sys/autoconf.h>
79 79 #include <sys/open.h>
80 80 #include <sys/stat.h>
81 81 #include <sys/file.h>
82 82 #include <sys/errno.h>
83 83 #include <sys/systm.h>
84 84 #include <sys/modctl.h>
85 85 #include <sys/kmem.h>
86 86 #include <sys/ddi.h>
87 87 #include <sys/sunddi.h>
88 88 #include <sys/sunndi.h>
89 89 #include <sys/devctl.h>
90 90 #include <sys/disp.h>
91 91 #include <sys/utsname.h>
92 92 #include <sys/pshot.h>
93 93 #include <sys/debug.h>
94 94
95 95 static int pshot_log = 0;
96 96 static int pshot_devctl_debug = 0;
97 97 static int pshot_debug_busy = 0;
98 98
99 99 static void *pshot_softstatep;
100 100
101 101 static int pshot_prop_autoattach;
102 102
103 103 #define MAXPWR 3
104 104
105 105
106 106 /*
107 107 * device configuration data
108 108 */
109 109
110 110 /* should keep in sync with current release */
111 111 static struct {
112 112 char *name;
113 113 char *val;
114 114 } pshot_nodetypes[] = {
115 115 {"DDI_NT_SERIAL", DDI_NT_SERIAL},
116 116 {"DDI_NT_SERIAL_MB", DDI_NT_SERIAL_MB},
117 117 {"DDI_NT_SERIAL_DO", DDI_NT_SERIAL_DO},
118 118 {"DDI_NT_SERIAL_MB_DO", DDI_NT_SERIAL_MB_DO},
119 119 {"DDI_NT_SERIAL_LOMCON", DDI_NT_SERIAL_LOMCON},
120 120 {"DDI_NT_BLOCK", DDI_NT_BLOCK},
121 121 {"DDI_NT_BLOCK_CHAN", DDI_NT_BLOCK_CHAN},
122 122 {"DDI_NT_BLOCK_WWN", DDI_NT_BLOCK_WWN},
123 123 {"DDI_NT_BLOCK_SAS", DDI_NT_BLOCK_SAS},
124 124 {"DDI_NT_CD", DDI_NT_CD},
125 125 {"DDI_NT_CD_CHAN", DDI_NT_CD_CHAN},
126 126 {"DDI_NT_FD", DDI_NT_FD},
127 127 {"DDI_NT_ENCLOSURE", DDI_NT_ENCLOSURE},
128 128 {"DDI_NT_SCSI_ENCLOSURE", DDI_NT_SCSI_ENCLOSURE},
129 129 {"DDI_NT_TAPE", DDI_NT_TAPE},
130 130 {"DDI_NT_NET", DDI_NT_NET},
131 131 {"DDI_NT_DISPLAY", DDI_NT_DISPLAY},
132 132 {"DDI_PSEUDO", DDI_PSEUDO},
133 133 {"DDI_NT_AUDIO", DDI_NT_AUDIO},
134 134 {"DDI_NT_MOUSE", DDI_NT_MOUSE},
135 135 {"DDI_NT_KEYBOARD", DDI_NT_KEYBOARD},
136 136 {"DDI_NT_PARALLEL", DDI_NT_PARALLEL},
137 137 {"DDI_NT_PRINTER", DDI_NT_PRINTER},
138 138 {"DDI_NT_UGEN", DDI_NT_UGEN},
139 139 {"DDI_NT_NEXUS", DDI_NT_NEXUS},
140 140 {"DDI_NT_SCSI_NEXUS", DDI_NT_SCSI_NEXUS},
141 141 {"DDI_NT_ATTACHMENT_POINT", DDI_NT_ATTACHMENT_POINT},
142 142 {"DDI_NT_SCSI_ATTACHMENT_POINT", DDI_NT_SCSI_ATTACHMENT_POINT},
143 143 {"DDI_NT_PCI_ATTACHMENT_POINT", DDI_NT_PCI_ATTACHMENT_POINT},
144 144 {"DDI_NT_SBD_ATTACHMENT_POINT", DDI_NT_SBD_ATTACHMENT_POINT},
145 145 {"DDI_NT_FC_ATTACHMENT_POINT", DDI_NT_FC_ATTACHMENT_POINT},
146 146 {"DDI_NT_USB_ATTACHMENT_POINT", DDI_NT_USB_ATTACHMENT_POINT},
147 147 {"DDI_NT_BLOCK_FABRIC", DDI_NT_BLOCK_FABRIC},
148 148 {"DDI_NT_AV_ASYNC", DDI_NT_AV_ASYNC},
149 149 {"DDI_NT_AV_ISOCH", DDI_NT_AV_ISOCH},
150 150 { NULL, NULL }
151 151 };
152 152
153 153 /* Node name */
154 154 static char *pshot_compat_diskname = "cdisk";
155 155
156 156 /* Compatible names... */
157 157 static char *pshot_compat_psramdisks[] = {
158 158 "psramhead",
159 159 "psramrom",
160 160 "psramdisk",
161 161 "psramd",
162 162 "psramwhat"
163 163 };
164 164
165 165 /*
166 166 * devices "natively" supported by pshot (i.e. included with SUNWiotu)
167 167 * used to initialize pshot_devices with
168 168 */
169 169 static pshot_device_t pshot_stock_devices[] = {
170 170 {"disk", DDI_NT_BLOCK, "gen_drv"},
171 171 {"disk_chan", DDI_NT_BLOCK_CHAN, "gen_drv"},
172 172 {"disk_wwn", DDI_NT_BLOCK_WWN, "gen_drv"},
173 173 {"disk_cdrom", DDI_NT_CD, "gen_drv"},
174 174 {"disk_cdrom.chan", DDI_NT_CD_CHAN, "gen_drv"},
175 175 /* Note: use bad_drv to force attach errors */
176 176 {"disk_fd", DDI_NT_FD, "bad_drv"},
177 177 {"tape", DDI_NT_TAPE, "gen_drv"},
178 178 {"net", DDI_NT_NET, "gen_drv"},
179 179 {"display", DDI_NT_DISPLAY, "gen_drv"},
180 180 {"pseudo", DDI_PSEUDO, "gen_drv"},
181 181 {"audio", DDI_NT_AUDIO, "gen_drv"},
182 182 {"mouse", DDI_NT_MOUSE, "gen_drv"},
183 183 {"keyboard", DDI_NT_KEYBOARD, "gen_drv"},
184 184 {"nexus", DDI_NT_NEXUS, "pshot"}
185 185 };
186 186 #define PSHOT_N_STOCK_DEVICES \
187 187 (sizeof (pshot_stock_devices) / sizeof (pshot_device_t))
188 188
189 189 static pshot_device_t *pshot_devices = NULL;
190 190 static size_t pshot_devices_len = 0;
191 191
192 192 /* protects <pshot_devices>, <pshot_devices_len> */
193 193 static kmutex_t pshot_devices_lock;
194 194
195 195
196 196 /*
197 197 * event testing
198 198 */
199 199
200 200 static ndi_event_definition_t pshot_ndi_event_defs[] = {
201 201 { PSHOT_EVENT_TAG_OFFLINE, PSHOT_EVENT_NAME_DEV_OFFLINE,
202 202 EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
203 203
204 204 { PSHOT_EVENT_TAG_DEV_RESET, PSHOT_EVENT_NAME_DEV_RESET,
205 205 EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
206 206
207 207 { PSHOT_EVENT_TAG_BUS_RESET, PSHOT_EVENT_NAME_BUS_RESET,
208 208 EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
209 209
210 210 { PSHOT_EVENT_TAG_BUS_QUIESCE, PSHOT_EVENT_NAME_BUS_QUIESCE,
211 211 EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
212 212
213 213 { PSHOT_EVENT_TAG_BUS_UNQUIESCE, PSHOT_EVENT_NAME_BUS_UNQUIESCE,
214 214 EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
215 215
216 216 { PSHOT_EVENT_TAG_TEST_POST, PSHOT_EVENT_NAME_BUS_TEST_POST,
217 217 EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT }
218 218 };
219 219
220 220
221 221 #define PSHOT_N_NDI_EVENTS \
222 222 (sizeof (pshot_ndi_event_defs) / sizeof (ndi_event_definition_t))
223 223
224 224 #ifdef DEBUG
225 225
226 226 static ndi_event_definition_t pshot_test_events[] = {
227 227 { 10, "test event 0", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
228 228 { 11, "test event 1", EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
229 229 { 12, "test event 2", EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
230 230 { 13, "test event 3", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
231 231 { 14, "test event 4", EPL_KERNEL, NDI_EVENT_POST_TO_ALL},
232 232 { 15, "test event 5", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
233 233 { 16, "test event 6", EPL_KERNEL, NDI_EVENT_POST_TO_ALL },
234 234 { 17, "test event 7", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }
235 235 };
236 236
237 237 static ndi_event_definition_t pshot_test_events_high[] = {
238 238 { 20, "test event high 0", EPL_HIGHLEVEL, NDI_EVENT_POST_TO_ALL}
239 239 };
240 240
241 241 #define PSHOT_N_TEST_EVENTS \
242 242 (sizeof (pshot_test_events)/sizeof (ndi_event_definition_t))
243 243 #endif
244 244
245 245 struct register_events {
246 246 char *event_name;
247 247 ddi_eventcookie_t event_cookie;
248 248 void (*event_callback)
249 249 (dev_info_t *,
250 250 ddi_eventcookie_t,
251 251 void *arg,
252 252 void *impldata);
253 253 ddi_callback_id_t cb_id;
254 254 };
255 255
256 256 struct register_events pshot_register_events[] = {
257 257 { PSHOT_EVENT_NAME_DEV_OFFLINE, 0, pshot_event_cb, 0 },
258 258 { PSHOT_EVENT_NAME_DEV_RESET, 0, pshot_event_cb, 0 },
259 259 { PSHOT_EVENT_NAME_BUS_RESET, 0, pshot_event_cb, 0 },
260 260 { PSHOT_EVENT_NAME_BUS_QUIESCE, 0, pshot_event_cb, 0 },
261 261 { PSHOT_EVENT_NAME_BUS_UNQUIESCE, 0, pshot_event_cb, 0 },
262 262 { PSHOT_EVENT_NAME_BUS_TEST_POST, 0, pshot_event_cb, 0 }
263 263 };
264 264
265 265 #define PSHOT_N_DDI_EVENTS \
266 266 (sizeof (pshot_register_events) / sizeof (struct register_events))
267 267
268 268
269 269 #ifdef DEBUG
270 270
271 271 static struct register_events pshot_register_test[] = {
272 272 { "test event 0", 0, pshot_event_cb_test, 0},
273 273 { "test event 1", 0, pshot_event_cb_test, 0},
274 274 { "test event 2", 0, pshot_event_cb_test, 0},
275 275 { "test event 3", 0, pshot_event_cb_test, 0},
276 276 { "test event 4", 0, pshot_event_cb_test, 0},
277 277 { "test event 5", 0, pshot_event_cb_test, 0},
278 278 { "test event 6", 0, pshot_event_cb_test, 0},
279 279 { "test event 7", 0, pshot_event_cb_test, 0}
280 280 };
281 281
282 282
283 283 static struct register_events pshot_register_high_test[] = {
284 284 {"test event high 0", 0, pshot_event_cb_test, 0}
285 285 };
286 286
287 287 #endif /* DEBUG */
288 288
289 289 static struct {
290 290 int ioctl_int;
291 291 char *ioctl_char;
292 292 } pshot_devctls[] = {
293 293 {DEVCTL_DEVICE_GETSTATE, "DEVCTL_DEVICE_GETSTATE"},
294 294 {DEVCTL_DEVICE_ONLINE, "DEVCTL_DEVICE_ONLINE"},
295 295 {DEVCTL_DEVICE_OFFLINE, "DEVCTL_DEVICE_OFFLINE"},
296 296 {DEVCTL_DEVICE_REMOVE, "DEVCTL_DEVICE_REMOVE"},
297 297 {DEVCTL_BUS_GETSTATE, "DEVCTL_BUS_GETSTATE"},
298 298 {DEVCTL_BUS_DEV_CREATE, "DEVCTL_BUS_DEV_CREATE"},
299 299 {DEVCTL_BUS_RESET, "DEVCTL_BUS_RESET"},
300 300 {DEVCTL_BUS_RESETALL, "DEVCTL_BUS_RESETALL"},
301 301 {0, NULL}
302 302 };
303 303
304 304 static struct bus_ops pshot_bus_ops = {
305 305 BUSO_REV, /* busops_rev */
306 306 nullbusmap, /* bus_map */
307 307 NULL, /* bus_get_intrspec */
308 308 NULL, /* bus_add_interspec */
309 309 NULL, /* bus_remove_interspec */
310 310 i_ddi_map_fault, /* bus_map_fault */
311 311 NULL, /* bus_dma_map */
312 312 ddi_dma_allochdl, /* bus_dma_allochdl */
313 313 ddi_dma_freehdl, /* bus_dma_freehdl */
314 314 ddi_dma_bindhdl, /* bus_dma_bindhdl */
315 315 ddi_dma_unbindhdl, /* bus_dma_unbindhdl */
316 316 ddi_dma_flush, /* bus_dma_flush */
317 317 ddi_dma_win, /* bus_dma_win */
318 318 ddi_dma_mctl, /* bus_dma_ctl */
319 319 pshot_ctl, /* bus_ctl */
320 320 ddi_bus_prop_op, /* bus_prop_op */
321 321 pshot_get_eventcookie, /* bus_get_eventcookie */
322 322 pshot_add_eventcall, /* bus_add_eventcall */
323 323 pshot_remove_eventcall, /* bus_remove_event */
324 324 pshot_post_event, /* bus_post_event */
325 325 NULL, /* bus_intr_ctl */
326 326 pshot_bus_config, /* bus_config */
327 327 pshot_bus_unconfig, /* bus_unconfig */
328 328 NULL, /* bus_fm_init */
329 329 NULL, /* bus_fm_fini */
330 330 NULL, /* bus_fm_access_enter */
331 331 NULL, /* bus_fm_access_exit */
332 332 pshot_bus_power, /* bus_power */
333 333 pshot_bus_introp /* bus_intr_op */
334 334 };
335 335
336 336 static struct cb_ops pshot_cb_ops = {
337 337 pshot_open, /* open */
338 338 pshot_close, /* close */
339 339 nodev, /* strategy */
340 340 nodev, /* print */
341 341 nodev, /* dump */
342 342 nodev, /* read */
343 343 nodev, /* write */
344 344 pshot_ioctl, /* ioctl */
345 345 nodev, /* devmap */
346 346 nodev, /* mmap */
347 347 nodev, /* segmap */
348 348 nochpoll, /* poll */
349 349 ddi_prop_op, /* prop_op */
350 350 NULL, /* streamtab */
351 351 D_NEW | D_MP | D_HOTPLUG, /* flags */
352 352 CB_REV, /* cb_rev */
353 353 nodev, /* aread */
354 354 nodev, /* awrite */
355 355 };
356 356
357 357 static struct dev_ops pshot_ops = {
358 358 DEVO_REV, /* devo_rev, */
359 359 0, /* refcnt */
360 360 pshot_info, /* getinfo */
361 361 nulldev, /* identify */
362 362 pshot_probe, /* probe */
363 363 pshot_attach, /* attach */
364 364 pshot_detach, /* detach */
365 365 nodev, /* reset */
366 366 &pshot_cb_ops, /* driver operations */
367 367 &pshot_bus_ops, /* bus operations */
368 368 pshot_power, /* power */
369 369 ddi_quiesce_not_supported, /* devo_quiesce */
370 370
371 371 };
372 372
373 373
↓ open down ↓ |
373 lines elided |
↑ open up ↑ |
374 374 /*
375 375 * Module linkage information for the kernel.
376 376 */
377 377 static struct modldrv modldrv = {
378 378 &mod_driverops,
379 379 "pshotnex",
380 380 &pshot_ops,
381 381 };
382 382
383 383 static struct modlinkage modlinkage = {
384 - MODREV_1, &modldrv, NULL
384 + MODREV_1, { &modldrv, NULL }
385 385 };
386 386
387 387
388 388 /*
389 389 * pshot_devices is set up on the first attach and destroyed on fini
390 390 *
391 391 * therefore PSHOT_PROP_DEV* properties may be set just for the root device,
392 392 * instead of being set globably, in pshot.conf by specifying the properties
393 393 * on a single line in the form:
394 394 * name="pshot" parent="/" <dev props ..>
395 395 * to unclutter a device tree snapshot.
396 396 * this of course produces a long single line that may wrap around several
397 397 * times on screen
398 398 */
399 399
400 400 int
401 401 _init(void)
402 402 {
403 403 int rv;
404 404
405 405 rv = ddi_soft_state_init(&pshot_softstatep, sizeof (pshot_t), 0);
406 406
407 407 if (rv != DDI_SUCCESS)
408 408 return (rv);
409 409
410 410 mutex_init(&pshot_devices_lock, NULL, MUTEX_DRIVER, NULL);
411 411 pshot_devices = NULL;
412 412 pshot_devices_len = 0;
413 413
414 414 if ((rv = mod_install(&modlinkage)) != 0) {
415 415 ddi_soft_state_fini(&pshot_softstatep);
416 416 mutex_destroy(&pshot_devices_lock);
417 417 }
418 418 return (rv);
419 419 }
420 420
421 421 int
422 422 _fini(void)
423 423 {
424 424 int rv;
425 425
426 426 if ((rv = mod_remove(&modlinkage)) != 0)
427 427 return (rv);
428 428
429 429 ddi_soft_state_fini(&pshot_softstatep);
430 430 mutex_destroy(&pshot_devices_lock);
431 431 if (pshot_devices)
432 432 pshot_devices_free(pshot_devices, pshot_devices_len);
433 433 return (0);
434 434 }
435 435
436 436 int
437 437 _info(struct modinfo *modinfop)
438 438 {
439 439 return (mod_info(&modlinkage, modinfop));
440 440 }
441 441
442 442
443 443 /*ARGSUSED*/
444 444 static int
445 445 pshot_probe(dev_info_t *devi)
446 446 {
447 447 int instance = ddi_get_instance(devi);
448 448 char *bus_addr;
449 449
450 450 /*
451 451 * Hook for tests to force probe fail
452 452 */
453 453 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
454 454 &bus_addr) == DDI_PROP_SUCCESS) {
455 455 if (strncmp(bus_addr, "failprobe", 9) == 0) {
456 456 if (pshot_debug)
457 457 cmn_err(CE_CONT, "pshot%d: "
458 458 "%s forced probe failure\n",
459 459 instance, bus_addr);
460 460 ddi_prop_free(bus_addr);
461 461 return (DDI_PROBE_FAILURE);
462 462 }
463 463 ddi_prop_free(bus_addr);
464 464 }
465 465
466 466 return (DDI_PROBE_SUCCESS);
467 467 }
468 468
469 469
470 470 /*ARGSUSED*/
471 471 static int
472 472 pshot_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
473 473 {
474 474 int instance;
475 475 minor_t minor;
476 476 pshot_t *pshot;
477 477
478 478 minor = getminor((dev_t)arg);
479 479 instance = pshot_minor_decode_inst(minor);
480 480 switch (infocmd) {
481 481 case DDI_INFO_DEVT2DEVINFO:
482 482 pshot = ddi_get_soft_state(pshot_softstatep, instance);
483 483 if (pshot == NULL) {
484 484 cmn_err(CE_WARN, "pshot_info: get soft state failed "
485 485 "on minor %u, instance %d", minor, instance);
486 486 return (DDI_FAILURE);
487 487 }
488 488 *result = (void *)pshot->dip;
489 489 break;
490 490 case DDI_INFO_DEVT2INSTANCE:
491 491 *result = (void *)(uintptr_t)instance;
492 492 break;
493 493 default:
494 494 cmn_err(CE_WARN, "pshot_info: unrecognized cmd 0x%x on "
495 495 "minor %u, instance %d", infocmd, minor, instance);
496 496 return (DDI_FAILURE);
497 497 }
498 498
499 499 return (DDI_SUCCESS);
500 500 }
501 501
502 502
503 503 static int
504 504 pshot_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
505 505 {
506 506 int instance = ddi_get_instance(devi);
507 507 pshot_t *pshot;
508 508 int rval, i;
509 509 int prop_flags = DDI_PROP_DONTPASS | DDI_PROP_NOTPROM;
510 510 char *bus_addr;
511 511 char *pm_comp[] = {
512 512 "NAME=bus",
513 513 "0=B3",
514 514 "1=B2",
515 515 "2=B1",
516 516 "3=B0"};
517 517 char *pm_hw_state = {"needs-suspend-resume"};
518 518
519 519 pshot_prop_autoattach = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
520 520 prop_flags, "autoattach", 0);
521 521
522 522 switch (cmd) {
523 523
524 524 case DDI_ATTACH:
525 525 if (pshot_debug)
526 526 cmn_err(CE_CONT, "attach: %s%d/pshot%d\n",
527 527 ddi_get_name(ddi_get_parent(devi)),
528 528 ddi_get_instance(ddi_get_parent(devi)),
529 529 instance);
530 530
531 531 /*
532 532 * Hook for tests to force attach fail
533 533 */
534 534 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
535 535 &bus_addr) == DDI_PROP_SUCCESS) && bus_addr != NULL) {
536 536 if (strncmp(bus_addr, "failattach", 10) == 0) {
537 537 if (pshot_debug)
538 538 cmn_err(CE_CONT, "pshot%d: "
539 539 "%s forced attach failure\n",
540 540 instance, bus_addr);
541 541 ddi_prop_free(bus_addr);
542 542 return (DDI_FAILURE);
543 543 }
544 544 ddi_prop_free(bus_addr);
545 545 }
546 546
547 547 /*
548 548 * minor nodes setup
549 549 */
550 550 if (ddi_soft_state_zalloc(pshot_softstatep, instance) !=
551 551 DDI_SUCCESS) {
552 552 return (DDI_FAILURE);
553 553 }
554 554 pshot = ddi_get_soft_state(pshot_softstatep, instance);
555 555 pshot->dip = devi;
556 556 pshot->instance = instance;
557 557 mutex_init(&pshot->lock, NULL, MUTEX_DRIVER, NULL);
558 558
559 559 /* set each minor, then create on dip all together */
560 560
561 561 i = PSHOT_NODENUM_DEVCTL;
562 562 pshot->nodes[i].pshot = pshot;
563 563 pshot->nodes[i].minor = pshot_minor_encode(instance, i);
564 564 (void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_DEVCTL,
565 565 PSHOT_MAX_MINOR_NAMELEN);
566 566
567 567 i = PSHOT_NODENUM_TESTCTL;
568 568 pshot->nodes[i].pshot = pshot;
569 569 pshot->nodes[i].minor = pshot_minor_encode(instance, i);
570 570 (void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_TESTCTL,
571 571 PSHOT_MAX_MINOR_NAMELEN);
572 572
573 573 /* this assumes contiguous a filling */
574 574 for (i = 0; i <= PSHOT_MAX_NODENUM; i++) {
575 575 if (ddi_create_minor_node(devi, pshot->nodes[i].name,
576 576 S_IFCHR, pshot->nodes[i].minor, DDI_NT_NEXUS, 0) !=
577 577 DDI_SUCCESS) {
578 578 cmn_err(CE_WARN, "attach: cannot create "
579 579 "minor %s", pshot->nodes[i].name);
580 580 goto FAIL_ATTACH;
581 581 }
582 582 }
583 583
584 584 /*
585 585 * pshot_devices setup
586 586 */
587 587 if (pshot_devices_setup(devi)) {
588 588 cmn_err(CE_WARN, "attach: pshot devices setup "
589 589 "failed");
590 590 goto FAIL_ATTACH;
591 591 }
592 592
593 593 /*
594 594 * events setup
595 595 */
596 596 for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
597 597 rval = ddi_get_eventcookie(devi,
598 598 pshot_register_events[i].event_name,
599 599 &pshot_register_events[i].event_cookie);
600 600
601 601 if (pshot_debug)
602 602 cmn_err(CE_CONT, "pshot%d: event=%s:"
603 603 "ddi_get_eventcookie rval=%d\n",
604 604 instance,
605 605 pshot_register_events[i].event_name, rval);
606 606
607 607 if (rval == DDI_SUCCESS) {
608 608 rval = ddi_add_event_handler(devi,
609 609 pshot_register_events[i].event_cookie,
610 610 pshot_register_events[i].event_callback,
611 611 (void *)pshot,
612 612 &pshot->callback_cache[i]);
613 613
614 614 if (pshot_debug)
615 615 cmn_err(CE_CONT, "pshot%d: event=%s: "
616 616 "ddi_add_event_handler rval=%d\n",
617 617 instance,
618 618 pshot_register_events[i].event_name,
619 619 rval);
620 620 }
621 621 }
622 622
623 623 #ifdef DEBUG
624 624 if (pshot_event_test_enable) {
625 625 pshot_event_test((void *)pshot);
626 626 (void) timeout(pshot_event_test_post_one, (void *)pshot,
627 627 instance * drv_usectohz(60000000));
628 628 }
629 629 #endif
630 630
631 631 /*
632 632 * allocate an ndi event handle
633 633 */
634 634 if (ndi_event_alloc_hdl(devi, NULL, &pshot->ndi_event_hdl,
635 635 NDI_SLEEP) != NDI_SUCCESS) {
636 636 goto FAIL_ATTACH;
637 637 }
638 638
639 639 pshot->ndi_events.ndi_events_version = NDI_EVENTS_REV1;
640 640 pshot->ndi_events.ndi_n_events = PSHOT_N_NDI_EVENTS;
641 641 pshot->ndi_events.ndi_event_defs = pshot_ndi_event_defs;
642 642
643 643 if (ndi_event_bind_set(pshot->ndi_event_hdl, &pshot->ndi_events,
644 644 NDI_SLEEP) != NDI_SUCCESS) {
645 645 cmn_err(CE_CONT, "pshot%d bind set failed\n",
646 646 instance);
647 647 }
648 648
649 649 /*
650 650 * setup a test for nexus auto-attach iff we are
651 651 * a second level pshot node (parent == /SUNW,pshot)
652 652 * enable by setting "autoattach=1" in pshot.conf
653 653 */
654 654 if ((PARENT_IS_PSHOT(devi)) && (pshot_prop_autoattach != 0) &&
655 655 (ddi_get_instance(ddi_get_parent(devi))) == 0)
656 656 pshot_setup_autoattach(devi);
657 657
658 658 /*
659 659 * initialize internal state to idle: busy = 0,
660 660 * power level = -1
661 661 */
662 662 mutex_enter(&pshot->lock);
663 663 pshot->busy = 0;
664 664 pshot->busy_ioctl = 0;
665 665 pshot->level = -1;
666 666 pshot->state &= ~STRICT_PARENT;
667 667 pshot->state |= PM_SUPPORTED;
668 668 mutex_exit(&pshot->lock);
669 669
670 670 /*
671 671 * Create the "pm-want-child-notification?" property
672 672 * for the root node /devices/pshot
673 673 */
674 674 if (instance == 0) {
675 675 if (pshot_debug) {
676 676 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:\n\t"
677 677 " create the"
678 678 " \"pm-want-child-notification?\" property"
679 679 " for the root node\n", instance);
680 680 }
681 681 if (ddi_prop_create(DDI_DEV_T_NONE, devi, 0,
682 682 "pm-want-child-notification?", NULL, 0)
683 683 != DDI_PROP_SUCCESS) {
684 684 cmn_err(CE_WARN, "%s%d:\n\t"
685 685 " unable to create the"
686 686 " \"pm-want-child-notification?\""
687 687 " property", ddi_get_name(devi),
688 688 ddi_get_instance(devi));
689 689
690 690 goto FAIL_ATTACH;
691 691 }
692 692 }
693 693
694 694 /*
695 695 * Check if the pm-want-child-notification? property was
696 696 * created in pshot_bus_config_setup_nexus() by the parent.
697 697 * Set the STRICT_PARENT flag if not.
698 698 */
699 699 if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
700 700 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
701 701 "pm-want-child-notification?") != 1) {
702 702 if (pshot_debug) {
703 703 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
704 704 " STRICT PARENT\n", instance);
705 705 }
706 706 mutex_enter(&pshot->lock);
707 707 pshot->state |= STRICT_PARENT;
708 708 mutex_exit(&pshot->lock);
709 709 } else {
710 710 if (pshot_debug) {
711 711 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
712 712 " INVOLVED PARENT\n", instance);
713 713 }
714 714 mutex_enter(&pshot->lock);
715 715 pshot->state &= ~STRICT_PARENT;
716 716 mutex_exit(&pshot->lock);
717 717 }
718 718
719 719 /*
720 720 * create the pm-components property: one component
721 721 * with 4 power levels.
722 722 * - skip for pshot@XXX,nopm and pshot@XXX,nopm_strict:
723 723 * "no-pm-components" property
724 724 */
725 725 if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
726 726 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
727 727 "no-pm-components") == 0) {
728 728 if (pshot_debug) {
729 729 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
730 730 " create the \"pm_components\" property\n",
731 731 instance);
732 732 }
733 733 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
734 734 "pm-components", pm_comp, 5) != DDI_PROP_SUCCESS) {
735 735 cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
736 736 " unable to create the \"pm-components\""
737 737 " property", ddi_get_name(devi),
738 738 ddi_get_instance(devi));
739 739
740 740 goto FAIL_ATTACH;
741 741 }
742 742 } else {
743 743 if (pshot_debug) {
744 744 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
745 745 " NO-PM_COMPONENTS PARENT\n", instance);
746 746 }
747 747 mutex_enter(&pshot->lock);
748 748 pshot->state &= ~PM_SUPPORTED;
749 749 mutex_exit(&pshot->lock);
750 750 }
751 751
752 752 /*
753 753 * create the property needed to get DDI_SUSPEND
754 754 * and DDI_RESUME calls
755 755 */
756 756 if (pshot_debug) {
757 757 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
758 758 " create pm-hardware-state property\n",
759 759 instance);
760 760 }
761 761 if (ddi_prop_update_string(DDI_DEV_T_NONE, devi,
762 762 "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) {
763 763 cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
764 764 " unable to create the \"pm-hardware-state\""
765 765 " property", ddi_get_name(devi),
766 766 ddi_get_instance(devi));
767 767
768 768 goto FAIL_ATTACH;
769 769 }
770 770
771 771 /*
772 772 * set power level to max via pm_raise_power(),
773 773 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
774 774 */
775 775 if (pshot->state & PM_SUPPORTED) {
776 776 if (pshot_debug) {
777 777 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
778 778 " raise power to MAXPWR\n", instance);
779 779 }
780 780 if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
781 781 DDI_SUCCESS) {
782 782 cmn_err(CE_WARN, "%s%d: DDI_ATTACH:"
783 783 " pm_raise_power failed",
784 784 ddi_get_name(devi),
785 785 ddi_get_instance(devi));
786 786
787 787 goto FAIL_ATTACH;
788 788
789 789 }
790 790 }
791 791
792 792 if (pshot_log)
793 793 cmn_err(CE_CONT, "pshot%d attached\n", instance);
794 794 ddi_report_dev(devi);
795 795
796 796 return (DDI_SUCCESS);
797 797 /*NOTREACHED*/
798 798 FAIL_ATTACH:
799 799 ddi_remove_minor_node(devi, NULL);
800 800 mutex_destroy(&pshot->lock);
801 801 ddi_soft_state_free(pshot_softstatep, instance);
802 802 return (DDI_FAILURE);
803 803
804 804 case DDI_RESUME:
805 805 if (pshot_debug) {
806 806 cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resuming\n",
807 807 instance);
808 808 }
809 809 pshot = ddi_get_soft_state(pshot_softstatep, instance);
810 810
811 811 /*
812 812 * set power level to max via pm_raise_power(),
813 813 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
814 814 */
815 815 if (pshot->state & PM_SUPPORTED) {
816 816 if (pshot_debug) {
817 817 cmn_err(CE_CONT, "pshot%d: DDI_RESUME:"
818 818 " raise power to MAXPWR\n", instance);
819 819 }
820 820 if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
821 821 DDI_SUCCESS) {
822 822 cmn_err(CE_WARN, "%s%d: DDI_RESUME:"
823 823 " pm_raise_power failed",
824 824 ddi_get_name(devi),
825 825 ddi_get_instance(devi));
826 826 }
827 827 }
828 828
829 829 if (pshot_debug) {
830 830 cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resumed\n",
831 831 instance);
832 832 }
833 833 return (DDI_SUCCESS);
834 834
835 835 default:
836 836 return (DDI_FAILURE);
837 837 }
838 838 }
839 839
840 840 static int
841 841 pshot_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
842 842 {
843 843 int instance = ddi_get_instance(devi);
844 844 int i, rval;
845 845 pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
846 846 int level_tmp;
847 847
848 848 if (pshot == NULL)
849 849 return (DDI_FAILURE);
850 850
851 851 switch (cmd) {
852 852
853 853 case DDI_DETACH:
854 854 if (pshot_debug)
855 855 cmn_err(CE_CONT, "pshot%d: DDI_DETACH\n", instance);
856 856 /*
857 857 * power off component 0
858 858 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
859 859 */
860 860 if (pshot->state & PM_SUPPORTED) {
861 861 if (pshot_debug) {
862 862 cmn_err(CE_CONT, "pshot%d: DDI_DETACH:"
863 863 " power off\n", instance);
864 864 }
865 865 if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
866 866 cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t"
867 867 "pm_lower_power failed for comp 0 to"
868 868 " level 0", ddi_get_name(devi),
869 869 ddi_get_instance(devi));
870 870
871 871 return (DDI_FAILURE);
872 872 }
873 873
874 874 /*
875 875 * Check if the power level is actually OFF.
876 876 * Issue pm_power_has_changed if not.
877 877 */
878 878 mutex_enter(&pshot->lock);
879 879 if (pshot->level != 0) {
880 880 if (pshot_debug) {
881 881 cmn_err(CE_NOTE, "pshot%d:"
882 882 " DDI_DETACH: power off via"
883 883 " pm_power_has_changed instead\n",
884 884 instance);
885 885 }
886 886 level_tmp = pshot->level;
887 887 pshot->level = 0;
888 888 if (pm_power_has_changed(pshot->dip, 0, 0) !=
889 889 DDI_SUCCESS) {
890 890 if (pshot_debug) {
891 891 cmn_err(CE_NOTE, "pshot%d:"
892 892 " DDI_DETACH:"
893 893 " pm_power_has_changed"
894 894 " failed\n", instance);
895 895 }
896 896 pshot->level = level_tmp;
897 897 mutex_exit(&pshot->lock);
898 898
899 899 return (DDI_FAILURE);
900 900 }
901 901 }
902 902 mutex_exit(&pshot->lock);
903 903 }
904 904
905 905 for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
906 906 if (pshot->callback_cache[i] != NULL) {
907 907 rval = ddi_remove_event_handler(
908 908 pshot->callback_cache[i]);
909 909 ASSERT(rval == DDI_SUCCESS);
910 910 }
911 911 }
912 912
913 913 #ifdef DEBUG
914 914 for (i = 0; i < PSHOT_N_TEST_EVENTS; i++) {
915 915 if (pshot->test_callback_cache[i] != NULL) {
916 916 rval = ddi_remove_event_handler(
917 917 pshot->test_callback_cache[i]);
918 918 ASSERT(rval == DDI_SUCCESS);
919 919 }
920 920 }
921 921 #endif
922 922 rval = ndi_event_free_hdl(pshot->ndi_event_hdl);
923 923 ASSERT(rval == DDI_SUCCESS);
924 924
925 925 if (pshot_log)
926 926 cmn_err(CE_CONT, "pshot%d detached\n", instance);
927 927
928 928 ddi_remove_minor_node(devi, NULL);
929 929 mutex_destroy(&pshot->lock);
930 930 ddi_soft_state_free(pshot_softstatep, instance);
931 931 break;
932 932
933 933 case DDI_SUSPEND:
934 934 if (pshot_debug)
935 935 cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND\n", instance);
936 936 /*
937 937 * fail the suspend if FAIL_SUSPEND_FLAG is set.
938 938 * clear the FAIL_SUSPEND_FLAG flag
939 939 */
940 940 mutex_enter(&pshot->lock);
941 941 if (pshot->state & FAIL_SUSPEND_FLAG) {
942 942 if (pshot_debug) {
943 943 cmn_err(CE_CONT, "pshot%d:"
944 944 " FAIL_SUSPEND_FLAG set, fail suspend\n",
945 945 ddi_get_instance(devi));
946 946 }
947 947 pshot->state &= ~FAIL_SUSPEND_FLAG;
948 948 rval = DDI_FAILURE;
949 949 } else {
950 950 rval = DDI_SUCCESS;
951 951 }
952 952 mutex_exit(&pshot->lock);
953 953
954 954 /*
955 955 * power OFF via pm_power_has_changed
956 956 */
957 957 mutex_enter(&pshot->lock);
958 958 if (pshot->state & PM_SUPPORTED) {
959 959 if (pshot_debug) {
960 960 cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND:"
961 961 " power off via pm_power_has_changed\n",
962 962 instance);
963 963 }
964 964 level_tmp = pshot->level;
965 965 pshot->level = 0;
966 966 if (pm_power_has_changed(pshot->dip, 0, 0) !=
967 967 DDI_SUCCESS) {
968 968 if (pshot_debug) {
969 969 cmn_err(CE_NOTE, "pshot%d:"
970 970 " DDI_SUSPEND:"
971 971 " pm_power_has_changed failed\n",
972 972 instance);
973 973 }
974 974 pshot->level = level_tmp;
975 975 rval = DDI_FAILURE;
976 976 }
977 977 }
978 978 mutex_exit(&pshot->lock);
979 979 return (rval);
980 980
981 981 default:
982 982 break;
983 983 }
984 984
985 985 return (DDI_SUCCESS);
986 986 }
987 987
988 988
989 989 /*
990 990 * returns number of bits to represent <val>
991 991 */
992 992 static size_t
993 993 pshot_numbits(size_t val)
994 994 {
995 995 size_t bitcnt;
996 996
997 997 if (val == 0)
998 998 return (0);
999 999 for (bitcnt = 1; 1 << bitcnt < val; bitcnt++)
1000 1000 ;
1001 1001 return (bitcnt);
1002 1002 }
1003 1003
1004 1004 /*
1005 1005 * returns a minor number encoded with instance <inst> and an index <nodenum>
1006 1006 * that identifies the minor node for this instance
1007 1007 */
1008 1008 static minor_t
1009 1009 pshot_minor_encode(int inst, minor_t nodenum)
1010 1010 {
1011 1011 return (((minor_t)inst << PSHOT_NODENUM_BITS()) |
1012 1012 (((1 << PSHOT_NODENUM_BITS()) - 1) & nodenum));
1013 1013 }
1014 1014
1015 1015 /*
1016 1016 * returns instance of <minor>
1017 1017 */
1018 1018 static int
1019 1019 pshot_minor_decode_inst(minor_t minor)
1020 1020 {
1021 1021 return (minor >> PSHOT_NODENUM_BITS());
1022 1022 }
1023 1023
1024 1024 /*
1025 1025 * returns node number indexing a minor node for the instance in <minor>
1026 1026 */
1027 1027 static minor_t
1028 1028 pshot_minor_decode_nodenum(minor_t minor)
1029 1029 {
1030 1030 return (minor & ((1 << PSHOT_NODENUM_BITS()) - 1));
1031 1031 }
1032 1032
1033 1033
1034 1034 /*
1035 1035 * pshot_bus_introp: pshot convert an interrupt number to an
1036 1036 * interrupt. NO OP for pseudo drivers.
1037 1037 */
1038 1038 /*ARGSUSED*/
1039 1039 static int
1040 1040 pshot_bus_introp(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1041 1041 ddi_intr_handle_impl_t *hdlp, void *result)
1042 1042 {
1043 1043 return (DDI_FAILURE);
1044 1044 }
1045 1045 static int
1046 1046 pshot_ctl(dev_info_t *dip, dev_info_t *rdip,
1047 1047 ddi_ctl_enum_t ctlop, void *arg, void *result)
1048 1048 {
1049 1049 int instance;
1050 1050 pshot_t *pshot;
1051 1051 char *childname;
1052 1052 int childinstance;
1053 1053 char *name;
1054 1054 int circ;
1055 1055 struct attachspec *as;
1056 1056 struct detachspec *ds;
1057 1057 int rval = DDI_SUCCESS;
1058 1058 int no_pm_components_child;
1059 1059
1060 1060 name = ddi_get_name(dip);
1061 1061 instance = ddi_get_instance(dip);
1062 1062 pshot = ddi_get_soft_state(pshot_softstatep, instance);
1063 1063 if (pshot == NULL) {
1064 1064 return (ENXIO);
1065 1065 }
1066 1066
1067 1067 switch (ctlop) {
1068 1068 case DDI_CTLOPS_REPORTDEV:
1069 1069 if (rdip == (dev_info_t *)0)
1070 1070 return (DDI_FAILURE);
1071 1071 cmn_err(CE_CONT, "?pshot-device: %s%d\n",
1072 1072 ddi_get_name(rdip), ddi_get_instance(rdip));
1073 1073 return (DDI_SUCCESS);
1074 1074
1075 1075 case DDI_CTLOPS_INITCHILD:
1076 1076 {
1077 1077 dev_info_t *child = (dev_info_t *)arg;
1078 1078
1079 1079 if (pshot_debug) {
1080 1080 cmn_err(CE_CONT, "initchild %s%d/%s%d state 0x%x\n",
1081 1081 ddi_get_name(dip), ddi_get_instance(dip),
1082 1082 ddi_node_name(child), ddi_get_instance(child),
1083 1083 DEVI(child)->devi_state);
1084 1084 }
1085 1085
1086 1086 return (pshot_initchild(dip, child));
1087 1087 }
1088 1088
1089 1089 case DDI_CTLOPS_UNINITCHILD:
1090 1090 {
1091 1091 dev_info_t *child = (dev_info_t *)arg;
1092 1092
1093 1093 if (pshot_debug) {
1094 1094 cmn_err(CE_CONT, "uninitchild %s%d/%s%d state 0x%x\n",
1095 1095 ddi_get_name(dip), ddi_get_instance(dip),
1096 1096 ddi_node_name(child), ddi_get_instance(child),
1097 1097 DEVI(child)->devi_state);
1098 1098 }
1099 1099
1100 1100 return (pshot_uninitchild(dip, child));
1101 1101 }
1102 1102
1103 1103 case DDI_CTLOPS_DMAPMAPC:
1104 1104 case DDI_CTLOPS_REPORTINT:
1105 1105 case DDI_CTLOPS_REGSIZE:
1106 1106 case DDI_CTLOPS_NREGS:
1107 1107 case DDI_CTLOPS_SIDDEV:
1108 1108 case DDI_CTLOPS_SLAVEONLY:
1109 1109 case DDI_CTLOPS_AFFINITY:
1110 1110 case DDI_CTLOPS_POKE:
1111 1111 case DDI_CTLOPS_PEEK:
1112 1112 /*
1113 1113 * These ops correspond to functions that "shouldn't" be called
1114 1114 * by a pseudo driver. So we whine when we're called.
1115 1115 */
1116 1116 cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
1117 1117 ddi_get_name(dip), ddi_get_instance(dip),
1118 1118 ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
1119 1119 return (DDI_FAILURE);
1120 1120
1121 1121 case DDI_CTLOPS_ATTACH:
1122 1122 {
1123 1123 dev_info_t *child = (dev_info_t *)rdip;
1124 1124 childname = ddi_node_name(child);
1125 1125 childinstance = ddi_get_instance(child);
1126 1126 as = (struct attachspec *)arg;
1127 1127
1128 1128 no_pm_components_child = 0;
1129 1129 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1130 1130 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1131 1131 "no-pm-components") == 1) {
1132 1132 no_pm_components_child = 1;
1133 1133 }
1134 1134 if (pshot_debug) {
1135 1135 cmn_err(CE_CONT, "%s%d: ctl_attach %s%d [%d]\n",
1136 1136 name, instance, childname, childinstance,
1137 1137 no_pm_components_child);
1138 1138 }
1139 1139
1140 1140 ndi_devi_enter(dip, &circ);
1141 1141
1142 1142 switch (as->when) {
1143 1143 case DDI_PRE:
1144 1144 /*
1145 1145 * Mark nexus busy before a child attaches.
1146 1146 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1147 1147 * - pshot@XXX,nopm_strict)
1148 1148 */
1149 1149 if (!(pshot->state & PM_SUPPORTED))
1150 1150 break;
1151 1151 mutex_enter(&pshot->lock);
1152 1152 ++(pshot->busy);
1153 1153 if (pshot_debug_busy) {
1154 1154 cmn_err(CE_CONT, "%s%d:"
1155 1155 " ctl_attach_pre: busy for %s%d:"
1156 1156 " busy = %d\n", name, instance,
1157 1157 childname, childinstance,
1158 1158 pshot->busy);
1159 1159 }
1160 1160 mutex_exit(&pshot->lock);
1161 1161 rval = pm_busy_component(dip, 0);
1162 1162 ASSERT(rval == DDI_SUCCESS);
1163 1163 break;
1164 1164 case DDI_POST:
1165 1165 /*
1166 1166 * Mark nexus idle after a child attaches.
1167 1167 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm).
1168 1168 * - also skip if this is not a stict parent and
1169 1169 * - the child is a tape device or a no-pm-components
1170 1170 * - nexus node.
1171 1171 */
1172 1172 if (!(pshot->state & PM_SUPPORTED) ||
1173 1173 (strcmp(childname, "tape") == 0 &&
1174 1174 !(pshot->state & STRICT_PARENT)) ||
1175 1175 no_pm_components_child)
1176 1176 break;
1177 1177 mutex_enter(&pshot->lock);
1178 1178 ASSERT(pshot->busy > 0);
1179 1179 --pshot->busy;
1180 1180 if (pshot_debug_busy) {
1181 1181 cmn_err(CE_CONT, "%s%d:"
1182 1182 " ctl_attach_post: idle for %s%d:"
1183 1183 " busy = %d\n", name, instance,
1184 1184 childname, childinstance,
1185 1185 pshot->busy);
1186 1186 }
1187 1187 mutex_exit(&pshot->lock);
1188 1188 rval = pm_idle_component(dip, 0);
1189 1189 ASSERT(rval == DDI_SUCCESS);
1190 1190 break;
1191 1191 }
1192 1192
1193 1193 ndi_devi_exit(dip, circ);
1194 1194
1195 1195 return (rval);
1196 1196 }
1197 1197 case DDI_CTLOPS_DETACH:
1198 1198 {
1199 1199 dev_info_t *child = (dev_info_t *)rdip;
1200 1200 childname = ddi_node_name(child);
1201 1201 childinstance = ddi_get_instance(child);
1202 1202 ds = (struct detachspec *)arg;
1203 1203
1204 1204 no_pm_components_child = 0;
1205 1205 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1206 1206 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1207 1207 "no-pm-components") == 1) {
1208 1208 no_pm_components_child = 1;
1209 1209 }
1210 1210 if (pshot_debug) {
1211 1211 cmn_err(CE_CONT,
1212 1212 "%s%d: ctl_detach %s%d [%d]\n",
1213 1213 name, instance, childname, childinstance,
1214 1214 no_pm_components_child);
1215 1215 }
1216 1216
1217 1217 ndi_devi_enter(dip, &circ);
1218 1218
1219 1219 switch (ds->when) {
1220 1220 case DDI_PRE:
1221 1221 /*
1222 1222 * Mark nexus busy before a child detaches.
1223 1223 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1224 1224 * - pshot@XXX,nopm_strict), or if the child is a
1225 1225 * - no-pm-components nexus node.
1226 1226 */
1227 1227 if (!(pshot->state & PM_SUPPORTED) ||
1228 1228 (strcmp(childname, "tape") == 0 &&
1229 1229 !(pshot->state & STRICT_PARENT)) ||
1230 1230 no_pm_components_child)
1231 1231 break;
1232 1232 mutex_enter(&pshot->lock);
1233 1233 ++(pshot->busy);
1234 1234 if (pshot_debug_busy) {
1235 1235 cmn_err(CE_CONT, "%s%d:"
1236 1236 " ctl_detach_pre: busy for %s%d:"
1237 1237 " busy = %d\n", name, instance,
1238 1238 childname, childinstance,
1239 1239 pshot->busy);
1240 1240 }
1241 1241 mutex_exit(&pshot->lock);
1242 1242 rval = pm_busy_component(dip, 0);
1243 1243 ASSERT(rval == DDI_SUCCESS);
1244 1244
1245 1245 break;
1246 1246 case DDI_POST:
1247 1247 /*
1248 1248 * Mark nexus idle after a child detaches.
1249 1249 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1250 1250 */
1251 1251 if (!(pshot->state & PM_SUPPORTED))
1252 1252 break;
1253 1253 mutex_enter(&pshot->lock);
1254 1254 ASSERT(pshot->busy > 0);
1255 1255 --pshot->busy;
1256 1256 if (pshot_debug_busy) {
1257 1257 cmn_err(CE_CONT, "%s%d:"
1258 1258 " ctl_detach_post: idle for %s%d:"
1259 1259 " busy = %d\n", name, instance,
1260 1260 childname, childinstance,
1261 1261 pshot->busy);
1262 1262 }
1263 1263 mutex_exit(&pshot->lock);
1264 1264 rval = pm_idle_component(dip, 0);
1265 1265 ASSERT(rval == DDI_SUCCESS);
1266 1266
1267 1267 /*
1268 1268 * Mark the driver idle if the NO_INVOL_FLAG
1269 1269 * is set. This is needed to make sure the
1270 1270 * parent is idle after the child detaches
1271 1271 * without calling pm_lower_power().
1272 1272 * Clear the NO_INVOL_FLAG.
1273 1273 * - also mark idle if a tape device has detached
1274 1274 */
1275 1275 if (!(pshot->state & NO_INVOL_FLAG))
1276 1276 break;
1277 1277 mutex_enter(&pshot->lock);
1278 1278 ASSERT(pshot->busy > 0);
1279 1279 --pshot->busy;
1280 1280 if (pshot_debug_busy) {
1281 1281 cmn_err(CE_CONT, "%s%d:"
1282 1282 " ctl_detach_post: NO_INVOL:"
1283 1283 " idle for %s%d: busy = %d\n",
1284 1284 name, instance, childname,
1285 1285 childinstance, pshot->busy);
1286 1286 }
1287 1287 pshot->state &= ~NO_INVOL_FLAG;
1288 1288 mutex_exit(&pshot->lock);
1289 1289 rval = pm_idle_component(dip, 0);
1290 1290 ASSERT(rval == DDI_SUCCESS);
1291 1291
1292 1292 break;
1293 1293 }
1294 1294
1295 1295 ndi_devi_exit(dip, circ);
1296 1296
1297 1297 return (rval);
1298 1298 }
1299 1299
1300 1300 case DDI_CTLOPS_BTOP:
1301 1301 case DDI_CTLOPS_BTOPR:
1302 1302 case DDI_CTLOPS_DVMAPAGESIZE:
1303 1303 case DDI_CTLOPS_IOMIN:
1304 1304 case DDI_CTLOPS_PTOB:
1305 1305 default:
1306 1306 /*
1307 1307 * The ops that we pass up (default). We pass up memory
1308 1308 * allocation oriented ops that we receive - these may be
1309 1309 * associated with pseudo HBA drivers below us with target
1310 1310 * drivers below them that use ddi memory allocation
1311 1311 * interfaces like scsi_alloc_consistent_buf.
1312 1312 */
1313 1313 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1314 1314 }
1315 1315 }
1316 1316
1317 1317 /*ARGSUSED0*/
1318 1318 static int
1319 1319 pshot_power(dev_info_t *dip, int cmpt, int level)
1320 1320 {
1321 1321 pshot_t *pshot;
1322 1322 int instance = ddi_get_instance(dip);
1323 1323 char *name = ddi_node_name(dip);
1324 1324 int circ;
1325 1325 int rv;
1326 1326
1327 1327 pshot = ddi_get_soft_state(pshot_softstatep, instance);
1328 1328 if (pshot == NULL) {
1329 1329
1330 1330 return (DDI_FAILURE);
1331 1331 }
1332 1332
1333 1333 ndi_devi_enter(dip, &circ);
1334 1334
1335 1335 /*
1336 1336 * set POWER_FLAG when power() is called.
1337 1337 * ioctl(DEVCT_PM_POWER) is a clear on read call.
1338 1338 */
1339 1339 mutex_enter(&pshot->lock);
1340 1340 pshot->state |= POWER_FLAG;
1341 1341 /*
1342 1342 * refuse to power OFF if the component is busy
1343 1343 */
1344 1344 if (pshot->busy != 0 && pshot->level > level) {
1345 1345 cmn_err(CE_WARN, "%s%d: power: REFUSING POWER LEVEL CHANGE"
1346 1346 " (%d->%d), DEVICE NOT IDLE: busy = %d",
1347 1347 name, instance, pshot->level, level, pshot->busy);
1348 1348 rv = DDI_FAILURE;
1349 1349 } else {
1350 1350 if (pshot_debug) {
1351 1351 cmn_err(CE_CONT, "%s%d: power: comp %d (%d->%d)\n",
1352 1352 name, instance, cmpt, pshot->level, level);
1353 1353 }
1354 1354 pshot->level = level;
1355 1355 rv = DDI_SUCCESS;
1356 1356 }
1357 1357 mutex_exit(&pshot->lock);
1358 1358
1359 1359 ndi_devi_exit(dip, circ);
1360 1360
1361 1361 return (rv);
1362 1362 }
1363 1363
1364 1364 /*ARGSUSED0*/
1365 1365 static int
1366 1366 pshot_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
1367 1367 void *arg, void *result)
1368 1368
1369 1369 {
1370 1370 int ret;
1371 1371 int instance = ddi_get_instance(dip);
1372 1372 char *name = ddi_node_name(dip);
1373 1373 pshot_t *pshot;
1374 1374 pm_bp_child_pwrchg_t *bpc;
1375 1375 pm_bp_nexus_pwrup_t bpn;
1376 1376 pm_bp_has_changed_t *bphc;
1377 1377 int pwrup_res;
1378 1378 int ret_failed = 0;
1379 1379 int pwrup_res_failed = 0;
1380 1380
1381 1381 pshot = ddi_get_soft_state(pshot_softstatep, instance);
1382 1382 if (pshot == NULL) {
1383 1383
1384 1384 return (DDI_FAILURE);
1385 1385 }
1386 1386
1387 1387 switch (op) {
1388 1388 case BUS_POWER_PRE_NOTIFICATION:
1389 1389 bpc = (pm_bp_child_pwrchg_t *)arg;
1390 1390 if (pshot_debug) {
1391 1391 cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1392 1392 " %s%d comp %d (%d->%d)\n",
1393 1393 name, instance, ddi_node_name(bpc->bpc_dip),
1394 1394 ddi_get_instance(bpc->bpc_dip),
1395 1395 bpc->bpc_comp, bpc->bpc_olevel,
1396 1396 bpc->bpc_nlevel);
1397 1397 }
1398 1398
1399 1399 /*
1400 1400 * mark parent busy if old_level is either -1 or 0,
1401 1401 * and new level is == MAXPWR
1402 1402 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1403 1403 */
1404 1404 if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1405 1405 bpc->bpc_olevel <= 0) && (pshot->state & PM_SUPPORTED)) {
1406 1406 mutex_enter(&pshot->lock);
1407 1407 ++(pshot->busy);
1408 1408 if (pshot_debug_busy) {
1409 1409 cmn_err(CE_CONT,
1410 1410 "%s%d: pre_bus_power:"
1411 1411 " busy parent for %s%d (%d->%d): "
1412 1412 " busy = %d\n",
1413 1413 name, instance,
1414 1414 ddi_node_name(bpc->bpc_dip),
1415 1415 ddi_get_instance(bpc->bpc_dip),
1416 1416 bpc->bpc_olevel, bpc->bpc_nlevel,
1417 1417 pshot->busy);
1418 1418 }
1419 1419 mutex_exit(&pshot->lock);
1420 1420 ret = pm_busy_component(dip, 0);
1421 1421 ASSERT(ret == DDI_SUCCESS);
1422 1422 }
1423 1423
1424 1424 /*
1425 1425 * if new_level > 0, power up parent, if not already at
1426 1426 * MAXPWR, via pm_busop_bus_power
1427 1427 * - skip for the no-pm nexus (pshot@XXX,nopm)
1428 1428 */
1429 1429 if (bpc->bpc_comp == 0 && bpc->bpc_nlevel > 0 &&
1430 1430 pshot->level < MAXPWR && (pshot->state & PM_SUPPORTED)) {
1431 1431 /*
1432 1432 * stuff the bpn struct
1433 1433 */
1434 1434 bpn.bpn_comp = 0;
1435 1435 bpn.bpn_level = MAXPWR;
1436 1436 bpn.bpn_private = bpc->bpc_private;
1437 1437 bpn.bpn_dip = dip;
1438 1438
1439 1439 /*
1440 1440 * ask pm to power parent up
1441 1441 */
1442 1442 if (pshot_debug) {
1443 1443 cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1444 1444 " pm_busop_bus_power on parent for %s%d"
1445 1445 " (%d->%d): enter", name, instance,
1446 1446 ddi_node_name(bpc->bpc_dip),
1447 1447 ddi_get_instance(bpc->bpc_dip),
1448 1448 bpc->bpc_olevel, bpc->bpc_nlevel);
1449 1449 }
1450 1450 ret = pm_busop_bus_power(dip, impl_arg,
1451 1451 BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
1452 1452 (void *)&pwrup_res);
1453 1453
1454 1454 /*
1455 1455 * check the return status individually,
1456 1456 * idle parent and exit if either failed.
1457 1457 */
1458 1458 if (ret != DDI_SUCCESS) {
1459 1459 cmn_err(CE_WARN,
1460 1460 "%s%d: pre_bus_power:"
1461 1461 " pm_busop_bus_power FAILED (ret) FOR"
1462 1462 " %s%d (%d->%d)",
1463 1463 name, instance,
1464 1464 ddi_node_name(bpc->bpc_dip),
1465 1465 ddi_get_instance(bpc->bpc_dip),
1466 1466 bpc->bpc_olevel, bpc->bpc_nlevel);
1467 1467 ret_failed = 1;
1468 1468 }
1469 1469 if (pwrup_res != DDI_SUCCESS) {
1470 1470 cmn_err(CE_WARN,
1471 1471 "%s%d: pre_bus_power:"
1472 1472 " pm_busop_bus_power FAILED (pwrup_res)"
1473 1473 " FOR %s%d (%d->%d)",
1474 1474 name, instance,
1475 1475 ddi_node_name(bpc->bpc_dip),
1476 1476 ddi_get_instance(bpc->bpc_dip),
1477 1477 bpc->bpc_olevel, bpc->bpc_nlevel);
1478 1478 pwrup_res_failed = 1;
1479 1479 }
1480 1480 if (ret_failed || pwrup_res_failed) {
1481 1481 /*
1482 1482 * decrement the busy count if it
1483 1483 * had been incremented.
1484 1484 */
1485 1485 if ((bpc->bpc_comp == 0 &&
1486 1486 bpc->bpc_nlevel == MAXPWR &&
1487 1487 bpc->bpc_olevel <= 0) &&
1488 1488 (pshot->state & PM_SUPPORTED)) {
1489 1489 mutex_enter(&pshot->lock);
1490 1490 ASSERT(pshot->busy > 0);
1491 1491 --(pshot->busy);
1492 1492 if (pshot_debug_busy) {
1493 1493 cmn_err(CE_CONT, "%s%d:"
1494 1494 " pm_busop_bus_power"
1495 1495 " failed: idle parent for"
1496 1496 " %s%d (%d->%d):"
1497 1497 " busy = %d\n",
1498 1498 name, instance,
1499 1499 ddi_node_name(
1500 1500 bpc->bpc_dip),
1501 1501 ddi_get_instance(
1502 1502 bpc->bpc_dip),
1503 1503 bpc->bpc_olevel,
1504 1504 bpc->bpc_nlevel,
1505 1505 pshot->busy);
1506 1506 }
1507 1507 mutex_exit(&pshot->lock);
1508 1508 ret = pm_idle_component(dip, 0);
1509 1509 ASSERT(ret == DDI_SUCCESS);
1510 1510 }
1511 1511 return (DDI_FAILURE);
1512 1512
1513 1513 } else {
1514 1514 if (pshot_debug) {
1515 1515 cmn_err(CE_CONT,
1516 1516 "%s%d: pre_bus_power:"
1517 1517 " pm_busop_bus_power on parent"
1518 1518 " for %s%d (%d->%d)\n",
1519 1519 name, instance,
1520 1520 ddi_node_name(bpc->bpc_dip),
1521 1521 ddi_get_instance(bpc->bpc_dip),
1522 1522 bpc->bpc_olevel, bpc->bpc_nlevel);
1523 1523 }
1524 1524 }
1525 1525 }
1526 1526 break;
1527 1527
1528 1528 case BUS_POWER_POST_NOTIFICATION:
1529 1529 bpc = (pm_bp_child_pwrchg_t *)arg;
1530 1530 if (pshot_debug) {
1531 1531 cmn_err(CE_CONT, "%s%d: post_bus_power:"
1532 1532 " %s%d comp %d (%d->%d) result %d\n",
1533 1533 name, instance, ddi_node_name(bpc->bpc_dip),
1534 1534 ddi_get_instance(bpc->bpc_dip),
1535 1535 bpc->bpc_comp, bpc->bpc_olevel,
1536 1536 bpc->bpc_nlevel, *(int *)result);
1537 1537 }
1538 1538
1539 1539 /*
1540 1540 * handle pm_busop_bus_power() failure case.
1541 1541 * mark parent idle if had been marked busy.
1542 1542 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1543 1543 */
1544 1544 if (*(int *)result != DDI_SUCCESS) {
1545 1545 cmn_err(CE_WARN,
1546 1546 "pshot%d: post_bus_power_failed:"
1547 1547 " pm_busop_bus_power FAILED FOR %s%d (%d->%d)",
1548 1548 instance, ddi_node_name(bpc->bpc_dip),
1549 1549 ddi_get_instance(bpc->bpc_dip),
1550 1550 bpc->bpc_olevel, bpc->bpc_nlevel);
1551 1551
1552 1552 if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1553 1553 bpc->bpc_olevel <= 0) &&
1554 1554 (pshot->state & PM_SUPPORTED)) {
1555 1555 mutex_enter(&pshot->lock);
1556 1556 ASSERT(pshot->busy > 0);
1557 1557 --(pshot->busy);
1558 1558 if (pshot_debug_busy) {
1559 1559 cmn_err(CE_CONT, "%s%d:"
1560 1560 " post_bus_power_failed:"
1561 1561 " idle parent for %s%d"
1562 1562 " (%d->%d): busy = %d\n",
1563 1563 name, instance,
1564 1564 ddi_node_name(bpc->bpc_dip),
1565 1565 ddi_get_instance(bpc->bpc_dip),
1566 1566 bpc->bpc_olevel, bpc->bpc_nlevel,
1567 1567 pshot->busy);
1568 1568 }
1569 1569 mutex_exit(&pshot->lock);
1570 1570 ret = pm_idle_component(dip, 0);
1571 1571 ASSERT(ret == DDI_SUCCESS);
1572 1572 }
1573 1573 }
1574 1574
1575 1575 /*
1576 1576 * Mark nexus idle when a child's comp 0
1577 1577 * is set to level 0 from level 1, 2, or 3 only.
1578 1578 * And only if result arg == DDI_SUCCESS.
1579 1579 * This will leave the parent busy when the child
1580 1580 * does not call pm_lower_power() on detach after
1581 1581 * unsetting the NO_LOWER_POWER flag.
1582 1582 * If so, need to notify the parent to mark itself
1583 1583 * idle anyway, else the no-involumtary-power-cycles
1584 1584 * test cases will report false passes!
1585 1585 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1586 1586 */
1587 1587 if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == 0 &&
1588 1588 !(bpc->bpc_olevel <= 0) &&
1589 1589 *(int *)result == DDI_SUCCESS) &&
1590 1590 (pshot->state & PM_SUPPORTED)) {
1591 1591 mutex_enter(&pshot->lock);
1592 1592 ASSERT(pshot->busy > 0);
1593 1593 --(pshot->busy);
1594 1594 if (pshot_debug_busy) {
1595 1595 cmn_err(CE_CONT,
1596 1596 "%s%d: post_bus_power:"
1597 1597 " idle parent for %s%d (%d->%d):"
1598 1598 " busy = %d\n", name, instance,
1599 1599 ddi_node_name(bpc->bpc_dip),
1600 1600 ddi_get_instance(bpc->bpc_dip),
1601 1601 bpc->bpc_olevel, bpc->bpc_nlevel,
1602 1602 pshot->busy);
1603 1603 }
1604 1604 mutex_exit(&pshot->lock);
1605 1605 ret = pm_idle_component(dip, 0);
1606 1606 ASSERT(ret == DDI_SUCCESS);
1607 1607 }
1608 1608 break;
1609 1609
1610 1610 case BUS_POWER_HAS_CHANGED:
1611 1611 bphc = (pm_bp_has_changed_t *)arg;
1612 1612 if (pshot_debug) {
1613 1613 cmn_err(CE_CONT, "%s%d: has_changed_bus_power:"
1614 1614 " %s%d comp %d (%d->%d) result %d\n",
1615 1615 name, instance, ddi_node_name(bphc->bphc_dip),
1616 1616 ddi_get_instance(bphc->bphc_dip),
1617 1617 bphc->bphc_comp, bphc->bphc_olevel,
1618 1618 bphc->bphc_nlevel, *(int *)result);
1619 1619 }
1620 1620
1621 1621 /*
1622 1622 * Mark nexus idle when a child's comp 0
1623 1623 * is set to level 0 from levels 1, 2, or 3 only.
1624 1624 *
1625 1625 * If powering up child leaf/nexus nodes via
1626 1626 * pm_power_has_changed() calls, first issue
1627 1627 * DEVCTL_PM_BUSY_COMP ioctl to mark parent busy
1628 1628 * before powering the parent up, then power up the
1629 1629 * child node.
1630 1630 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1631 1631 */
1632 1632 if ((bphc->bphc_comp == 0 && bphc->bphc_nlevel == 0 &&
1633 1633 !(bphc->bphc_olevel <= 0)) &&
1634 1634 pshot->state & PM_SUPPORTED) {
1635 1635 mutex_enter(&pshot->lock);
1636 1636 ASSERT(pshot->busy > 0);
1637 1637 --(pshot->busy);
1638 1638 if (pshot_debug_busy) {
1639 1639 cmn_err(CE_CONT,
1640 1640 "%s%d: has_changed_bus_power:"
1641 1641 " idle parent for %s%d (%d->%d):"
1642 1642 " busy = %d\n", name, instance,
1643 1643 ddi_node_name(bphc->bphc_dip),
1644 1644 ddi_get_instance(bphc->bphc_dip),
1645 1645 bphc->bphc_olevel,
1646 1646 bphc->bphc_nlevel, pshot->busy);
1647 1647 }
1648 1648 mutex_exit(&pshot->lock);
1649 1649 ret = pm_idle_component(dip, 0);
1650 1650 ASSERT(ret == DDI_SUCCESS);
1651 1651 }
1652 1652 break;
1653 1653
1654 1654 default:
1655 1655 return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
1656 1656
1657 1657 }
1658 1658
1659 1659 return (DDI_SUCCESS);
1660 1660 }
1661 1661
1662 1662 static int
1663 1663 pshot_initchild(dev_info_t *dip, dev_info_t *child)
1664 1664 {
1665 1665 char name[64];
1666 1666 char *bus_addr;
1667 1667 char *c_nodename;
1668 1668 int bus_id;
1669 1669 dev_info_t *enum_child;
1670 1670 int enum_base;
1671 1671 int enum_extent;
1672 1672
1673 1673
1674 1674 /* check for bus_enum node */
1675 1675
1676 1676 #ifdef NOT_USED
1677 1677 if (impl_ddi_merge_child(child) != DDI_SUCCESS)
1678 1678 return (DDI_FAILURE);
1679 1679 #endif
1680 1680
1681 1681 enum_base = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1682 1682 "busid_ebase", 0);
1683 1683
1684 1684 enum_extent = ddi_prop_get_int(DDI_DEV_T_ANY, child,
1685 1685 DDI_PROP_DONTPASS, "busid_range", 0);
1686 1686
1687 1687 /*
1688 1688 * bus enumeration node
1689 1689 */
1690 1690 if ((enum_base != 0) && (enum_extent != 0)) {
1691 1691 c_nodename = ddi_node_name(child);
1692 1692 bus_id = enum_base;
1693 1693 for (; bus_id < enum_extent; bus_id++) {
1694 1694 if (ndi_devi_alloc(dip, c_nodename, DEVI_PSEUDO_NODEID,
1695 1695 &enum_child) != NDI_SUCCESS)
1696 1696 return (DDI_FAILURE);
1697 1697
1698 1698 (void) sprintf(name, "%d", bus_id);
1699 1699 if (ndi_prop_update_string(DDI_DEV_T_NONE, enum_child,
1700 1700 "bus-addr", name) != DDI_PROP_SUCCESS) {
1701 1701 (void) ndi_devi_free(enum_child);
1702 1702 return (DDI_FAILURE);
1703 1703 }
1704 1704
1705 1705 if (ndi_devi_online(enum_child, 0) !=
1706 1706 DDI_SUCCESS) {
1707 1707 (void) ndi_devi_free(enum_child);
1708 1708 return (DDI_FAILURE);
1709 1709 }
1710 1710 }
1711 1711 /*
1712 1712 * fail the enumeration node itself
1713 1713 */
1714 1714 return (DDI_FAILURE);
1715 1715 }
1716 1716
1717 1717 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 0, "bus-addr",
1718 1718 &bus_addr) != DDI_PROP_SUCCESS) {
1719 1719 cmn_err(CE_WARN, "pshot_initchild: bus-addr not defined (%s)",
1720 1720 ddi_node_name(child));
1721 1721 return (DDI_NOT_WELL_FORMED);
1722 1722 }
1723 1723
1724 1724 if (strlen(bus_addr) == 0) {
1725 1725 cmn_err(CE_WARN, "pshot_initchild: NULL bus-addr (%s)",
1726 1726 ddi_node_name(child));
1727 1727 ddi_prop_free(bus_addr);
1728 1728 return (DDI_FAILURE);
1729 1729 }
1730 1730
1731 1731 if (strncmp(bus_addr, "failinit", 8) == 0) {
1732 1732 if (pshot_debug)
1733 1733 cmn_err(CE_CONT,
1734 1734 "pshot%d: %s forced INITCHILD failure\n",
1735 1735 ddi_get_instance(dip), bus_addr);
1736 1736 ddi_prop_free(bus_addr);
1737 1737 return (DDI_FAILURE);
1738 1738 }
1739 1739
1740 1740 if (pshot_log) {
1741 1741 cmn_err(CE_CONT, "initchild %s%d/%s@%s\n",
1742 1742 ddi_get_name(dip), ddi_get_instance(dip),
1743 1743 ddi_node_name(child), bus_addr);
1744 1744 }
1745 1745
1746 1746 ddi_set_name_addr(child, bus_addr);
1747 1747 ddi_prop_free(bus_addr);
1748 1748 return (DDI_SUCCESS);
1749 1749 }
1750 1750
1751 1751 /*ARGSUSED*/
1752 1752 static int
1753 1753 pshot_uninitchild(dev_info_t *dip, dev_info_t *child)
1754 1754 {
1755 1755 ddi_set_name_addr(child, NULL);
1756 1756 return (DDI_SUCCESS);
1757 1757 }
1758 1758
1759 1759
1760 1760 /*
1761 1761 * devctl IOCTL support
1762 1762 */
1763 1763 /* ARGSUSED */
1764 1764 static int
1765 1765 pshot_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1766 1766 {
1767 1767 int instance;
1768 1768 pshot_t *pshot;
1769 1769
1770 1770 if (otyp != OTYP_CHR)
1771 1771 return (EINVAL);
1772 1772
1773 1773 instance = pshot_minor_decode_inst(getminor(*devp));
1774 1774 if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1775 1775 return (ENXIO);
1776 1776
1777 1777 /*
1778 1778 * Access is currently determined on a per-instance basis.
1779 1779 * If we want per-node, then need to add state and lock members to
1780 1780 * pshot_minor_t
1781 1781 */
1782 1782 mutex_enter(&pshot->lock);
1783 1783 if (((flags & FEXCL) && (pshot->state & IS_OPEN)) ||
1784 1784 (!(flags & FEXCL) && (pshot->state & IS_OPEN_EXCL))) {
1785 1785 mutex_exit(&pshot->lock);
1786 1786 return (EBUSY);
1787 1787 }
1788 1788 pshot->state |= IS_OPEN;
1789 1789 if (flags & FEXCL)
1790 1790 pshot->state |= IS_OPEN_EXCL;
1791 1791
1792 1792 if (pshot_debug)
1793 1793 cmn_err(CE_CONT, "pshot%d open\n", instance);
1794 1794
1795 1795 mutex_exit(&pshot->lock);
1796 1796 return (0);
1797 1797 }
1798 1798
1799 1799 /*
1800 1800 * pshot_close
1801 1801 */
1802 1802 /* ARGSUSED */
1803 1803 static int
1804 1804 pshot_close(dev_t dev, int flag, int otyp, cred_t *credp)
1805 1805 {
1806 1806 int instance;
1807 1807 pshot_t *pshot;
1808 1808
1809 1809 if (otyp != OTYP_CHR)
1810 1810 return (EINVAL);
1811 1811
1812 1812 instance = pshot_minor_decode_inst(getminor(dev));
1813 1813 if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1814 1814 return (ENXIO);
1815 1815
1816 1816 mutex_enter(&pshot->lock);
1817 1817 pshot->state &= ~(IS_OPEN | IS_OPEN_EXCL);
1818 1818 mutex_exit(&pshot->lock);
1819 1819 if (pshot_debug)
1820 1820 cmn_err(CE_CONT, "pshot%d closed\n", instance);
1821 1821 return (0);
1822 1822 }
1823 1823
1824 1824
1825 1825 /*
1826 1826 * pshot_ioctl: redirects to appropriate command handler based on various
1827 1827 * criteria
1828 1828 */
1829 1829 /* ARGSUSED */
1830 1830 static int
1831 1831 pshot_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1832 1832 int *rvalp)
1833 1833 {
1834 1834 pshot_t *pshot;
1835 1835 int instance;
1836 1836 minor_t nodenum;
1837 1837 char *nodename;
1838 1838
1839 1839 instance = pshot_minor_decode_inst(getminor(dev));
1840 1840 if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1841 1841 return (ENXIO);
1842 1842
1843 1843 nodenum = pshot_minor_decode_nodenum(getminor(dev));
1844 1844 nodename = pshot->nodes[nodenum].name;
1845 1845
1846 1846 if (pshot_debug)
1847 1847 cmn_err(CE_CONT,
1848 1848 "pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n",
1849 1849 instance, (void *)dev, cmd, (void *)arg, mode);
1850 1850
1851 1851 if (strcmp(nodename, PSHOT_NODENAME_DEVCTL) == 0)
1852 1852 return (pshot_devctl(pshot, nodenum, cmd, arg, mode, credp,
1853 1853 rvalp));
1854 1854
1855 1855 if (strcmp(nodename, PSHOT_NODENAME_TESTCTL) == 0)
1856 1856 return (pshot_testctl(pshot, nodenum, cmd, arg, mode, credp,
1857 1857 rvalp));
1858 1858
1859 1859 cmn_err(CE_WARN, "pshot_ioctl: unmatched nodename on minor %u",
1860 1860 pshot->nodes[nodenum].minor);
1861 1861 return (ENXIO);
1862 1862 }
1863 1863
1864 1864
1865 1865 /*
1866 1866 * pshot_devctl: handle DEVCTL operations
1867 1867 */
1868 1868 /* ARGSUSED */
1869 1869 static int
1870 1870 pshot_devctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
1871 1871 cred_t *credp, int *rvalp)
1872 1872 {
1873 1873 dev_info_t *self;
1874 1874 dev_info_t *child = NULL;
1875 1875 struct devctl_iocdata *dcp;
1876 1876 uint_t state;
1877 1877 int rv = 0;
1878 1878 uint_t flags;
1879 1879 int instance;
1880 1880 int i;
1881 1881 int ret;
1882 1882
1883 1883 self = pshot->dip;
1884 1884
1885 1885 flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0;
1886 1886 instance = pshot->instance;
1887 1887
1888 1888 /*
1889 1889 * We can use the generic implementation for these ioctls
1890 1890 */
1891 1891 for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
1892 1892 if (pshot_devctls[i].ioctl_int == cmd) {
1893 1893 if (pshot_debug)
1894 1894 cmn_err(CE_CONT, "pshot%d devctl: %s",
1895 1895 instance, pshot_devctls[i].ioctl_char);
1896 1896 }
1897 1897 }
1898 1898 switch (cmd) {
1899 1899 case DEVCTL_DEVICE_GETSTATE:
1900 1900 case DEVCTL_DEVICE_ONLINE:
1901 1901 case DEVCTL_DEVICE_OFFLINE:
1902 1902 case DEVCTL_DEVICE_REMOVE:
1903 1903 case DEVCTL_BUS_GETSTATE:
1904 1904 case DEVCTL_BUS_DEV_CREATE:
1905 1905 rv = ndi_devctl_ioctl(self, cmd, arg, mode, flags);
1906 1906 if (pshot_debug && rv != 0) {
1907 1907 cmn_err(CE_CONT, "pshot%d ndi_devctl_ioctl:"
1908 1908 " failed, rv = %d", instance, rv);
1909 1909 }
1910 1910
1911 1911 return (rv);
1912 1912 }
1913 1913
1914 1914 /*
1915 1915 * read devctl ioctl data
1916 1916 */
1917 1917 if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1918 1918 return (EFAULT);
1919 1919
1920 1920 switch (cmd) {
1921 1921
1922 1922 case DEVCTL_DEVICE_RESET:
1923 1923 if (pshot_debug)
1924 1924 cmn_err(CE_CONT, "pshot%d devctl:"
1925 1925 " DEVCTL_DEVICE_RESET\n", instance);
1926 1926 rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
1927 1927 child, (void *)self);
1928 1928 ASSERT(rv == NDI_SUCCESS);
1929 1929 break;
1930 1930
1931 1931 case DEVCTL_BUS_QUIESCE:
1932 1932 if (pshot_debug)
1933 1933 cmn_err(CE_CONT, "pshot%d devctl:"
1934 1934 " DEVCTL_BUS_QUIESCE\n", instance);
1935 1935 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1936 1936 if (state == BUS_QUIESCED) {
1937 1937 break;
1938 1938 }
1939 1939 (void) ndi_set_bus_state(self, BUS_QUIESCED);
1940 1940 }
1941 1941 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
1942 1942 child, (void *)self);
1943 1943 ASSERT(rv == NDI_SUCCESS);
1944 1944
1945 1945 break;
1946 1946
1947 1947 case DEVCTL_BUS_UNQUIESCE:
1948 1948 if (pshot_debug)
1949 1949 cmn_err(CE_CONT, "pshot%d devctl:"
1950 1950 " DEVCTL_BUS_UNQUIESCE\n", instance);
1951 1951 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1952 1952 if (state == BUS_ACTIVE) {
1953 1953 break;
1954 1954 }
1955 1955 }
1956 1956
1957 1957 /*
1958 1958 * quiesce the bus through bus-specific means
1959 1959 */
1960 1960 (void) ndi_set_bus_state(self, BUS_ACTIVE);
1961 1961 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
1962 1962 child, (void *)self);
1963 1963 ASSERT(rv == NDI_SUCCESS);
1964 1964 break;
1965 1965
1966 1966 case DEVCTL_BUS_RESET:
1967 1967 case DEVCTL_BUS_RESETALL:
1968 1968 /*
1969 1969 * no reset support for the pseudo bus
1970 1970 * but if there were....
1971 1971 */
1972 1972 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
1973 1973 child, (void *)self);
1974 1974 ASSERT(rv == NDI_SUCCESS);
1975 1975 break;
1976 1976
1977 1977 /*
1978 1978 * PM related ioctls
1979 1979 */
1980 1980 case DEVCTL_PM_BUSY_COMP:
1981 1981 /*
1982 1982 * mark component 0 busy.
1983 1983 * Keep track of ioctl updates to the busy count
1984 1984 * via pshot->busy_ioctl.
1985 1985 */
1986 1986 if (pshot_debug) {
1987 1987 cmn_err(CE_CONT, "pshot%d devctl:"
1988 1988 " DEVCTL_PM_BUSY_COMP\n", instance);
1989 1989 }
1990 1990 mutex_enter(&pshot->lock);
1991 1991 ++(pshot->busy);
1992 1992 ++(pshot->busy_ioctl);
1993 1993 if (pshot_debug_busy) {
1994 1994 cmn_err(CE_CONT, "pshot%d:"
1995 1995 " DEVCTL_PM_BUSY_COMP comp 0 busy"
1996 1996 " %d busy_ioctl %d\n", instance, pshot->busy,
1997 1997 pshot->busy_ioctl);
1998 1998 }
1999 1999 mutex_exit(&pshot->lock);
2000 2000 ret = pm_busy_component(pshot->dip, 0);
2001 2001 ASSERT(ret == DDI_SUCCESS);
2002 2002
2003 2003 break;
2004 2004
2005 2005 case DEVCTL_PM_BUSY_COMP_TEST:
2006 2006 /*
2007 2007 * test bus's busy state
2008 2008 */
2009 2009 if (pshot_debug) {
2010 2010 cmn_err(CE_CONT, "pshot%d devctl:"
2011 2011 " DEVCTL_PM_BUSY_COMP_TEST\n", instance);
2012 2012 }
2013 2013 mutex_enter(&pshot->lock);
2014 2014 state = pshot->busy;
2015 2015 if (copyout(&state, dcp->cpyout_buf,
2016 2016 sizeof (uint_t)) != 0) {
2017 2017 cmn_err(CE_WARN, "pshot%d devctl:"
2018 2018 " DEVCTL_PM_BUSY_COMP_TEST: copyout failed",
2019 2019 instance);
2020 2020 rv = EINVAL;
2021 2021 }
2022 2022 if (pshot_debug_busy) {
2023 2023 cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_BUSY_COMP_TEST:"
2024 2024 " comp 0 busy %d busy_ioctl %d\n", instance,
2025 2025 state, pshot->busy_ioctl);
2026 2026 }
2027 2027 mutex_exit(&pshot->lock);
2028 2028 break;
2029 2029
2030 2030 case DEVCTL_PM_IDLE_COMP:
2031 2031 /*
2032 2032 * mark component 0 idle.
2033 2033 * NOP if pshot->busy_ioctl <= 0.
2034 2034 */
2035 2035 if (pshot_debug) {
2036 2036 cmn_err(CE_CONT, "pshot%d devctl:"
2037 2037 " DEVCTL_PM_IDLE_COMP\n", instance);
2038 2038 }
2039 2039 mutex_enter(&pshot->lock);
2040 2040 if (pshot->busy_ioctl > 0) {
2041 2041 ASSERT(pshot->busy > 0);
2042 2042 --(pshot->busy);
2043 2043 --(pshot->busy_ioctl);
2044 2044 if (pshot_debug_busy) {
2045 2045 cmn_err(CE_CONT, "pshot%d:"
2046 2046 " DEVCTL_PM_IDLE_COM: comp 0"
2047 2047 " busy %d busy_ioctl %d\n", instance,
2048 2048 pshot->busy, pshot->busy_ioctl);
2049 2049 }
2050 2050 mutex_exit(&pshot->lock);
2051 2051 ret = pm_idle_component(pshot->dip, 0);
2052 2052 ASSERT(ret == DDI_SUCCESS);
2053 2053
2054 2054 } else {
2055 2055 mutex_exit(&pshot->lock);
2056 2056 }
2057 2057 break;
2058 2058
2059 2059 case DEVCTL_PM_RAISE_PWR:
2060 2060 /*
2061 2061 * raise component 0 to full power level MAXPWR via a
2062 2062 * pm_raise_power() call
2063 2063 */
2064 2064 if (pshot_debug) {
2065 2065 cmn_err(CE_CONT, "pshot%d devctl:"
2066 2066 " DEVCTL_PM_RAISE_PWR\n", instance);
2067 2067 }
2068 2068 if (pm_raise_power(pshot->dip, 0, MAXPWR) != DDI_SUCCESS) {
2069 2069 rv = EINVAL;
2070 2070 } else {
2071 2071 mutex_enter(&pshot->lock);
2072 2072 if (pshot_debug) {
2073 2073 cmn_err(CE_CONT, "pshot%d:"
2074 2074 " DEVCTL_PM_RAISE_POWER: comp 0"
2075 2075 " to level %d\n", instance, pshot->level);
2076 2076 }
2077 2077 mutex_exit(&pshot->lock);
2078 2078 }
2079 2079 break;
2080 2080
2081 2081 case DEVCTL_PM_LOWER_PWR:
2082 2082 /*
2083 2083 * pm_lower_power() call for negative testing
2084 2084 * expected to fail.
2085 2085 */
2086 2086 if (pshot_debug) {
2087 2087 cmn_err(CE_CONT, "pshot%d devctl:"
2088 2088 " DEVCTL_PM_LOWER_PWR\n", instance);
2089 2089 }
2090 2090 if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
2091 2091 rv = EINVAL;
2092 2092 } else {
2093 2093 mutex_enter(&pshot->lock);
2094 2094 if (pshot_debug) {
2095 2095 cmn_err(CE_CONT, "pshot%d:"
2096 2096 " DEVCTL_PM_LOWER_POWER comp 0"
2097 2097 " to level %d\n", instance, pshot->level);
2098 2098 }
2099 2099 mutex_exit(&pshot->lock);
2100 2100 }
2101 2101 break;
2102 2102
2103 2103 case DEVCTL_PM_CHANGE_PWR_LOW:
2104 2104 /*
2105 2105 * inform the PM framework that component 0 has changed
2106 2106 * power level to 0 via a pm_power_has_changed() call
2107 2107 */
2108 2108 if (pshot_debug) {
2109 2109 cmn_err(CE_CONT, "pshot%d devctl:"
2110 2110 " DEVCTL_PM_CHANGE_PWR_LOW\n", instance);
2111 2111 }
2112 2112 mutex_enter(&pshot->lock);
2113 2113 pshot->level = 0;
2114 2114 if (pm_power_has_changed(pshot->dip, 0, 0) != DDI_SUCCESS) {
2115 2115 rv = EINVAL;
2116 2116 } else {
2117 2117 if (pshot_debug) {
2118 2118 cmn_err(CE_CONT, "pshot%d:"
2119 2119 " DEVCTL_PM_CHANGE_PWR_LOW comp 0 to"
2120 2120 " level %d\n", instance, pshot->level);
2121 2121 }
2122 2122 }
2123 2123 mutex_exit(&pshot->lock);
2124 2124 break;
2125 2125
2126 2126 case DEVCTL_PM_CHANGE_PWR_HIGH:
2127 2127 /*
2128 2128 * inform the PM framework that component 0 has changed
2129 2129 * power level to MAXPWR via a pm_power_has_changed() call
2130 2130 */
2131 2131 if (pshot_debug) {
2132 2132 cmn_err(CE_CONT, "pshot%d devctl:"
2133 2133 " DEVCTL_PM_CHANGE_PWR_HIGH\n", instance);
2134 2134 }
2135 2135 mutex_enter(&pshot->lock);
2136 2136 pshot->level = MAXPWR;
2137 2137 if (pm_power_has_changed(pshot->dip, 0, MAXPWR)
2138 2138 != DDI_SUCCESS) {
2139 2139 rv = EINVAL;
2140 2140 } else {
2141 2141 if (pshot_debug) {
2142 2142 cmn_err(CE_CONT, "pshot%d:"
2143 2143 " DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to"
2144 2144 " level %d\n", instance, pshot->level);
2145 2145 }
2146 2146 }
2147 2147 mutex_exit(&pshot->lock);
2148 2148 break;
2149 2149
2150 2150 case DEVCTL_PM_POWER:
2151 2151 /*
2152 2152 * test if the pshot_power() routine has been called,
2153 2153 * then clear
2154 2154 */
2155 2155 if (pshot_debug) {
2156 2156 cmn_err(CE_CONT, "pshot%d devctl:"
2157 2157 " DEVCTL_PM_POWER\n", instance);
2158 2158 }
2159 2159 mutex_enter(&pshot->lock);
2160 2160 state = (pshot->state & POWER_FLAG) ? 1 : 0;
2161 2161 if (copyout(&state, dcp->cpyout_buf,
2162 2162 sizeof (uint_t)) != 0) {
2163 2163 cmn_err(CE_WARN, "pshot%d devctl:"
2164 2164 " DEVCTL_PM_POWER: copyout failed",
2165 2165 instance);
2166 2166 rv = EINVAL;
2167 2167 }
2168 2168 if (pshot_debug) {
2169 2169 cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_POWER:"
2170 2170 " POWER_FLAG = %d\n", instance, state);
2171 2171 }
2172 2172 pshot->state &= ~POWER_FLAG;
2173 2173 mutex_exit(&pshot->lock);
2174 2174 break;
2175 2175
2176 2176 case DEVCTL_PM_FAIL_SUSPEND:
2177 2177 /*
2178 2178 * fail DDI_SUSPEND
2179 2179 */
2180 2180 if (pshot_debug) {
2181 2181 cmn_err(CE_CONT, "pshot%d devctl:"
2182 2182 " DEVCTL_PM_FAIL_SUSPEND\n", instance);
2183 2183 }
2184 2184 mutex_enter(&pshot->lock);
2185 2185 pshot->state |= FAIL_SUSPEND_FLAG;
2186 2186 mutex_exit(&pshot->lock);
2187 2187 if (pshot_debug) {
2188 2188 cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_FAIL_SUSPEND\n",
2189 2189 instance);
2190 2190 }
2191 2191 break;
2192 2192
2193 2193 case DEVCTL_PM_BUS_STRICT_TEST:
2194 2194 /*
2195 2195 * test the STRICT_PARENT flag:
2196 2196 * set => STRICT PARENT
2197 2197 * not set => INVOLVED PARENT
2198 2198 */
2199 2199 mutex_enter(&pshot->lock);
2200 2200 state = (pshot->state & STRICT_PARENT) ? 1 : 0;
2201 2201 if (copyout(&state, dcp->cpyout_buf,
2202 2202 sizeof (uint_t)) != 0) {
2203 2203 cmn_err(CE_WARN, "pshot%d devctl:"
2204 2204 " DEVCTL_PM_BUS_STRICT_TEST: copyout failed",
2205 2205 instance);
2206 2206 rv = EINVAL;
2207 2207 }
2208 2208 if (pshot_debug) {
2209 2209 cmn_err(CE_CONT, "pshot%d devctl:"
2210 2210 " DEVCTL_PM_BUS_STRICT_TEST: type = %s\n",
2211 2211 instance, ((state == 0) ? "INVOLVED" : "STRICT"));
2212 2212 }
2213 2213 mutex_exit(&pshot->lock);
2214 2214 break;
2215 2215
2216 2216 case DEVCTL_PM_BUS_NO_INVOL:
2217 2217 /*
2218 2218 * Set the NO_INVOL_FLAG flag to
2219 2219 * notify the driver that the child will not
2220 2220 * call pm_lower_power() on detach.
2221 2221 * The driver needs to mark itself idle twice
2222 2222 * during DDI_CTLOPS_DETACH (post).
2223 2223 */
2224 2224 if (pshot_debug) {
2225 2225 cmn_err(CE_CONT, "pshot%d devctl:"
2226 2226 " DEVCTL_PM_BUS_NO_INVOL\n", instance);
2227 2227 }
2228 2228 mutex_enter(&pshot->lock);
2229 2229 pshot->state |= NO_INVOL_FLAG;
2230 2230 mutex_exit(&pshot->lock);
2231 2231 break;
2232 2232
2233 2233 default:
2234 2234 rv = ENOTTY;
2235 2235 }
2236 2236
2237 2237 ndi_dc_freehdl(dcp);
2238 2238 return (rv);
2239 2239 }
2240 2240
2241 2241
2242 2242 /*
2243 2243 * pshot_testctl: handle other test operations
2244 2244 * - If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which
2245 2245 * child to direct the DEVCTL to, if applicable;
2246 2246 * furthermore, any cmd here can be sent by layered ioctls (unlike
2247 2247 * those to pshot_devctl() which must come from userland)
2248 2248 */
2249 2249 /* ARGSUSED */
2250 2250 static int
2251 2251 pshot_testctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
2252 2252 cred_t *credp, int *rvalp)
2253 2253 {
2254 2254 dev_info_t *self;
2255 2255 dev_info_t *child = NULL;
2256 2256 uint_t state;
2257 2257 int rv = 0;
2258 2258 int instance;
2259 2259 int i;
2260 2260
2261 2261 /* uint_t flags; */
2262 2262
2263 2263 /* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */
2264 2264 self = pshot->dip;
2265 2265 instance = pshot->instance;
2266 2266
2267 2267 if (cmd & DEVCTL_IOC) {
2268 2268 child = e_ddi_hold_devi_by_dev((dev_t)arg, 0);
2269 2269 }
2270 2270
2271 2271 for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
2272 2272 if (pshot_devctls[i].ioctl_int == cmd) {
2273 2273 if (pshot_debug)
2274 2274 cmn_err(CE_CONT, "pshot%d devctl: %s",
2275 2275 instance, pshot_devctls[i].ioctl_char);
2276 2276 }
2277 2277 }
2278 2278 switch (cmd) {
2279 2279 case DEVCTL_DEVICE_RESET:
2280 2280 if (pshot_debug)
2281 2281 cmn_err(CE_CONT, "pshot%d testctl:"
2282 2282 " DEVCTL_PM_POWER\n", instance);
2283 2283 rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
2284 2284 child, (void *)self);
2285 2285 ASSERT(rv == NDI_SUCCESS);
2286 2286 break;
2287 2287
2288 2288 case DEVCTL_BUS_QUIESCE:
2289 2289 if (pshot_debug)
2290 2290 cmn_err(CE_CONT, "pshot%d testctl:"
2291 2291 " DEVCTL_PM_POWER\n", instance);
2292 2292 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2293 2293 if (state == BUS_QUIESCED) {
2294 2294 break;
2295 2295 }
2296 2296 (void) ndi_set_bus_state(self, BUS_QUIESCED);
2297 2297 }
2298 2298 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
2299 2299 child, (void *)self);
2300 2300 ASSERT(rv == NDI_SUCCESS);
2301 2301
2302 2302 break;
2303 2303
2304 2304 case DEVCTL_BUS_UNQUIESCE:
2305 2305 if (pshot_debug)
2306 2306 cmn_err(CE_CONT, "pshot%d testctl:"
2307 2307 " DEVCTL_PM_POWER\n", instance);
2308 2308 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2309 2309 if (state == BUS_ACTIVE) {
2310 2310 break;
2311 2311 }
2312 2312 }
2313 2313
2314 2314 /*
2315 2315 * quiesce the bus through bus-specific means
2316 2316 */
2317 2317 (void) ndi_set_bus_state(self, BUS_ACTIVE);
2318 2318 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
2319 2319 child, (void *)self);
2320 2320 ASSERT(rv == NDI_SUCCESS);
2321 2321 break;
2322 2322
2323 2323 case DEVCTL_BUS_RESET:
2324 2324 case DEVCTL_BUS_RESETALL:
2325 2325 /*
2326 2326 * no reset support for the pseudo bus
2327 2327 * but if there were....
2328 2328 */
2329 2329 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
2330 2330 child, (void *)self);
2331 2331 ASSERT(rv == NDI_SUCCESS);
2332 2332 break;
2333 2333
2334 2334 default:
2335 2335 rv = ENOTTY;
2336 2336 }
2337 2337
2338 2338 if (child != NULL)
2339 2339 ddi_release_devi(child);
2340 2340 return (rv);
2341 2341 }
2342 2342
2343 2343
2344 2344 static int
2345 2345 pshot_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
2346 2346 char *eventname, ddi_eventcookie_t *event_cookiep)
2347 2347 {
2348 2348 int instance = ddi_get_instance(dip);
2349 2349 pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2350 2350
2351 2351 if (pshot_debug)
2352 2352 cmn_err(CE_CONT, "pshot%d: "
2353 2353 "pshot_get_eventcookie:\n\t"
2354 2354 "dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n",
2355 2355 instance, (void *)dip, (void *)rdip,
2356 2356 ddi_node_name(rdip), ddi_get_instance(rdip),
2357 2357 eventname);
2358 2358
2359 2359
2360 2360 return (ndi_event_retrieve_cookie(pshot->ndi_event_hdl,
2361 2361 rdip, eventname, event_cookiep, NDI_EVENT_NOPASS));
2362 2362 }
2363 2363
2364 2364 static int
2365 2365 pshot_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
2366 2366 ddi_eventcookie_t cookie,
2367 2367 void (*callback)(), void *arg, ddi_callback_id_t *cb_id)
2368 2368 {
2369 2369 int instance = ddi_get_instance(dip);
2370 2370 pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2371 2371
2372 2372 if (pshot_debug)
2373 2373 cmn_err(CE_CONT, "pshot%d: "
2374 2374 "pshot_add_eventcall:\n\t"
2375 2375 "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t"
2376 2376 "cb = 0x%p, arg = 0x%p\n",
2377 2377 instance, (void *)dip, (void *)rdip,
2378 2378 ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
2379 2379 NDI_EVENT_NAME(cookie), (void *)callback, arg);
2380 2380
2381 2381 /* add callback to our event handle */
2382 2382 return (ndi_event_add_callback(pshot->ndi_event_hdl, rdip,
2383 2383 cookie, callback, arg, NDI_SLEEP, cb_id));
2384 2384 }
2385 2385
2386 2386 static int
2387 2387 pshot_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
2388 2388 {
2389 2389
2390 2390 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
2391 2391
2392 2392 int instance = ddi_get_instance(dip);
2393 2393 pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2394 2394
2395 2395 ASSERT(cb);
2396 2396
2397 2397 if (pshot_debug)
2398 2398 cmn_err(CE_CONT, "pshot%d: "
2399 2399 "pshot_remove_eventcall:\n\t"
2400 2400 "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n",
2401 2401 instance, (void *)dip, (void *)cb->ndi_evtcb_dip,
2402 2402 ddi_node_name(cb->ndi_evtcb_dip),
2403 2403 ddi_get_instance(cb->ndi_evtcb_dip),
2404 2404 (void *)cb->ndi_evtcb_cookie,
2405 2405 NDI_EVENT_NAME(cb->ndi_evtcb_cookie));
2406 2406
2407 2407 return (ndi_event_remove_callback(pshot->ndi_event_hdl, cb_id));
2408 2408 }
2409 2409
2410 2410 static int
2411 2411 pshot_post_event(dev_info_t *dip, dev_info_t *rdip,
2412 2412 ddi_eventcookie_t cookie, void *impl_data)
2413 2413 {
2414 2414 int instance = ddi_get_instance(dip);
2415 2415 pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2416 2416
2417 2417 if (pshot_debug) {
2418 2418 if (rdip) {
2419 2419 cmn_err(CE_CONT, "pshot%d: "
2420 2420 "pshot_post_event:\n\t"
2421 2421 "dip = 0x%p rdip = 0x%p (%s%d\n\t"
2422 2422 "cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n",
2423 2423 instance, (void *)dip, (void *)rdip,
2424 2424 ddi_node_name(rdip), ddi_get_instance(rdip),
2425 2425 (void *)cookie,
2426 2426 NDI_EVENT_NAME(cookie), impl_data);
2427 2427 } else {
2428 2428 cmn_err(CE_CONT, "pshot%d: "
2429 2429 "pshot_post_event:\n\t"
2430 2430 "dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n",
2431 2431 instance, (void *)dip, (void *)cookie,
2432 2432 NDI_EVENT_NAME(cookie), impl_data);
2433 2433 }
2434 2434 }
2435 2435
2436 2436 /* run callbacks for this event */
2437 2437 return (ndi_event_run_callbacks(pshot->ndi_event_hdl, rdip,
2438 2438 cookie, impl_data));
2439 2439 }
2440 2440
2441 2441 /*
2442 2442 * the nexus driver will generate events
2443 2443 * that need to go to children
2444 2444 */
2445 2445 static int
2446 2446 pshot_event(pshot_t *pshot, int event_tag, dev_info_t *child,
2447 2447 void *bus_impldata)
2448 2448 {
2449 2449 ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(
2450 2450 pshot->ndi_event_hdl, event_tag);
2451 2451
2452 2452 if (pshot_debug) {
2453 2453 if (child) {
2454 2454 cmn_err(CE_CONT, "pshot%d: "
2455 2455 "pshot_event: event_tag = 0x%x (%s)\n\t"
2456 2456 "child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n",
2457 2457 pshot->instance, event_tag,
2458 2458 ndi_event_tag_to_name(pshot->ndi_event_hdl,
2459 2459 event_tag),
2460 2460 (void *)child, ddi_node_name(child),
2461 2461 ddi_get_instance(child), bus_impldata,
2462 2462 ddi_node_name((dev_info_t *)bus_impldata),
2463 2463 ddi_get_instance((dev_info_t *)bus_impldata));
2464 2464 } else {
2465 2465 cmn_err(CE_CONT, "pshot%d: "
2466 2466 "pshot_event: event_tag = 0x%x (%s)\n\t"
2467 2467 "child = NULL, bus_impl = 0x%p (%s%d)\n",
2468 2468 pshot->instance, event_tag,
2469 2469 ndi_event_tag_to_name(pshot->ndi_event_hdl,
2470 2470 event_tag),
2471 2471 bus_impldata,
2472 2472 ddi_node_name((dev_info_t *)bus_impldata),
2473 2473 ddi_get_instance((dev_info_t *)bus_impldata));
2474 2474 }
2475 2475 }
2476 2476
2477 2477 return (ndi_event_run_callbacks(pshot->ndi_event_hdl,
2478 2478 child, cookie, bus_impldata));
2479 2479 }
2480 2480
2481 2481
2482 2482 /*
2483 2483 * the pshot driver event notification callback
2484 2484 */
2485 2485 static void
2486 2486 pshot_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
2487 2487 void *arg, void *bus_impldata)
2488 2488 {
2489 2489 pshot_t *pshot = (pshot_t *)arg;
2490 2490 int event_tag;
2491 2491
2492 2492 /* look up the event */
2493 2493 event_tag = NDI_EVENT_TAG(cookie);
2494 2494
2495 2495 if (pshot_debug) {
2496 2496 cmn_err(CE_CONT, "pshot%d: "
2497 2497 "pshot_event_cb:\n\t"
2498 2498 "dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t"
2499 2499 "arg = 0x%p bus_impl = 0x%p (%s%d)\n",
2500 2500 pshot->instance, (void *)dip, (void *)cookie,
2501 2501 NDI_EVENT_NAME(cookie), event_tag, arg, bus_impldata,
2502 2502 ddi_node_name((dev_info_t *)bus_impldata),
2503 2503 ddi_get_instance((dev_info_t *)bus_impldata));
2504 2504 }
2505 2505
2506 2506 switch (event_tag) {
2507 2507 case PSHOT_EVENT_TAG_OFFLINE:
2508 2508 case PSHOT_EVENT_TAG_BUS_RESET:
2509 2509 case PSHOT_EVENT_TAG_BUS_QUIESCE:
2510 2510 case PSHOT_EVENT_TAG_BUS_UNQUIESCE:
2511 2511 /* notify all subscribers of the this event */
2512 2512 (void) ndi_event_run_callbacks(pshot->ndi_event_hdl,
2513 2513 NULL, cookie, bus_impldata);
2514 2514 if (pshot_debug) {
2515 2515 cmn_err(CE_CONT, "pshot%d: event=%s\n\t"
2516 2516 "pshot_event_cb\n", pshot->instance,
2517 2517 NDI_EVENT_NAME(cookie));
2518 2518 }
2519 2519 /*FALLTHRU*/
2520 2520 case PSHOT_EVENT_TAG_TEST_POST:
2521 2521 case PSHOT_EVENT_TAG_DEV_RESET:
2522 2522 default:
2523 2523 return;
2524 2524 }
2525 2525 }
2526 2526
2527 2527 static int
2528 2528 pshot_bus_config(dev_info_t *parent, uint_t flags,
2529 2529 ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
2530 2530 {
2531 2531 int rval;
2532 2532 char *devname;
2533 2533 char *devstr, *cname, *caddr;
2534 2534 int devstrlen;
2535 2535 int circ;
2536 2536 pshot_t *pshot;
2537 2537 int instance = ddi_get_instance(parent);
2538 2538
2539 2539 if (pshot_debug) {
2540 2540 flags |= NDI_DEVI_DEBUG;
2541 2541 cmn_err(CE_CONT,
2542 2542 "pshot%d: bus_config %s flags=0x%x\n",
2543 2543 ddi_get_instance(parent),
2544 2544 (op == BUS_CONFIG_ONE) ? (char *)arg : "", flags);
2545 2545 }
2546 2546
2547 2547 pshot = ddi_get_soft_state(pshot_softstatep, instance);
2548 2548 if (pshot == NULL) {
2549 2549
2550 2550 return (NDI_FAILURE);
2551 2551 }
2552 2552
2553 2553 /*
2554 2554 * Hold the nexus across the bus_config
2555 2555 */
2556 2556 ndi_devi_enter(parent, &circ);
2557 2557
2558 2558 switch (op) {
2559 2559 case BUS_CONFIG_ONE:
2560 2560
2561 2561 /*
2562 2562 * lookup and hold child device, create if not found
2563 2563 */
2564 2564 devname = (char *)arg;
2565 2565 devstrlen = strlen(devname) + 1;
2566 2566 devstr = i_ddi_strdup(devname, KM_SLEEP);
2567 2567 i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2568 2568
2569 2569 /*
2570 2570 * The framework ensures that the node has
2571 2571 * a name but each nexus is responsible for
2572 2572 * the bus address name space. This driver
2573 2573 * requires that a bus address be specified,
2574 2574 * as will most nexus drivers.
2575 2575 */
2576 2576 ASSERT(cname && strlen(cname) > 0);
2577 2577 if (caddr == NULL || strlen(caddr) == 0) {
2578 2578 cmn_err(CE_WARN,
2579 2579 "pshot%d: malformed name %s (no bus address)",
2580 2580 ddi_get_instance(parent), devname);
2581 2581 kmem_free(devstr, devstrlen);
2582 2582 ndi_devi_exit(parent, circ);
2583 2583 return (NDI_FAILURE);
2584 2584 }
2585 2585
2586 2586 /*
2587 2587 * Handle a few special cases for testing purposes
2588 2588 */
2589 2589 rval = pshot_bus_config_test_specials(parent,
2590 2590 devname, cname, caddr);
2591 2591
2592 2592 if (rval == NDI_SUCCESS) {
2593 2593 /*
2594 2594 * Set up either a leaf or nexus device
2595 2595 */
2596 2596 if (strcmp(cname, "pshot") == 0) {
2597 2597 rval = pshot_bus_config_setup_nexus(parent,
2598 2598 cname, caddr);
2599 2599 } else {
2600 2600 rval = pshot_bus_config_setup_leaf(parent,
2601 2601 cname, caddr);
2602 2602 }
2603 2603 }
2604 2604
2605 2605 kmem_free(devstr, devstrlen);
2606 2606 break;
2607 2607
2608 2608 case BUS_CONFIG_DRIVER:
2609 2609 case BUS_CONFIG_ALL:
2610 2610 rval = NDI_SUCCESS;
2611 2611 break;
2612 2612
2613 2613 default:
2614 2614 rval = NDI_FAILURE;
2615 2615 break;
2616 2616 }
2617 2617
2618 2618 if (rval == NDI_SUCCESS)
2619 2619 rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
2620 2620
2621 2621 ndi_devi_exit(parent, circ);
2622 2622
2623 2623 if (pshot_debug)
2624 2624 cmn_err(CE_CONT, "pshot%d: bus_config %s\n",
2625 2625 ddi_get_instance(parent),
2626 2626 (rval == NDI_SUCCESS) ? "ok" : "failed");
2627 2627
2628 2628 return (rval);
2629 2629 }
2630 2630
2631 2631 static int
2632 2632 pshot_bus_unconfig(dev_info_t *parent, uint_t flags,
2633 2633 ddi_bus_config_op_t op, void *arg)
2634 2634 {
2635 2635 major_t major;
2636 2636 int rval = NDI_SUCCESS;
2637 2637 int circ;
2638 2638
2639 2639 if (pshot_debug) {
2640 2640 flags |= NDI_DEVI_DEBUG;
2641 2641 cmn_err(CE_CONT,
2642 2642 "pshot%d: bus_unconfig %s flags=0x%x\n",
2643 2643 ddi_get_instance(parent),
2644 2644 (op == BUS_UNCONFIG_ONE) ? (char *)arg : "", flags);
2645 2645 }
2646 2646
2647 2647 /*
2648 2648 * Hold the nexus across the bus_unconfig
2649 2649 */
2650 2650 ndi_devi_enter(parent, &circ);
2651 2651
2652 2652 switch (op) {
2653 2653 case BUS_UNCONFIG_ONE:
2654 2654 /*
2655 2655 * Nothing special required here
2656 2656 */
2657 2657 if (pshot_debug) {
2658 2658 cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2659 2659 " BUS_UNCONFIG_ONE\n", ddi_get_instance(parent));
2660 2660 }
2661 2661 break;
2662 2662
2663 2663 case BUS_UNCONFIG_DRIVER:
2664 2664 if (pshot_debug > 0) {
2665 2665 major = (major_t)(uintptr_t)arg;
2666 2666 cmn_err(CE_CONT,
2667 2667 "pshot%d: BUS_UNCONFIG_DRIVER: %s\n",
2668 2668 ddi_get_instance(parent),
2669 2669 ddi_major_to_name(major));
2670 2670 }
2671 2671 break;
2672 2672
2673 2673 case BUS_UNCONFIG_ALL:
2674 2674 if (pshot_debug) {
2675 2675 cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2676 2676 " BUS_UNCONFIG_ALL\n", ddi_get_instance(parent));
2677 2677 }
2678 2678 break;
2679 2679
2680 2680 default:
2681 2681 if (pshot_debug) {
2682 2682 cmn_err(CE_CONT, "pshot%d: bus_unconfig: DEFAULT\n",
2683 2683 ddi_get_instance(parent));
2684 2684 }
2685 2685 rval = NDI_FAILURE;
2686 2686 }
2687 2687
2688 2688 if (rval == NDI_SUCCESS)
2689 2689 rval = ndi_busop_bus_unconfig(parent, flags, op, arg);
2690 2690
2691 2691 ndi_devi_exit(parent, circ);
2692 2692
2693 2693 if (pshot_debug)
2694 2694 cmn_err(CE_CONT, "pshot%d: bus_unconfig %s\n",
2695 2695 ddi_get_instance(parent),
2696 2696 (rval == NDI_SUCCESS) ? "ok" : "failed");
2697 2697
2698 2698 return (rval);
2699 2699 }
2700 2700
2701 2701 static dev_info_t *
2702 2702 pshot_findchild(dev_info_t *pdip, char *cname, char *caddr)
2703 2703 {
2704 2704 dev_info_t *dip;
2705 2705 char *addr;
2706 2706
2707 2707 ASSERT(cname != NULL && caddr != NULL);
2708 2708 ASSERT(DEVI_BUSY_OWNED(pdip));
2709 2709
2710 2710 for (dip = ddi_get_child(pdip); dip != NULL;
2711 2711 dip = ddi_get_next_sibling(dip)) {
2712 2712 if (strcmp(cname, ddi_node_name(dip)) != 0)
2713 2713 continue;
2714 2714
2715 2715 if ((addr = ddi_get_name_addr(dip)) == NULL) {
2716 2716 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
2717 2717 "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2718 2718 if (strcmp(caddr, addr) == 0) {
2719 2719 ddi_prop_free(addr);
2720 2720 return (dip);
2721 2721 }
2722 2722 ddi_prop_free(addr);
2723 2723 }
2724 2724 } else {
2725 2725 if (strcmp(caddr, addr) == 0)
2726 2726 return (dip);
2727 2727 }
2728 2728 }
2729 2729
2730 2730 return (NULL);
2731 2731 }
2732 2732
2733 2733 static void
2734 2734 pshot_nexus_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2735 2735 char *caddr)
2736 2736 {
2737 2737 char *extension;
2738 2738
2739 2739 /*
2740 2740 * extract the address extension
2741 2741 */
2742 2742 extension = strstr(caddr, ",");
2743 2743 if (extension != NULL) {
2744 2744 ++extension;
2745 2745 } else {
2746 2746 extension = "null";
2747 2747 }
2748 2748
2749 2749 /*
2750 2750 * Create the "pm-want-child-notification?" property for all
2751 2751 * nodes that do not have the "pm_strict" or "nopm_strict"
2752 2752 * extension
2753 2753 */
2754 2754 if (strcmp(extension, "pm_strict") != 0 &&
2755 2755 strcmp(extension, "nopm_strict") != 0) {
2756 2756 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2757 2757 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2758 2758 "pm-want-child-notification?") == 0) {
2759 2759 if (pshot_debug) {
2760 2760 cmn_err(CE_CONT, "pshot%d:"
2761 2761 " nexus_properties:\n\tcreate the"
2762 2762 " \"pm-want-child-notification?\""
2763 2763 " property for %s@%s\n",
2764 2764 ddi_get_instance(parent), cname, caddr);
2765 2765 }
2766 2766 if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2767 2767 "pm-want-child-notification?", NULL, 0)
2768 2768 != DDI_PROP_SUCCESS) {
2769 2769 cmn_err(CE_WARN, "pshot%d:"
2770 2770 " nexus_properties:\n\tunable to create"
2771 2771 " the \"pm-want-child-notification?\""
2772 2772 " property for %s@%s",
2773 2773 ddi_get_instance(parent), cname, caddr);
2774 2774 }
2775 2775 }
2776 2776 }
2777 2777
2778 2778 /*
2779 2779 * Create the "no-pm-components" property for all nodes
2780 2780 * with extension "nopm" or "nopm_strict"
2781 2781 */
2782 2782 if (strcmp(extension, "nopm") == 0 ||
2783 2783 strcmp(extension, "nopm_strict") == 0) {
2784 2784 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2785 2785 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2786 2786 "no-pm-components") == 0) {
2787 2787 if (pshot_debug) {
2788 2788 cmn_err(CE_CONT, "pshot%d:"
2789 2789 " nexus_properties:\n\tcreate the"
2790 2790 " \"no-pm-components\""
2791 2791 " property for %s@%s\n",
2792 2792 ddi_get_instance(parent), cname, caddr);
2793 2793 }
2794 2794 if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2795 2795 "no-pm-components", NULL, 0)
2796 2796 != DDI_PROP_SUCCESS) {
2797 2797 cmn_err(CE_WARN, "pshot%d:"
2798 2798 " nexus_properties:\n\tunable to create"
2799 2799 " the \"no-pm-components\""
2800 2800 " property for %s@%s",
2801 2801 ddi_get_instance(parent), cname, caddr);
2802 2802 }
2803 2803 }
2804 2804 }
2805 2805 }
2806 2806
2807 2807 static void
2808 2808 pshot_leaf_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2809 2809 char *caddr)
2810 2810 {
2811 2811 char *extension;
2812 2812
2813 2813 /*
2814 2814 * extract the address extension
2815 2815 */
2816 2816 extension = strstr(caddr, ",");
2817 2817 if (extension != NULL) {
2818 2818 ++extension;
2819 2819 } else {
2820 2820 extension = "null";
2821 2821 }
2822 2822
2823 2823 /*
2824 2824 * Create the "no-involuntary-power-cycles" property for
2825 2825 * all leaf nodes with extension "no_invol"
2826 2826 */
2827 2827 if (strcmp(extension, "no_invol") == 0) {
2828 2828 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2829 2829 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2830 2830 "no-involuntary-power-cycles") == 0) {
2831 2831 if (pshot_debug) {
2832 2832 cmn_err(CE_CONT, "pshot%d:"
2833 2833 " leaf_properties:\n\tcreate the"
2834 2834 " \"no-involuntary-power-cycles\""
2835 2835 " property for %s@%s\n",
2836 2836 ddi_get_instance(parent), cname, caddr);
2837 2837 }
2838 2838 if (ddi_prop_create(DDI_DEV_T_NONE, child,
2839 2839 DDI_PROP_CANSLEEP,
2840 2840 "no-involuntary-power-cycles", NULL, 0)
2841 2841 != DDI_PROP_SUCCESS) {
2842 2842 cmn_err(CE_WARN, "pshot%d:"
2843 2843 " leaf_properties:\n\tunable to create the"
2844 2844 " \"no-involuntary-power-cycles\""
2845 2845 " property for %s@%s",
2846 2846 ddi_get_instance(parent), cname, caddr);
2847 2847 }
2848 2848 }
2849 2849 }
2850 2850
2851 2851 /*
2852 2852 * Create the "dependency-property" property for all leaf
2853 2853 * nodes with extension "dep_prop"
2854 2854 * to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl
2855 2855 */
2856 2856 if (strcmp(extension, "dep_prop") == 0) {
2857 2857 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2858 2858 (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2859 2859 "dependency-property") == 0) {
2860 2860 if (pshot_debug) {
2861 2861 cmn_err(CE_CONT, "pshot%d:"
2862 2862 " leaf_properties:\n\tcreate the"
2863 2863 " \"dependency-property\""
2864 2864 " property for %s@%s\n",
2865 2865 ddi_get_instance(parent), cname, caddr);
2866 2866 }
2867 2867 if (ddi_prop_create(DDI_DEV_T_NONE, child,
2868 2868 DDI_PROP_CANSLEEP, "dependency-property", NULL, 0)
2869 2869 != DDI_PROP_SUCCESS) {
2870 2870 cmn_err(CE_WARN, "pshot%d:"
2871 2871 " leaf_properties:\n\tunable to create the"
2872 2872 " \"dependency-property\" property for"
2873 2873 " %s@%s", ddi_get_instance(parent),
2874 2874 cname, caddr);
2875 2875 }
2876 2876 }
2877 2877 }
2878 2878 }
2879 2879
2880 2880 /*
2881 2881 * BUS_CONFIG_ONE: setup a child nexus instance.
2882 2882 */
2883 2883 static int
2884 2884 pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr)
2885 2885 {
2886 2886 dev_info_t *child;
2887 2887 int rval;
2888 2888
2889 2889 ASSERT(parent != 0);
2890 2890 ASSERT(cname != NULL);
2891 2891 ASSERT(caddr != NULL);
2892 2892
2893 2893 child = pshot_findchild(parent, cname, caddr);
2894 2894 if (child) {
2895 2895 if (pshot_debug) {
2896 2896 cmn_err(CE_CONT,
2897 2897 "pshot%d: bus_config one %s@%s found\n",
2898 2898 ddi_get_instance(parent), cname, caddr);
2899 2899 }
2900 2900
2901 2901 /*
2902 2902 * create the "pm-want-child-notification?" property
2903 2903 * for this child, if it doesn't already exist
2904 2904 */
2905 2905 (void) pshot_nexus_properties(parent, child, cname, caddr);
2906 2906
2907 2907 return (NDI_SUCCESS);
2908 2908 }
2909 2909
2910 2910 ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2911 2911 ASSERT(child != NULL);
2912 2912
2913 2913 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2914 2914 "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2915 2915 cmn_err(CE_WARN, "pshot%d: _prop_update %s@%s failed",
2916 2916 ddi_get_instance(parent), cname, caddr);
2917 2917 (void) ndi_devi_free(child);
2918 2918 return (NDI_FAILURE);
2919 2919 }
2920 2920
2921 2921 rval = ndi_devi_bind_driver(child, 0);
2922 2922 if (rval != NDI_SUCCESS) {
2923 2923 cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
2924 2924 ddi_get_instance(parent), cname);
2925 2925 (void) ndi_devi_free(child);
2926 2926 return (NDI_FAILURE);
2927 2927 }
2928 2928
2929 2929 /*
2930 2930 * create the "pm-want-child-notification?" property
2931 2931 */
2932 2932 (void) pshot_nexus_properties(parent, child, cname, caddr);
2933 2933
2934 2934 return (NDI_SUCCESS);
2935 2935 }
2936 2936
2937 2937 /*
2938 2938 * BUS_CONFIG_ONE: setup a child leaf device instance.
2939 2939 * for testing purposes, we will create nodes of a variety of types.
2940 2940 */
2941 2941 static int
2942 2942 pshot_bus_config_setup_leaf(dev_info_t *parent, char *cname, char *caddr)
2943 2943 {
2944 2944 dev_info_t *child;
2945 2945 char *compat_name;
2946 2946 char *nodetype;
2947 2947 int rval;
2948 2948 int i;
2949 2949
2950 2950 ASSERT(parent != 0);
2951 2951 ASSERT(cname != NULL);
2952 2952 ASSERT(caddr != NULL);
2953 2953
2954 2954 /*
2955 2955 * if we already have a node with this name, return it
2956 2956 */
2957 2957 if ((child = pshot_findchild(parent, cname, caddr)) != NULL) {
2958 2958 /*
2959 2959 * create the "no-involuntary-power-cycles" or
2960 2960 * the "dependency-property" property, if they
2961 2961 * don't already exit
2962 2962 */
2963 2963 (void) pshot_leaf_properties(parent, child, cname, caddr);
2964 2964
2965 2965 return (NDI_SUCCESS);
2966 2966 }
2967 2967
2968 2968 ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2969 2969 ASSERT(child != NULL);
2970 2970
2971 2971 if (ndi_prop_update_string(DDI_DEV_T_NONE, child, "bus-addr",
2972 2972 caddr) != DDI_PROP_SUCCESS) {
2973 2973 (void) ndi_devi_free(child);
2974 2974 return (NDI_FAILURE);
2975 2975 }
2976 2976
2977 2977 /*
2978 2978 * test compatible naming
2979 2979 * if the child nodename is "cdisk", attach the list of compatible
2980 2980 * named disks
2981 2981 */
2982 2982 if (strcmp(cname, pshot_compat_diskname) == 0) {
2983 2983 if ((ndi_prop_update_string_array(DDI_DEV_T_NONE,
2984 2984 child, "compatible", (char **)pshot_compat_psramdisks,
2985 2985 5)) != DDI_PROP_SUCCESS) {
2986 2986 (void) ndi_devi_free(child);
2987 2987 return (NDI_FAILURE);
2988 2988 }
2989 2989 } else {
2990 2990 for (i = 0; i < pshot_devices_len && pshot_devices[i].name;
2991 2991 i++) {
2992 2992 if (strcmp(cname, pshot_devices[i].name) == 0) {
2993 2993 compat_name = pshot_devices[i].compat;
2994 2994 nodetype = pshot_devices[i].nodetype;
2995 2995 if (pshot_debug) {
2996 2996 cmn_err(CE_CONT, "pshot%d: %s %s %s\n",
2997 2997 ddi_get_instance(parent), cname,
2998 2998 compat_name, nodetype);
2999 2999 }
3000 3000 if ((ndi_prop_update_string_array(
3001 3001 DDI_DEV_T_NONE, child, "compatible",
3002 3002 &compat_name, 1)) != DDI_PROP_SUCCESS) {
3003 3003 (void) ndi_devi_free(child);
3004 3004 return (NDI_FAILURE);
3005 3005 }
3006 3006 if ((ndi_prop_update_string(
3007 3007 DDI_DEV_T_NONE, child, "node-type",
3008 3008 nodetype)) != DDI_PROP_SUCCESS) {
3009 3009 (void) ndi_devi_free(child);
3010 3010 return (NDI_FAILURE);
3011 3011 }
3012 3012 }
3013 3013 }
3014 3014 }
3015 3015
3016 3016 rval = ndi_devi_bind_driver(child, 0);
3017 3017 if (rval != NDI_SUCCESS) {
3018 3018 cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
3019 3019 ddi_get_instance(parent), cname);
3020 3020 (void) ndi_devi_free(child);
3021 3021 return (NDI_FAILURE);
3022 3022 }
3023 3023
3024 3024 /*
3025 3025 * create the "no-involuntary-power-cycles" or
3026 3026 * the "dependency-property" property
3027 3027 */
3028 3028 (void) pshot_leaf_properties(parent, child, cname, caddr);
3029 3029
3030 3030 return (NDI_SUCCESS);
3031 3031 }
3032 3032
3033 3033 /*
3034 3034 * Handle some special cases for testing bus_config via pshot
3035 3035 *
3036 3036 * Match these special address formats to behavior:
3037 3037 *
3038 3038 * err.* - induce bus_config error
3039 3039 * delay - induce 1 second of bus_config delay time
3040 3040 * delay,n - induce n seconds of bus_config delay time
3041 3041 * wait - induce 1 second of bus_config wait time
3042 3042 * wait,n - induce n seconds of bus_config wait time
3043 3043 * failinit.* - induce error at INITCHILD
3044 3044 * failprobe.* - induce error at probe
3045 3045 * failattach.* - induce error at attach
3046 3046 */
3047 3047 /*ARGSUSED*/
3048 3048 static int
3049 3049 pshot_bus_config_test_specials(dev_info_t *parent, char *devname,
3050 3050 char *cname, char *caddr)
3051 3051 {
3052 3052 char *p;
3053 3053 int n;
3054 3054
3055 3055 if (strncmp(caddr, "err", 3) == 0) {
3056 3056 if (pshot_debug)
3057 3057 cmn_err(CE_CONT,
3058 3058 "pshot%d: %s forced failure\n",
3059 3059 ddi_get_instance(parent), devname);
3060 3060 return (NDI_FAILURE);
3061 3061 }
3062 3062
3063 3063 /*
3064 3064 * The delay and wait strings have the same effect.
3065 3065 * The "wait[,]" support should be removed once the
3066 3066 * devfs test suites are fixed.
3067 3067 * NOTE: delay should not be called from interrupt context
3068 3068 */
3069 3069 ASSERT(!servicing_interrupt());
3070 3070
3071 3071 if (strncmp(caddr, "delay,", 6) == 0) {
3072 3072 p = caddr+6;
3073 3073 n = stoi(&p);
3074 3074 if (*p != 0)
3075 3075 n = 1;
3076 3076 if (pshot_debug)
3077 3077 cmn_err(CE_CONT,
3078 3078 "pshot%d: %s delay %d second\n",
3079 3079 ddi_get_instance(parent), devname, n);
3080 3080 delay(n * drv_usectohz(1000000));
3081 3081 } else if (strncmp(caddr, "delay", 5) == 0) {
3082 3082 if (pshot_debug)
3083 3083 cmn_err(CE_CONT,
3084 3084 "pshot%d: %s delay 1 second\n",
3085 3085 ddi_get_instance(parent), devname);
3086 3086 delay(drv_usectohz(1000000));
3087 3087 } else if (strncmp(caddr, "wait,", 5) == 0) {
3088 3088 p = caddr+5;
3089 3089 n = stoi(&p);
3090 3090 if (*p != 0)
3091 3091 n = 1;
3092 3092 if (pshot_debug)
3093 3093 cmn_err(CE_CONT,
3094 3094 "pshot%d: %s wait %d second\n",
3095 3095 ddi_get_instance(parent), devname, n);
3096 3096 delay(n * drv_usectohz(1000000));
3097 3097 } else if (strncmp(caddr, "wait", 4) == 0) {
3098 3098 if (pshot_debug)
3099 3099 cmn_err(CE_CONT,
3100 3100 "pshot%d: %s wait 1 second\n",
3101 3101 ddi_get_instance(parent), devname);
3102 3102 delay(drv_usectohz(1000000));
3103 3103 }
3104 3104
3105 3105 return (NDI_SUCCESS);
3106 3106 }
3107 3107
3108 3108 /*
3109 3109 * translate nodetype name to actual value
3110 3110 */
3111 3111 static char *
3112 3112 pshot_str2nt(char *str)
3113 3113 {
3114 3114 int i;
3115 3115
3116 3116 for (i = 0; pshot_nodetypes[i].name; i++) {
3117 3117 if (strcmp(pshot_nodetypes[i].name, str) == 0)
3118 3118 return (pshot_nodetypes[i].val);
3119 3119 }
3120 3120 return (NULL);
3121 3121 }
3122 3122
3123 3123 /*
3124 3124 * grows array pointed to by <dstp>, with <src> data
3125 3125 * <dstlen> = # elements of the original <*dstp>
3126 3126 * <srclen> = # elements of <src>
3127 3127 *
3128 3128 * on success, returns 0 and a pointer to the new array through <dstp> with
3129 3129 * <srclen> + <dstlen> number of elements;
3130 3130 * else returns non-zero
3131 3131 *
3132 3132 * a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen>
3133 3133 */
3134 3134 static int
3135 3135 pshot_devices_grow(pshot_device_t **dstp, size_t dstlen,
3136 3136 const pshot_device_t *src, size_t srclen)
3137 3137 {
3138 3138 size_t i;
3139 3139 pshot_device_t *newdst;
3140 3140
3141 3141 newdst = kmem_alloc((srclen + dstlen) * sizeof (*src),
3142 3142 KM_SLEEP);
3143 3143
3144 3144 /* keep old pointers and dup new ones */
3145 3145 if (*dstp)
3146 3146 bcopy(*dstp, newdst, dstlen * sizeof (*src));
3147 3147 for (i = 0; i < srclen; i++) {
3148 3148 newdst[i + dstlen].name =
3149 3149 i_ddi_strdup(src[i].name, KM_SLEEP);
3150 3150
3151 3151 newdst[i + dstlen].nodetype =
3152 3152 i_ddi_strdup(src[i].nodetype, KM_SLEEP);
3153 3153
3154 3154 newdst[i + dstlen].compat =
3155 3155 i_ddi_strdup(src[i].compat, KM_SLEEP);
3156 3156 }
3157 3157
3158 3158 /* do last */
3159 3159 if (*dstp)
3160 3160 kmem_free(*dstp, dstlen * sizeof (*src));
3161 3161 *dstp = newdst;
3162 3162 return (0);
3163 3163 }
3164 3164
3165 3165 /*
3166 3166 * free a pshot_device_t array <dp> with <len> elements
3167 3167 * null pointers within the elements are ok
3168 3168 */
3169 3169 static void
3170 3170 pshot_devices_free(pshot_device_t *dp, size_t len)
3171 3171 {
3172 3172 size_t i;
3173 3173
3174 3174 for (i = 0; i < len; i++) {
3175 3175 if (dp[i].name)
3176 3176 kmem_free(dp[i].name, strlen(dp[i].name) + 1);
3177 3177 if (dp[i].nodetype)
3178 3178 kmem_free(dp[i].nodetype, strlen(dp[i].nodetype) + 1);
3179 3179 if (dp[i].compat)
3180 3180 kmem_free(dp[i].compat, strlen(dp[i].compat) + 1);
3181 3181 }
3182 3182 kmem_free(dp, len * sizeof (*dp));
3183 3183 }
3184 3184
3185 3185 /*
3186 3186 * returns an array of pshot_device_t parsed from <dip>'s properties
3187 3187 *
3188 3188 * property structure (i.e. pshot.conf) for pshot:
3189 3189 *
3190 3190 * corresponding | pshot_device_t array elements
3191 3191 * pshot_device_t |
3192 3192 * member by prop name | [0] [1] [2]
3193 3193 * ----------------------|--------------|-------------|-----------------------
3194 3194 * <PSHOT_PROP_DEVNAME> ="disk", "tape", "testdev";
3195 3195 * <PSHOT_PROP_DEVNT> ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype";
3196 3196 * <PSHOT_PROP_DEVCOMPAT>="testdrv", "testdrv", "testdrv";
3197 3197 *
3198 3198 *
3199 3199 * if any of these properties are specified, then:
3200 3200 * - all the members must be specified
3201 3201 * - the number of elements for each string array property must be the same
3202 3202 * - no empty strings allowed
3203 3203 * - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in
3204 3204 * sys/sunddi.h
3205 3205 *
3206 3206 * NOTE: the pshot_nodetypes[] table should be kept in sync with the list
3207 3207 * of ddi nodetypes. It's not normally critical to always be in sync so
3208 3208 * keeping this up-to-date can usually be done "on-demand".
3209 3209 *
3210 3210 * if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed.
3211 3211 * these will be duplicated verbatim
3212 3212 */
3213 3213 static pshot_device_t *
3214 3214 pshot_devices_from_props(dev_info_t *dip, size_t *lenp, int flags)
3215 3215 {
3216 3216 pshot_device_t *devarr = NULL;
3217 3217 char **name_arr = NULL, **nt_arr = NULL, **compat_arr = NULL;
3218 3218 uint_t name_arr_len, nt_arr_len, compat_arr_len;
3219 3219 uint_t i;
3220 3220 char *str;
3221 3221
3222 3222 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3223 3223 PSHOT_PROP_DEVNAME, &name_arr, &name_arr_len) !=
3224 3224 DDI_PROP_SUCCESS)
3225 3225 name_arr = NULL;
3226 3226
3227 3227 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3228 3228 PSHOT_PROP_DEVNT, &nt_arr, &nt_arr_len) !=
3229 3229 DDI_PROP_SUCCESS)
3230 3230 nt_arr = NULL;
3231 3231
3232 3232 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3233 3233 PSHOT_PROP_DEVCOMPAT, &compat_arr, &compat_arr_len) !=
3234 3234 DDI_PROP_SUCCESS)
3235 3235 compat_arr = NULL;
3236 3236
3237 3237 /*
3238 3238 * warn about any incorrect usage, if specified
3239 3239 */
3240 3240 if (!(name_arr || nt_arr || compat_arr))
3241 3241 return (NULL);
3242 3242
3243 3243 if (!(name_arr && nt_arr && compat_arr) ||
3244 3244 (name_arr_len != nt_arr_len) ||
3245 3245 (name_arr_len != compat_arr_len))
3246 3246 goto FAIL;
3247 3247
3248 3248 for (i = 0; i < name_arr_len; i++) {
3249 3249 if (*name_arr[i] == '\0' ||
3250 3250 *nt_arr[i] == '\0' ||
3251 3251 *compat_arr[i] == '\0')
3252 3252 goto FAIL;
3253 3253 }
3254 3254
3255 3255 devarr = kmem_zalloc(name_arr_len * sizeof (*devarr), KM_SLEEP);
3256 3256 for (i = 0; i < name_arr_len; i++) {
3257 3257 devarr[i].name = i_ddi_strdup(name_arr[i], KM_SLEEP);
3258 3258 devarr[i].compat = i_ddi_strdup(compat_arr[i], KM_SLEEP);
3259 3259
3260 3260 if ((str = pshot_str2nt(nt_arr[i])) == NULL)
3261 3261 if (flags & PSHOT_DEV_ANYNT)
3262 3262 str = nt_arr[i];
3263 3263 else
3264 3264 goto FAIL;
3265 3265 devarr[i].nodetype = i_ddi_strdup(str, KM_SLEEP);
3266 3266 }
3267 3267 ddi_prop_free(name_arr);
3268 3268 ddi_prop_free(nt_arr);
3269 3269 ddi_prop_free(compat_arr);
3270 3270
3271 3271 /* set <*lenp> ONLY on success */
3272 3272 *lenp = name_arr_len;
3273 3273
3274 3274 return (devarr);
3275 3275 /*NOTREACHED*/
3276 3276 FAIL:
3277 3277 cmn_err(CE_WARN, "malformed device specification property");
3278 3278 if (name_arr)
3279 3279 ddi_prop_free(name_arr);
3280 3280 if (nt_arr)
3281 3281 ddi_prop_free(nt_arr);
3282 3282 if (compat_arr)
3283 3283 ddi_prop_free(compat_arr);
3284 3284 if (devarr)
3285 3285 pshot_devices_free(devarr, name_arr_len);
3286 3286 return (NULL);
3287 3287 }
3288 3288
3289 3289 /*
3290 3290 * if global <pshot_devices> was not set up already (i.e. is NULL):
3291 3291 * sets up global <pshot_devices> and <pshot_devices_len>,
3292 3292 * using device properties from <dip> and global <pshot_stock_devices>.
3293 3293 * device properties, if any, overrides pshot_stock_devices.
3294 3294 *
3295 3295 * returns 0 on success (or if pshot_devices already set up)
3296 3296 *
3297 3297 * INTERNAL LOCKING: <pshot_devices_lock>
3298 3298 */
3299 3299 static int
3300 3300 pshot_devices_setup(dev_info_t *dip)
3301 3301 {
3302 3302 pshot_device_t *newdevs = NULL;
3303 3303 size_t newdevs_len = 0;
3304 3304 int rv = 0;
3305 3305
3306 3306 mutex_enter(&pshot_devices_lock);
3307 3307 if (pshot_devices != NULL)
3308 3308 goto FAIL;
3309 3309
3310 3310 ASSERT(pshot_devices_len == 0);
3311 3311
3312 3312 newdevs = pshot_devices_from_props(dip, &newdevs_len, PSHOT_DEV_ANYNT);
3313 3313 rv = pshot_devices_grow(&newdevs, newdevs_len, pshot_stock_devices,
3314 3314 PSHOT_N_STOCK_DEVICES);
3315 3315 if (rv != 0) {
3316 3316 cmn_err(CE_WARN, "pshot_devices_setup: pshot_devices_grow "
3317 3317 "failed");
3318 3318 goto FAIL;
3319 3319 }
3320 3320 newdevs_len += PSHOT_N_STOCK_DEVICES;
3321 3321
3322 3322 pshot_devices = newdevs;
3323 3323 pshot_devices_len = newdevs_len;
3324 3324 rv = 0;
3325 3325 FAIL:
3326 3326 if (rv && newdevs)
3327 3327 pshot_devices_free(newdevs, newdevs_len);
3328 3328 mutex_exit(&pshot_devices_lock);
3329 3329 return (rv);
3330 3330 }
3331 3331
3332 3332
3333 3333 #ifdef NOTNEEDED
3334 3334 /* ARGSUSED */
3335 3335 static int
3336 3336 pshot_probe_family(dev_info_t *self, ddi_probe_method_t probe_how,
3337 3337 dev_info_t **return_dip)
3338 3338 {
3339 3339 char name[64];
3340 3340 uint_t bus_id;
3341 3341 dev_info_t *child;
3342 3342
3343 3343 for (bus_id = 10; bus_id < 20; bus_id++) {
3344 3344 (void) sprintf(name, "%d", bus_id);
3345 3345 if ((ndi_devi_alloc(self, "psramd", DEVI_SID_NODEID,
3346 3346 &child)) != NDI_SUCCESS) {
3347 3347 return (DDI_FAILURE);
3348 3348 }
3349 3349
3350 3350 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
3351 3351 "bus-addr", name) != DDI_PROP_SUCCESS) {
3352 3352 (void) ndi_devi_free(child);
3353 3353 if (return_dip != NULL)
3354 3354 *return_dip = (dev_info_t *)NULL;
3355 3355 return (DDI_FAILURE);
3356 3356 }
3357 3357
3358 3358 if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
3359 3359 return (DDI_FAILURE);
3360 3360 }
3361 3361 }
3362 3362 return (DDI_SUCCESS);
3363 3363 }
3364 3364
3365 3365 static int
3366 3366 strtoi(char *str)
3367 3367 {
3368 3368 int c;
3369 3369 int val;
3370 3370
3371 3371 for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
3372 3372 val *= 10;
3373 3373 val += c - '0';
3374 3374 }
3375 3375 return (val);
3376 3376 }
3377 3377
3378 3378 #endif
3379 3379
3380 3380 static void
3381 3381 pshot_setup_autoattach(dev_info_t *devi)
3382 3382 {
3383 3383 dev_info_t *l1child, *l2child;
3384 3384 int rv;
3385 3385
3386 3386 rv = ndi_devi_alloc(devi, "pshot", DEVI_SID_NODEID, &l1child);
3387 3387 if (rv == NDI_SUCCESS) {
3388 3388 (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3389 3389 "bus-addr", "0");
3390 3390 rv = ndi_devi_alloc(l1child, "port", DEVI_SID_NODEID,
3391 3391 &l2child);
3392 3392 if (rv == NDI_SUCCESS)
3393 3393 (void) ndi_prop_update_string(DDI_DEV_T_NONE,
3394 3394 l2child, "bus-addr", "99");
3395 3395 }
3396 3396
3397 3397 rv = ndi_devi_alloc(devi, "port", DEVI_SID_NODEID, &l1child);
3398 3398 if (rv == NDI_SUCCESS)
3399 3399 (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3400 3400 "bus-addr", "99");
3401 3401
3402 3402 rv = ndi_devi_alloc(devi, "gen_drv", DEVI_SID_NODEID, &l1child);
3403 3403 if (rv == NDI_SUCCESS)
3404 3404 (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3405 3405 "bus-addr", "99");
3406 3406
3407 3407 rv = ndi_devi_alloc(devi, "no_driver", DEVI_SID_NODEID, &l1child);
3408 3408 if (rv == NDI_SUCCESS)
3409 3409 (void) ndi_devi_alloc(l1child, "no_driver", DEVI_SID_NODEID,
3410 3410 &l2child);
3411 3411 }
3412 3412
3413 3413 #ifdef PRUNE_SNUBS
3414 3414
3415 3415 #define PRUNE_THIS_NODE(d) (((d)->devi_node_name != NULL) && \
3416 3416 (DEVI_PROM_NODE((d)->devi_nodeid)) && \
3417 3417 ((d)->devi_addr == NULL))
3418 3418 /*
3419 3419 * test code to remove OBP nodes that have not attached
3420 3420 */
3421 3421 static void
3422 3422 prune_snubs(const char *name)
3423 3423 {
3424 3424 struct dev_info *nex_dip, *cdip, *cndip;
3425 3425 int maj;
3426 3426 int rv;
3427 3427
3428 3428 maj = ddi_name_to_major((char *)name);
3429 3429 if (maj != -1) {
3430 3430 nex_dip = (struct dev_info *)devnamesp[maj].dn_head;
3431 3431 while (nex_dip != NULL) {
3432 3432 cndip = ddi_get_child(nex_dip);
3433 3433 while ((cdip = cndip) != NULL) {
3434 3434 cndip = cdip->devi_sibling;
3435 3435 if (PRUNE_THIS_NODE(cdip)) {
3436 3436 cmn_err(CE_NOTE,
3437 3437 "parent %s@%s pruning node %s",
3438 3438 nex_dip->devi_node_name,
3439 3439 nex_dip->devi_addr,
3440 3440 cdip->devi_node_name);
3441 3441 rv = ndi_devi_offline(cdip,
3442 3442 NDI_DEVI_REMOVE);
3443 3443 if (rv != NDI_SUCCESS)
3444 3444 cmn_err(CE_NOTE,
3445 3445 "failed to prune node, "
3446 3446 "err %d", rv);
3447 3447 }
3448 3448 }
3449 3449 nex_dip = nex_dip->devi_next;
3450 3450 }
3451 3451 }
3452 3452 }
3453 3453
3454 3454 #endif /* PRUBE_SNUBS */
3455 3455
3456 3456 #ifdef KERNEL_DEVICE_TREE_WALKER
3457 3457 static kthread_id_t pwt;
3458 3458 static kmutex_t pwl;
3459 3459 static kcondvar_t pwcv;
3460 3460
3461 3461 static void
3462 3462 pshot_walk_tree()
3463 3463 {
3464 3464 static int pshot_devnode(dev_info_t *dip, void * arg);
3465 3465
3466 3466 dev_info_t *root = ddi_root_node();
3467 3467 ddi_walk_devs(root, pshot_devnode, NULL);
3468 3468 }
3469 3469
3470 3470 static void
3471 3471 pshot_walk_thread()
3472 3472 {
3473 3473 static void pshot_timeout(void *arg);
3474 3474 static kthread_id_t pwt;
3475 3475
3476 3476 pwt = curthread;
3477 3477 mutex_init(&pwl, NULL, MUTEX_DRIVER, NULL);
3478 3478 cv_init(&pwcv, NULL, CV_DRIVER, NULL);
3479 3479
3480 3480 while (1) {
3481 3481 pshot_walk_tree();
3482 3482 mutex_enter(&pwl);
3483 3483 (void) timeout(pshot_timeout, NULL, 5 * drv_usectohz(1000000));
3484 3484 cv_wait(&pwcv, &pwl);
3485 3485 mutex_exit(&pwl);
3486 3486 }
3487 3487 }
3488 3488
3489 3489 static void
3490 3490 pshot_timeout(void *arg)
3491 3491 {
3492 3492 mutex_enter(&pwl);
3493 3493 cv_signal(&pwcv);
3494 3494 mutex_exit(&pwl);
3495 3495 }
3496 3496
3497 3497 static int
3498 3498 pshot_devnode(dev_info_t *dip, void *arg)
3499 3499 {
3500 3500 dev_info_t *f_dip;
3501 3501
3502 3502 if (dip != ddi_root_node()) {
3503 3503 f_dip = ndi_devi_find((dev_info_t *)DEVI(dip)->devi_parent,
3504 3504 DEVI(dip)->devi_node_name, DEVI(dip)->devi_addr);
3505 3505 if (f_dip != dip) {
3506 3506 cmn_err(CE_NOTE, "!pshot_devnode: failed lookup"
3507 3507 "node (%s/%s@%s)\n",
3508 3508 DEVI(DEVI(dip)->devi_parent)->devi_node_name,
3509 3509 (DEVI(dip)->devi_node_name ?
3510 3510 DEVI(dip)->devi_node_name : "NULL"),
3511 3511 (DEVI(dip)->devi_addr ? DEVI(dip)->devi_addr :
3512 3512 "NULL"));
3513 3513 }
3514 3514 }
3515 3515 return (DDI_WALK_CONTINUE);
3516 3516 }
3517 3517 #endif /* KERNEL_DEVICE_TREE_WALKER */
3518 3518
3519 3519 #ifdef DEBUG
3520 3520 static void
3521 3521 pshot_event_cb_test(dev_info_t *dip, ddi_eventcookie_t cookie,
3522 3522 void *arg, void *bus_impldata)
3523 3523 {
3524 3524 pshot_t *softstate = (pshot_t *)arg;
3525 3525 int event_tag;
3526 3526
3527 3527 /* look up the event */
3528 3528 event_tag = NDI_EVENT_TAG(cookie);
3529 3529 cmn_err(CE_CONT, "pshot_event_cb_test:\n\t"
3530 3530 "dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t"
3531 3531 "arg = 0x%p bus_impl = 0x%p\n",
3532 3532 (void *)dip, (void *)cookie, NDI_EVENT_NAME(cookie),
3533 3533 event_tag, (void *)softstate, (void *)bus_impldata);
3534 3534
3535 3535 }
3536 3536
3537 3537 static void
3538 3538 pshot_event_test(void *arg)
3539 3539 {
3540 3540 pshot_t *pshot = (pshot_t *)arg;
3541 3541 ndi_event_hdl_t hdl;
3542 3542 ndi_event_set_t events;
3543 3543 int i, rval;
3544 3544
3545 3545 (void) ndi_event_alloc_hdl(pshot->dip, NULL, &hdl, NDI_SLEEP);
3546 3546
3547 3547 events.ndi_events_version = NDI_EVENTS_REV1;
3548 3548 events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3549 3549 events.ndi_event_defs = pshot_test_events;
3550 3550
3551 3551 cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3552 3552 delay(drv_usectohz(1000000));
3553 3553 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3554 3554 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3555 3555
3556 3556 cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3557 3557 delay(drv_usectohz(1000000));
3558 3558 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3559 3559 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3560 3560
3561 3561 cmn_err(CE_CONT, "pshot: unbinding all events\n");
3562 3562 delay(drv_usectohz(1000000));
3563 3563 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3564 3564 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3565 3565
3566 3566
3567 3567 cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3568 3568 delay(drv_usectohz(1000000));
3569 3569 events.ndi_n_events = 1;
3570 3570 events.ndi_event_defs = pshot_test_events_high;
3571 3571 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3572 3572 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3573 3573
3574 3574 cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3575 3575 delay(drv_usectohz(1000000));
3576 3576 events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3577 3577 events.ndi_event_defs = pshot_test_events;
3578 3578 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3579 3579 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3580 3580
3581 3581 cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3582 3582 delay(drv_usectohz(1000000));
3583 3583 events.ndi_n_events = 1;
3584 3584 events.ndi_event_defs = pshot_test_events_high;
3585 3585 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3586 3586 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3587 3587
3588 3588 cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3589 3589 delay(drv_usectohz(1000000));
3590 3590 events.ndi_n_events = 1;
3591 3591 events.ndi_event_defs = pshot_test_events_high;
3592 3592 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3593 3593 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3594 3594
3595 3595 cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3596 3596 delay(drv_usectohz(1000000));
3597 3597 events.ndi_n_events = 1;
3598 3598 events.ndi_event_defs = pshot_test_events_high;
3599 3599 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3600 3600 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3601 3601
3602 3602 cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3603 3603 delay(drv_usectohz(1000000));
3604 3604 events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3605 3605 events.ndi_event_defs = pshot_test_events;
3606 3606 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3607 3607 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3608 3608
3609 3609 cmn_err(CE_CONT, "pshot: unbinding first 2 events\n");
3610 3610 delay(drv_usectohz(1000000));
3611 3611 events.ndi_n_events = 2;
3612 3612 events.ndi_event_defs = pshot_test_events;
3613 3613 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3614 3614 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3615 3615
3616 3616 cmn_err(CE_CONT, "pshot: unbinding first 2 events again\n");
3617 3617 delay(drv_usectohz(1000000));
3618 3618 events.ndi_n_events = 2;
3619 3619 events.ndi_event_defs = pshot_test_events;
3620 3620 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3621 3621 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3622 3622
3623 3623 cmn_err(CE_CONT, "pshot: unbinding middle 2 events\n");
3624 3624 delay(drv_usectohz(1000000));
3625 3625 events.ndi_n_events = 2;
3626 3626 events.ndi_event_defs = &pshot_test_events[4];
3627 3627 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3628 3628 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3629 3629
3630 3630 cmn_err(CE_CONT, "pshot: binding those 2 events back\n");
3631 3631 delay(drv_usectohz(1000000));
3632 3632 events.ndi_n_events = 2;
3633 3633 events.ndi_event_defs = &pshot_test_events[4];
3634 3634 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3635 3635 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3636 3636
3637 3637 cmn_err(CE_CONT, "pshot: unbinding 2 events\n");
3638 3638 delay(drv_usectohz(1000000));
3639 3639 events.ndi_n_events = 2;
3640 3640 events.ndi_event_defs = &pshot_test_events[4];
3641 3641 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3642 3642 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3643 3643
3644 3644 cmn_err(CE_CONT, "pshot: unbinding all events\n");
3645 3645 delay(drv_usectohz(1000000));
3646 3646 events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3647 3647 events.ndi_event_defs = pshot_test_events;
3648 3648 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3649 3649 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3650 3650
3651 3651 cmn_err(CE_CONT, "pshot: unbinding 1 event\n");
3652 3652 delay(drv_usectohz(1000000));
3653 3653 events.ndi_n_events = 1;
3654 3654 events.ndi_event_defs = &pshot_test_events[2];
3655 3655 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3656 3656 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3657 3657
3658 3658 cmn_err(CE_CONT, "pshot: unbinding 1 event\n");
3659 3659 delay(drv_usectohz(1000000));
3660 3660 events.ndi_n_events = 1;
3661 3661 events.ndi_event_defs = &pshot_test_events[3];
3662 3662 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3663 3663 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3664 3664
3665 3665 cmn_err(CE_CONT, "pshot: unbinding 1 event\n");
3666 3666 delay(drv_usectohz(1000000));
3667 3667 events.ndi_n_events = 1;
3668 3668 events.ndi_event_defs = &pshot_test_events[6];
3669 3669 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3670 3670 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3671 3671
3672 3672 cmn_err(CE_CONT, "pshot: unbinding 1 event\n");
3673 3673 delay(drv_usectohz(1000000));
3674 3674 events.ndi_n_events = 1;
3675 3675 events.ndi_event_defs = &pshot_test_events[7];
3676 3676 rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3677 3677 cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3678 3678
3679 3679 events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3680 3680 events.ndi_event_defs = pshot_test_events;
3681 3681
3682 3682 cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3683 3683 delay(drv_usectohz(1000000));
3684 3684 rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3685 3685 cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3686 3686
3687 3687 cmn_err(CE_CONT, "pshot: adding 8 callbacks\n");
3688 3688 delay(drv_usectohz(1000000));
3689 3689 for (i = 0; i < 8; i++) {
3690 3690 rval = ndi_event_add_callback(hdl, pshot->dip,
3691 3691 ndi_event_tag_to_cookie(hdl,
3692 3692 pshot_test_events[i].ndi_event_tag),
3693 3693 pshot_event_cb_test,
3694 3694 (void *)(uintptr_t)pshot_test_events[i].ndi_event_tag,
3695 3695 NDI_SLEEP, &pshot->test_callback_cache[i]);
3696 3696 ASSERT(rval == NDI_SUCCESS);
3697 3697 }
3698 3698
3699 3699 cmn_err(CE_CONT, "pshot: event callbacks\n");
3700 3700
3701 3701 for (i = 10; i < 18; i++) {
3702 3702 ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3703 3703
3704 3704 rval = ndi_event_run_callbacks(hdl, pshot->dip, cookie,
3705 3705 (void *)hdl);
3706 3706
3707 3707 cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3708 3708 i, rval);
3709 3709 delay(drv_usectohz(1000000));
3710 3710 }
3711 3711
3712 3712 cmn_err(CE_CONT, "pshot: redo event callbacks\n");
3713 3713
3714 3714 for (i = 10; i < 18; i++) {
3715 3715 ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3716 3716
3717 3717 rval = ndi_event_run_callbacks(hdl,
3718 3718 pshot->dip, cookie, (void *)hdl);
3719 3719
3720 3720 cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3721 3721 i, rval);
3722 3722 delay(drv_usectohz(1000000));
3723 3723 }
3724 3724
3725 3725 cmn_err(CE_CONT, "pshot: removing 8 callbacks\n");
3726 3726 delay(drv_usectohz(1000000));
3727 3727
3728 3728 for (i = 0; i < 8; i++) {
3729 3729 (void) ndi_event_remove_callback(hdl,
3730 3730 pshot->test_callback_cache[i]);
3731 3731
3732 3732 pshot->test_callback_cache[i] = 0;
3733 3733 }
3734 3734
3735 3735 cmn_err(CE_CONT, "pshot: freeing handle with bound set\n");
3736 3736 delay(drv_usectohz(1000000));
3737 3737
3738 3738 rval = ndi_event_free_hdl(hdl);
3739 3739
3740 3740 ASSERT(rval == NDI_SUCCESS);
3741 3741
3742 3742 }
3743 3743
3744 3744 void
3745 3745 pshot_event_test_post_one(void *arg)
3746 3746 {
3747 3747 pshot_t *pshot = (pshot_t *)arg;
3748 3748 int rval;
3749 3749 ddi_eventcookie_t cookie;
3750 3750
3751 3751 cmn_err(CE_CONT, "pshot%d: pshot_event_post_one event\n",
3752 3752 pshot->instance);
3753 3753
3754 3754 if (ddi_get_eventcookie(pshot->dip, PSHOT_EVENT_NAME_BUS_TEST_POST,
3755 3755 &cookie) != DDI_SUCCESS) {
3756 3756 cmn_err(CE_NOTE, "pshot_bus_test_post cookie not found");
3757 3757 return;
3758 3758 }
3759 3759
3760 3760 rval = ndi_post_event(pshot->dip, pshot->dip, cookie, NULL);
3761 3761
3762 3762 cmn_err(CE_CONT, "pshot%d: pshot_event_post_one rval=%d\n",
3763 3763 pshot->instance, rval);
3764 3764
3765 3765 (void) timeout(pshot_event_test_post_one, (void *)pshot,
3766 3766 pshot->instance * drv_usectohz(60000000));
3767 3767
3768 3768 }
3769 3769 #endif /* DEBUG */
↓ open down ↓ |
3375 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX