1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2000, 2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * fc_ops.c: Framework generic fcode ops 32 */ 33 #include <sys/types.h> 34 #include <sys/kmem.h> 35 #include <sys/systm.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 #include <sys/sunndi.h> 39 #include <sys/modctl.h> 40 #include <sys/fcode.h> 41 #include <sys/ddi_implfuncs.h> 42 #include <sys/ndi_impldefs.h> 43 #include <sys/ethernet.h> 44 45 static int fco_new_device(dev_info_t *, fco_handle_t, fc_ci_t *); 46 static int fco_finish_device(dev_info_t *, fco_handle_t, fc_ci_t *); 47 static int fco_create_property(dev_info_t *, fco_handle_t, fc_ci_t *); 48 49 static int fco_validate(dev_info_t *, fco_handle_t, fc_ci_t *); 50 static int fco_invalidate(dev_info_t *, fco_handle_t, fc_ci_t *); 51 static int fco_exit(dev_info_t *, fco_handle_t, fc_ci_t *); 52 53 static int fco_getproplen(dev_info_t *, fco_handle_t, fc_ci_t *); 54 static int fco_getprop(dev_info_t *, fco_handle_t, fc_ci_t *); 55 56 static int fco_ap_phandle(dev_info_t *, fco_handle_t, fc_ci_t *); 57 static int fco_child(dev_info_t *, fco_handle_t, fc_ci_t *); 58 static int fco_peer(dev_info_t *, fco_handle_t, fc_ci_t *); 59 static int fco_parent(dev_info_t *, fco_handle_t, fc_ci_t *); 60 static int fco_alloc_phandle(dev_info_t *, fco_handle_t, fc_ci_t *); 61 62 static int fco_local_ether_addr(dev_info_t *, fco_handle_t, fc_ci_t *); 63 64 struct fc_ops_v { 65 char *svc_name; 66 fc_ops_t *f; 67 }; 68 69 static struct fc_ops_v fov[] = { 70 { "open", fc_fail_op}, 71 { "close", fc_fail_op}, 72 { "$find", fc_fail_op}, 73 { "encode-unit", fc_fail_op}, 74 { "decode-unit", fc_fail_op}, 75 { FC_GET_MY_PROPLEN, fco_getproplen}, 76 { FC_GET_MY_PROP, fco_getprop}, 77 { FC_GET_PKG_PROPLEN, fco_getproplen}, 78 { FC_GET_PKG_PROP, fco_getprop}, 79 { FC_GET_IN_PROPLEN, fco_getproplen}, 80 { FC_GET_IN_PROP, fco_getprop}, 81 { FC_NEW_DEVICE, fco_new_device}, 82 { FC_FINISH_DEVICE, fco_finish_device}, 83 { FC_CREATE_PROPERTY, fco_create_property}, 84 { FC_AP_PHANDLE, fco_ap_phandle}, 85 { "child", fco_child}, 86 { "peer", fco_peer}, 87 { FC_PARENT, fco_parent}, 88 { FC_ALLOC_PHANDLE, fco_alloc_phandle}, 89 { FC_SVC_VALIDATE, fco_validate}, 90 { FC_SVC_INVALIDATE, fco_invalidate}, 91 { FC_SVC_EXIT, fco_exit}, 92 { "local-ether-addr", fco_local_ether_addr}, 93 { NULL, NULL} 94 }; 95 96 /* 97 * Allocate a handle for the ops function .. our handle is a resource list 98 * Return the handle to our caller, so it can call us with it when we need it. 99 */ 100 /*ARGSUSED*/ 101 fco_handle_t 102 fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child, 103 void *fcode, size_t fcode_size, char *unit_address, void *bus_args) 104 { 105 fco_handle_t rp; 106 char *up; 107 108 rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 109 rp->next_handle = NULL; /* nobody is downstream */ 110 rp->ap = ap; 111 rp->child = child; 112 rp->fcode = fcode; 113 rp->fcode_size = fcode_size; 114 if (unit_address) { 115 up = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP); 116 (void) strcpy(up, unit_address); 117 rp->unit_address = up; 118 } 119 rp->bus_args = NULL; /* generic module has no bus args */ 120 fc_phandle_table_alloc(fc_handle_to_phandle_head(rp)); 121 122 (void) fc_dip_to_phandle(fc_handle_to_phandle_head(rp), ap); 123 124 /* 125 * Create our copy of the device tree. 126 */ 127 fc_create_device_tree(ap, &rp->dtree); 128 return (rp); 129 } 130 131 /* 132 * Free any resources associated with this handle. 133 */ 134 void 135 fc_ops_free_handle(fco_handle_t rp) 136 { 137 struct fc_resource *ip, *np; 138 139 if (rp->unit_address) 140 kmem_free(rp->unit_address, strlen(rp->unit_address) + 1); 141 142 if (rp->dtree) 143 fc_remove_device_tree(&rp->dtree); 144 145 fc_phandle_table_free(fc_handle_to_phandle_head(rp)); 146 147 for (ip = rp->head; ip != NULL; ip = np) { 148 np = ip->next; 149 switch (ip->type) { 150 case RT_NODEID: 151 impl_ddi_free_nodeid(ip->fc_nodeid_r); 152 break; 153 default: 154 cmn_err(CE_CONT, "pci_fc_ops_free: " 155 "unknown resource type %d\n", ip->type); 156 break; 157 } 158 fc_rem_resource(rp, ip); 159 kmem_free(ip, sizeof (struct fc_resource)); 160 } 161 kmem_free(rp, sizeof (struct fc_resource_list)); 162 } 163 164 int 165 fc_ops(dev_info_t *ap, fco_handle_t handle, fc_ci_t *cp) 166 { 167 struct fc_ops_v *pv; 168 char *name = fc_cell2ptr(cp->svc_name); 169 170 for (pv = fov; pv->svc_name != NULL; ++pv) 171 if (strcmp(pv->svc_name, name) == 0) 172 return (pv->f(ap, handle, cp)); 173 174 return (-1); 175 } 176 177 /* 178 * The interpreter can't do get-inherited-property directly, 179 * because we don't want to return a kernel address, so it 180 * has to break up the request into a get-proplen and get-prop 181 * call so it can allocate memory for the property and pass that 182 * buffer in to get-prop. The buffer should be 'suitably aligned'. 183 * 184 * XXX: We don't know the property type, so we can't return 185 * prop-encoded arrays, which fortunately, isn't a problem 186 * on big-endian machines. 187 * 188 * get-proplen has one result: proplen 189 * proplen is returned as -1 if the propname doesn't exist and 190 * as zero if the property is a boolean property. 191 * 192 * get-prop has one result: proplen, returned as -1 if propname doesn't exist. 193 */ 194 195 /* 196 * fco_getproplen ( propname phandle -- proplen ) 197 */ 198 199 /*ARGSUSED*/ 200 static int 201 fco_getproplen(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 202 { 203 int proplen; 204 int flags = 0; 205 fc_phandle_t h; 206 dev_info_t *dip; 207 char *pnp; 208 char propname[OBP_MAXPROPNAME]; 209 210 if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL) 211 flags |= DDI_PROP_DONTPASS; 212 213 if (fc_cell2int(cp->nargs) != 2) 214 return (fc_syntax_error(cp, "nargs must be 2")); 215 216 if (fc_cell2int(cp->nresults) < 1) 217 return (fc_syntax_error(cp, "nresults must be > 0")); 218 219 /* 220 * Make sure this is a handle we gave out ... 221 */ 222 h = fc_cell2phandle(fc_arg(cp, 0)); 223 if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL) 224 return (fc_priv_error(cp, "unknown handle")); 225 226 /* 227 * XXX: We should care if the string is longer than OBP_MAXPROPNAME 228 */ 229 pnp = fc_cell2ptr(fc_arg(cp, 1)); 230 bzero(propname, OBP_MAXPROPNAME); 231 if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL)) 232 return (fc_priv_error(cp, "EFAULT copying in propname")); 233 234 if (ddi_getproplen(DDI_DEV_T_ANY, dip, flags, propname, &proplen)) 235 proplen = -1; 236 237 fc_result(cp, 0) = fc_int2cell(proplen); 238 cp->nresults = fc_int2cell(1); 239 return (fc_success_op(ap, rp, cp)); 240 } 241 242 /* 243 * fco_getprop ( propname buffer phandle -- proplen ) 244 */ 245 246 /*ARGSUSED*/ 247 static int 248 fco_getprop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 249 { 250 int proplen = -1; 251 int flags = DDI_PROP_CANSLEEP; 252 char *pnp, *bp; 253 fc_phandle_t h; 254 dev_info_t *dip; 255 char propname[OBP_MAXPROPNAME]; 256 257 if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL) 258 flags |= DDI_PROP_DONTPASS; 259 260 if (fc_cell2int(cp->nargs) != 3) 261 return (fc_syntax_error(cp, "nargs must be 3")); 262 263 if (fc_cell2int(cp->nresults) < 1) 264 return (fc_syntax_error(cp, "nresults must be > 0")); 265 266 /* 267 * Make sure this is a handle we gave out ... 268 */ 269 h = fc_cell2phandle(fc_arg(cp, 0)); 270 if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL) 271 return (fc_priv_error(cp, "unknown handle")); 272 273 /* 274 * XXX: We should care if the string is longer than OBP_MAXPROPNAME 275 */ 276 pnp = fc_cell2ptr(fc_arg(cp, 2)); 277 bzero(propname, OBP_MAXPROPNAME); 278 if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL)) 279 return (fc_priv_error(cp, "EFAULT copying in propname")); 280 281 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, flags, 282 propname, (caddr_t)&bp, &proplen)) 283 proplen = -1; 284 285 if (proplen > 0) { 286 char *up = fc_cell2ptr(fc_arg(cp, 1)); 287 int error; 288 289 error = copyout(bp, up, proplen); 290 kmem_free(bp, proplen); 291 if (error) 292 return (fc_priv_error(cp, "EFAULT copying data out")); 293 } 294 295 cp->nresults = fc_int2cell(1); 296 fc_result(cp, 0) = fc_int2cell(proplen); 297 return (fc_success_op(ap, rp, cp)); 298 } 299 300 static int 301 fco_ap_phandle(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 302 { 303 fc_phandle_t h; 304 305 if (fc_cell2int(cp->nargs) != 0) 306 return (fc_syntax_error(cp, "nargs must be 0")); 307 308 if (fc_cell2int(cp->nresults) < 1) 309 return (fc_syntax_error(cp, "nresults must be > 0")); 310 311 FC_DEBUG1(9, CE_CONT, "fco_ap_phandle: Looking up ap dip %p\n", ap); 312 313 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), ap); 314 cp->nresults = fc_int2cell(1); 315 fc_result(cp, 0) = fc_phandle2cell(h); 316 return (fc_success_op(ap, rp, cp)); 317 } 318 319 static int 320 fco_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 321 { 322 fc_phandle_t h; 323 dev_info_t *dip; 324 325 if (fc_cell2int(cp->nargs) != 1) 326 return (fc_syntax_error(cp, "nargs must be 1")); 327 328 if (fc_cell2int(cp->nresults) < 1) 329 return (fc_syntax_error(cp, "nresults must be > 0")); 330 331 /* 332 * Make sure this is a handle we gave out ... 333 */ 334 h = fc_cell2phandle(fc_arg(cp, 0)); 335 if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL) 336 return (fc_priv_error(cp, "unknown handle")); 337 338 /* 339 * Find the child and if there is one, return it ... 340 */ 341 dip = ddi_get_child(dip); 342 h = 0; 343 if (dip != NULL) 344 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip); 345 346 cp->nresults = fc_int2cell(1); 347 fc_result(cp, 0) = fc_phandle2cell(h); 348 return (fc_success_op(ap, rp, cp)); 349 } 350 351 static int 352 fco_peer(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 353 { 354 fc_phandle_t h; 355 dev_info_t *dip; 356 357 if (fc_cell2int(cp->nargs) != 1) 358 return (fc_syntax_error(cp, "nargs must be 1")); 359 360 if (fc_cell2int(cp->nresults) < 1) 361 return (fc_syntax_error(cp, "nresults must be > 0")); 362 363 /* 364 * Make sure this is a handle we gave out ... 365 */ 366 h = fc_cell2phandle(fc_arg(cp, 0)); 367 if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL) 368 return (fc_priv_error(cp, "unknown handle")); 369 370 /* 371 * Find the child and if there is one, return it ... 372 */ 373 dip = ddi_get_next_sibling(dip); 374 h = 0; 375 if (dip != NULL) 376 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip); 377 378 cp->nresults = fc_int2cell(1); 379 fc_result(cp, 0) = fc_phandle2cell(h); 380 return (fc_success_op(ap, rp, cp)); 381 } 382 383 static int 384 fco_parent(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 385 { 386 fc_phandle_t h; 387 dev_info_t *dip; 388 389 if (fc_cell2int(cp->nargs) != 1) 390 return (fc_syntax_error(cp, "nargs must be 1")); 391 392 if (fc_cell2int(cp->nresults) < 1) 393 return (fc_syntax_error(cp, "nresults must be > 0")); 394 395 /* 396 * Make sure this is a handle we gave out ... 397 */ 398 h = fc_cell2phandle(fc_arg(cp, 0)); 399 if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL) 400 return (fc_priv_error(cp, "unknown handle")); 401 402 /* 403 * Find the parent and if there is one, return it ... 404 */ 405 dip = ddi_get_parent(dip); 406 h = 0; 407 if (dip != NULL) 408 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip); 409 410 cp->nresults = fc_int2cell(1); 411 fc_result(cp, 0) = fc_phandle2cell(h); 412 return (fc_success_op(ap, rp, cp)); 413 } 414 415 /* 416 * Allocate a phandle ... we don't currently track the phandle. 417 */ 418 static int 419 fco_alloc_phandle(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 420 { 421 fc_phandle_t h; 422 int n; 423 struct fc_resource *ip; 424 425 if (fc_cell2int(cp->nargs) != 0) 426 return (fc_syntax_error(cp, "nargs must be 0")); 427 428 if (fc_cell2int(cp->nresults) < 1) 429 return (fc_syntax_error(cp, "nresults must be > 0")); 430 431 if (impl_ddi_alloc_nodeid(&n)) 432 return (fc_priv_error(cp, "Can't allocate a nodeid")); 433 434 /* 435 * Log the nodeid resource so we can release it later if we need to. 436 */ 437 ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 438 ip->type = RT_NODEID; 439 ip->fc_nodeid_r = n; 440 fc_add_resource(rp, ip); 441 442 h = (fc_phandle_t)n; 443 444 cp->nresults = fc_int2cell(1); 445 fc_result(cp, 0) = fc_phandle2cell(h); 446 return (fc_success_op(ap, rp, cp)); 447 } 448 449 static struct fc_resource * 450 find_nodeid_resource(fco_handle_t rp, int n) 451 { 452 struct fc_resource *ip; 453 454 fc_lock_resource_list(rp); 455 for (ip = rp->head; ip != NULL; ip = ip->next) { 456 if (ip->type != RT_NODEID) 457 continue; 458 if (ip->fc_nodeid_r == n) 459 break; 460 } 461 fc_unlock_resource_list(rp); 462 463 return (ip); 464 } 465 466 /* 467 * fco_new_device ( name-cstr unit-addr-cstr parent.phandle phandle -- ) 468 */ 469 static int 470 fco_new_device(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 471 { 472 fc_phandle_t ph, ch; 473 dev_info_t *pdev, *cdev; 474 char *s; 475 int createmode = 0; 476 char *unit_address = NULL; 477 char nodename[OBP_MAXPROPNAME]; 478 479 if (fc_cell2int(cp->nargs) != 4) 480 return (fc_syntax_error(cp, "nargs must be 4")); 481 482 /* 483 * Make sure these are handles we gave out ... and we have 484 * a corresponding parent devinfo node. 485 */ 486 ph = fc_cell2phandle(fc_arg(cp, 1)); 487 pdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), ph); 488 if (pdev == NULL) 489 return (fc_priv_error(cp, "unknown parent phandle")); 490 491 ch = fc_cell2phandle(fc_arg(cp, 0)); 492 cdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), ch); 493 494 switch (rp->cdip_state) { 495 496 case FC_CDIP_NOSTATE: 497 /* 498 * The first child must be a child of the attachment point. 499 */ 500 if (pdev != ap) 501 return (fc_priv_error(cp, "first child must be a " 502 "child of the attachment point")); 503 504 /* 505 * If this bus has a config child, the first child must 506 * be the configuration child. Otherwise, the child must 507 * be a new (unknown) node. 508 */ 509 if (cdev != NULL) { 510 if (rp->child != NULL) { 511 if (cdev != rp->child) 512 return (fc_priv_error(cp, "first " 513 "child must be the " 514 "configuration child")); 515 } else { 516 return (fc_priv_error(cp, "known child -- " 517 "unknown child expected")); 518 } 519 } 520 break; 521 522 case FC_CDIP_DONE: 523 /* 524 * If we've already created the first child, this 525 * child must be unknown and the parent must be a known 526 * child of the attachment point. 527 */ 528 if (cdev) 529 return (fc_priv_error(cp, "known child -- " 530 "unknown child expected")); 531 if (fc_find_node(pdev, fc_handle_to_dtree(rp)) == NULL) 532 return (fc_priv_error(cp, "parent is an unknown " 533 "child of the attachment point")); 534 break; 535 536 default: 537 /* 538 * If we're in some other state, we shouldn't be here. 539 */ 540 return (fc_priv_error(cp, "bad node-creation state")); 541 /* NOTREACHED */ 542 } 543 544 /* 545 * Get the nodename and the unit address. 546 */ 547 s = fc_cell2ptr(fc_arg(cp, 3)); 548 bzero(nodename, OBP_MAXPROPNAME); 549 if (copyinstr(s, nodename, OBP_MAXPROPNAME - 1, NULL)) 550 return (fc_priv_error(cp, "EFAULT copying in nodename")); 551 552 s = fc_cell2ptr(fc_arg(cp, 2)); 553 unit_address = kmem_zalloc(OBP_MAXPATHLEN, KM_SLEEP); 554 if (copyinstr(s, unit_address, OBP_MAXPATHLEN - 1, NULL)) { 555 kmem_free(unit_address, OBP_MAXPATHLEN); 556 return (fc_priv_error(cp, "EFAULT copying in unit address")); 557 } 558 559 /* 560 * If cdev is NULL, we have to create the child, otherwise, the 561 * child already exists and we're just merging properties into 562 * the existing node. The node must be unbound. 563 */ 564 565 if (cdev == NULL) 566 createmode = 1; 567 568 if (createmode) { 569 struct fc_resource *ip; 570 int nodeid; 571 /* 572 * Make sure 'ch' is a nodeid we gave the interpreter. 573 * It must be on our resource list. 574 */ 575 if ((ip = find_nodeid_resource(rp, (int)ch)) == NULL) { 576 kmem_free(unit_address, OBP_MAXPATHLEN); 577 return (fc_priv_error(cp, "Unknown phandle")); 578 } 579 580 /* 581 * Allocate a self-identifying, persistent node with 582 * the auto-free attribute. 583 */ 584 if (ndi_devi_alloc(pdev, nodename, DEVI_SID_NODEID, &cdev)) { 585 kmem_free(unit_address, OBP_MAXPATHLEN); 586 return (fc_priv_error(cp, "Can't create node")); 587 } 588 589 /* 590 * Free the nodeid we just allocated here, and use 591 * the one we handed in. Retain the attributes of 592 * the original SID nodetype. 593 */ 594 nodeid = ddi_get_nodeid(cdev); 595 i_ndi_set_nodeid(cdev, (int)ch); 596 impl_ddi_free_nodeid(nodeid); 597 598 /* 599 * Remove nodeid 'ch' from our resource list, now that it 600 * will be managed by the ddi framework. 601 */ 602 fc_rem_resource(rp, ip); 603 kmem_free(ip, sizeof (struct fc_resource)); 604 605 } else if (strcmp(ddi_node_name(cdev), nodename) != 0) { 606 FC_DEBUG2(1, CE_CONT, "Changing <%s> nodename to <%s>\n", 607 ddi_node_name(cdev), nodename); 608 if (ndi_devi_set_nodename(cdev, nodename, 0)) { 609 kmem_free(unit_address, OBP_MAXPATHLEN); 610 return (fc_priv_error(cp, "Can't set ndi nodename")); 611 } 612 } 613 614 if (fc_ndi_prop_update(DDI_DEV_T_NONE, cdev, "name", 615 (uchar_t *)nodename, strlen(nodename) + 1)) { 616 kmem_free(unit_address, OBP_MAXPATHLEN); 617 if (createmode) 618 (void) ndi_devi_free(cdev); 619 return (fc_priv_error(cp, "Can't create name property")); 620 } 621 622 /* 623 * Add the dip->phandle translation to our list of known phandles. 624 */ 625 fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), cdev, ch); 626 627 /* 628 * Add the new node to our copy of the subtree. 629 */ 630 fc_add_child(cdev, pdev, fc_handle_to_dtree(rp)); 631 632 rp->cdip = cdev; 633 rp->cdip_state = FC_CDIP_STARTED; 634 635 kmem_free(unit_address, OBP_MAXPATHLEN); 636 cp->nresults = fc_int2cell(0); 637 return (fc_success_op(ap, rp, cp)); 638 } 639 640 /* 641 * fco_finish_device ( phandle -- ) 642 */ 643 static int 644 fco_finish_device(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 645 { 646 fc_phandle_t h; 647 dev_info_t *cdev; 648 649 if (fc_cell2int(cp->nargs) != 1) 650 return (fc_syntax_error(cp, "nargs must be 1")); 651 652 if (rp->cdip_state != FC_CDIP_STARTED) 653 return (fc_priv_error(cp, "bad node-creation state")); 654 655 h = fc_cell2phandle(fc_arg(cp, 0)); 656 cdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h); 657 if (cdev != rp->cdip) 658 return (fc_priv_error(cp, "bad phandle")); 659 660 /* 661 * We don't want to online children of the attachment point. 662 * We'll 'config' them online later. 663 * 664 * XXX - APA - I've changed this a bit. The only time we don't 665 * want to bind the device is if the parent is the attachment point 666 * and the device is the same as the device that was passed to 667 * the interpreter. We assume the configurator will do the binding. 668 */ 669 if ((ddi_get_parent(cdev) == ap) && (cdev == rp->child)) { 670 FC_DEBUG2(5, CE_CONT, "fc_finish_device: " 671 "*not* binding <%s> dip %p\n", ddi_node_name(cdev), cdev); 672 } else { 673 FC_DEBUG2(5, CE_CONT, "fc_finish_device: binding <%s> dip %p\n", 674 ddi_node_name(cdev), cdev); 675 676 (void) ndi_devi_bind_driver(cdev, 0); 677 } 678 679 rp->cdip_state = FC_CDIP_DONE; 680 cp->nresults = fc_int2cell(0); 681 return (fc_success_op(ap, rp, cp)); 682 } 683 684 /* 685 * fco_create_property ( propname-cstr buf len phandle -- ) 686 */ 687 static int 688 fco_create_property(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 689 { 690 char *buf, *bp, *pnp; 691 size_t len; 692 fc_phandle_t h; 693 dev_info_t *dev; 694 int error; 695 char propname[OBP_MAXPROPNAME]; 696 697 if (fc_cell2int(cp->nargs) != 4) 698 return (fc_syntax_error(cp, "nargs must be 4")); 699 700 h = fc_cell2phandle(fc_arg(cp, 0)); 701 len = fc_cell2size(fc_arg(cp, 1)); 702 bp = fc_cell2ptr(fc_arg(cp, 2)); 703 pnp = fc_cell2ptr(fc_arg(cp, 3)); 704 705 dev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h); 706 if (dev == NULL) 707 return (fc_priv_error(cp, "bad phandle")); 708 709 bzero(propname, OBP_MAXPROPNAME); 710 if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL)) 711 return (fc_priv_error(cp, "EFAULT copying in propname")); 712 713 buf = NULL; 714 if (len != 0) { 715 buf = kmem_zalloc(len, KM_SLEEP); 716 if (copyin(bp, buf, len)) { 717 kmem_free(buf, len); 718 return (fc_priv_error(cp, "EFAULT copying in propval")); 719 } 720 } 721 722 /* 723 * check for propname: 'name' ... we don't allow it 724 * by changed here. It has to be specified when the node 725 * is created. 726 */ 727 if (strcmp(propname, "name") == 0) { 728 char *n = ddi_node_name(dev); 729 730 if (len == 0) 731 return (fc_priv_error(cp, "setting <name> to NULL")); 732 if ((len < (strlen(n) + 1)) || (strcmp(n, buf) != 0)) { 733 kmem_free(buf, len); 734 return (fc_priv_error(cp, "changing <name> property")); 735 } 736 /* 737 * Since we're not changing the value, and we already created 738 * the 'name' property when we created the node ... 739 */ 740 kmem_free(buf, len); 741 cp->nresults = fc_int2cell(0); 742 return (fc_success_op(ap, rp, cp)); 743 } 744 745 error = fc_ndi_prop_update(DDI_DEV_T_NONE, dev, propname, 746 (uchar_t *)buf, len); 747 748 if (len != 0) 749 kmem_free(buf, len); 750 751 if (error) 752 return (fc_priv_error(cp, "Can't create property")); 753 754 cp->nresults = fc_int2cell(0); 755 return (fc_success_op(ap, rp, cp)); 756 } 757 758 /* 759 * Make sure any in-progress activity is completed, 760 * and for now, online the subtree. 761 * XXX: Presumably the configurator will online the subtree 762 * XXX: by doing an ndi_devi_online with NDI_CONFIG on the child 763 * XXX: if there is one. For now, we're doing it here. 764 * XXX: For buses without a configurator (and thus no config child), 765 * XXX: we have to do it here. 766 * 767 */ 768 static int 769 fco_validate(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 770 { 771 rp->cdip_state = FC_CDIP_CONFIG; 772 773 cp->nresults = fc_int2cell(0); 774 return (fc_success_op(ap, rp, cp)); 775 } 776 777 static void 778 remove_subtree(dev_info_t *root, struct fc_device_tree *subtree) 779 { 780 dev_info_t *child; 781 782 /* 783 * Remove the subtree, depth first. Each iterative 784 * call gets another child at each level of the tree 785 * until there are no more children. 786 */ 787 while ((child = fc_child_node(root, subtree)) != NULL) 788 remove_subtree(child, subtree); 789 790 /* 791 * Delete the subtree root and remove its record from our 792 * copy of the subtree. 793 */ 794 fc_remove_child(root, subtree); 795 (void) ndi_devi_offline(root, NDI_UNCONFIG | NDI_DEVI_REMOVE); 796 } 797 798 static int 799 fco_invalidate(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 800 { 801 dev_info_t *root, *child; 802 struct fc_device_tree *subtree = fc_handle_to_dtree(rp); 803 int configured = (rp->cdip_state == FC_CDIP_CONFIG); 804 805 /* 806 * If we created any children, delete them. The root node is the 807 * config child, if one exists for this bus, otherwise it's the 808 * attachment point. 809 * 810 * Our copy of the subtree only contains records of nodes we created 811 * under the subtree root and contains the parent->child linkage 812 * that isn't yet established in the real device tree. 813 * 814 * XXX: What we don't do is restore the config child node to it's 815 * pre-interpretive state. (We may have added properties to 816 * that node. It's not clear if its necessary to clean them up.) 817 */ 818 root = rp->child ? rp->child : ap; 819 820 while ((child = fc_child_node(root, subtree)) != NULL) { 821 FC_DEBUG2(1, CE_CONT, "fco_invalidate: remove subtree " 822 "<%s> dip %p\n", ddi_node_name(child), child); 823 remove_subtree(child, subtree); 824 } 825 826 if (configured) 827 (void) ndi_devi_offline(root, NDI_UNCONFIG); 828 829 cp->nresults = fc_int2cell(0); 830 return (fc_success_op(ap, rp, cp)); 831 } 832 833 static int 834 fco_exit(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 835 { 836 FC_DEBUG0(1, CE_CONT, "exit op not implemented .. succeeding\n"); 837 cp->nresults = fc_int2cell(0); 838 return (fc_success_op(ap, rp, cp)); 839 } 840 841 /* 842 * Needed to implement 'mac-address' Fcode, no obvious place to pick this 843 * info up from user-land. 844 */ 845 static int 846 fco_local_ether_addr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 847 { 848 if (fc_cell2int(cp->nargs) != 0) 849 return (fc_syntax_error(cp, "nargs must be 0")); 850 851 if (fc_cell2int(cp->nresults) != 2) 852 return (fc_syntax_error(cp, "nresults must be 2")); 853 854 cp->nresults = fc_int2cell(2); 855 856 (void) localetheraddr(NULL, (struct ether_addr *)(&fc_result(cp, 0))); 857 858 return (fc_success_op(ap, rp, cp)); 859 } 860 861 #ifdef DEBUG 862 void 863 fc_debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, 864 uintptr_t a4, uintptr_t a5) 865 { 866 cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5); 867 } 868 #endif 869