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