Print this page
5253 kmem_alloc/kmem_zalloc won't fail with KM_SLEEP
5254 getrbuf won't fail with KM_SLEEP
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/pciex/hotplug/pcie_hp.c
+++ new/usr/src/uts/common/io/pciex/hotplug/pcie_hp.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * This file contains the common hotplug code that is used by Standard
29 29 * PCIe and PCI HotPlug Controller code.
30 30 *
31 31 * NOTE: This file is compiled and delivered through misc/pcie module.
32 32 */
33 33
34 34 #include <sys/types.h>
35 35 #include <sys/conf.h>
36 36 #include <sys/kmem.h>
37 37 #include <sys/debug.h>
38 38 #include <sys/vtrace.h>
39 39 #include <sys/autoconf.h>
40 40 #include <sys/varargs.h>
41 41 #include <sys/ddi_impldefs.h>
42 42 #include <sys/time.h>
43 43 #include <sys/note.h>
44 44 #include <sys/callb.h>
45 45 #include <sys/ddi.h>
46 46 #include <sys/sunddi.h>
47 47 #include <sys/sunndi.h>
48 48 #include <sys/sysevent.h>
49 49 #include <sys/sysevent/eventdefs.h>
50 50 #include <sys/sysevent/dr.h>
51 51 #include <sys/pci_impl.h>
52 52 #include <sys/pci_cap.h>
53 53 #include <sys/hotplug/pci/pcicfg.h>
54 54 #include <sys/hotplug/pci/pcie_hp.h>
55 55 #include <sys/hotplug/pci/pciehpc.h>
56 56 #include <sys/hotplug/pci/pcishpc.h>
57 57 #include <io/pciex/pcieb.h>
58 58
59 59 /* Local functions prototype */
60 60 static int pcie_hp_list_occupants(dev_info_t *dip, void *arg);
61 61 static int pcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip,
62 62 char *cn_name);
63 63 static int pcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num);
64 64 static int pcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg);
65 65 static int pcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg);
66 66 static int pcie_hp_match_dev_func(dev_info_t *dip, void *hdl);
67 67 static boolean_t pcie_hp_match_dev(dev_info_t *dip, int dev_num);
68 68 static int pcie_hp_get_df_from_port_name(char *cn_name, int *dev_num,
69 69 int *func_num);
70 70 static int pcie_hp_create_port_name_num(dev_info_t *dip,
71 71 ddi_hp_cn_info_t *cn_info);
72 72 static int pcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num,
73 73 int func_num);
74 74
75 75 /*
76 76 * Global functions (called by other drivers/modules)
77 77 */
78 78
79 79 /*
80 80 * return description text for led state
81 81 */
82 82 char *
83 83 pcie_led_state_text(pcie_hp_led_state_t state)
84 84 {
85 85 switch (state) {
86 86 case PCIE_HP_LED_ON:
87 87 return (PCIEHPC_PROP_VALUE_ON);
88 88 case PCIE_HP_LED_OFF:
89 89 return (PCIEHPC_PROP_VALUE_OFF);
90 90 case PCIE_HP_LED_BLINK:
91 91 default:
92 92 return (PCIEHPC_PROP_VALUE_BLINK);
93 93 }
94 94 }
95 95
96 96 /*
97 97 * return description text for slot condition
98 98 */
99 99 char *
100 100 pcie_slot_condition_text(ap_condition_t condition)
101 101 {
102 102 switch (condition) {
103 103 case AP_COND_UNKNOWN:
104 104 return (PCIEHPC_PROP_VALUE_UNKNOWN);
105 105 case AP_COND_OK:
106 106 return (PCIEHPC_PROP_VALUE_OK);
107 107 case AP_COND_FAILING:
108 108 return (PCIEHPC_PROP_VALUE_FAILING);
109 109 case AP_COND_FAILED:
110 110 return (PCIEHPC_PROP_VALUE_FAILED);
111 111 case AP_COND_UNUSABLE:
112 112 return (PCIEHPC_PROP_VALUE_UNUSABLE);
113 113 default:
114 114 return (PCIEHPC_PROP_VALUE_UNKNOWN);
115 115 }
116 116 }
117 117
118 118 /*
119 119 * routine to copy in a nvlist from userland
120 120 */
121 121 int
↓ open down ↓ |
121 lines elided |
↑ open up ↑ |
122 122 pcie_copyin_nvlist(char *packed_buf, size_t packed_sz, nvlist_t **nvlp)
123 123 {
124 124 int ret = DDI_SUCCESS;
125 125 char *packed;
126 126 nvlist_t *dest = NULL;
127 127
128 128 if (packed_buf == NULL || packed_sz == 0)
129 129 return (DDI_EINVAL);
130 130
131 131 /* copyin packed nvlist */
132 - if ((packed = kmem_alloc(packed_sz, KM_SLEEP)) == NULL)
133 - return (DDI_ENOMEM);
132 + packed = kmem_alloc(packed_sz, KM_SLEEP);
134 133
135 134 if (copyin(packed_buf, packed, packed_sz) != 0) {
136 135 cmn_err(CE_WARN, "pcie_copyin_nvlist: copyin failed.\n");
137 136 ret = DDI_FAILURE;
138 137 goto copyin_cleanup;
139 138 }
140 139
141 140 /* unpack packed nvlist */
142 141 if ((ret = nvlist_unpack(packed, packed_sz, &dest, KM_SLEEP)) != 0) {
143 142 cmn_err(CE_WARN, "pcie_copyin_nvlist: nvlist_unpack "
144 143 "failed with err %d\n", ret);
145 144 switch (ret) {
146 145 case EINVAL:
147 146 case ENOTSUP:
148 147 ret = DDI_EINVAL;
149 148 goto copyin_cleanup;
150 149 case ENOMEM:
151 150 ret = DDI_ENOMEM;
152 151 goto copyin_cleanup;
153 152 default:
154 153 ret = DDI_FAILURE;
155 154 goto copyin_cleanup;
156 155 }
157 156 }
158 157 *nvlp = dest;
159 158 copyin_cleanup:
160 159 kmem_free(packed, packed_sz);
161 160 return (ret);
162 161 }
163 162
164 163 /*
165 164 * routine to copy out a nvlist to userland
166 165 */
167 166 int
168 167 pcie_copyout_nvlist(nvlist_t *nvl, char *packed_buf, size_t *buf_sz)
169 168 {
170 169 int err = 0;
171 170 char *buf = NULL;
172 171 size_t packed_sz;
173 172
174 173 if (nvl == NULL || packed_buf == NULL || buf_sz == NULL)
175 174 return (DDI_EINVAL);
176 175
177 176 /* pack nvlist, the library will allocate memory */
178 177 if ((err = nvlist_pack(nvl, &buf, &packed_sz, NV_ENCODE_NATIVE, 0))
179 178 != 0) {
180 179 cmn_err(CE_WARN, "pcie_copyout_nvlist: nvlist_pack "
181 180 "failed with err %d\n", err);
182 181 switch (err) {
183 182 case EINVAL:
184 183 case ENOTSUP:
185 184 return (DDI_EINVAL);
186 185 case ENOMEM:
187 186 return (DDI_ENOMEM);
188 187 default:
189 188 return (DDI_FAILURE);
190 189 }
191 190 }
192 191 if (packed_sz > *buf_sz) {
193 192 return (DDI_EINVAL);
194 193 }
195 194
196 195 /* copyout packed nvlist */
197 196 if (copyout(buf, packed_buf, packed_sz) != 0) {
198 197 cmn_err(CE_WARN, "pcie_copyout_nvlist: copyout " "failed.\n");
199 198 kmem_free(buf, packed_sz);
200 199 return (DDI_FAILURE);
201 200 }
202 201
203 202 *buf_sz = packed_sz;
204 203 kmem_free(buf, packed_sz);
205 204 return (DDI_SUCCESS);
206 205 }
207 206
208 207 /*
209 208 * init bus_hp_op entry and init hotpluggable slots & virtual ports
210 209 */
211 210 int
212 211 pcie_hp_init(dev_info_t *dip, caddr_t arg)
213 212 {
214 213 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
215 214 int ret = DDI_SUCCESS, count;
216 215 dev_info_t *cdip;
217 216
218 217 if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
219 218 /* Init hotplug controller */
220 219 ret = pciehpc_init(dip, arg);
221 220 } else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
222 221 ret = pcishpc_init(dip);
223 222 }
224 223
225 224 if (ret != DDI_SUCCESS) {
226 225 PCIE_DBG("pcie_hp_init: initialize hotplug "
227 226 "controller failed with %d\n", ret);
228 227 return (ret);
229 228 }
230 229
231 230 ndi_devi_enter(dip, &count);
232 231
233 232 /* Create port for the first level children */
234 233 cdip = ddi_get_child(dip);
235 234 while (cdip != NULL) {
236 235 if ((ret = pcie_hp_register_port(cdip, dip, NULL))
237 236 != DDI_SUCCESS) {
238 237 /* stop and cleanup */
239 238 break;
240 239 }
241 240 cdip = ddi_get_next_sibling(cdip);
242 241 }
243 242 ndi_devi_exit(dip, count);
244 243 if (ret != DDI_SUCCESS) {
245 244 cmn_err(CE_WARN, "pcie_hp_init: initialize virtual "
246 245 "hotplug port failed with %d\n", ret);
247 246 (void) pcie_hp_uninit(dip);
248 247
249 248 return (ret);
250 249 }
251 250
252 251 return (DDI_SUCCESS);
253 252 }
254 253
255 254 /*
256 255 * uninit the hotpluggable slots and virtual ports
257 256 */
258 257 int
259 258 pcie_hp_uninit(dev_info_t *dip)
260 259 {
261 260 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
262 261 pcie_hp_unreg_port_t arg;
263 262
264 263 /*
265 264 * Must set arg.rv to NDI_SUCCESS so that if there's no port
266 265 * under this dip, we still return success thus the bridge
267 266 * driver can be successfully detached.
268 267 *
269 268 * Note that during the probe PCI configurator calls
270 269 * ndi_devi_offline() to detach driver for a new probed bridge,
271 270 * so that it can reprogram the resources for the bridge,
272 271 * ndi_devi_offline() calls into pcieb_detach() which in turn
273 272 * calls into this function. In this case there are no ports
274 273 * created under a new probe bridge dip, as ports are only
275 274 * created after the configurator finishing probing, thus the
276 275 * ndi_hp_walk_cn() will see no ports when this is called
277 276 * from the PCI configurtor.
278 277 */
279 278 arg.nexus_dip = dip;
280 279 arg.connector_num = DDI_HP_CN_NUM_NONE;
281 280 arg.rv = NDI_SUCCESS;
282 281
283 282 /* tear down all virtual hotplug handles */
284 283 ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
285 284
286 285 if (arg.rv != NDI_SUCCESS)
287 286 return (DDI_FAILURE);
288 287
289 288 if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
290 289 (void) pciehpc_uninit(dip);
291 290 else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
292 291 (void) pcishpc_uninit(dip);
293 292
294 293 return (DDI_SUCCESS);
295 294 }
296 295
297 296 /*
298 297 * interrupt handler
299 298 */
300 299 int
301 300 pcie_hp_intr(dev_info_t *dip)
302 301 {
303 302 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
304 303 int ret = DDI_INTR_UNCLAIMED;
305 304
306 305 if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
307 306 ret = pciehpc_intr(dip);
308 307 else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
309 308 ret = pcishpc_intr(dip);
310 309
311 310 return (ret);
312 311 }
313 312
314 313 /*
315 314 * Probe the given PCIe/PCI Hotplug Connection (CN).
316 315 */
317 316 /*ARGSUSED*/
318 317 int
319 318 pcie_hp_probe(pcie_hp_slot_t *slot_p)
320 319 {
321 320 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
322 321 dev_info_t *dip = ctrl_p->hc_dip;
323 322
324 323 /*
325 324 * Call the configurator to probe a given PCI hotplug
326 325 * Hotplug Connection (CN).
327 326 */
328 327 if (pcicfg_configure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
329 328 != PCICFG_SUCCESS) {
330 329 PCIE_DBG("pcie_hp_probe() failed\n");
331 330 return (DDI_FAILURE);
332 331 }
333 332 slot_p->hs_condition = AP_COND_OK;
334 333 pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
335 334 slot_p->hs_minor), slot_p->hs_device_num);
336 335
337 336 /*
338 337 * Create ports for the newly probed devices.
339 338 * Note, this is only for the first level children because the
340 339 * descendants' ports will be created during bridge driver attach.
341 340 */
342 341 return (pcie_hp_register_ports_for_dev(dip, slot_p->hs_device_num));
343 342 }
344 343
345 344 /*
346 345 * Unprobe the given PCIe/PCI Hotplug Connection (CN):
347 346 * 1. remove all child device nodes
348 347 * 2. unregister all dependent ports
349 348 */
350 349 /*ARGSUSED*/
351 350 int
352 351 pcie_hp_unprobe(pcie_hp_slot_t *slot_p)
353 352 {
354 353 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
355 354 dev_info_t *dip = ctrl_p->hc_dip;
356 355 pcie_hp_unreg_port_t arg;
357 356
358 357 /*
359 358 * Call the configurator to unprobe a given PCI hotplug
360 359 * Hotplug Connection (CN).
361 360 */
362 361 if (pcicfg_unconfigure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
363 362 != PCICFG_SUCCESS) {
364 363 PCIE_DBG("pcie_hp_unprobe() failed\n");
365 364 return (DDI_FAILURE);
366 365 }
367 366 slot_p->hs_condition = AP_COND_UNKNOWN;
368 367 pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
369 368 slot_p->hs_minor));
370 369
371 370 /*
372 371 * Remove ports for the unprobed devices.
373 372 * Note, this is only for the first level children because the
374 373 * descendants' ports were already removed during bridge driver dettach.
375 374 */
376 375 arg.nexus_dip = dip;
377 376 arg.connector_num = slot_p->hs_info.cn_num;
378 377 arg.rv = NDI_SUCCESS;
379 378 ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
380 379
381 380 return (arg.rv == NDI_SUCCESS) ? (DDI_SUCCESS) : (DDI_FAILURE);
382 381 }
383 382
384 383 /* Read-only probe: no hardware register programming. */
385 384 int
386 385 pcie_read_only_probe(dev_info_t *dip, char *cn_name, dev_info_t **pcdip)
387 386 {
388 387 long dev, func;
389 388 int ret;
390 389 char *sp;
391 390 dev_info_t *cdip;
392 391
393 392 *pcdip = NULL;
394 393 /*
395 394 * Parse the string of a pci Port name and get the device number
396 395 * and function number.
397 396 */
398 397 if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
399 398 return (DDI_EINVAL);
400 399 if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
401 400 return (DDI_EINVAL);
402 401
403 402 ret = pcicfg_configure(dip, (int)dev, (int)func,
404 403 PCICFG_FLAG_READ_ONLY);
405 404 if (ret == PCICFG_SUCCESS) {
406 405 cdip = pcie_hp_devi_find(dip, (int)dev, (int)func);
407 406 *pcdip = cdip;
408 407 }
409 408 return (ret);
410 409 }
411 410
412 411 /* Read-only unprobe: no hardware register programming. */
413 412 int
414 413 pcie_read_only_unprobe(dev_info_t *dip, char *cn_name)
415 414 {
416 415 long dev, func;
417 416 int ret;
418 417 char *sp;
419 418
420 419 /*
421 420 * Parse the string of a pci Port name and get the device number
422 421 * and function number.
423 422 */
424 423 if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
425 424 return (DDI_EINVAL);
426 425 if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
427 426 return (DDI_EINVAL);
428 427
429 428 ret = pcicfg_unconfigure(dip, (int)dev, (int)func,
430 429 PCICFG_FLAG_READ_ONLY);
431 430
432 431 return (ret);
433 432 }
434 433
435 434 /* Control structure used to find a device in the devinfo tree */
436 435 struct pcie_hp_find_ctrl {
437 436 uint_t device;
438 437 uint_t function;
439 438 dev_info_t *dip;
440 439 };
441 440
442 441 /*
443 442 * find a devinfo node with specified device and function number
444 443 * in the device tree under 'dip'
445 444 */
446 445 dev_info_t *
447 446 pcie_hp_devi_find(dev_info_t *dip, uint_t device, uint_t function)
448 447 {
449 448 struct pcie_hp_find_ctrl ctrl;
450 449 int count;
451 450
452 451 ctrl.device = device;
453 452 ctrl.function = function;
454 453 ctrl.dip = NULL;
455 454
456 455 ndi_devi_enter(dip, &count);
457 456 ddi_walk_devs(ddi_get_child(dip), pcie_hp_match_dev_func,
458 457 (void *)&ctrl);
459 458 ndi_devi_exit(dip, count);
460 459
461 460 return (ctrl.dip);
462 461 }
463 462
464 463 /*
465 464 * routine to create 'pci-occupant' property for a hotplug slot
466 465 */
467 466 void
468 467 pcie_hp_create_occupant_props(dev_info_t *dip, dev_t dev, int pci_dev)
469 468 {
470 469 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
471 470 pcie_hp_ctrl_t *ctrl_p = (pcie_hp_ctrl_t *)bus_p->bus_hp_ctrl;
472 471 pcie_hp_slot_t *slotp;
473 472 pcie_hp_cn_cfg_t cn_cfg;
474 473 pcie_hp_occupant_info_t *occupant;
475 474 int circular, i;
476 475
477 476 ndi_devi_enter(dip, &circular);
478 477
479 478 if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
480 479 slotp = (ctrl_p && (pci_dev == 0)) ?
481 480 ctrl_p->hc_slots[pci_dev] : NULL;
482 481 } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
483 482 if (ctrl_p) {
484 483 int slot_num;
485 484
486 485 slot_num = (ctrl_p->hc_device_increases) ?
487 486 (pci_dev - ctrl_p->hc_device_start) :
488 487 (pci_dev + ctrl_p->hc_device_start);
489 488
490 489 slotp = ctrl_p->hc_slots[slot_num];
491 490 } else {
492 491 slotp = NULL;
493 492 }
494 493 }
495 494
496 495 if (slotp == NULL)
497 496 return;
498 497
499 498 occupant = kmem_alloc(sizeof (pcie_hp_occupant_info_t), KM_SLEEP);
500 499 occupant->i = 0;
501 500
502 501 cn_cfg.flag = B_FALSE;
503 502 cn_cfg.rv = NDI_SUCCESS;
504 503 cn_cfg.dip = NULL;
505 504 cn_cfg.slotp = (void *)slotp;
506 505 cn_cfg.cn_private = (void *)occupant;
507 506
508 507 ddi_walk_devs(ddi_get_child(dip), pcie_hp_list_occupants,
509 508 (void *)&cn_cfg);
510 509
511 510 if (occupant->i == 0) {
512 511 /* no occupants right now, need to create stub property */
513 512 char *c[] = { "" };
514 513 (void) ddi_prop_update_string_array(dev, dip, "pci-occupant",
515 514 c, 1);
516 515 } else {
517 516 (void) ddi_prop_update_string_array(dev, dip, "pci-occupant",
518 517 occupant->id, occupant->i);
519 518 }
520 519
521 520 for (i = 0; i < occupant->i; i++)
522 521 kmem_free(occupant->id[i], sizeof (char[MAXPATHLEN]));
523 522
524 523 kmem_free(occupant, sizeof (pcie_hp_occupant_info_t));
525 524
526 525 ndi_devi_exit(dip, circular);
527 526 }
528 527
529 528 /*
530 529 * routine to remove 'pci-occupant' property for a hotplug slot
531 530 */
532 531 void
533 532 pcie_hp_delete_occupant_props(dev_info_t *dip, dev_t dev)
534 533 {
535 534 (void) ddi_prop_remove(dev, dip, "pci-occupant");
536 535 }
537 536
538 537 /*
539 538 * general code to create a minor node, called from hotplug controller
540 539 * drivers.
541 540 */
542 541 int
543 542 pcie_create_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
544 543 {
545 544 dev_info_t *dip = ctrl_p->hc_dip;
546 545 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[slot];
547 546 ddi_hp_cn_info_t *info_p = &slot_p->hs_info;
548 547
549 548 if (ddi_create_minor_node(dip, info_p->cn_name,
550 549 S_IFCHR, slot_p->hs_minor,
551 550 DDI_NT_PCI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
552 551 return (DDI_FAILURE);
553 552 }
554 553
555 554 (void) ddi_prop_update_int(DDI_DEV_T_NONE,
556 555 dip, "ap-names", 1 << slot_p->hs_device_num);
557 556
558 557 return (DDI_SUCCESS);
559 558 }
560 559
561 560 /*
562 561 * general code to remove a minor node, called from hotplug controller
563 562 * drivers.
564 563 */
565 564 void
566 565 pcie_remove_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
567 566 {
568 567 ddi_remove_minor_node(ctrl_p->hc_dip,
569 568 ctrl_p->hc_slots[slot]->hs_info.cn_name);
570 569 }
571 570
572 571 /*
573 572 * Local functions (called within this file)
574 573 */
575 574
576 575 /*
577 576 * Register ports for all the children with device number device_num
578 577 */
579 578 static int
580 579 pcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num)
581 580 {
582 581 dev_info_t *cdip;
583 582 int rv;
584 583
585 584 for (cdip = ddi_get_child(dip); cdip;
586 585 cdip = ddi_get_next_sibling(cdip)) {
587 586 if (pcie_hp_match_dev(cdip, device_num)) {
588 587 /*
589 588 * Found the newly probed device under the
590 589 * current slot. Register a port for it.
591 590 */
592 591 if ((rv = pcie_hp_register_port(cdip, dip, NULL))
593 592 != DDI_SUCCESS)
594 593 return (rv);
595 594 } else {
596 595 continue;
597 596 }
598 597 }
599 598
600 599 return (DDI_SUCCESS);
601 600 }
602 601
603 602 /*
604 603 * Unregister ports of a pci bridge dip, get called from ndi_hp_walk_cn()
605 604 *
606 605 * If connector_num is specified, then unregister the slot's dependent ports
607 606 * only; Otherwise, unregister all ports of a pci bridge dip.
608 607 */
609 608 static int
610 609 pcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg)
611 610 {
612 611 pcie_hp_unreg_port_t *unreg_arg = (pcie_hp_unreg_port_t *)arg;
613 612 dev_info_t *dip = unreg_arg->nexus_dip;
614 613 int rv = NDI_SUCCESS;
615 614
616 615 if (info->cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT) {
617 616 unreg_arg->rv = rv;
618 617 return (DDI_WALK_CONTINUE);
619 618 }
620 619
621 620 if (unreg_arg->connector_num != DDI_HP_CN_NUM_NONE) {
622 621 /* Unregister ports for all unprobed devices under a slot. */
623 622 if (unreg_arg->connector_num == info->cn_num_dpd_on) {
624 623
625 624 rv = ndi_hp_unregister(dip, info->cn_name);
626 625 }
627 626 } else {
628 627
629 628 /* Unregister all ports of a pci bridge dip. */
630 629 rv = ndi_hp_unregister(dip, info->cn_name);
631 630 }
632 631
633 632 unreg_arg->rv = rv;
634 633 if (rv == NDI_SUCCESS)
635 634 return (DDI_WALK_CONTINUE);
636 635 else
637 636 return (DDI_WALK_TERMINATE);
638 637 }
639 638
640 639 /*
641 640 * Find a port according to cn_name and get the port's state.
642 641 */
643 642 static int
644 643 pcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg)
645 644 {
646 645 pcie_hp_port_state_t *port = (pcie_hp_port_state_t *)arg;
647 646
648 647 if (info->cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT)
649 648 return (DDI_WALK_CONTINUE);
650 649
651 650 if (strcmp(info->cn_name, port->cn_name) == 0) {
652 651 /* Matched. */
653 652 port->cn_state = info->cn_state;
654 653 port->rv = DDI_SUCCESS;
655 654
656 655 return (DDI_WALK_TERMINATE);
657 656 }
658 657
659 658 return (DDI_WALK_CONTINUE);
660 659 }
661 660
662 661 /*
663 662 * Find the physical slot with the given device number;
664 663 * return the slot if found.
665 664 */
666 665 static pcie_hp_slot_t *
667 666 pcie_find_physical_slot(dev_info_t *dip, int dev_num)
668 667 {
669 668 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
670 669 pcie_hp_ctrl_t *ctrl = PCIE_GET_HP_CTRL(dip);
671 670
672 671 if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
673 672 /* PCIe has only one slot */
674 673 return (dev_num == 0) ? (ctrl->hc_slots[0]) : (NULL);
675 674 } else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
676 675 for (int slot = 0; slot < ctrl->hc_num_slots_impl; slot++) {
677 676 if (ctrl->hc_slots[slot]->hs_device_num == dev_num) {
678 677 /* found */
679 678 return (ctrl->hc_slots[slot]);
680 679 }
681 680 }
682 681 }
683 682
684 683 return (NULL);
685 684 }
686 685
687 686 /*
688 687 * setup slot name/slot-number info for the port which is being registered.
689 688 */
690 689 static int
691 690 pcie_hp_create_port_name_num(dev_info_t *dip, ddi_hp_cn_info_t *cn_info)
692 691 {
693 692 int ret, dev_num, func_num, name_len;
694 693 dev_info_t *pdip = ddi_get_parent(dip);
695 694 pcie_bus_t *bus_p = PCIE_DIP2BUS(pdip);
696 695 pcie_hp_slot_t *slot;
697 696 pcie_req_id_t bdf;
698 697 char tmp[PCIE_HP_DEV_FUNC_NUM_STRING_LEN];
699 698
700 699 ret = pcie_get_bdf_from_dip(dip, &bdf);
701 700 if (ret != DDI_SUCCESS) {
702 701 return (ret);
703 702 }
704 703 if (PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p) ||
705 704 PCIE_IS_PCI2PCIE(bus_p)) {
706 705 /*
707 706 * It is under a PCIe device, devcie number is always 0;
708 707 * function number might > 8 in ARI supported case.
709 708 */
710 709 dev_num = 0;
711 710 func_num = (bdf & ((~PCI_REG_BUS_M) >> 8));
712 711 } else {
713 712 dev_num = (bdf & (PCI_REG_DEV_M >> 8)) >> 3;
714 713 func_num = bdf & (PCI_REG_FUNC_M >> 8);
715 714 }
716 715 /*
717 716 * The string length of dev_num and func_num must be no longer than 4
718 717 * including the string end mark. (With ARI case considered, e.g.,
719 718 * dev_num=0x0, func_num=0xff.)
720 719 */
721 720 (void) snprintf(tmp, PCIE_HP_DEV_FUNC_NUM_STRING_LEN, "%x%x",
722 721 dev_num, func_num);
723 722 /*
724 723 * Calculate the length of cn_name.
725 724 * The format of pci port name is: pci.d,f
726 725 * d stands for dev_num, f stands for func_num. So the length of the
727 726 * name string can be calculated as following.
728 727 */
729 728 name_len = strlen(tmp) + PCIE_HP_PORT_NAME_STRING_LEN + 1;
730 729
731 730 cn_info->cn_name = (char *)kmem_zalloc(name_len, KM_SLEEP);
732 731 (void) snprintf(cn_info->cn_name, name_len, "pci.%x,%x",
733 732 dev_num, func_num);
734 733 cn_info->cn_num = (dev_num << 8) | func_num;
735 734 slot = pcie_find_physical_slot(pdip, dev_num);
736 735
737 736 cn_info->cn_num_dpd_on = slot ?
738 737 slot->hs_info.cn_num : DDI_HP_CN_NUM_NONE;
739 738
740 739 return (DDI_SUCCESS);
741 740 }
742 741
743 742 /*
744 743 * Extract device and function number from port name, whose format is
745 744 * something like 'pci.1,0'
746 745 */
747 746 static int
748 747 pcie_hp_get_df_from_port_name(char *cn_name, int *dev_num, int *func_num)
749 748 {
750 749 int name_len, ret;
751 750 long d, f;
752 751 char *sp;
753 752
754 753 /* some checks for the input name */
755 754 name_len = strlen(cn_name);
756 755 if ((name_len <= PCIE_HP_PORT_NAME_STRING_LEN) ||
757 756 (name_len > (PCIE_HP_PORT_NAME_STRING_LEN +
758 757 PCIE_HP_DEV_FUNC_NUM_STRING_LEN - 1)) ||
759 758 (strncmp("pci.", cn_name, 4) != 0)) {
760 759 return (DDI_EINVAL);
761 760 }
762 761 ret = ddi_strtol(cn_name + 4, &sp, 10, &d);
763 762 if (ret != DDI_SUCCESS)
764 763 return (ret);
765 764
766 765 if (strncmp(",", sp, 1) != 0)
767 766 return (DDI_EINVAL);
768 767
769 768 ret = ddi_strtol(sp + 1, NULL, 10, &f);
770 769 if (ret != DDI_SUCCESS)
771 770 return (ret);
772 771 *dev_num = (int)d;
773 772 *func_num = (int)f;
774 773
775 774 return (ret);
776 775 }
777 776
778 777 /*
779 778 * Check/copy cn_name and set connection numbers.
780 779 * If it is a valid name, then setup cn_info for the newly created port.
781 780 */
782 781 static int
783 782 pcie_hp_setup_port_name_num(dev_info_t *pdip, char *cn_name,
784 783 ddi_hp_cn_info_t *cn_info)
785 784 {
786 785 int dev_num, func_num, ret;
787 786 pcie_hp_slot_t *slot;
788 787
789 788 if ((ret = pcie_hp_get_df_from_port_name(cn_name, &dev_num, &func_num))
790 789 != DDI_SUCCESS)
791 790 return (ret);
792 791
793 792 if (pcie_hp_check_hardware_existence(pdip, dev_num, func_num) ==
794 793 DDI_SUCCESS) {
795 794 cn_info->cn_state = DDI_HP_CN_STATE_PRESENT;
796 795 } else {
797 796 cn_info->cn_state = DDI_HP_CN_STATE_EMPTY;
798 797 }
799 798
800 799 cn_info->cn_name = ddi_strdup(cn_name, KM_SLEEP);
801 800 cn_info->cn_num = (dev_num << 8) | func_num;
802 801
803 802 slot = pcie_find_physical_slot(pdip, dev_num);
804 803 if (slot) {
805 804 cn_info->cn_num_dpd_on = slot->hs_info.cn_num;
806 805 } else {
807 806 cn_info->cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
808 807 }
809 808 return (DDI_SUCCESS);
810 809 }
811 810
812 811 static int
813 812 ndi2ddi(int n)
814 813 {
815 814 int ret;
816 815
817 816 switch (n) {
818 817 case NDI_SUCCESS:
819 818 ret = DDI_SUCCESS;
820 819 break;
821 820 case NDI_NOMEM:
822 821 ret = DDI_ENOMEM;
823 822 break;
824 823 case NDI_BUSY:
825 824 ret = DDI_EBUSY;
826 825 break;
827 826 case NDI_EINVAL:
828 827 ret = DDI_EINVAL;
829 828 break;
830 829 case NDI_ENOTSUP:
831 830 ret = DDI_ENOTSUP;
832 831 break;
833 832 case NDI_FAILURE:
834 833 default:
835 834 ret = DDI_FAILURE;
836 835 break;
837 836 }
838 837 return (ret);
839 838 }
840 839
841 840 /*
842 841 * Common routine to create and register a new port
843 842 *
844 843 * Create an empty port if dip is NULL, and cn_name needs to be specified in
845 844 * this case. Otherwise, create a port mapping to the specified dip, and cn_name
846 845 * is not needed in this case.
847 846 */
848 847 static int
849 848 pcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip, char *cn_name)
850 849 {
851 850 ddi_hp_cn_info_t *cn_info;
852 851 int ret;
853 852
854 853 ASSERT((dip == NULL) != (cn_name == NULL));
855 854 cn_info = kmem_zalloc(sizeof (ddi_hp_cn_info_t), KM_SLEEP);
856 855 if (dip != NULL)
857 856 ret = pcie_hp_create_port_name_num(dip, cn_info);
858 857 else
859 858 ret = pcie_hp_setup_port_name_num(pdip, cn_name, cn_info);
860 859
861 860 if (ret != DDI_SUCCESS) {
862 861 kmem_free(cn_info, sizeof (ddi_hp_cn_info_t));
863 862 return (ret);
864 863 }
865 864
866 865 cn_info->cn_child = dip;
867 866 cn_info->cn_type = DDI_HP_CN_TYPE_VIRTUAL_PORT;
868 867 cn_info->cn_type_str = DDI_HP_CN_TYPE_STR_PORT;
869 868
870 869 ret = ndi_hp_register(pdip, cn_info);
871 870
872 871 kmem_free(cn_info->cn_name, strlen(cn_info->cn_name) + 1);
873 872 kmem_free(cn_info, sizeof (ddi_hp_cn_info_t));
874 873
875 874 return (ndi2ddi(ret));
876 875 }
877 876
878 877 /* Check if there is a piece of hardware exist corresponding to the cn_name */
879 878 static int
880 879 pcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num, int func_num)
881 880 {
882 881
883 882 /*
884 883 * VHPTODO:
885 884 * According to device and function number, check if there is a hardware
886 885 * device exists. Currently, this function can not be reached before
887 886 * we enable state transition to or from "Port-Empty" or "Port-Present"
888 887 * states. When the pci device type project is integrated, we are going
889 888 * to call the pci config space access interfaces introduced by it.
890 889 */
891 890 _NOTE(ARGUNUSED(dip, dev_num, func_num));
892 891
893 892 return (DDI_SUCCESS);
894 893 }
895 894
896 895 /*
897 896 * Dispatch hotplug commands to different hotplug controller drivers, including
898 897 * physical and virtual hotplug operations.
899 898 */
900 899 /* ARGSUSED */
901 900 int
902 901 pcie_hp_common_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
903 902 void *arg, void *result)
904 903 {
905 904 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
906 905 int ret = DDI_SUCCESS;
907 906
908 907 PCIE_DBG("pcie_hp_common_ops: dip=%p cn_name=%s op=%x arg=%p\n",
909 908 dip, cn_name, op, arg);
910 909
911 910 switch (op) {
912 911 case DDI_HPOP_CN_CREATE_PORT:
913 912 {
914 913 /* create an empty port */
915 914 return (pcie_hp_register_port(NULL, dip, cn_name));
916 915 }
917 916 case DDI_HPOP_CN_CHANGE_STATE:
918 917 {
919 918 ddi_hp_cn_state_t curr_state;
920 919 ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
921 920 pcie_hp_port_state_t state_arg;
922 921
923 922 if (target_state < DDI_HP_CN_STATE_PORT_EMPTY) {
924 923 /* this is for physical slot state change */
925 924 break;
926 925 }
927 926 PCIE_DBG("pcie_hp_common_ops: change port state"
928 927 " dip=%p cn_name=%s"
929 928 " op=%x arg=%p\n", (void *)dip, cn_name, op, arg);
930 929
931 930 state_arg.rv = DDI_FAILURE;
932 931 state_arg.cn_name = cn_name;
933 932 ndi_hp_walk_cn(dip, pcie_hp_get_port_state, &state_arg);
934 933 if (state_arg.rv != DDI_SUCCESS) {
935 934 /* can not find the port */
936 935 return (DDI_EINVAL);
937 936 }
938 937 curr_state = state_arg.cn_state;
939 938 /*
940 939 * Check if this is for changing port's state: change to/from
941 940 * PORT_EMPTY/PRESENT states.
942 941 */
943 942 if (curr_state < target_state) {
944 943 /* Upgrade state */
945 944 switch (curr_state) {
946 945 case DDI_HP_CN_STATE_PORT_EMPTY:
947 946 if (target_state ==
948 947 DDI_HP_CN_STATE_PORT_PRESENT) {
949 948 int dev_num, func_num;
950 949
951 950 ret = pcie_hp_get_df_from_port_name(
952 951 cn_name, &dev_num, &func_num);
953 952 if (ret != DDI_SUCCESS)
954 953 goto port_state_done;
955 954
956 955 ret = pcie_hp_check_hardware_existence(
957 956 dip, dev_num, func_num);
958 957 } else if (target_state ==
959 958 DDI_HP_CN_STATE_OFFLINE) {
960 959 ret = pcie_read_only_probe(dip,
961 960 cn_name, (dev_info_t **)result);
962 961 } else
963 962 ret = DDI_EINVAL;
964 963
965 964 goto port_state_done;
966 965 case DDI_HP_CN_STATE_PORT_PRESENT:
967 966 if (target_state ==
968 967 DDI_HP_CN_STATE_OFFLINE)
969 968 ret = pcie_read_only_probe(dip,
970 969 cn_name, (dev_info_t **)result);
971 970 else
972 971 ret = DDI_EINVAL;
973 972
974 973 goto port_state_done;
975 974 default:
976 975 ASSERT("unexpected state");
977 976 }
978 977 } else {
979 978 /* Downgrade state */
980 979 switch (curr_state) {
981 980 case DDI_HP_CN_STATE_PORT_PRESENT:
982 981 {
983 982 int dev_num, func_num;
984 983
985 984 ret = pcie_hp_get_df_from_port_name(cn_name,
986 985 &dev_num, &func_num);
987 986 if (ret != DDI_SUCCESS)
988 987 goto port_state_done;
989 988
990 989 ret = pcie_hp_check_hardware_existence(dip,
991 990 dev_num, func_num);
992 991
993 992 goto port_state_done;
994 993 }
995 994 case DDI_HP_CN_STATE_OFFLINE:
996 995 ret = pcie_read_only_unprobe(dip, cn_name);
997 996
998 997 goto port_state_done;
999 998 default:
1000 999 ASSERT("unexpected state");
1001 1000 }
1002 1001 }
1003 1002 port_state_done:
1004 1003 *(ddi_hp_cn_state_t *)result = curr_state;
1005 1004 return (ret);
1006 1005 }
1007 1006 default:
1008 1007 break;
1009 1008 }
1010 1009
1011 1010 if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
1012 1011 /* PCIe hotplug */
1013 1012 ret = pciehpc_hp_ops(dip, cn_name, op, arg, result);
1014 1013 } else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
1015 1014 /* PCI SHPC hotplug */
1016 1015 ret = pcishpc_hp_ops(dip, cn_name, op, arg, result);
1017 1016 } else {
1018 1017 cmn_err(CE_WARN, "pcie_hp_common_ops: op is not supported."
1019 1018 " dip=%p cn_name=%s"
1020 1019 " op=%x arg=%p\n", (void *)dip, cn_name, op, arg);
1021 1020 ret = DDI_ENOTSUP;
1022 1021 }
1023 1022
1024 1023 #if defined(__i386) || defined(__amd64)
1025 1024 /*
1026 1025 * like in attach, since hotplugging can change error registers,
1027 1026 * we need to ensure that the proper bits are set on this port
1028 1027 * after a configure operation
1029 1028 */
1030 1029 if ((ret == DDI_SUCCESS) && (op == DDI_HPOP_CN_CHANGE_STATE) &&
1031 1030 (*(ddi_hp_cn_state_t *)arg == DDI_HP_CN_STATE_ENABLED))
1032 1031 pcieb_intel_error_workaround(dip);
1033 1032 #endif
1034 1033
1035 1034 return (ret);
1036 1035 }
1037 1036
1038 1037 /*
1039 1038 * pcie_hp_match_dev_func:
1040 1039 * Match dip's PCI device number and function number with input ones.
1041 1040 */
1042 1041 static int
1043 1042 pcie_hp_match_dev_func(dev_info_t *dip, void *hdl)
1044 1043 {
1045 1044 struct pcie_hp_find_ctrl *ctrl = (struct pcie_hp_find_ctrl *)hdl;
1046 1045 pci_regspec_t *pci_rp;
1047 1046 int length;
1048 1047 int pci_dev, pci_func;
1049 1048
1050 1049 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1051 1050 "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
1052 1051 ctrl->dip = NULL;
1053 1052 return (DDI_WALK_TERMINATE);
1054 1053 }
1055 1054
1056 1055 /* get the PCI device address info */
1057 1056 pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
1058 1057 pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
1059 1058
1060 1059 /*
1061 1060 * free the memory allocated by ddi_prop_lookup_int_array
1062 1061 */
1063 1062 ddi_prop_free(pci_rp);
1064 1063
1065 1064 if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
1066 1065 /* found the match for the specified device address */
1067 1066 ctrl->dip = dip;
1068 1067 return (DDI_WALK_TERMINATE);
1069 1068 }
1070 1069
1071 1070 /*
1072 1071 * continue the walk to the next sibling to look for a match.
1073 1072 */
1074 1073 return (DDI_WALK_PRUNECHILD);
1075 1074 }
1076 1075
1077 1076 /*
1078 1077 * pcie_hp_match_dev:
1079 1078 * Match the dip's pci device number with the input dev_num
1080 1079 */
1081 1080 static boolean_t
1082 1081 pcie_hp_match_dev(dev_info_t *dip, int dev_num)
1083 1082 {
1084 1083 pci_regspec_t *pci_rp;
1085 1084 int length;
1086 1085 int pci_dev;
1087 1086
1088 1087 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1089 1088 "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
1090 1089 return (B_FALSE);
1091 1090 }
1092 1091
1093 1092 /* get the PCI device address info */
1094 1093 pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
1095 1094
1096 1095 /*
1097 1096 * free the memory allocated by ddi_prop_lookup_int_array
1098 1097 */
1099 1098 ddi_prop_free(pci_rp);
1100 1099
1101 1100 if (pci_dev == dev_num) {
1102 1101 /* found the match for the specified device address */
1103 1102 return (B_TRUE);
1104 1103 }
1105 1104
1106 1105 return (B_FALSE);
1107 1106 }
1108 1107
1109 1108 /*
1110 1109 * Callback function to match with device number in order to list
1111 1110 * occupants under a specific slot
1112 1111 */
1113 1112 static int
1114 1113 pcie_hp_list_occupants(dev_info_t *dip, void *arg)
1115 1114 {
1116 1115 pcie_hp_cn_cfg_t *cn_cfg_p = (pcie_hp_cn_cfg_t *)arg;
1117 1116 pcie_hp_occupant_info_t *occupant =
1118 1117 (pcie_hp_occupant_info_t *)cn_cfg_p->cn_private;
1119 1118 pcie_hp_slot_t *slot_p =
1120 1119 (pcie_hp_slot_t *)cn_cfg_p->slotp;
1121 1120 int pci_dev;
1122 1121 pci_regspec_t *pci_rp;
1123 1122 int length;
1124 1123 major_t major;
1125 1124
1126 1125 /*
1127 1126 * Get the PCI device number information from the devinfo
1128 1127 * node. Since the node may not have the address field
1129 1128 * setup (this is done in the DDI_INITCHILD of the parent)
1130 1129 * we look up the 'reg' property to decode that information.
1131 1130 */
1132 1131 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
1133 1132 DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
1134 1133 (uint_t *)&length) != DDI_PROP_SUCCESS) {
1135 1134 cn_cfg_p->rv = DDI_FAILURE;
1136 1135 cn_cfg_p->dip = dip;
1137 1136 return (DDI_WALK_TERMINATE);
1138 1137 }
1139 1138
1140 1139 /* get the pci device id information */
1141 1140 pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
1142 1141
1143 1142 /*
1144 1143 * free the memory allocated by ddi_prop_lookup_int_array
1145 1144 */
1146 1145 ddi_prop_free(pci_rp);
1147 1146
1148 1147 /*
1149 1148 * Match the node for the device number of the slot.
1150 1149 */
1151 1150 if (pci_dev == slot_p->hs_device_num) {
1152 1151
1153 1152 major = ddi_driver_major(dip);
1154 1153
1155 1154 /*
1156 1155 * If the node is not yet attached, then don't list it
1157 1156 * as an occupant. This is valid, since nothing can be
1158 1157 * consuming it until it is attached, and cfgadm will
1159 1158 * ask for the property explicitly which will cause it
1160 1159 * to be re-freshed right before checking with rcm.
1161 1160 */
1162 1161 if ((major == DDI_MAJOR_T_NONE) || !i_ddi_devi_attached(dip))
1163 1162 return (DDI_WALK_PRUNECHILD);
1164 1163
1165 1164 /*
1166 1165 * If we have used all our occupants then print mesage
1167 1166 * and terminate walk.
1168 1167 */
1169 1168 if (occupant->i >= PCIE_HP_MAX_OCCUPANTS) {
1170 1169 cmn_err(CE_WARN,
1171 1170 "pcie (%s%d): unable to list all occupants",
1172 1171 ddi_driver_name(ddi_get_parent(dip)),
1173 1172 ddi_get_instance(ddi_get_parent(dip)));
1174 1173 return (DDI_WALK_TERMINATE);
1175 1174 }
1176 1175
1177 1176 /*
1178 1177 * No need to hold the dip as ddi_walk_devs
1179 1178 * has already arranged that for us.
1180 1179 */
1181 1180 occupant->id[occupant->i] =
1182 1181 kmem_alloc(sizeof (char[MAXPATHLEN]), KM_SLEEP);
1183 1182 (void) ddi_pathname(dip, (char *)occupant->id[occupant->i]);
1184 1183 occupant->i++;
1185 1184 }
1186 1185
1187 1186 /*
1188 1187 * continue the walk to the next sibling to look for a match
1189 1188 * or to find other nodes if this card is a multi-function card.
1190 1189 */
1191 1190 return (DDI_WALK_PRUNECHILD);
1192 1191 }
1193 1192
1194 1193 /*
1195 1194 * Generate the System Event for ESC_DR_REQ.
1196 1195 * One of the consumers is pcidr, it calls to libcfgadm to perform a
1197 1196 * configure or unconfigure operation to the AP.
1198 1197 */
1199 1198 void
1200 1199 pcie_hp_gen_sysevent_req(char *slot_name, int hint,
1201 1200 dev_info_t *self, int kmflag)
1202 1201 {
1203 1202 sysevent_id_t eid;
1204 1203 nvlist_t *ev_attr_list = NULL;
1205 1204 char cn_path[MAXPATHLEN];
1206 1205 char *ap_id;
1207 1206 int err, ap_id_len;
1208 1207
1209 1208 /*
1210 1209 * Minor device name (AP) will be bus path
1211 1210 * concatenated with slot name
1212 1211 */
1213 1212 (void) strcpy(cn_path, "/devices");
1214 1213 (void) ddi_pathname(self, cn_path + strlen("/devices"));
1215 1214
1216 1215 ap_id_len = strlen(cn_path) + strlen(":") +
1217 1216 strlen(slot_name) + 1;
1218 1217 ap_id = kmem_zalloc(ap_id_len, kmflag);
1219 1218 if (ap_id == NULL) {
1220 1219 cmn_err(CE_WARN,
1221 1220 "%s%d: Failed to allocate memory for AP ID: %s:%s",
1222 1221 ddi_driver_name(self), ddi_get_instance(self),
1223 1222 cn_path, slot_name);
1224 1223
1225 1224 return;
1226 1225 }
1227 1226
1228 1227 (void) strcpy(ap_id, cn_path);
1229 1228 (void) strcat(ap_id, ":");
1230 1229 (void) strcat(ap_id, slot_name);
1231 1230
1232 1231 err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
1233 1232 if (err != 0) {
1234 1233 cmn_err(CE_WARN,
1235 1234 "%s%d: Failed to allocate memory "
1236 1235 "for event attributes%s", ddi_driver_name(self),
1237 1236 ddi_get_instance(self), ESC_DR_REQ);
1238 1237
1239 1238 kmem_free(ap_id, ap_id_len);
1240 1239 return;
1241 1240 }
1242 1241
1243 1242 switch (hint) {
1244 1243
1245 1244 case SE_INVESTIGATE_RES: /* fall through */
1246 1245 case SE_INCOMING_RES: /* fall through */
1247 1246 case SE_OUTGOING_RES: /* fall through */
1248 1247
1249 1248 err = nvlist_add_string(ev_attr_list, DR_REQ_TYPE,
1250 1249 SE_REQ2STR(hint));
1251 1250
1252 1251 if (err != 0) {
1253 1252 cmn_err(CE_WARN,
1254 1253 "%s%d: Failed to add attr [%s] "
1255 1254 "for %s event", ddi_driver_name(self),
1256 1255 ddi_get_instance(self),
1257 1256 DR_REQ_TYPE, ESC_DR_REQ);
1258 1257
1259 1258 goto done;
1260 1259 }
1261 1260 break;
1262 1261
1263 1262 default:
1264 1263 cmn_err(CE_WARN, "%s%d: Unknown hint on sysevent",
1265 1264 ddi_driver_name(self), ddi_get_instance(self));
1266 1265
1267 1266 goto done;
1268 1267 }
1269 1268
1270 1269 /*
1271 1270 * Add attachment point as attribute (common attribute)
1272 1271 */
1273 1272
1274 1273 err = nvlist_add_string(ev_attr_list, DR_AP_ID, ap_id);
1275 1274
1276 1275 if (err != 0) {
1277 1276 cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event",
1278 1277 ddi_driver_name(self), ddi_get_instance(self),
1279 1278 DR_AP_ID, EC_DR);
1280 1279
1281 1280 goto done;
1282 1281 }
1283 1282
1284 1283
1285 1284 /*
1286 1285 * Log this event with sysevent framework.
1287 1286 */
1288 1287
1289 1288 err = ddi_log_sysevent(self, DDI_VENDOR_SUNW, EC_DR,
1290 1289 ESC_DR_REQ, ev_attr_list, &eid,
1291 1290 ((kmflag == KM_SLEEP) ? DDI_SLEEP : DDI_NOSLEEP));
1292 1291 if (err != 0) {
1293 1292 cmn_err(CE_WARN, "%s%d: Failed to log %s event",
1294 1293 ddi_driver_name(self), ddi_get_instance(self), EC_DR);
1295 1294 }
1296 1295
1297 1296 done:
1298 1297 nvlist_free(ev_attr_list);
1299 1298 kmem_free(ap_id, ap_id_len);
1300 1299 }
↓ open down ↓ |
1157 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX