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