1*03831d35Sstevel /* 2*03831d35Sstevel * CDDL HEADER START 3*03831d35Sstevel * 4*03831d35Sstevel * The contents of this file are subject to the terms of the 5*03831d35Sstevel * Common Development and Distribution License (the "License"). 6*03831d35Sstevel * You may not use this file except in compliance with the License. 7*03831d35Sstevel * 8*03831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*03831d35Sstevel * or http://www.opensolaris.org/os/licensing. 10*03831d35Sstevel * See the License for the specific language governing permissions 11*03831d35Sstevel * and limitations under the License. 12*03831d35Sstevel * 13*03831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 14*03831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*03831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 16*03831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 17*03831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 18*03831d35Sstevel * 19*03831d35Sstevel * CDDL HEADER END 20*03831d35Sstevel */ 21*03831d35Sstevel 22*03831d35Sstevel /* 23*03831d35Sstevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*03831d35Sstevel * Use is subject to license terms. 25*03831d35Sstevel */ 26*03831d35Sstevel 27*03831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*03831d35Sstevel 29*03831d35Sstevel #include <sys/stat.h> 30*03831d35Sstevel #include <sys/conf.h> 31*03831d35Sstevel #include <sys/modctl.h> 32*03831d35Sstevel #include <sys/ddi.h> 33*03831d35Sstevel #include <sys/rmc_comm_dp.h> 34*03831d35Sstevel #include <sys/rmc_comm_dp_boot.h> 35*03831d35Sstevel #include <sys/rmc_comm_drvintf.h> 36*03831d35Sstevel #include <sys/cyclic.h> 37*03831d35Sstevel #include <sys/rmc_comm.h> 38*03831d35Sstevel #include <sys/machsystm.h> 39*03831d35Sstevel #include <sys/file.h> 40*03831d35Sstevel #include <sys/rmcadm.h> 41*03831d35Sstevel 42*03831d35Sstevel /* 43*03831d35Sstevel * functions local to this driver. 44*03831d35Sstevel */ 45*03831d35Sstevel static int rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 46*03831d35Sstevel void **resultp); 47*03831d35Sstevel static int rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 48*03831d35Sstevel static int rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 49*03831d35Sstevel static int rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 50*03831d35Sstevel static int rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p); 51*03831d35Sstevel static int rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 52*03831d35Sstevel cred_t *cred_p, int *rval_p); 53*03831d35Sstevel 54*03831d35Sstevel /* 55*03831d35Sstevel * Driver entry points 56*03831d35Sstevel */ 57*03831d35Sstevel static struct cb_ops rmcadm_cb_ops = { 58*03831d35Sstevel rmcadm_open, /* open */ 59*03831d35Sstevel rmcadm_close, /* close */ 60*03831d35Sstevel nodev, /* strategy() */ 61*03831d35Sstevel nodev, /* print() */ 62*03831d35Sstevel nodev, /* dump() */ 63*03831d35Sstevel nodev, /* read() */ 64*03831d35Sstevel nodev, /* write() */ 65*03831d35Sstevel rmcadm_ioctl, /* ioctl() */ 66*03831d35Sstevel nodev, /* devmap() */ 67*03831d35Sstevel nodev, /* mmap() */ 68*03831d35Sstevel ddi_segmap, /* segmap() */ 69*03831d35Sstevel nochpoll, /* poll() */ 70*03831d35Sstevel ddi_prop_op, /* prop_op() */ 71*03831d35Sstevel NULL, /* cb_str */ 72*03831d35Sstevel D_NEW | D_MP /* cb_flag */ 73*03831d35Sstevel }; 74*03831d35Sstevel 75*03831d35Sstevel 76*03831d35Sstevel static struct dev_ops rmcadm_ops = { 77*03831d35Sstevel DEVO_REV, 78*03831d35Sstevel 0, /* ref count */ 79*03831d35Sstevel rmcadm_getinfo, /* getinfo() */ 80*03831d35Sstevel nulldev, /* identify() */ 81*03831d35Sstevel nulldev, /* probe() */ 82*03831d35Sstevel rmcadm_attach, /* attach() */ 83*03831d35Sstevel rmcadm_detach, /* detach */ 84*03831d35Sstevel nodev, /* reset */ 85*03831d35Sstevel &rmcadm_cb_ops, /* pointer to cb_ops structure */ 86*03831d35Sstevel (struct bus_ops *)NULL, 87*03831d35Sstevel nulldev /* power() */ 88*03831d35Sstevel }; 89*03831d35Sstevel 90*03831d35Sstevel /* 91*03831d35Sstevel * Loadable module support. 92*03831d35Sstevel */ 93*03831d35Sstevel extern struct mod_ops mod_driverops; 94*03831d35Sstevel 95*03831d35Sstevel static struct modldrv modldrv = { 96*03831d35Sstevel &mod_driverops, /* Type of module. This is a driver */ 97*03831d35Sstevel "rmcadm control driver v%I%", /* Name of the module */ 98*03831d35Sstevel &rmcadm_ops /* pointer to the dev_ops structure */ 99*03831d35Sstevel }; 100*03831d35Sstevel 101*03831d35Sstevel static struct modlinkage modlinkage = { 102*03831d35Sstevel MODREV_1, 103*03831d35Sstevel &modldrv, 104*03831d35Sstevel NULL 105*03831d35Sstevel }; 106*03831d35Sstevel 107*03831d35Sstevel static dev_info_t *rmcadm_dip = NULL; 108*03831d35Sstevel 109*03831d35Sstevel extern void pmugpio_reset(); 110*03831d35Sstevel 111*03831d35Sstevel /* 112*03831d35Sstevel * Utilities... 113*03831d35Sstevel */ 114*03831d35Sstevel 115*03831d35Sstevel /* 116*03831d35Sstevel * to return the errno from the rmc_comm error status 117*03831d35Sstevel */ 118*03831d35Sstevel int 119*03831d35Sstevel rmcadm_get_errno(int status) 120*03831d35Sstevel { 121*03831d35Sstevel int retval = EIO; 122*03831d35Sstevel 123*03831d35Sstevel /* errors from RMC */ 124*03831d35Sstevel switch (status) { 125*03831d35Sstevel case RCENOSOFTSTATE: 126*03831d35Sstevel /* invalid/NULL soft state structure */ 127*03831d35Sstevel retval = EIO; 128*03831d35Sstevel break; 129*03831d35Sstevel case RCENODATALINK: 130*03831d35Sstevel /* data protocol not available (down) */ 131*03831d35Sstevel retval = EIO; 132*03831d35Sstevel break; 133*03831d35Sstevel case RCENOMEM: 134*03831d35Sstevel /* memory problems */ 135*03831d35Sstevel retval = ENOMEM; 136*03831d35Sstevel break; 137*03831d35Sstevel case RCECANTRESEND: 138*03831d35Sstevel /* resend failed */ 139*03831d35Sstevel retval = EIO; 140*03831d35Sstevel break; 141*03831d35Sstevel case RCEMAXRETRIES: 142*03831d35Sstevel /* reply not received - retries exceeded */ 143*03831d35Sstevel retval = EINTR; 144*03831d35Sstevel break; 145*03831d35Sstevel case RCETIMEOUT: 146*03831d35Sstevel /* reply not received - command has timed out */ 147*03831d35Sstevel retval = EINTR; 148*03831d35Sstevel break; 149*03831d35Sstevel case RCEINVCMD: 150*03831d35Sstevel /* data protocol cmd not supported */ 151*03831d35Sstevel retval = ENOTSUP; 152*03831d35Sstevel break; 153*03831d35Sstevel case RCEINVARG: 154*03831d35Sstevel /* invalid argument(s) */ 155*03831d35Sstevel retval = ENOTSUP; 156*03831d35Sstevel break; 157*03831d35Sstevel case RCEGENERIC: 158*03831d35Sstevel /* generic error */ 159*03831d35Sstevel retval = EIO; 160*03831d35Sstevel break; 161*03831d35Sstevel default: 162*03831d35Sstevel retval = EIO; 163*03831d35Sstevel break; 164*03831d35Sstevel } 165*03831d35Sstevel return (retval); 166*03831d35Sstevel } 167*03831d35Sstevel 168*03831d35Sstevel int 169*03831d35Sstevel _init(void) 170*03831d35Sstevel { 171*03831d35Sstevel int error = 0; 172*03831d35Sstevel 173*03831d35Sstevel error = mod_install(&modlinkage); 174*03831d35Sstevel return (error); 175*03831d35Sstevel } 176*03831d35Sstevel 177*03831d35Sstevel 178*03831d35Sstevel int 179*03831d35Sstevel _info(struct modinfo *modinfop) 180*03831d35Sstevel { 181*03831d35Sstevel return (mod_info(&modlinkage, modinfop)); 182*03831d35Sstevel } 183*03831d35Sstevel 184*03831d35Sstevel 185*03831d35Sstevel int 186*03831d35Sstevel _fini(void) 187*03831d35Sstevel { 188*03831d35Sstevel int error = 0; 189*03831d35Sstevel 190*03831d35Sstevel error = mod_remove(&modlinkage); 191*03831d35Sstevel if (error) 192*03831d35Sstevel return (error); 193*03831d35Sstevel return (error); 194*03831d35Sstevel } 195*03831d35Sstevel 196*03831d35Sstevel 197*03831d35Sstevel /* ARGSUSED */ 198*03831d35Sstevel static int 199*03831d35Sstevel rmcadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 200*03831d35Sstevel { 201*03831d35Sstevel minor_t m = getminor((dev_t)arg); 202*03831d35Sstevel 203*03831d35Sstevel switch (cmd) { 204*03831d35Sstevel case DDI_INFO_DEVT2DEVINFO: 205*03831d35Sstevel if ((m != 0) || (rmcadm_dip == NULL)) { 206*03831d35Sstevel *resultp = NULL; 207*03831d35Sstevel return (DDI_FAILURE); 208*03831d35Sstevel } 209*03831d35Sstevel *resultp = rmcadm_dip; 210*03831d35Sstevel return (DDI_SUCCESS); 211*03831d35Sstevel case DDI_INFO_DEVT2INSTANCE: 212*03831d35Sstevel *resultp = (void *)(uintptr_t)m; 213*03831d35Sstevel return (DDI_SUCCESS); 214*03831d35Sstevel default: 215*03831d35Sstevel return (DDI_FAILURE); 216*03831d35Sstevel } 217*03831d35Sstevel } 218*03831d35Sstevel 219*03831d35Sstevel 220*03831d35Sstevel static int 221*03831d35Sstevel rmcadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 222*03831d35Sstevel { 223*03831d35Sstevel int instance; 224*03831d35Sstevel int err; 225*03831d35Sstevel 226*03831d35Sstevel switch (cmd) { 227*03831d35Sstevel case DDI_ATTACH: 228*03831d35Sstevel /* 229*03831d35Sstevel * only allow one instance 230*03831d35Sstevel */ 231*03831d35Sstevel instance = ddi_get_instance(dip); 232*03831d35Sstevel if (instance != 0) 233*03831d35Sstevel return (DDI_FAILURE); 234*03831d35Sstevel 235*03831d35Sstevel err = ddi_create_minor_node(dip, "rmcadm", S_IFCHR, 236*03831d35Sstevel instance, DDI_PSEUDO, NULL); 237*03831d35Sstevel if (err != DDI_SUCCESS) 238*03831d35Sstevel return (DDI_FAILURE); 239*03831d35Sstevel 240*03831d35Sstevel /* 241*03831d35Sstevel * Register with rmc_comm to prevent it being detached 242*03831d35Sstevel */ 243*03831d35Sstevel err = rmc_comm_register(); 244*03831d35Sstevel if (err != DDI_SUCCESS) { 245*03831d35Sstevel ddi_remove_minor_node(dip, NULL); 246*03831d35Sstevel return (DDI_FAILURE); 247*03831d35Sstevel } 248*03831d35Sstevel 249*03831d35Sstevel /* Remember the dev info */ 250*03831d35Sstevel rmcadm_dip = dip; 251*03831d35Sstevel 252*03831d35Sstevel ddi_report_dev(dip); 253*03831d35Sstevel return (DDI_SUCCESS); 254*03831d35Sstevel case DDI_RESUME: 255*03831d35Sstevel return (DDI_SUCCESS); 256*03831d35Sstevel default: 257*03831d35Sstevel return (DDI_FAILURE); 258*03831d35Sstevel } 259*03831d35Sstevel } 260*03831d35Sstevel 261*03831d35Sstevel 262*03831d35Sstevel static int 263*03831d35Sstevel rmcadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 264*03831d35Sstevel { 265*03831d35Sstevel int instance; 266*03831d35Sstevel 267*03831d35Sstevel switch (cmd) { 268*03831d35Sstevel case DDI_DETACH: 269*03831d35Sstevel instance = ddi_get_instance(dip); 270*03831d35Sstevel if (instance != 0) 271*03831d35Sstevel return (DDI_FAILURE); 272*03831d35Sstevel 273*03831d35Sstevel rmcadm_dip = NULL; 274*03831d35Sstevel ddi_remove_minor_node(dip, NULL); 275*03831d35Sstevel rmc_comm_unregister(); 276*03831d35Sstevel return (DDI_SUCCESS); 277*03831d35Sstevel case DDI_SUSPEND: 278*03831d35Sstevel return (DDI_SUCCESS); 279*03831d35Sstevel default: 280*03831d35Sstevel return (DDI_FAILURE); 281*03831d35Sstevel } 282*03831d35Sstevel } 283*03831d35Sstevel 284*03831d35Sstevel /*ARGSUSED*/ 285*03831d35Sstevel static int 286*03831d35Sstevel rmcadm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 287*03831d35Sstevel { 288*03831d35Sstevel int error = 0; 289*03831d35Sstevel int instance = getminor(*dev_p); 290*03831d35Sstevel 291*03831d35Sstevel if (instance != 0) 292*03831d35Sstevel return (ENXIO); 293*03831d35Sstevel 294*03831d35Sstevel if ((error = drv_priv(cred_p)) != 0) { 295*03831d35Sstevel cmn_err(CE_WARN, "rmcadm: inst %d drv_priv failed", 296*03831d35Sstevel instance); 297*03831d35Sstevel return (error); 298*03831d35Sstevel } 299*03831d35Sstevel return (error); 300*03831d35Sstevel } 301*03831d35Sstevel 302*03831d35Sstevel /*ARGSUSED*/ 303*03831d35Sstevel static int 304*03831d35Sstevel rmcadm_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 305*03831d35Sstevel { 306*03831d35Sstevel return (DDI_SUCCESS); 307*03831d35Sstevel } 308*03831d35Sstevel 309*03831d35Sstevel /*ARGSUSED*/ 310*03831d35Sstevel static int 311*03831d35Sstevel rmcadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 312*03831d35Sstevel int *rval_p) 313*03831d35Sstevel { 314*03831d35Sstevel int instance = getminor(dev); 315*03831d35Sstevel int retval = 0; 316*03831d35Sstevel rmcadm_request_response_t rr; 317*03831d35Sstevel rmcadm_send_srecord_bp_t ssbp; 318*03831d35Sstevel rmc_comm_msg_t rmc_req, *rmc_reqp = &rmc_req; 319*03831d35Sstevel rmc_comm_msg_t rmc_resp, *rmc_respp = &rmc_resp; 320*03831d35Sstevel caddr_t user_req_buf; 321*03831d35Sstevel caddr_t user_data_buf; 322*03831d35Sstevel caddr_t user_resp_buf; 323*03831d35Sstevel 324*03831d35Sstevel if (instance != 0) 325*03831d35Sstevel return (ENXIO); 326*03831d35Sstevel 327*03831d35Sstevel switch (cmd) { 328*03831d35Sstevel 329*03831d35Sstevel case RMCADM_REQUEST_RESPONSE: 330*03831d35Sstevel case RMCADM_REQUEST_RESPONSE_BP: 331*03831d35Sstevel 332*03831d35Sstevel /* 333*03831d35Sstevel * first copy in the request_response structure 334*03831d35Sstevel */ 335*03831d35Sstevel #ifdef _MULTI_DATAMODEL 336*03831d35Sstevel switch (ddi_model_convert_from(mode & FMODELS)) { 337*03831d35Sstevel case DDI_MODEL_ILP32: 338*03831d35Sstevel { 339*03831d35Sstevel /* 340*03831d35Sstevel * For use when a 32 bit app makes a call into a 341*03831d35Sstevel * 64 bit ioctl 342*03831d35Sstevel */ 343*03831d35Sstevel rmcadm_request_response32_t rr32; 344*03831d35Sstevel 345*03831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&rr32, 346*03831d35Sstevel sizeof (rr32), mode)) { 347*03831d35Sstevel return (EFAULT); 348*03831d35Sstevel } 349*03831d35Sstevel rr.req.msg_type = rr32.req.msg_type; 350*03831d35Sstevel rr.req.msg_len = rr32.req.msg_len; 351*03831d35Sstevel rr.req.msg_bytes = rr32.req.msg_bytes; 352*03831d35Sstevel rr.req.msg_buf = (caddr_t)(uintptr_t)rr32.req.msg_buf; 353*03831d35Sstevel rr.resp.msg_type = rr32.resp.msg_type; 354*03831d35Sstevel rr.resp.msg_len = rr32.resp.msg_len; 355*03831d35Sstevel rr.resp.msg_bytes = rr32.resp.msg_bytes; 356*03831d35Sstevel rr.resp.msg_buf = (caddr_t)(uintptr_t)rr32.resp.msg_buf; 357*03831d35Sstevel rr.wait_time = rr32.wait_time; 358*03831d35Sstevel break; 359*03831d35Sstevel } 360*03831d35Sstevel case DDI_MODEL_NONE: 361*03831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&rr, 362*03831d35Sstevel sizeof (rr), mode)) { 363*03831d35Sstevel return (EFAULT); 364*03831d35Sstevel } 365*03831d35Sstevel break; 366*03831d35Sstevel } 367*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */ 368*03831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&rr, 369*03831d35Sstevel sizeof (rr), mode) != 0) { 370*03831d35Sstevel return (EFAULT); 371*03831d35Sstevel } 372*03831d35Sstevel #endif /* _MULTI_DATAMODEL */ 373*03831d35Sstevel 374*03831d35Sstevel /* 375*03831d35Sstevel * save the user request buffer pointer 376*03831d35Sstevel */ 377*03831d35Sstevel user_req_buf = rr.req.msg_buf; 378*03831d35Sstevel 379*03831d35Sstevel if (user_req_buf != NULL) { 380*03831d35Sstevel /* 381*03831d35Sstevel * copy in the request data 382*03831d35Sstevel */ 383*03831d35Sstevel rr.req.msg_buf = kmem_alloc(rr.req.msg_len, KM_SLEEP); 384*03831d35Sstevel 385*03831d35Sstevel if (ddi_copyin(user_req_buf, rr.req.msg_buf, 386*03831d35Sstevel rr.req.msg_len, mode) != 0) { 387*03831d35Sstevel 388*03831d35Sstevel kmem_free(rr.req.msg_buf, rr.req.msg_len); 389*03831d35Sstevel rr.req.msg_buf = user_req_buf; 390*03831d35Sstevel return (EFAULT); 391*03831d35Sstevel } 392*03831d35Sstevel } else { 393*03831d35Sstevel if (rr.req.msg_len > 0) 394*03831d35Sstevel /* 395*03831d35Sstevel * msg_len should be 0 if buffer is NULL! 396*03831d35Sstevel */ 397*03831d35Sstevel return (EINVAL); 398*03831d35Sstevel } 399*03831d35Sstevel 400*03831d35Sstevel /* 401*03831d35Sstevel * save the user request buffer pointer 402*03831d35Sstevel */ 403*03831d35Sstevel user_resp_buf = rr.resp.msg_buf; 404*03831d35Sstevel if (user_resp_buf != NULL) { 405*03831d35Sstevel rr.resp.msg_buf = kmem_alloc(rr.resp.msg_len, KM_SLEEP); 406*03831d35Sstevel } 407*03831d35Sstevel 408*03831d35Sstevel /* 409*03831d35Sstevel * send the request (or BP request) via the rmc_comm driver 410*03831d35Sstevel */ 411*03831d35Sstevel rmc_reqp->msg_type = rr.req.msg_type; 412*03831d35Sstevel rmc_reqp->msg_buf = rr.req.msg_buf; 413*03831d35Sstevel rmc_reqp->msg_len = rr.req.msg_len; 414*03831d35Sstevel rmc_reqp->msg_bytes = rr.req.msg_bytes; 415*03831d35Sstevel 416*03831d35Sstevel if (cmd == RMCADM_REQUEST_RESPONSE) { 417*03831d35Sstevel 418*03831d35Sstevel /* 419*03831d35Sstevel * check if response is expected. If so, fill in 420*03831d35Sstevel * the response data structure 421*03831d35Sstevel */ 422*03831d35Sstevel if (rr.resp.msg_type != DP_NULL_MSG) { 423*03831d35Sstevel 424*03831d35Sstevel rmc_respp->msg_type = rr.resp.msg_type; 425*03831d35Sstevel rmc_respp->msg_buf = rr.resp.msg_buf; 426*03831d35Sstevel rmc_respp->msg_len = rr.resp.msg_len; 427*03831d35Sstevel rmc_respp->msg_bytes = rr.resp.msg_bytes; 428*03831d35Sstevel 429*03831d35Sstevel } else { 430*03831d35Sstevel 431*03831d35Sstevel rmc_respp = (rmc_comm_msg_t *)NULL; 432*03831d35Sstevel } 433*03831d35Sstevel 434*03831d35Sstevel rr.status = rmc_comm_request_response( 435*03831d35Sstevel rmc_reqp, rmc_respp, rr.wait_time); 436*03831d35Sstevel 437*03831d35Sstevel } else { /* RMCADM_REQUEST_RESPONSE_BP */ 438*03831d35Sstevel 439*03831d35Sstevel /* 440*03831d35Sstevel * check if a BP message is expected back. If so, 441*03831d35Sstevel * fill in the response data structure 442*03831d35Sstevel */ 443*03831d35Sstevel if (rr.resp.msg_buf != NULL) { 444*03831d35Sstevel 445*03831d35Sstevel rmc_respp->msg_type = rr.resp.msg_type; 446*03831d35Sstevel rmc_respp->msg_buf = rr.resp.msg_buf; 447*03831d35Sstevel rmc_respp->msg_len = rr.resp.msg_len; 448*03831d35Sstevel rmc_respp->msg_bytes = rr.resp.msg_bytes; 449*03831d35Sstevel 450*03831d35Sstevel } else { 451*03831d35Sstevel 452*03831d35Sstevel rmc_respp = (rmc_comm_msg_t *)NULL; 453*03831d35Sstevel } 454*03831d35Sstevel 455*03831d35Sstevel rr.status = rmc_comm_request_response_bp( 456*03831d35Sstevel rmc_reqp, rmc_respp, rr.wait_time); 457*03831d35Sstevel } 458*03831d35Sstevel 459*03831d35Sstevel /* 460*03831d35Sstevel * if a response was expected, copy back the (actual) number 461*03831d35Sstevel * of bytes of the response returned by the 462*03831d35Sstevel * rmc_comm_request_response function (msg_bytes field) 463*03831d35Sstevel */ 464*03831d35Sstevel if (rmc_respp != NULL) { 465*03831d35Sstevel rr.resp.msg_bytes = rmc_respp->msg_bytes; 466*03831d35Sstevel } 467*03831d35Sstevel 468*03831d35Sstevel if (rr.status != RCNOERR) { 469*03831d35Sstevel 470*03831d35Sstevel retval = rmcadm_get_errno(rr.status); 471*03831d35Sstevel 472*03831d35Sstevel } else if (user_resp_buf != NULL) { 473*03831d35Sstevel /* 474*03831d35Sstevel * copy out the user response buffer 475*03831d35Sstevel */ 476*03831d35Sstevel if (ddi_copyout(rr.resp.msg_buf, user_resp_buf, 477*03831d35Sstevel rr.resp.msg_bytes, mode) != 0) { 478*03831d35Sstevel retval = EFAULT; 479*03831d35Sstevel } 480*03831d35Sstevel } 481*03831d35Sstevel 482*03831d35Sstevel /* 483*03831d35Sstevel * now copy out the updated request_response structure 484*03831d35Sstevel */ 485*03831d35Sstevel if (rr.req.msg_buf) 486*03831d35Sstevel kmem_free(rr.req.msg_buf, rr.req.msg_len); 487*03831d35Sstevel if (rr.resp.msg_buf) 488*03831d35Sstevel kmem_free(rr.resp.msg_buf, rr.resp.msg_len); 489*03831d35Sstevel 490*03831d35Sstevel rr.req.msg_buf = user_req_buf; 491*03831d35Sstevel rr.resp.msg_buf = user_resp_buf; 492*03831d35Sstevel 493*03831d35Sstevel #ifdef _MULTI_DATAMODEL 494*03831d35Sstevel switch (ddi_model_convert_from(mode & FMODELS)) { 495*03831d35Sstevel case DDI_MODEL_ILP32: 496*03831d35Sstevel { 497*03831d35Sstevel /* 498*03831d35Sstevel * For use when a 32 bit app makes a call into a 499*03831d35Sstevel * 64 bit ioctl 500*03831d35Sstevel */ 501*03831d35Sstevel rmcadm_request_response32_t rr32; 502*03831d35Sstevel 503*03831d35Sstevel rr32.req.msg_type = rr.req.msg_type; 504*03831d35Sstevel rr32.req.msg_len = rr.req.msg_len; 505*03831d35Sstevel rr32.req.msg_bytes = rr.req.msg_bytes; 506*03831d35Sstevel rr32.req.msg_buf = (caddr32_t)(uintptr_t)rr.req.msg_buf; 507*03831d35Sstevel rr32.resp.msg_type = rr.resp.msg_type; 508*03831d35Sstevel rr32.resp.msg_len = rr.resp.msg_len; 509*03831d35Sstevel rr32.resp.msg_bytes = rr.resp.msg_bytes; 510*03831d35Sstevel rr32.resp.msg_buf = 511*03831d35Sstevel (caddr32_t)(uintptr_t)rr.resp.msg_buf; 512*03831d35Sstevel rr32.wait_time = rr.wait_time; 513*03831d35Sstevel rr32.status = rr.status; 514*03831d35Sstevel if (ddi_copyout((caddr_t)&rr32, (caddr_t)arg, 515*03831d35Sstevel sizeof (rr32), mode)) { 516*03831d35Sstevel return (EFAULT); 517*03831d35Sstevel } 518*03831d35Sstevel break; 519*03831d35Sstevel } 520*03831d35Sstevel case DDI_MODEL_NONE: 521*03831d35Sstevel if (ddi_copyout((caddr_t)&rr, (caddr_t)arg, 522*03831d35Sstevel sizeof (rr), mode)) 523*03831d35Sstevel return (EFAULT); 524*03831d35Sstevel break; 525*03831d35Sstevel } 526*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */ 527*03831d35Sstevel if (ddi_copyout((caddr_t)&rr, (caddr_t)arg, sizeof (rr), 528*03831d35Sstevel mode) != 0) 529*03831d35Sstevel return (EFAULT); 530*03831d35Sstevel #endif /* _MULTI_DATAMODEL */ 531*03831d35Sstevel break; 532*03831d35Sstevel 533*03831d35Sstevel 534*03831d35Sstevel case RMCADM_SEND_SRECORD_BP: 535*03831d35Sstevel 536*03831d35Sstevel /* 537*03831d35Sstevel * first copy in the request_response structure 538*03831d35Sstevel */ 539*03831d35Sstevel #ifdef _MULTI_DATAMODEL 540*03831d35Sstevel switch (ddi_model_convert_from(mode & FMODELS)) { 541*03831d35Sstevel case DDI_MODEL_ILP32: 542*03831d35Sstevel { 543*03831d35Sstevel /* 544*03831d35Sstevel * For use when a 32 bit app makes a call into a 545*03831d35Sstevel * 64 bit ioctl 546*03831d35Sstevel */ 547*03831d35Sstevel rmcadm_send_srecord_bp32_t ssbp32; 548*03831d35Sstevel 549*03831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp32, 550*03831d35Sstevel sizeof (ssbp32), mode)) { 551*03831d35Sstevel return (EFAULT); 552*03831d35Sstevel } 553*03831d35Sstevel ssbp.data_len = ssbp32.data_len; 554*03831d35Sstevel ssbp.data_buf = (caddr_t)(uintptr_t)ssbp32.data_buf; 555*03831d35Sstevel ssbp.resp_bp.msg_type = ssbp32.resp_bp.msg_type; 556*03831d35Sstevel ssbp.resp_bp.msg_len = ssbp32.resp_bp.msg_len; 557*03831d35Sstevel ssbp.resp_bp.msg_bytes = ssbp32.resp_bp.msg_bytes; 558*03831d35Sstevel ssbp.resp_bp.msg_buf = 559*03831d35Sstevel (caddr_t)(uintptr_t)ssbp32.resp_bp.msg_buf; 560*03831d35Sstevel ssbp.wait_time = ssbp32.wait_time; 561*03831d35Sstevel break; 562*03831d35Sstevel } 563*03831d35Sstevel case DDI_MODEL_NONE: 564*03831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp, 565*03831d35Sstevel sizeof (ssbp), mode)) 566*03831d35Sstevel return (EFAULT); 567*03831d35Sstevel break; 568*03831d35Sstevel } 569*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */ 570*03831d35Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&ssbp, 571*03831d35Sstevel sizeof (ssbp), mode) != 0) 572*03831d35Sstevel return (EFAULT); 573*03831d35Sstevel #endif /* _MULTI_DATAMODEL */ 574*03831d35Sstevel 575*03831d35Sstevel /* 576*03831d35Sstevel * save the user data buffer pointer 577*03831d35Sstevel */ 578*03831d35Sstevel user_data_buf = ssbp.data_buf; 579*03831d35Sstevel 580*03831d35Sstevel if (user_data_buf != NULL) { 581*03831d35Sstevel /* 582*03831d35Sstevel * copy in the srecord data 583*03831d35Sstevel */ 584*03831d35Sstevel ssbp.data_buf = kmem_alloc(ssbp.data_len, KM_SLEEP); 585*03831d35Sstevel 586*03831d35Sstevel if (ddi_copyin(user_data_buf, ssbp.data_buf, 587*03831d35Sstevel ssbp.data_len, mode) != 0) { 588*03831d35Sstevel 589*03831d35Sstevel kmem_free(ssbp.data_buf, ssbp.data_len); 590*03831d35Sstevel ssbp.data_buf = user_data_buf; 591*03831d35Sstevel return (EFAULT); 592*03831d35Sstevel } 593*03831d35Sstevel } else { 594*03831d35Sstevel return (EINVAL); /* request can't be NULL! */ 595*03831d35Sstevel } 596*03831d35Sstevel 597*03831d35Sstevel /* 598*03831d35Sstevel * save the user request buffer pointer 599*03831d35Sstevel */ 600*03831d35Sstevel user_resp_buf = ssbp.resp_bp.msg_buf; 601*03831d35Sstevel if (user_resp_buf != NULL) { 602*03831d35Sstevel ssbp.resp_bp.msg_buf = 603*03831d35Sstevel kmem_alloc(ssbp.resp_bp.msg_len, KM_SLEEP); 604*03831d35Sstevel } else { 605*03831d35Sstevel 606*03831d35Sstevel kmem_free(ssbp.data_buf, ssbp.data_len); 607*03831d35Sstevel return (EINVAL); 608*03831d35Sstevel } 609*03831d35Sstevel 610*03831d35Sstevel /* 611*03831d35Sstevel * send the srecord via the rmc_comm driver and get the reply 612*03831d35Sstevel * back (BP message) 613*03831d35Sstevel */ 614*03831d35Sstevel 615*03831d35Sstevel rmc_respp->msg_type = ssbp.resp_bp.msg_type; 616*03831d35Sstevel rmc_respp->msg_buf = ssbp.resp_bp.msg_buf; 617*03831d35Sstevel rmc_respp->msg_len = ssbp.resp_bp.msg_len; 618*03831d35Sstevel rmc_respp->msg_bytes = ssbp.resp_bp.msg_bytes; 619*03831d35Sstevel 620*03831d35Sstevel ssbp.status = rmc_comm_send_srecord_bp(ssbp.data_buf, 621*03831d35Sstevel ssbp.data_len, rmc_respp, ssbp.wait_time); 622*03831d35Sstevel 623*03831d35Sstevel /* 624*03831d35Sstevel * copy back the actual size of the returned message 625*03831d35Sstevel */ 626*03831d35Sstevel ssbp.resp_bp.msg_bytes = rmc_respp->msg_bytes; 627*03831d35Sstevel 628*03831d35Sstevel if (ssbp.status != RCNOERR) { 629*03831d35Sstevel retval = rmcadm_get_errno(ssbp.status); 630*03831d35Sstevel 631*03831d35Sstevel } else if (user_resp_buf != NULL) { 632*03831d35Sstevel /* 633*03831d35Sstevel * copy out the user BP response buffer 634*03831d35Sstevel */ 635*03831d35Sstevel if (ddi_copyout(ssbp.resp_bp.msg_buf, user_resp_buf, 636*03831d35Sstevel ssbp.resp_bp.msg_bytes, mode) != 0) { 637*03831d35Sstevel retval = EFAULT; 638*03831d35Sstevel } 639*03831d35Sstevel } 640*03831d35Sstevel 641*03831d35Sstevel /* 642*03831d35Sstevel * now copy out the updated request_response structure 643*03831d35Sstevel */ 644*03831d35Sstevel if (ssbp.data_buf) 645*03831d35Sstevel kmem_free(ssbp.data_buf, ssbp.data_len); 646*03831d35Sstevel if (ssbp.resp_bp.msg_buf) 647*03831d35Sstevel kmem_free(ssbp.resp_bp.msg_buf, ssbp.resp_bp.msg_len); 648*03831d35Sstevel 649*03831d35Sstevel ssbp.data_buf = user_data_buf; 650*03831d35Sstevel ssbp.resp_bp.msg_buf = user_resp_buf; 651*03831d35Sstevel 652*03831d35Sstevel #ifdef _MULTI_DATAMODEL 653*03831d35Sstevel switch (ddi_model_convert_from(mode & FMODELS)) { 654*03831d35Sstevel case DDI_MODEL_ILP32: 655*03831d35Sstevel { 656*03831d35Sstevel /* 657*03831d35Sstevel * For use when a 32 bit app makes a call into a 658*03831d35Sstevel * 64 bit ioctl 659*03831d35Sstevel */ 660*03831d35Sstevel rmcadm_send_srecord_bp32_t ssbp32; 661*03831d35Sstevel 662*03831d35Sstevel ssbp32.data_len = ssbp.data_len; 663*03831d35Sstevel ssbp32.data_buf = (caddr32_t)(uintptr_t)ssbp.data_buf; 664*03831d35Sstevel ssbp32.resp_bp.msg_type = ssbp.resp_bp.msg_type; 665*03831d35Sstevel ssbp32.resp_bp.msg_len = ssbp.resp_bp.msg_len; 666*03831d35Sstevel ssbp32.resp_bp.msg_bytes = ssbp.resp_bp.msg_bytes; 667*03831d35Sstevel ssbp32.resp_bp.msg_buf = 668*03831d35Sstevel (caddr32_t)(uintptr_t)ssbp.resp_bp.msg_buf; 669*03831d35Sstevel ssbp32.wait_time = ssbp.wait_time; 670*03831d35Sstevel 671*03831d35Sstevel if (ddi_copyout((caddr_t)&ssbp32, (caddr_t)arg, 672*03831d35Sstevel sizeof (ssbp32), mode)) { 673*03831d35Sstevel return (EFAULT); 674*03831d35Sstevel } 675*03831d35Sstevel break; 676*03831d35Sstevel } 677*03831d35Sstevel case DDI_MODEL_NONE: 678*03831d35Sstevel if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg, 679*03831d35Sstevel sizeof (ssbp), mode)) 680*03831d35Sstevel return (EFAULT); 681*03831d35Sstevel break; 682*03831d35Sstevel } 683*03831d35Sstevel #else /* ! _MULTI_DATAMODEL */ 684*03831d35Sstevel if (ddi_copyout((caddr_t)&ssbp, (caddr_t)arg, sizeof (ssbp), 685*03831d35Sstevel mode) != 0) 686*03831d35Sstevel return (EFAULT); 687*03831d35Sstevel #endif /* _MULTI_DATAMODEL */ 688*03831d35Sstevel break; 689*03831d35Sstevel 690*03831d35Sstevel 691*03831d35Sstevel case RMCADM_RESET_SP: 692*03831d35Sstevel pmugpio_reset(); 693*03831d35Sstevel retval = 0; 694*03831d35Sstevel break; 695*03831d35Sstevel default: 696*03831d35Sstevel retval = ENOTSUP; 697*03831d35Sstevel break; 698*03831d35Sstevel } 699*03831d35Sstevel return (retval); 700*03831d35Sstevel } 701