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 2003 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 * fcode helper driver -- provide priv. access and kernel communication 31 * to the userland fcode interpreter. 32 */ 33 #include <sys/types.h> 34 #include <sys/cred.h> 35 #include <sys/mman.h> 36 #include <sys/kmem.h> 37 #include <sys/conf.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/sunndi.h> 41 #include <sys/ddi_impldefs.h> 42 #include <sys/ndi_impldefs.h> 43 #include <sys/modctl.h> 44 #include <sys/stat.h> 45 #include <sys/fcode.h> 46 47 static int fc_max_opens = 32; /* Up to this many simultaneous opens */ 48 49 /* 50 * Soft state associated with each instance of driver open. 51 */ 52 static struct fc_state { 53 int state; /* available flag or active state */ 54 struct fc_request *req; /* Active Request */ 55 } *fc_states; 56 57 #define FC_STATE_INACTIVE 0 /* Unopen, available for use */ 58 #define FC_STATE_OPEN 1 /* Inital open */ 59 #define FC_STATE_READ_DONE 2 /* blocking read done */ 60 #define FC_STATE_IN_PROGRESS 3 /* FC_GET_PARAMETERS done, active */ 61 #define FC_STATE_VALIDATED 4 /* FC_VALIDATE done, active */ 62 #define FC_STATE_ACTIVE(s) ((s) != 0) 63 #define FC_STATE_AVAILABLE(s) ((s) == FC_STATE_INACTIVE) 64 65 static kmutex_t fc_open_lock; /* serialize instance assignment */ 66 static kcondvar_t fc_open_cv; /* wait for available open */ 67 static int fc_open_count; /* number of current open instance */ 68 69 static int fc_open(dev_t *, int, int, cred_t *); 70 static int fc_close(dev_t, int, int, cred_t *); 71 static int fc_read(dev_t, struct uio *, cred_t *); 72 static int fc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 73 static int fc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 74 static int fc_attach(dev_info_t *, ddi_attach_cmd_t cmd); 75 static int fc_detach(dev_info_t *, ddi_detach_cmd_t cmd); 76 77 static int fc_get_parameters(dev_t, intptr_t, int, cred_t *, int *); 78 static int fc_get_my_args(dev_t, intptr_t, int, cred_t *, int *); 79 static int fc_run_priv(dev_t, intptr_t, int, cred_t *, int *); 80 static int fc_validate(dev_t, intptr_t, int, cred_t *, int *); 81 static int fc_get_fcode(dev_t, intptr_t, int, cred_t *, int *); 82 83 static struct cb_ops fc_cb_ops = { 84 fc_open, /* open */ 85 fc_close, /* close */ 86 nodev, /* strategy */ 87 nodev, /* print */ 88 nodev, /* dump */ 89 fc_read, /* read */ 90 nodev, /* write */ 91 fc_ioctl, /* ioctl */ 92 nodev, /* devmap */ 93 nodev, /* mmap */ 94 nodev, /* segmap */ 95 nochpoll, /* poll */ 96 ddi_prop_op, /* prop_op */ 97 NULL, /* streamtab */ 98 D_NEW | D_MP /* Driver compatibility flag */ 99 }; 100 101 static struct dev_ops fcode_ops = { 102 DEVO_REV, /* devo_rev, */ 103 0, /* refcnt */ 104 fc_info, /* info */ 105 nulldev, /* identify */ 106 nulldev, /* probe */ 107 fc_attach, /* attach */ 108 fc_detach, /* detach */ 109 nodev, /* reset */ 110 &fc_cb_ops, /* driver operations */ 111 NULL /* bus operations */ 112 }; 113 114 /* 115 * Module linkage information for the kernel. 116 */ 117 static struct modldrv modldrv = { 118 &mod_driverops, 119 "FCode driver %I%", 120 &fcode_ops 121 }; 122 123 static struct modlinkage modlinkage = { 124 MODREV_1, 125 &modldrv, 126 NULL 127 }; 128 129 #ifndef lint 130 static char _depends_on[] = "misc/fcodem"; 131 #endif 132 133 int 134 _init(void) 135 { 136 int error; 137 138 mutex_init(&fc_open_lock, NULL, MUTEX_DRIVER, NULL); 139 cv_init(&fc_open_cv, NULL, CV_DRIVER, NULL); 140 141 error = mod_install(&modlinkage); 142 if (error != 0) { 143 mutex_destroy(&fc_open_lock); 144 cv_destroy(&fc_open_cv); 145 return (error); 146 } 147 148 return (0); 149 } 150 151 int 152 _info(struct modinfo *modinfop) 153 { 154 return (mod_info(&modlinkage, modinfop)); 155 } 156 157 int 158 _fini(void) 159 { 160 int error; 161 162 error = mod_remove(&modlinkage); 163 if (error != 0) { 164 return (error); 165 } 166 167 mutex_destroy(&fc_open_lock); 168 cv_destroy(&fc_open_cv); 169 return (0); 170 } 171 172 static dev_info_t *fc_dip; 173 174 /*ARGSUSED*/ 175 static int 176 fc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 177 { 178 int error = DDI_FAILURE; 179 180 switch (infocmd) { 181 case DDI_INFO_DEVT2DEVINFO: 182 *result = (void *)fc_dip; 183 error = DDI_SUCCESS; 184 break; 185 case DDI_INFO_DEVT2INSTANCE: 186 /* All dev_t's map to the same, single instance */ 187 *result = (void *)0; 188 error = DDI_SUCCESS; 189 break; 190 default: 191 break; 192 } 193 194 return (error); 195 } 196 197 static int 198 fc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 199 { 200 int error = DDI_FAILURE; 201 202 switch (cmd) { 203 204 case DDI_ATTACH: 205 fc_open_count = 0; 206 fc_states = kmem_zalloc( 207 fc_max_opens * sizeof (struct fc_state), KM_SLEEP); 208 209 if (ddi_create_minor_node(dip, "fcode", S_IFCHR, 210 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 211 kmem_free(fc_states, 212 fc_max_opens * sizeof (struct fc_state)); 213 error = DDI_FAILURE; 214 } else { 215 fc_dip = dip; 216 ddi_report_dev(dip); 217 218 error = DDI_SUCCESS; 219 } 220 break; 221 default: 222 error = DDI_FAILURE; 223 break; 224 } 225 226 return (error); 227 } 228 229 static int 230 fc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 231 { 232 int error = DDI_FAILURE; 233 234 switch (cmd) { 235 236 case DDI_DETACH: 237 ddi_remove_minor_node(dip, NULL); 238 fc_dip = NULL; 239 kmem_free(fc_states, fc_max_opens * sizeof (struct fc_state)); 240 241 error = DDI_SUCCESS; 242 break; 243 default: 244 error = DDI_FAILURE; 245 break; 246 } 247 248 return (error); 249 } 250 251 /* 252 * Allow multiple opens by tweaking the dev_t such that it looks like each 253 * open is getting a different minor device. Each minor gets a separate 254 * entry in the fc_states[] table. 255 */ 256 /*ARGSUSED*/ 257 static int 258 fc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 259 { 260 int m; 261 struct fc_state *st; 262 263 if (getminor(*devp) != 0) 264 return (EINVAL); 265 266 mutex_enter(&fc_open_lock); 267 268 while (fc_open_count >= fc_max_opens) { 269 /* 270 * maximum open instance reached, wait for a close 271 */ 272 FC_DEBUG0(1, CE_WARN, 273 "fcode: Maximum fcode open reached, waiting for exit\n"); 274 275 if (cv_wait_sig(&fc_open_cv, &fc_open_lock) == 0) { 276 mutex_exit(&fc_open_lock); 277 return (EINTR); 278 /*NOTREACHED*/ 279 } 280 } 281 fc_open_count++; 282 283 for (m = 0, st = fc_states; m < fc_max_opens; m++, st++) { 284 if (FC_STATE_ACTIVE(st->state)) 285 continue; 286 287 st->state = FC_STATE_OPEN; 288 st->req = 0; 289 break; /* It's ours. */ 290 } 291 mutex_exit(&fc_open_lock); 292 293 ASSERT(m < fc_max_opens); 294 *devp = makedevice(getmajor(*devp), (minor_t)(m + 1)); 295 296 FC_DEBUG2(9, CE_CONT, "fc_open: open count = %d (%d)\n", 297 fc_open_count, m + 1); 298 299 return (0); 300 } 301 302 /*ARGSUSED*/ 303 static int 304 fc_close(dev_t dev, int flag, int otype, cred_t *cred_p) 305 { 306 struct fc_state *st; 307 int m = (int)getminor(dev) - 1; 308 struct fc_request *fp; 309 struct fc_client_interface *cp; 310 311 st = fc_states + m; 312 ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 313 314 /* 315 * The close indicates we're done with this request. 316 * If we haven't validated this request, then something 317 * bad may have happened (ie: perhaps the user program was 318 * killed), so we should invalidate it, then close the session. 319 */ 320 321 if (st->state == FC_STATE_READ_DONE) { 322 fp = st->req; 323 fp->error = FC_ERROR; 324 } 325 326 if (st->state > FC_STATE_READ_DONE) { 327 328 cp = kmem_zalloc(sizeof (struct fc_client_interface), KM_SLEEP); 329 fp = st->req; 330 ASSERT(fp); 331 ASSERT(fp->ap_ops); 332 333 if (st->state != FC_STATE_VALIDATED) { 334 FC_DEBUG0(1, CE_CONT, 335 "fc_close: Send invalidate cmd\n"); 336 cp->svc_name = fc_ptr2cell(FC_SVC_INVALIDATE); 337 (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 338 fp->error = FC_ERROR; 339 } 340 341 bzero(cp, sizeof (struct fc_client_interface)); 342 FC_DEBUG0(9, CE_CONT, "fc_close: Sending exit cmd\n"); 343 cp->svc_name = fc_ptr2cell(FC_SVC_EXIT); 344 (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 345 346 kmem_free(cp, sizeof (struct fc_client_interface)); 347 } 348 349 /* 350 * Mark the request as done ... 351 */ 352 if ((fp = st->req) != NULL) 353 fc_finish_request(fp); 354 355 /* 356 * rectify count and signal any waiters 357 */ 358 mutex_enter(&fc_open_lock); 359 st->state = FC_STATE_INACTIVE; 360 st->req = 0; 361 FC_DEBUG2(9, CE_CONT, "fc_close: open count = %d (%d)\n", 362 fc_open_count, m + 1); 363 if (fc_open_count >= fc_max_opens) { 364 cv_broadcast(&fc_open_cv); 365 } 366 fc_open_count--; 367 mutex_exit(&fc_open_lock); 368 369 return (0); 370 } 371 372 /*ARGSUSED*/ 373 static int 374 fc_read(dev_t dev, struct uio *uio, cred_t *cred) 375 { 376 struct fc_state *st; 377 int m = (int)getminor(dev) - 1; 378 struct fc_request *fp; 379 380 st = fc_states + m; 381 ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 382 383 /* 384 * Wait for a internal request for the interpreter 385 * and sleep till one arrives. When one arrives, 386 * return from the read. (No data is actually returned). 387 */ 388 389 if (st->state != FC_STATE_OPEN) { 390 cmn_err(CE_CONT, "fc_read: Wrong state (%d) for read\n", 391 st->state); 392 return (EINVAL); 393 } 394 395 /* 396 * Wait for a request, allowing the wait to be interrupted. 397 */ 398 if ((fp = fc_get_request()) == NULL) 399 return (EINTR); 400 401 FC_DEBUG1(3, CE_CONT, "fc_read: request fp: %p\n", fp); 402 403 /* 404 * Update our state and store the request pointer. 405 */ 406 mutex_enter(&fc_open_lock); 407 st->req = fp; 408 st->state = FC_STATE_READ_DONE; 409 mutex_exit(&fc_open_lock); 410 411 return (0); 412 } 413 414 /*ARGSUSED*/ 415 static int 416 fc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 417 { 418 struct fc_state *st; 419 int m = (int)getminor(dev) - 1; 420 421 if (m >= fc_max_opens) { 422 return (EINVAL); 423 } 424 425 st = fc_states + m; 426 ASSERT(FC_STATE_ACTIVE(st->state)); 427 428 switch (cmd) { 429 case FC_GET_PARAMETERS: 430 /* 431 * This should be the first command and is used to 432 * return data about the request, including the 433 * the fcode address and size and the unit address 434 * of the new child. The fcode offset,size can later 435 * be used as an offset in an mmap request to allow 436 * the fcode to be mapped in. 437 */ 438 return (fc_get_parameters(dev, arg, mode, credp, rvalp)); 439 440 case FC_GET_MY_ARGS: 441 /* 442 * Get the inital setting of my-args. This should be done 443 * after FC_GET_PARAMETERS. 444 */ 445 return (fc_get_my_args(dev, arg, mode, credp, rvalp)); 446 447 case FC_RUN_PRIV: 448 /* 449 * Run a priveledged op on behalf of the interpreter, 450 * or download device tree data from the interpreter. 451 */ 452 return (fc_run_priv(dev, arg, mode, credp, rvalp)); 453 454 case FC_VALIDATE: 455 /* 456 * The interpreter is done, mark state as done, validating 457 * the data downloaded into the kernel. 458 */ 459 return (fc_validate(dev, arg, mode, credp, rvalp)); 460 461 case FC_GET_FCODE_DATA: 462 /* 463 * Copy out device fcode to user buffer. 464 */ 465 return (fc_get_fcode(dev, arg, mode, credp, rvalp)); 466 467 } 468 /* 469 * Invalid ioctl command 470 */ 471 return (ENOTTY); 472 } 473 474 /* 475 * fc_get_parameters: Get information about the current request. 476 * The input 'arg' is a pointer to 'struct fc_parameters' which 477 * we write back to the caller with the information from the req 478 * structure. 479 */ 480 481 /*ARGSUSED*/ 482 static int 483 fc_get_parameters(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 484 { 485 struct fc_state *st; 486 int m = (int)getminor(dev) - 1; 487 fco_handle_t rp; 488 struct fc_parameters *fcp; 489 490 st = fc_states + m; 491 ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 492 493 /* 494 * It's an error if we're not in state FC_STATE_READ_DONE 495 */ 496 497 if (st->state != FC_STATE_READ_DONE) { 498 cmn_err(CE_CONT, "fc_ioctl: fc_get_parameters: " 499 "wrong state (%d)\n", st->state); 500 return (EINVAL); 501 } 502 503 ASSERT(st->req != NULL); 504 rp = st->req->handle; 505 506 FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_parameters fp: %p\n", st->req); 507 508 /* 509 * Create and copyout the attachment point ihandle, 510 * the fcode kaddr,len and the unit address. 511 * Note how we treat ihandles and phandles (they are the same thing 512 * only accross this interface ... a dev_info_t *.) 513 */ 514 fcp = kmem_zalloc(sizeof (struct fc_parameters), KM_SLEEP); 515 fcp->fcode_size = rp->fcode_size; 516 (void) strncpy(fcp->unit_address, rp->unit_address, 517 sizeof (fcp->unit_address) - 1); 518 519 /* 520 * XXX - APA This needs to be made more bus independant. 521 */ 522 if (rp->bus_args) { 523 bcopy(rp->bus_args, &fcp->config_address, sizeof (int)); 524 525 FC_DEBUG1(3, CE_CONT, "fc_ioctl: config_address=%x\n", 526 fcp->config_address); 527 528 } else { 529 FC_DEBUG0(3, CE_CONT, "fc_ioctl: fc_get_parameters " 530 "There are no bus specific arguments\n"); 531 } 532 if (copyout(fcp, (void *)arg, sizeof (struct fc_parameters)) == -1) { 533 kmem_free(fcp, sizeof (struct fc_parameters)); 534 return (EFAULT); 535 } 536 kmem_free(fcp, sizeof (struct fc_parameters)); 537 538 /* 539 * Update our state 540 */ 541 mutex_enter(&fc_open_lock); 542 st->state = FC_STATE_IN_PROGRESS; 543 mutex_exit(&fc_open_lock); 544 545 return (0); 546 } 547 548 /* 549 * fc_get_my_args: Get the initial setting for my-args. 550 * The input 'arg' is a pointer where the my-arg string is written 551 * to. The string is NULL terminated. 552 */ 553 554 /*ARGSUSED*/ 555 static int 556 fc_get_my_args(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 557 { 558 struct fc_state *st; 559 int m = (int)getminor(dev) - 1; 560 fco_handle_t rp; 561 562 st = fc_states + m; 563 ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 564 565 /* 566 * It's an error if we're not in state FC_STATE_READ_DONE 567 */ 568 569 if (st->state != FC_STATE_IN_PROGRESS) { 570 cmn_err(CE_CONT, "fc_ioctl: fc_get_my_args: " 571 "wrong state (%d)\n", st->state); 572 return (EINVAL); 573 } 574 575 ASSERT(st->req != NULL); 576 rp = st->req->handle; 577 578 FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_my_args fp: %p\n", st->req); 579 580 if (rp->my_args == NULL) { 581 FC_DEBUG0(3, CE_CONT, "fc_ioctl: fc_get_my_args " 582 "There are no bus specific my-args\n"); 583 return (EINVAL); 584 } 585 586 if (strlen(rp->my_args) > FC_GET_MY_ARGS_BUFLEN) { 587 FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_my_args " 588 "my-args is larger than %d\n", FC_GET_MY_ARGS_BUFLEN); 589 return (EINVAL); 590 591 } 592 593 if (copyout(rp->my_args, (void *)arg, strlen(rp->my_args) + 1) == -1) { 594 return (EFAULT); 595 } 596 597 return (0); 598 } 599 600 /*ARGSUSED*/ 601 static int 602 fc_run_priv(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 603 { 604 struct fc_state *st; 605 int m = (int)getminor(dev) - 1; 606 struct fc_request *fp; 607 608 struct fc_client_interface tc, *cp, *ap; 609 size_t csize; 610 int nresults, nargs, error; 611 char *name; 612 613 ap = (struct fc_client_interface *)arg; 614 615 st = fc_states + m; 616 ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 617 618 /* 619 * It's an error if we're not in state FC_STATE_IN_PROGRESS 620 */ 621 622 if (st->state != FC_STATE_IN_PROGRESS) { 623 cmn_err(CE_CONT, "fc_ioctl: fc_run_priv: wrong state (%d)\n", 624 st->state); 625 return (EINVAL); 626 } 627 628 /* 629 * Get the first three cells to figure out how large the buffer 630 * needs to be; allocate it and copy it in. The array is variable 631 * sized based on the fixed portion plus the given number of arg. 632 * cells and given number of result cells. 633 */ 634 if (copyin((void *)arg, &tc, 3 * sizeof (fc_cell_t))) { 635 FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 636 "fault copying in first 2 cells from %p\n", arg); 637 return (EFAULT); 638 } 639 640 /* 641 * XXX We should probably limit #args and #results to something 642 * reasonable without blindly copying it in. 643 */ 644 nresults = fc_cell2int(tc.nresults); /* save me for later */ 645 nargs = fc_cell2int(tc.nargs); 646 csize = (FCC_FIXED_CELLS + nargs + nresults) * sizeof (fc_cell_t); 647 cp = kmem_zalloc(csize, KM_SLEEP); 648 /* 649 * Don't bother copying in the result cells 650 */ 651 if (copyin((void *)arg, cp, csize - (nresults * sizeof (fc_cell_t)))) { 652 FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 653 "fault copying in argument array from %p\n", arg); 654 kmem_free(cp, csize); 655 return (EFAULT); 656 } 657 /* 658 * reset the error fields. 659 */ 660 cp->error = fc_int2cell(0); 661 cp->priv_error = fc_int2cell(0); 662 663 /* 664 * Copy in the service name into our copy of the array. 665 * Later, be careful not to copy out the svc name pointer. 666 */ 667 name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 668 if (copyinstr(fc_cell2ptr(cp->svc_name), name, 669 FC_SVC_NAME_LEN - 1, NULL)) { 670 FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv " 671 "fault copying in service name from %p\n", 672 fc_cell2ptr(cp->svc_name)); 673 kmem_free(cp, csize); 674 kmem_free(name, FC_SVC_NAME_LEN); 675 return (EFAULT); 676 } 677 cp->svc_name = fc_ptr2cell(name); 678 679 FC_DEBUG3(7, CE_CONT, "fc_ioctl: fc_run_priv: " 680 "service name <%s> nargs %d nresults %d\n", 681 name, fc_cell2int(cp->nargs), fc_cell2int(cp->nresults)); 682 683 /* 684 * Call the driver's ops function to provide the service 685 */ 686 fp = st->req; 687 ASSERT(fp->ap_ops); 688 689 error = fp->ap_ops(fp->ap_dip, fp->handle, cp); 690 691 /* 692 * If error is non-zero, we need to log the error and 693 * the service name, and write back the error to the 694 * callers argument array. 695 */ 696 697 if (error || cp->error) { 698 FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv: " 699 "service name <%s> was unserviced\n", name); 700 cp->error = FC_ERR_SVC_NAME; 701 cp->nresults = fc_int2cell(0); 702 error = copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 703 error |= copyout(&cp->nresults, &ap->nresults, 704 sizeof (fc_cell_t)); 705 kmem_free(cp, csize); 706 kmem_free(name, FC_SVC_NAME_LEN); 707 if (error) { 708 FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 709 "fault copying out error result\n"); 710 return (EFAULT); 711 } 712 return (0); 713 } 714 715 if (cp->priv_error) { 716 FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_run_priv: " 717 "service name <%s> caused a priv violation\n", name); 718 cp->priv_error = FC_PRIV_ERROR; 719 cp->nresults = fc_int2cell(0); 720 error = copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 721 error |= copyout(&cp->priv_error, &ap->priv_error, 722 sizeof (fc_cell_t)); 723 error |= copyout(&cp->nresults, &ap->nresults, 724 sizeof (fc_cell_t)); 725 kmem_free(cp, csize); 726 kmem_free(name, FC_SVC_NAME_LEN); 727 if (error) { 728 FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 729 "fault copying out priv error result\n"); 730 return (EFAULT); 731 } 732 return (0); 733 } 734 735 /* 736 * We believe we have a successful result at this point, thus we 737 * have to copy out the actual number of result cells to be 738 * returned, the two error fields and each of the results. 739 */ 740 741 if (fc_cell2int(cp->nresults) > nresults) 742 cmn_err(CE_PANIC, "fc_ioctl: fc_run_priv: " 743 "results (from ops function) overflow\n"); 744 745 error = copyout(&cp->nresults, &ap->nresults, sizeof (fc_cell_t)); 746 error |= copyout(&cp->error, &ap->error, sizeof (fc_cell_t)); 747 error |= copyout(&cp->priv_error, &ap->priv_error, sizeof (fc_cell_t)); 748 if ((error == 0) && cp->nresults) 749 error |= copyout(&fc_result(cp, 0), &(ap->v[nargs]), 750 cp->nresults * sizeof (fc_cell_t)); 751 752 kmem_free(cp, csize); 753 kmem_free(name, FC_SVC_NAME_LEN); 754 755 if (error) { 756 FC_DEBUG0(1, CE_CONT, "fc_ioctl: fc_run_priv " 757 "fault copying out (good) results\n"); 758 return (EFAULT); 759 } 760 return (0); 761 } 762 763 /*ARGSUSED*/ 764 static int 765 fc_validate(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 766 { 767 struct fc_state *st; 768 int m = (int)getminor(dev) - 1; 769 struct fc_request *fp; 770 struct fc_client_interface *cp; 771 772 st = fc_states + m; 773 ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 774 775 /* 776 * It's an error if we're not in state FC_STATE_IN_PROGRESS 777 */ 778 if (st->state != FC_STATE_IN_PROGRESS) { 779 cmn_err(CE_CONT, "fc_ioctl: fc_validate: wrong state (%d)\n", 780 st->state); 781 return (EINVAL); 782 } 783 784 FC_DEBUG0(2, CE_CONT, "fc_ioctl: fc_validate: Sending validate cmd\n"); 785 786 /* 787 * Send a "validate" command down the line. 788 * The command has no arguments and no results. 789 */ 790 cp = kmem_zalloc(sizeof (struct fc_client_interface), KM_SLEEP); 791 cp->svc_name = fc_ptr2cell(FC_SVC_VALIDATE); 792 793 fp = st->req; 794 ASSERT(fp->ap_ops); 795 (void) fp->ap_ops(fp->ap_dip, fp->handle, cp); 796 797 kmem_free(cp, sizeof (struct fc_client_interface)); 798 799 /* 800 * Update our state. 801 */ 802 mutex_enter(&fc_open_lock); 803 st->state = FC_STATE_VALIDATED; 804 mutex_exit(&fc_open_lock); 805 return (0); 806 } 807 808 /* 809 * fc_get_fcode: Copy out device fcode to user buffer. 810 * The input 'arg' is a pointer to 'fc_fcode_info_t' which 811 * should have fcode_size field set. The fcode_ptr field is a 812 * pointer to a user buffer of fcode_size. 813 */ 814 815 /*ARGSUSED*/ 816 static int 817 fc_get_fcode(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp) 818 { 819 struct fc_state *st; 820 int m = (int)getminor(dev) - 1; 821 fco_handle_t rp; 822 struct fc_fcode_info fcode_info; 823 824 st = fc_states + m; 825 ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state)); 826 827 ASSERT(st->req != NULL); 828 rp = st->req->handle; 829 830 FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_get_fcode fp: %p\n", st->req); 831 832 /* 833 * Get the fc_fcode_info structure from userland. 834 */ 835 if (copyin((void *)arg, &fcode_info, sizeof (fc_fcode_info_t))) { 836 FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_get_fcode " 837 "fault copying in fcode_info from %p\n", arg); 838 return (EFAULT); 839 } 840 841 /* 842 * Validate that buffer size is what we expect. 843 */ 844 if (fcode_info.fcode_size != rp->fcode_size) { 845 FC_DEBUG2(1, CE_CONT, "fc_ioctl: fc_get_fcode " 846 "requested size (0x%x) doesn't match real size (0x%x)\n", 847 fcode_info.fcode_size, rp->fcode_size); 848 return (EINVAL); 849 } 850 851 /* 852 * Copyout the fcode. 853 */ 854 if (copyout(rp->fcode, fcode_info.fcode_ptr, rp->fcode_size) == -1) { 855 FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_get_fcode " 856 "fault copying out fcode to %p\n", fcode_info.fcode_ptr); 857 return (EFAULT); 858 } 859 860 return (0); 861 } 862