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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #include <sys/types.h> 29 #include <sys/conf.h> 30 #include <sys/file.h> 31 #include <sys/ddi.h> 32 #include <sys/sunddi.h> 33 #include <sys/modctl.h> 34 #include <sys/sunndi.h> 35 #include <sys/ddi_impldefs.h> 36 #include <sys/obpdefs.h> 37 #include <sys/cmn_err.h> 38 #include <sys/errno.h> 39 #include <sys/debug.h> 40 #include <sys/sysmacros.h> 41 #include <sys/autoconf.h> 42 #include <sys/stat.h> 43 #include <sys/kmem.h> 44 #include <sys/sgsbbc_mailbox.h> 45 #include <sys/sgfrutree.h> 46 #include <sys/sgfru_priv.h> 47 #include <sys/sgfru_mbox.h> 48 49 /* 50 * This driver implements the ioctls for the serengeti frutree picl plugin 51 * and the serengeti fruaccess library. These are all private, 52 * platform-dependent interfaces. 53 */ 54 55 /* Global Variables */ 56 57 #ifdef DEBUG 58 uint_t sgfru_debug = 0; 59 #endif /* DEBUG */ 60 61 /* Opaque state structure pointer */ 62 static void *sgfru_statep; /* sgfru soft state hook */ 63 64 /* 65 * the maximum amount of time this driver is prepared to wait for the mailbox 66 * to reply before it decides to timeout. 67 */ 68 int sgfru_mbox_wait = SGFRU_DEFAULT_MAX_MBOX_WAIT_TIME; 69 70 /* Module Variables */ 71 72 /* 73 * Driver entry points. These are located in sgfru.c so as to 74 * not cause a warning for the sgfru adb macro. 75 */ 76 static struct cb_ops sgfru_cb_ops = { 77 sgfru_open, /* open */ 78 sgfru_close, /* close */ 79 nulldev, /* strategy */ 80 nulldev, /* print */ 81 nulldev, /* dump */ 82 nulldev, /* read */ 83 nulldev, /* write */ 84 sgfru_ioctl, /* ioctl */ 85 nulldev, /* devmap */ 86 nulldev, /* mmap */ 87 nulldev, /* segmap */ 88 nochpoll, /* poll */ 89 ddi_prop_op, /* cb_prop_op */ 90 NULL, /* streamtab */ 91 D_NEW | D_MP /* Driver compatibility flag */ 92 }; 93 94 static struct dev_ops sgfru_ops = { 95 DEVO_REV, /* devo_rev, */ 96 0, /* refcnt */ 97 ddi_getinfo_1to1, /* info */ 98 nulldev, /* identify */ 99 nulldev, /* probe */ 100 sgfru_attach, /* attach */ 101 sgfru_detach, /* detach */ 102 nodev, /* reset */ 103 &sgfru_cb_ops, /* driver operations */ 104 (struct bus_ops *)0, /* bus operations */ 105 nulldev, /* power */ 106 ddi_quiesce_not_needed, /* quiesce */ 107 }; 108 109 /* 110 * Loadable module support. This is located in sgfru.c so as to 111 * pick up the 1.8 version of sgfru.c. 112 */ 113 extern struct mod_ops mod_driverops; 114 115 static struct modldrv modldrv = { 116 &mod_driverops, /* Type of module. This one is a pseudo driver */ 117 "FRU Driver", 118 &sgfru_ops, /* driver ops */ 119 }; 120 121 static struct modlinkage modlinkage = { 122 MODREV_1, 123 (void *)&modldrv, 124 NULL 125 }; 126 127 int 128 _init(void) 129 { 130 int error = 0; 131 132 /* Allocate the soft state info and add the module. */ 133 if ((error = ddi_soft_state_init(&sgfru_statep, 134 sizeof (sgfru_soft_state_t), 1)) == 0 && 135 (error = mod_install(&modlinkage)) != 0) { 136 ddi_soft_state_fini(&sgfru_statep); 137 } 138 return (error); 139 } 140 141 int 142 _fini(void) 143 { 144 int error = 0; 145 146 /* Remove the module and free the soft state info. */ 147 if ((error = mod_remove(&modlinkage)) == 0) { 148 ddi_soft_state_fini(&sgfru_statep); 149 } 150 return (error); 151 } 152 153 int 154 _info(struct modinfo *modinfop) 155 { 156 return (mod_info(&modlinkage, modinfop)); 157 } 158 159 static int 160 sgfru_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 161 { 162 sgfru_soft_state_t *softsp; 163 int instance; 164 int error; 165 static fn_t f = "sgfru_attach"; 166 167 switch (cmd) { 168 case DDI_ATTACH: 169 instance = ddi_get_instance(dip); 170 171 error = ddi_soft_state_zalloc(sgfru_statep, instance); 172 if (error != DDI_SUCCESS) { 173 cmn_err(CE_WARN, "sgfru:%s: cannot allocate fru state " 174 "for inst %d.", f, instance); 175 return (DDI_FAILURE); 176 } 177 softsp = ddi_get_soft_state(sgfru_statep, instance); 178 if (softsp == NULL) { 179 ddi_soft_state_free(sgfru_statep, instance); 180 cmn_err(CE_WARN, "sgfru:%s: could not get state " 181 "structure for inst %d.", f, instance); 182 return (DDI_FAILURE); 183 } 184 softsp->fru_dip = dip; 185 softsp->fru_pdip = ddi_get_parent(softsp->fru_dip); 186 softsp->instance = instance; 187 188 error = ddi_create_minor_node(dip, SGFRU_DRV_NAME, S_IFCHR, 189 instance, DDI_PSEUDO, NULL); 190 if (error == DDI_FAILURE) { 191 ddi_soft_state_free(sgfru_statep, instance); 192 return (DDI_FAILURE); 193 } 194 195 ddi_report_dev(dip); 196 197 return (DDI_SUCCESS); 198 199 case DDI_RESUME: 200 return (DDI_SUCCESS); 201 202 default: 203 return (DDI_FAILURE); 204 } 205 } 206 207 static int 208 sgfru_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 209 { 210 int instance; 211 sgfru_soft_state_t *softsp; 212 static fn_t f = "sgfru_detach"; 213 214 instance = ddi_get_instance(dip); 215 216 softsp = ddi_get_soft_state(sgfru_statep, instance); 217 if (softsp == NULL) { 218 cmn_err(CE_WARN, "sgfru:%s: could not get state " 219 "structure for inst %d.", f, instance); 220 return (DDI_FAILURE); 221 } 222 223 switch (cmd) { 224 case DDI_DETACH: 225 ddi_soft_state_free(sgfru_statep, instance); 226 ddi_remove_minor_node(dip, NULL); 227 return (DDI_SUCCESS); 228 229 case DDI_SUSPEND: 230 return (DDI_SUCCESS); 231 232 default: 233 return (DDI_FAILURE); 234 } 235 } 236 237 /*ARGSUSED*/ 238 static int 239 sgfru_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 240 { 241 int error = 0; 242 int instance = getminor(*dev_p); 243 sgfru_soft_state_t *softsp; 244 static fn_t f = "sgfru_open"; 245 246 if ((error = drv_priv(cred_p)) != 0) { 247 cmn_err(CE_WARN, "sgfru:%s: inst %d drv_priv failed", 248 f, instance); 249 return (error); 250 } 251 softsp = (sgfru_soft_state_t *)ddi_get_soft_state(sgfru_statep, 252 instance); 253 if (softsp == (sgfru_soft_state_t *)NULL) { 254 cmn_err(CE_WARN, "sgfru:%s: inst %d ddi_get_soft_state failed", 255 f, instance); 256 return (ENXIO); 257 } 258 return (error); 259 } 260 261 /*ARGSUSED*/ 262 static int 263 sgfru_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 264 { 265 int instance = getminor(dev); 266 sgfru_soft_state_t *softsp = (sgfru_soft_state_t *) 267 ddi_get_soft_state(sgfru_statep, instance); 268 269 if (softsp == (sgfru_soft_state_t *)NULL) 270 return (ENXIO); 271 return (DDI_SUCCESS); 272 } 273 274 /* 275 * This function disperses the ioctls from the serengeti libpiclfruhier plugin 276 * and the serengeti libpiclfruaccess library to the appropriate sub-functions. 277 */ 278 /*ARGSUSED*/ 279 static int 280 sgfru_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 281 int *rval_p) 282 { 283 sgfru_soft_state_t *softsp; 284 int instance = getminor(dev); 285 sgfru_init_arg_t init_arg; 286 int32_t ret = 0; 287 static fn_t f = "sgfru_ioctl"; 288 289 290 softsp = ddi_get_soft_state(sgfru_statep, instance); 291 if (softsp == NULL) { 292 return (ENXIO); 293 } 294 PR_STATE("sgfru:%s: dev %lx cmd %d, instance %d\n", 295 f, dev, cmd, instance); 296 297 init_arg.dev = dev; 298 init_arg.cmd = cmd; 299 init_arg.mode = mode; 300 init_arg.argp = arg; 301 302 switch (cmd) { 303 304 case SGFRU_GETSECTIONS: 305 ret = sgfru_getsections(&init_arg); 306 break; 307 308 case SGFRU_GETSEGMENTS: 309 ret = sgfru_getsegments(&init_arg); 310 break; 311 312 case SGFRU_ADDSEGMENT: 313 ret = sgfru_addsegment(&init_arg); 314 break; 315 316 case SGFRU_READRAWSEGMENT: 317 ret = sgfru_readsegment(&init_arg); 318 break; 319 320 case SGFRU_WRITERAWSEGMENT: 321 ret = sgfru_writesegment(&init_arg); 322 break; 323 324 case SGFRU_GETPACKETS: 325 ret = sgfru_getpackets(&init_arg); 326 break; 327 328 case SGFRU_APPENDPACKET: 329 ret = sgfru_appendpacket(&init_arg); 330 break; 331 332 case SGFRU_GETPAYLOAD: 333 ret = sgfru_getpayload(&init_arg); 334 break; 335 336 case SGFRU_UPDATEPAYLOAD: 337 ret = sgfru_updatepayload(&init_arg); 338 break; 339 340 case SGFRU_GETNUMSECTIONS: 341 case SGFRU_GETNUMSEGMENTS: 342 case SGFRU_GETNUMPACKETS: 343 ret = sgfru_getnum(&init_arg); 344 break; 345 346 case SGFRU_DELETESEGMENT: 347 case SGFRU_DELETEPACKET: 348 ret = sgfru_delete(&init_arg); 349 break; 350 351 case SGFRU_GETCHILDLIST: 352 ret = sgfru_getchildlist(&init_arg); 353 break; 354 355 case SGFRU_GETCHILDHANDLES: 356 ret = sgfru_getchildhandles(&init_arg); 357 break; 358 359 case SGFRU_GETNODEINFO: 360 ret = sgfru_getnodeinfo(&init_arg); 361 break; 362 363 default: 364 ret = EINVAL; 365 break; 366 } 367 368 return (ret); 369 } 370 371 /* 372 * Used for private SGFRU_GETCHILDLIST ioctl. 373 */ 374 static int 375 sgfru_getchildlist(const sgfru_init_arg_t *iargp) 376 { 377 int32_t ret; 378 caddr_t datap; 379 size_t ssize, size; 380 frup_info_t clist; 381 fru_cnt_t max_cnt; 382 node_t *clistp; 383 static fn_t f = "sgfru_getchildlist"; 384 385 /* copyin child_info_t aka frup_info_t */ 386 if (sgfru_copyin_frup(iargp, &clist) != 0) { 387 return (EFAULT); 388 } 389 390 /* check on kmem_alloc space requirements */ 391 max_cnt = clist.fru_cnt; 392 if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) { 393 return (EINVAL); 394 } 395 396 /* allocate buffer for unpadded fru_info_t + node_t's */ 397 size = (size_t)(FRU_INFO_SIZE + (max_cnt * NODE_SIZE)); 398 datap = kmem_zalloc(size, KM_SLEEP); 399 PR_NODE("sgfru:%s: FRU_INFO_SIZE %lu NODE_SIZE %lu size %lu\n", 400 f, FRU_INFO_SIZE, NODE_SIZE, size); 401 PR_NODE("sgfru:%s: handle %lx cnt %d buffer 0x%p\n", f, 402 clist.fru_hdl, clist.fru_cnt, clist.frus); 403 404 /* call mailbox */ 405 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &clist.fru_info)) 406 != 0) { 407 kmem_free(datap, size); 408 return (ret); 409 } 410 411 /* allocate buffer for padded node_t's */ 412 ssize = (size_t)(max_cnt * sizeof (node_t)); 413 clistp = (node_t *)kmem_zalloc(ssize, KM_SLEEP); 414 415 /* translate unpadded to padded fru_info_t + node_t's */ 416 if ((ret = sgfru_node_pad(datap, max_cnt, &clist.fru_info, clistp)) 417 != 0) { 418 kmem_free(datap, size); 419 kmem_free(clistp, ssize); 420 return (ret); 421 } 422 /* free node_t buffer */ 423 kmem_free(datap, size); 424 425 /* copy out fru_info_t */ 426 if (sgfru_copyout_fru(iargp, &clist.fru_info) != 0) { 427 kmem_free(clistp, ssize); 428 return (EFAULT); 429 } 430 /* copyout node_t's */ 431 if (sgfru_copyout_nodes(iargp, &clist, clistp) != 0) { 432 kmem_free(clistp, ssize); 433 return (EFAULT); 434 } 435 /* free node_t buffer */ 436 kmem_free(clistp, ssize); 437 438 return (ret); 439 } 440 441 /* 442 * Used for private SGFRU_GETCHILDHANDLES ioctl. 443 */ 444 static int 445 sgfru_getchildhandles(const sgfru_init_arg_t *iargp) 446 { 447 int32_t ret; 448 size_t size; 449 caddr_t datap, tdatap; 450 frup_info_t hdls; 451 fru_info_t hinfo; 452 fru_cnt_t max_cnt; 453 static fn_t f = "sgfru_getchildhandles"; 454 455 /* copyin handles_t aka frup_info_t */ 456 if (sgfru_copyin_frup(iargp, &hdls) != 0) { 457 return (EFAULT); 458 } 459 PR_HANDLE("sgfru:%s: handle %lx\n", f, hdls.fru_hdl); 460 461 /* check on kmem_alloc space requirements */ 462 max_cnt = hdls.fru_cnt; 463 if ((max_cnt <= 0) || (max_cnt > MAX_HANDLES)) { 464 return (EINVAL); 465 } 466 467 /* allocate buffer for child fru_hdl_t's */ 468 size = (size_t)(FRU_INFO_SIZE + (max_cnt * FRU_HDL_SIZE)); 469 datap = kmem_zalloc(size, KM_SLEEP); 470 471 /* call mailbox */ 472 ret = sgfru_mbox(iargp->cmd, datap, size, &hdls.fru_info); 473 if (ret != 0) { 474 kmem_free(datap, size); 475 return (ret); 476 } 477 478 /* translate unpadded to fru_info_t */ 479 tdatap = sgfru_fru_pad(datap, &hinfo); 480 481 /* copyout actual fru_cnt */ 482 if (sgfru_copyout_fru(iargp, &hinfo) != 0) { 483 kmem_free(datap, size); 484 return (EFAULT); 485 } 486 PR_HANDLE("sgfru:%s: count %x\n", f, hinfo.cnt); 487 488 /* copyout fru_hdl_t's */ 489 if (sgfru_copyout_handles(iargp, &hdls, (fru_hdl_t *)tdatap) != 0) { 490 kmem_free(datap, size); 491 return (EFAULT); 492 } 493 494 /* free datap buffer */ 495 kmem_free(datap, size); 496 497 return (ret); 498 } 499 500 /* 501 * Used for private SGFRU_GETNODEINFO ioctl. 502 */ 503 static int 504 sgfru_getnodeinfo(const sgfru_init_arg_t *iargp) 505 { 506 int32_t ret; 507 caddr_t datap; 508 size_t size; 509 frup_info_t nodeinfo; 510 node_t node; 511 static fn_t f = "sgfru_getnodeinfo"; 512 513 /* copyin node_info_t aka frup_info_t */ 514 if (sgfru_copyin_frup(iargp, &nodeinfo) != 0) { 515 return (EFAULT); 516 } 517 518 /* allocate unpadded buffer for node_t */ 519 size = (size_t)(NODE_SIZE); 520 datap = kmem_zalloc(size, KM_SLEEP); 521 522 PR_NODE("sgfru:%s: handle %lx size 0x%lx\n", f, nodeinfo.fru_hdl, size); 523 /* call mailbox */ 524 ret = sgfru_mbox(iargp->cmd, datap, size, &nodeinfo.fru_info); 525 if (ret != 0) { 526 kmem_free(datap, size); 527 return (ret); 528 } 529 530 /* translate unpadded to padded node_t */ 531 if ((ret = sgfru_node_pad(datap, 0, NULL, &node)) 532 != 0) { 533 kmem_free(datap, size); 534 return (ret); 535 } 536 537 /* free node_t buffer */ 538 kmem_free(datap, size); 539 540 /* copyout node_t */ 541 if (sgfru_copyout_nodes(iargp, &nodeinfo, &node) != 0) { 542 return (EFAULT); 543 } 544 PR_NODE("sgfru:%s: handle %lx nodename %s has_children %d class %d\n", 545 f, node.handle, node.nodename, node.has_children, node.class); 546 547 return (ret); 548 } 549 550 /* 551 * Used for fru_get_sections(). 552 */ 553 static int 554 sgfru_getsections(const sgfru_init_arg_t *iargp) 555 { 556 int32_t ret; 557 caddr_t datap; 558 size_t ssize, size; 559 frup_info_t sects; 560 fru_cnt_t max_cnt; 561 section_t *sectp; 562 563 /* copyin sections_t aka frup_info_t */ 564 if (sgfru_copyin_frup(iargp, §s) != 0) { 565 return (EFAULT); 566 } 567 /* check on kmem_alloc space requirements */ 568 max_cnt = sects.fru_cnt; 569 if ((max_cnt <= 0) || (max_cnt > MAX_SECTIONS)) { 570 return (EINVAL); 571 } 572 573 /* allocate buffer for unpadded fru_info_t + section_t's */ 574 size = (size_t)(FRU_INFO_SIZE + (max_cnt * SECTION_SIZE)); 575 datap = kmem_zalloc(size, KM_SLEEP); 576 577 /* call mailbox */ 578 if ((ret = sgfru_mbox(iargp->cmd, datap, size, §s.fru_info)) 579 != 0) { 580 kmem_free(datap, size); 581 return (ret); 582 } 583 584 /* allocate buffer for padded section_t's */ 585 ssize = (size_t)(max_cnt * sizeof (section_t)); 586 sectp = (section_t *)kmem_zalloc(ssize, KM_SLEEP); 587 588 /* translate unpadded to padded fru_info_t + section_t's */ 589 if ((ret = sgfru_section_pad(datap, max_cnt, §s.fru_info, sectp)) 590 != 0) { 591 kmem_free(datap, size); 592 kmem_free(sectp, ssize); 593 return (ret); 594 } 595 /* free section_t buffer */ 596 kmem_free(datap, size); 597 598 /* copy out fru_info_t */ 599 if (sgfru_copyout_fru(iargp, §s.fru_info) != 0) { 600 kmem_free(sectp, ssize); 601 return (EFAULT); 602 } 603 /* copyout section_t's */ 604 if (sgfru_copyout_sections(iargp, §s, sectp) != 0) { 605 kmem_free(sectp, ssize); 606 return (EFAULT); 607 } 608 /* free section_t buffer */ 609 kmem_free(sectp, ssize); 610 611 return (ret); 612 } 613 614 /* 615 * Used for fru_get_segments(). 616 */ 617 static int 618 sgfru_getsegments(const sgfru_init_arg_t *iargp) 619 { 620 int32_t ret; 621 caddr_t datap; 622 size_t ssize, size; 623 frup_info_t segs; 624 fru_cnt_t max_cnt; 625 segment_t *segp; 626 627 /* copyin frup_info_t */ 628 if (sgfru_copyin_frup(iargp, &segs) != 0) { 629 return (EFAULT); 630 } 631 /* check on kmem_alloc space requirements */ 632 max_cnt = segs.fru_cnt; 633 if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTS)) { 634 return (EINVAL); 635 } 636 637 /* allocate unpadded buffer for fru_info_t + segment_t's */ 638 size = (size_t)(FRU_INFO_SIZE + (max_cnt * SEGMENT_SIZE)); 639 datap = kmem_zalloc(size, KM_SLEEP); 640 641 /* call mailbox */ 642 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) { 643 kmem_free(datap, size); 644 return (ret); 645 } 646 647 /* allocate buffer for padded segment_t's */ 648 ssize = (size_t)(max_cnt * sizeof (segment_t)); 649 segp = (segment_t *)kmem_zalloc(ssize, KM_SLEEP); 650 651 /* translate unpadded to padded fru_info_t + segment_t's */ 652 if ((ret = sgfru_segment_pad(datap, max_cnt, &segs.fru_info, segp)) 653 != 0) { 654 kmem_free(datap, size); 655 kmem_free(segp, ssize); 656 return (ret); 657 } 658 /* free segment_t buffer */ 659 kmem_free(datap, size); 660 661 /* copy out fru_info_t */ 662 if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) { 663 kmem_free(segp, ssize); 664 return (EFAULT); 665 } 666 /* copyout segment_t's */ 667 if (sgfru_copyout_segments(iargp, &segs, segp) != 0) { 668 kmem_free(segp, ssize); 669 return (EFAULT); 670 } 671 /* free segment_t buffer */ 672 kmem_free(segp, ssize); 673 674 return (ret); 675 } 676 677 static int 678 sgfru_addsegment(const sgfru_init_arg_t *iargp) 679 { 680 int32_t ret; 681 caddr_t datap; 682 size_t size; 683 frup_info_t seg; 684 segment_t segment; 685 fru_hdl_t *hdlp; 686 static fn_t f = "sgfru_addsegment"; 687 688 /* copyin frup_info_t */ 689 if (sgfru_copyin_frup(iargp, &seg) != 0) { 690 return (EFAULT); 691 } 692 /* copyin segment_t */ 693 if (sgfru_copyin_segment(iargp, &seg, &segment) != 0) { 694 return (EFAULT); 695 } 696 PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n", 697 f, seg.fru_hdl, seg.fru_cnt); 698 PR_SEGMENT("sgfru:%s: handle %lx, name %s, descriptor 0x%x, " 699 "offset 0x%x, length 0x%x\n", f, segment.handle, segment.name, 700 segment.descriptor, segment.offset, segment.length); 701 702 /* allocate buffer for unpadded section_hdl_t + segment_t */ 703 size = (size_t)(SECTION_HDL_SIZE + SEGMENT_SIZE); 704 datap = kmem_zalloc(size, KM_SLEEP); 705 /* translate padded to unpadded section_hdl_t + segment_t */ 706 sgfru_segment_unpad(&seg.fru_info, &segment, datap); 707 708 /* call mailbox */ 709 ret = sgfru_mbox(iargp->cmd, datap, size, &seg.fru_info); 710 if (ret != 0) { 711 kmem_free(datap, size); 712 return (ret); 713 } 714 715 /* copyout updated section_hdl_t */ 716 hdlp = (fru_hdl_t *)(datap + sizeof (fru_hdl_t)); 717 if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) { 718 kmem_free(datap, size); 719 return (EFAULT); 720 } 721 /* copyout new segment_hdl_t */ 722 if (sgfru_copyout_handle(iargp, seg.frus, --hdlp) != 0) { 723 kmem_free(datap, size); 724 return (EFAULT); 725 } 726 /* free segment_t buffer */ 727 kmem_free(datap, size); 728 729 return (ret); 730 } 731 732 /* 733 * Used for fru_read_segment(). 734 */ 735 static int 736 sgfru_readsegment(const sgfru_init_arg_t *iargp) 737 { 738 int32_t ret; 739 caddr_t datap, tdatap; 740 size_t size; 741 frup_info_t segs; 742 fru_info_t sinfo; 743 fru_cnt_t max_cnt; 744 static fn_t f = "sgfru_readsegment"; 745 746 /* copyin one segments_t aka frup_info_t */ 747 if (sgfru_copyin_frup(iargp, &segs) != 0) { 748 return (EFAULT); 749 } 750 /* check on kmem_alloc space requirements */ 751 max_cnt = segs.fru_cnt; 752 if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) { 753 return (EINVAL); 754 } 755 PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n", 756 f, segs.fru_hdl, segs.fru_cnt); 757 758 /* allocate unpadded buffer for raw data */ 759 size = (size_t)(FRU_INFO_SIZE + max_cnt); 760 datap = kmem_zalloc(size, KM_SLEEP); 761 762 /* call mailbox */ 763 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) { 764 kmem_free(datap, size); 765 return (ret); 766 } 767 768 /* translate unpadded to padded fru_info_t */ 769 tdatap = sgfru_fru_pad(datap, &sinfo); 770 PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n", 771 f, sinfo.hdl, sinfo.cnt); 772 773 /* copyout actual fru_cnt */ 774 if (sgfru_copyout_fru(iargp, &sinfo) != 0) { 775 kmem_free(datap, size); 776 return (EFAULT); 777 } 778 /* copyout raw segment data */ 779 if (sgfru_copyout_buffer(iargp, &segs, tdatap) != 0) { 780 kmem_free(datap, size); 781 return (EFAULT); 782 } 783 /* free buffer */ 784 kmem_free(datap, size); 785 786 return (ret); 787 } 788 789 /* 790 * Used for fru_write_segment(). 791 */ 792 static int 793 sgfru_writesegment(const sgfru_init_arg_t *iargp) 794 { 795 int32_t ret; 796 caddr_t datap, tdatap; 797 size_t size; 798 frup_info_t segs; 799 fru_cnt_t max_cnt; 800 static fn_t f = "sgfru_writesegment"; 801 802 /* copyin frup_info_t */ 803 if (sgfru_copyin_frup(iargp, &segs) != 0) { 804 return (EFAULT); 805 } 806 /* check on kmem_alloc space requirements */ 807 max_cnt = segs.fru_cnt; 808 if ((max_cnt <= 0) || (max_cnt > MAX_SEGMENTSIZE)) { 809 return (EINVAL); 810 } 811 PR_SEGMENT("sgfru:%s: handle %lx, max cnt %d\n", 812 f, segs.fru_hdl, segs.fru_cnt); 813 814 /* allocate unpadded buffer for fru_info_t + raw data */ 815 size = (size_t)(FRU_INFO_SIZE + max_cnt); 816 datap = kmem_zalloc(size, KM_SLEEP); 817 818 /* translate padded to unpadded fru_info_t */ 819 tdatap = sgfru_fru_unpad(&segs.fru_info, datap); 820 821 /* copyin raw segment data */ 822 if (sgfru_copyin_buffer(iargp, segs.frus, max_cnt, tdatap) != 0) { 823 kmem_free(datap, size); 824 return (EFAULT); 825 } 826 827 /* call mailbox */ 828 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &segs.fru_info)) != 0) { 829 kmem_free(datap, size); 830 return (ret); 831 } 832 /* free buffer */ 833 kmem_free(datap, size); 834 835 PR_SEGMENT("sgfru:%s: handle %lx, actual cnt %d\n", 836 f, segs.fru_hdl, segs.fru_cnt); 837 /* copyout updated segment handle and actual fru_cnt */ 838 if (sgfru_copyout_fru(iargp, &segs.fru_info) != 0) { 839 return (EFAULT); 840 } 841 842 return (ret); 843 } 844 845 /* 846 * Used for fru_get_packets(). 847 */ 848 static int 849 sgfru_getpackets(const sgfru_init_arg_t *iargp) 850 { 851 int32_t ret; 852 caddr_t datap; 853 size_t ssize, size; 854 frup_info_t packs; 855 fru_cnt_t max_cnt; 856 packet_t *packp; 857 858 /* copyin packets_t aka frup_info_t */ 859 if (sgfru_copyin_frup(iargp, &packs) != 0) { 860 return (EFAULT); 861 } 862 /* check on kmem_alloc space requirements */ 863 max_cnt = packs.fru_cnt; 864 if ((max_cnt <= 0) || (max_cnt > MAX_PACKETS)) { 865 return (EINVAL); 866 } 867 868 /* allocate buffer for unpadded fru_info_t + packet_t's */ 869 size = (size_t)(FRU_INFO_SIZE + (max_cnt * PACKET_SIZE)); 870 datap = kmem_zalloc(size, KM_SLEEP); 871 872 /* call mailbox */ 873 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &packs.fru_info)) 874 != 0) { 875 kmem_free(datap, size); 876 return (ret); 877 } 878 879 /* allocate buffer for padded packet_t's */ 880 ssize = (size_t)(max_cnt * sizeof (packet_t)); 881 packp = (packet_t *)kmem_zalloc(ssize, KM_SLEEP); 882 883 /* translate unpadded to padded fru_info_t + packet_t's */ 884 if ((ret = sgfru_packet_pad(datap, max_cnt, &packs.fru_info, packp)) 885 != 0) { 886 kmem_free(datap, size); 887 kmem_free(packp, ssize); 888 return (ret); 889 } 890 /* free packet_t buffer */ 891 kmem_free(datap, size); 892 893 /* copy out fru_info_t */ 894 if (sgfru_copyout_fru(iargp, &packs.fru_info) != 0) { 895 kmem_free(packp, ssize); 896 return (EFAULT); 897 } 898 /* copyout packet_t's */ 899 if (sgfru_copyout_packets(iargp, &packs, packp) != 0) { 900 kmem_free(packp, ssize); 901 return (EFAULT); 902 } 903 /* free packet_t buffer */ 904 kmem_free(packp, ssize); 905 906 return (ret); 907 } 908 909 /* 910 * Used for fru_append_packet(). 911 */ 912 static int 913 sgfru_appendpacket(const sgfru_init_arg_t *iargp) 914 { 915 int32_t ret = 0; 916 caddr_t datap, tdatap; 917 size_t size; 918 append_info_t append; 919 fru_cnt_t max_cnt; 920 fru_hdl_t *hdlp; 921 caddr_t addr; 922 923 /* copyin append_info_t */ 924 if (sgfru_copyin_append(iargp, &append) != 0) { 925 return (EFAULT); 926 } 927 /* check on kmem_alloc space requirements */ 928 max_cnt = append.payload_cnt; 929 if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) { 930 return (EINVAL); 931 } 932 933 /* allocate buffer for unpadded fru_info_t + packet_t + payload */ 934 size = (size_t)(FRU_INFO_SIZE + PACKET_SIZE + max_cnt); 935 datap = kmem_zalloc(size, KM_SLEEP); 936 /* translate padded to unpadded fru_info_t plus packet_t */ 937 tdatap = sgfru_packet_unpad(&append.payload.fru_info, &append.packet, 938 datap); 939 940 /* copyin payload to the end of the unpadded buffer */ 941 if (sgfru_copyin_buffer(iargp, append.payload_data, append.payload_cnt, 942 tdatap) != 0) { 943 kmem_free(datap, size); 944 return (EFAULT); 945 } 946 947 /* call mailbox */ 948 if ((ret = sgfru_mbox(iargp->cmd, datap, size, 949 &append.payload.fru_info)) != 0) { 950 kmem_free(datap, size); 951 return (ret); 952 } 953 954 /* copyout new packet_hdl_t */ 955 hdlp = (fru_hdl_t *)datap; 956 if (sgfru_copyout_handle(iargp, (void *)iargp->argp, hdlp) != 0) { 957 kmem_free(datap, size); 958 return (EFAULT); 959 } 960 /* copyout updated segment_hdl_t */ 961 addr = (caddr_t)(iargp->argp + sizeof (packet_t)); 962 if (sgfru_copyout_handle(iargp, addr, ++hdlp) != 0) { 963 kmem_free(datap, size); 964 return (EFAULT); 965 } 966 967 /* free buffer */ 968 kmem_free(datap, size); 969 970 return (ret); 971 } 972 973 /* 974 * Used for fru_get_payload(). 975 */ 976 static int 977 sgfru_getpayload(const sgfru_init_arg_t *iargp) 978 { 979 int32_t ret; 980 caddr_t datap, tdatap; 981 size_t size; 982 frup_info_t payld; 983 fru_info_t pinfo; 984 fru_cnt_t max_cnt; 985 static fn_t f = "sgfru_getpayload"; 986 987 /* copyin payload_t aka frup_info_t */ 988 if (sgfru_copyin_frup(iargp, &payld) != 0) { 989 return (EFAULT); 990 } 991 PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n", 992 f, payld.fru_hdl, payld.fru_cnt); 993 994 /* check on kmem_alloc space requirements */ 995 max_cnt = payld.fru_cnt; 996 if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) { 997 return (EINVAL); 998 } 999 1000 /* allocate buffer for fru_info_t + payload */ 1001 size = (size_t)(FRU_INFO_SIZE + max_cnt); 1002 datap = kmem_zalloc(size, KM_SLEEP); 1003 1004 /* call mailbox */ 1005 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info)) 1006 != 0) { 1007 kmem_free(datap, size); 1008 return (ret); 1009 } 1010 1011 /* translate unpadded to padded fru_info_t */ 1012 tdatap = sgfru_fru_pad(datap, &pinfo); 1013 PR_PAYLOAD("sgfru:%s: handle %lx, max cnt %d\n", 1014 f, pinfo.hdl, pinfo.cnt); 1015 1016 /* copyout actual fru_cnt */ 1017 if (sgfru_copyout_fru(iargp, &pinfo) != 0) { 1018 kmem_free(datap, size); 1019 return (EFAULT); 1020 } 1021 /* copyout raw packet data, aka the payload */ 1022 if (sgfru_copyout_buffer(iargp, &payld, tdatap) != 0) { 1023 kmem_free(datap, size); 1024 return (EFAULT); 1025 } 1026 1027 /* free buffer */ 1028 kmem_free(datap, size); 1029 1030 return (ret); 1031 } 1032 1033 /* 1034 * Used for fru_update_payload(). 1035 */ 1036 static int 1037 sgfru_updatepayload(const sgfru_init_arg_t *iargp) 1038 { 1039 int32_t ret; 1040 caddr_t datap, tdatap; 1041 size_t size; 1042 frup_info_t payld; 1043 fru_cnt_t max_cnt; 1044 static fn_t f = "sgfru_updatepayload"; 1045 1046 /* copyin frup_info_t */ 1047 if (sgfru_copyin_frup(iargp, &payld) != 0) { 1048 return (EFAULT); 1049 } 1050 /* check on kmem_alloc space requirements */ 1051 max_cnt = payld.fru_cnt; 1052 if ((max_cnt <= 0) || (max_cnt > MAX_PAYLOADSIZE)) { 1053 return (EINVAL); 1054 } 1055 1056 /* allocate buffer for fru_info_t + payload */ 1057 size = (size_t)(FRU_INFO_SIZE + max_cnt); 1058 datap = kmem_zalloc(size, KM_SLEEP); 1059 1060 /* translate padded to unpadded fru_info_t */ 1061 tdatap = sgfru_fru_unpad(&payld.fru_info, datap); 1062 1063 /* copyin payload */ 1064 if (sgfru_copyin_buffer(iargp, payld.frus, max_cnt, tdatap) != 0) { 1065 kmem_free(datap, size); 1066 return (EFAULT); 1067 } 1068 PR_PAYLOAD("sgfru_updatepayload: handle %lx, actual cnt %d\n", 1069 payld.fru_hdl, payld.fru_cnt); 1070 1071 /* call mailbox */ 1072 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &payld.fru_info)) 1073 != 0) { 1074 kmem_free(datap, size); 1075 return (ret); 1076 } 1077 1078 /* free buffer */ 1079 kmem_free(datap, size); 1080 1081 /* copyout new packet_hdl_t and actual count */ 1082 if (sgfru_copyout_fru(iargp, &payld.fru_info) != 0) { 1083 return (EFAULT); 1084 } 1085 PR_PAYLOAD("sgfru:%s: new handle %lx, cnt %d\n", 1086 f, payld.fru_hdl, payld.fru_cnt); 1087 1088 return (ret); 1089 } 1090 1091 /* 1092 * Used for fru_get_num_[sections|segments|packets](). 1093 */ 1094 static int 1095 sgfru_getnum(const sgfru_init_arg_t *iargp) 1096 { 1097 int32_t ret; 1098 caddr_t datap; 1099 size_t size; 1100 fru_info_t fru_info; 1101 1102 /* copyin fru_info_t */ 1103 if (sgfru_copyin_fru(iargp, &fru_info) != 0) { 1104 return (EFAULT); 1105 } 1106 1107 size = sizeof (fru_cnt_t); 1108 datap = (caddr_t)&fru_info.cnt; 1109 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) { 1110 return (ret); 1111 } 1112 1113 /* copyout fru_info_t */ 1114 if (sgfru_copyout_fru(iargp, &fru_info) != 0) { 1115 return (EFAULT); 1116 } 1117 return (ret); 1118 } 1119 1120 /* 1121 * Used for fru_delete_[segment|packet]. 1122 */ 1123 static int 1124 sgfru_delete(const sgfru_init_arg_t *iargp) 1125 { 1126 int32_t ret; 1127 caddr_t datap; 1128 size_t size; 1129 fru_info_t fru_info; 1130 static fn_t f = "sgfru_delete"; 1131 1132 /* copyin fru_info_t */ 1133 if (sgfru_copyin_fru(iargp, &fru_info) != 0) { 1134 return (EFAULT); 1135 } 1136 PR_SEGMENT("sgfru:%s: delete handle %lx\n", f, fru_info.hdl); 1137 1138 size = sizeof (fru_hdl_t); 1139 datap = (caddr_t)&fru_info.hdl; 1140 if ((ret = sgfru_mbox(iargp->cmd, datap, size, &fru_info)) != 0) { 1141 return (ret); 1142 } 1143 1144 PR_SEGMENT("sgfru:%s: new parent handle %lx\n", f, fru_info.hdl); 1145 /* copyout fru_info_t */ 1146 if (sgfru_copyout_fru(iargp, &fru_info) != 0) { 1147 return (EFAULT); 1148 } 1149 return (ret); 1150 } 1151 1152 /* 1153 * Calls the sgsbbc mailbox with data, returns data and status info. 1154 */ 1155 static int 1156 sgfru_mbox(const int cmd, char *datap, const size_t size, fru_info_t *fru) 1157 { 1158 sbbc_msg_t request, *reqp = &request; 1159 sbbc_msg_t response, *resp = &response; 1160 fru_hdl_t hdls[2] = {0, 0}; 1161 fru_hdl_t hdl = fru->hdl; 1162 int rv = 0; 1163 static fn_t f = "sgfru_mbox"; 1164 1165 bzero((caddr_t)&request, sizeof (sbbc_msg_t)); 1166 reqp->msg_type.type = SGFRU_MBOX; 1167 bzero((caddr_t)&response, sizeof (sbbc_msg_t)); 1168 resp->msg_type.type = SGFRU_MBOX; 1169 PR_MBOX("sgfru:%s: cmd 0x%x, size %lu\n", f, cmd, size); 1170 1171 switch (cmd) { 1172 1173 case SGFRU_GETCHILDLIST: 1174 reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST; 1175 reqp->msg_len = sizeof (fru_info_t); 1176 reqp->msg_buf = (caddr_t)fru; 1177 resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDLIST; 1178 resp->msg_len = size; 1179 resp->msg_buf = datap; 1180 break; 1181 1182 case SGFRU_GETCHILDHANDLES: 1183 reqp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES; 1184 reqp->msg_len = sizeof (fru_info_t); 1185 reqp->msg_buf = (caddr_t)fru; 1186 resp->msg_type.sub_type = SGFRU_MBOX_GETCHILDHANDLES; 1187 resp->msg_len = size; 1188 resp->msg_buf = datap; 1189 break; 1190 1191 case SGFRU_GETNODEINFO: 1192 reqp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO; 1193 reqp->msg_len = sizeof (fru_hdl_t); 1194 reqp->msg_buf = (caddr_t)&hdl; 1195 resp->msg_type.sub_type = SGFRU_MBOX_GETNODEINFO; 1196 resp->msg_len = size; 1197 resp->msg_buf = datap; 1198 break; 1199 1200 case SGFRU_GETNUMSECTIONS: 1201 reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS; 1202 reqp->msg_len = sizeof (fru_hdl_t); 1203 reqp->msg_buf = (caddr_t)&hdl; 1204 resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSECTIONS; 1205 resp->msg_len = size; 1206 resp->msg_buf = datap; 1207 break; 1208 1209 case SGFRU_GETNUMSEGMENTS: 1210 reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS; 1211 reqp->msg_len = sizeof (fru_hdl_t); 1212 reqp->msg_buf = (caddr_t)&hdl; 1213 resp->msg_type.sub_type = SGFRU_MBOX_GETNUMSEGMENTS; 1214 resp->msg_len = size; 1215 resp->msg_buf = datap; 1216 break; 1217 1218 case SGFRU_GETNUMPACKETS: 1219 reqp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS; 1220 reqp->msg_len = sizeof (fru_hdl_t); 1221 reqp->msg_buf = (caddr_t)&hdl; 1222 resp->msg_type.sub_type = SGFRU_MBOX_GETNUMPACKETS; 1223 resp->msg_len = size; 1224 resp->msg_buf = datap; 1225 break; 1226 1227 case SGFRU_GETSECTIONS: 1228 reqp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS; 1229 reqp->msg_len = sizeof (fru_info_t); 1230 reqp->msg_buf = (caddr_t)fru; 1231 resp->msg_type.sub_type = SGFRU_MBOX_GETSECTIONS; 1232 resp->msg_len = size; 1233 resp->msg_buf = datap; 1234 break; 1235 1236 case SGFRU_GETSEGMENTS: 1237 reqp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS; 1238 reqp->msg_len = sizeof (fru_info_t); 1239 reqp->msg_buf = (caddr_t)fru; 1240 resp->msg_type.sub_type = SGFRU_MBOX_GETSEGMENTS; 1241 resp->msg_len = size; 1242 resp->msg_buf = datap; 1243 break; 1244 1245 case SGFRU_GETPACKETS: 1246 reqp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS; 1247 reqp->msg_len = sizeof (fru_info_t); 1248 reqp->msg_buf = (caddr_t)fru; 1249 resp->msg_type.sub_type = SGFRU_MBOX_GETPACKETS; 1250 resp->msg_len = size; 1251 resp->msg_buf = datap; 1252 break; 1253 1254 case SGFRU_ADDSEGMENT: 1255 reqp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT; 1256 reqp->msg_len = size; 1257 reqp->msg_buf = datap; 1258 resp->msg_type.sub_type = SGFRU_MBOX_ADDSEGMENT; 1259 resp->msg_len = sizeof (hdls); 1260 resp->msg_buf = (caddr_t)&hdls; 1261 break; 1262 1263 case SGFRU_APPENDPACKET: 1264 reqp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET; 1265 reqp->msg_len = size; 1266 reqp->msg_buf = (caddr_t)datap; 1267 resp->msg_type.sub_type = SGFRU_MBOX_APPENDPACKET; 1268 resp->msg_len = sizeof (hdls); 1269 resp->msg_buf = (caddr_t)&hdls; 1270 break; 1271 1272 case SGFRU_DELETESEGMENT: 1273 reqp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT; 1274 reqp->msg_len = size; 1275 reqp->msg_buf = (caddr_t)datap; 1276 resp->msg_type.sub_type = SGFRU_MBOX_DELETESEGMENT; 1277 resp->msg_len = sizeof (fru_hdl_t); 1278 resp->msg_buf = (caddr_t)&hdl; 1279 break; 1280 1281 case SGFRU_READRAWSEGMENT: 1282 reqp->msg_type.sub_type = SGFRU_MBOX_READRAWSEGMENT; 1283 reqp->msg_len = sizeof (fru_info_t); 1284 reqp->msg_buf = (caddr_t)fru; 1285 resp->msg_type.sub_type = SGFRU_READRAWSEGMENT; 1286 resp->msg_len = size; 1287 resp->msg_buf = datap; 1288 break; 1289 1290 case SGFRU_WRITERAWSEGMENT: 1291 reqp->msg_type.sub_type = SGFRU_MBOX_WRITERAWSEGMENT; 1292 reqp->msg_len = size; 1293 reqp->msg_buf = datap; 1294 resp->msg_type.sub_type = SGFRU_WRITERAWSEGMENT; 1295 resp->msg_len = sizeof (fru_info_t); 1296 resp->msg_buf = (caddr_t)fru; 1297 break; 1298 1299 case SGFRU_DELETEPACKET: 1300 reqp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET; 1301 reqp->msg_len = size; 1302 reqp->msg_buf = (caddr_t)datap; 1303 resp->msg_type.sub_type = SGFRU_MBOX_DELETEPACKET; 1304 resp->msg_len = sizeof (fru_hdl_t); 1305 resp->msg_buf = (caddr_t)&hdl; 1306 break; 1307 1308 case SGFRU_GETPAYLOAD: 1309 reqp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD; 1310 reqp->msg_len = sizeof (fru_info_t); 1311 reqp->msg_buf = (caddr_t)fru; 1312 resp->msg_type.sub_type = SGFRU_MBOX_GETPAYLOAD; 1313 resp->msg_len = size; 1314 resp->msg_buf = datap; 1315 break; 1316 1317 case SGFRU_UPDATEPAYLOAD: 1318 reqp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD; 1319 reqp->msg_len = size; 1320 reqp->msg_buf = datap; 1321 resp->msg_type.sub_type = SGFRU_MBOX_UPDATEPAYLOAD; 1322 resp->msg_len = sizeof (fru_info_t); 1323 resp->msg_buf = (caddr_t)fru; 1324 break; 1325 1326 default: 1327 return (EINVAL); 1328 } 1329 1330 rv = sbbc_mbox_request_response(reqp, resp, sgfru_mbox_wait); 1331 PR_MBOX("sgfru:%s: rv %d, msg_status %d\n", f, rv, resp->msg_status); 1332 1333 if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 1334 1335 /* errors from sgsbbc */ 1336 if (resp->msg_status > 0) { 1337 return (resp->msg_status); 1338 } 1339 1340 /* errors from SCAPP */ 1341 switch (resp->msg_status) { 1342 1343 case SG_MBOX_STATUS_COMMAND_FAILURE: 1344 /* internal SCAPP error */ 1345 return (EINTR); 1346 1347 case SG_MBOX_STATUS_HARDWARE_FAILURE: 1348 /* seprom read/write errors */ 1349 return (EIO); 1350 1351 case SG_MBOX_STATUS_ILLEGAL_PARAMETER: 1352 /* illegal ioctl parameter */ 1353 return (EINVAL); 1354 1355 case SG_MBOX_STATUS_BOARD_ACCESS_DENIED: 1356 /* board access denied */ 1357 return (EACCES); 1358 1359 case SG_MBOX_STATUS_STALE_CONTENTS: 1360 /* stale contents */ 1361 return (ESTALE); 1362 1363 case SG_MBOX_STATUS_STALE_OBJECT: 1364 /* stale handle */ 1365 return (ENOENT); 1366 1367 case SG_MBOX_STATUS_NO_SEPROM_SPACE: 1368 /* seprom lacks space */ 1369 return (ENOSPC); 1370 1371 case SG_MBOX_STATUS_NO_MEMORY: 1372 /* user prog. lacks space */ 1373 return (ENOMEM); 1374 1375 case SG_MBOX_STATUS_NOT_SUPPORTED: 1376 /* unsupported operation */ 1377 return (ENOTSUP); 1378 1379 default: 1380 return (EIO); 1381 } 1382 } 1383 1384 switch (cmd) { 1385 1386 /* 1387 * These two calls get back two handles, a new handle for the 1388 * added segment or packet, and an updated parent handle. 1389 */ 1390 case SGFRU_ADDSEGMENT: 1391 case SGFRU_APPENDPACKET: 1392 bcopy(hdls, datap, sizeof (hdls)); 1393 break; 1394 1395 /* These two calls get an updated parent handle. */ 1396 case SGFRU_DELETESEGMENT: 1397 case SGFRU_DELETEPACKET: 1398 fru->hdl = hdl; 1399 break; 1400 1401 default: 1402 break; 1403 } 1404 1405 return (0); 1406 } 1407 1408 /* 1409 * Used to copy in one frup_info_t from user. 1410 */ 1411 static int 1412 sgfru_copyin_frup(const sgfru_init_arg_t *argp, frup_info_t *frup) 1413 { 1414 static fn_t f = "sgfru_copyin_frup"; 1415 1416 bzero((caddr_t)frup, sizeof (frup_info_t)); 1417 #ifdef _MULTI_DATAMODEL 1418 if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) { 1419 frup32_info_t frup32; 1420 1421 bzero((caddr_t)&frup32, sizeof (frup32_info_t)); 1422 if (ddi_copyin((void *)argp->argp, (void *)&frup32, 1423 sizeof (frup32_info_t), argp->mode) != DDI_SUCCESS) { 1424 cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin " 1425 "frup32_t struct", f); 1426 return (EFAULT); 1427 } 1428 frup->fru_hdl = frup32.fru_hdl; 1429 frup->fru_cnt = frup32.fru_cnt; 1430 frup->frus = (void *)(uintptr_t)frup32.frus; 1431 PR_STATE("sgfru:%s: frus %p %x hdl %lx cnt %d\n", 1432 f, frup->frus, frup32.frus, frup->fru_hdl, frup->fru_cnt); 1433 1434 } else 1435 #endif /* _MULTI_DATAMODEL */ 1436 if (ddi_copyin((void *)argp->argp, (void *)frup, 1437 sizeof (frup_info_t), argp->mode) != DDI_SUCCESS) { 1438 cmn_err(CE_WARN, 1439 "sgfru:%s: failed to copyin frup_info_t struct", f); 1440 return (EFAULT); 1441 } 1442 return (0); 1443 } 1444 1445 /* 1446 * Used to copy in one fru_info_t from user. 1447 */ 1448 static int 1449 sgfru_copyin_fru(const sgfru_init_arg_t *argp, fru_info_t *fru) 1450 { 1451 static fn_t f = "sgfru_copyin_fru"; 1452 1453 bzero((caddr_t)fru, sizeof (fru_info_t)); 1454 if (ddi_copyin((void *)argp->argp, (void *)fru, 1455 sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) { 1456 cmn_err(CE_WARN, 1457 "sgfru:%s: failed to copyin fru_info_t struct", f); 1458 return (EFAULT); 1459 } 1460 return (0); 1461 } 1462 1463 /* 1464 * Used to copy in segment_t from user. 1465 */ 1466 static int 1467 sgfru_copyin_segment(const sgfru_init_arg_t *argp, const frup_info_t *frup, 1468 segment_t *segp) 1469 { 1470 static fn_t f = "sgfru_copyin_segment"; 1471 1472 bzero((caddr_t)segp, sizeof (segment_t)); 1473 if (ddi_copyin((void *)frup->frus, (void *)segp, 1474 sizeof (segment_t), argp->mode) != DDI_SUCCESS) { 1475 cmn_err(CE_WARN, 1476 "sgfru:%s: failed to copyin segment_t struct", f); 1477 return (EFAULT); 1478 } 1479 return (0); 1480 } 1481 1482 /* 1483 * Used to copy in segment handle, packet and payload data from user. 1484 */ 1485 static int 1486 sgfru_copyin_append(const sgfru_init_arg_t *argp, append_info_t *app) 1487 { 1488 static fn_t f = "sgfru_copyin_append"; 1489 1490 bzero((caddr_t)app, sizeof (append_info_t)); 1491 #ifdef _MULTI_DATAMODEL 1492 if (ddi_model_convert_from(argp->mode & FMODELS) == DDI_MODEL_ILP32) { 1493 append32_info_t app32; 1494 1495 bzero((caddr_t)&app32, sizeof (append32_info_t)); 1496 if (ddi_copyin((void *)argp->argp, (void *)&app32, 1497 sizeof (append32_info_t), argp->mode) != DDI_SUCCESS) { 1498 cmn_err(CE_WARN, "sgfru:%s: (32 bit) failed to copyin " 1499 "append32_info_t struct", f); 1500 return (EFAULT); 1501 } 1502 app->packet = app32.packet; 1503 app->payload_hdl = app32.payload_hdl; 1504 app->payload_cnt = app32.payload_cnt; 1505 app->payload_data = (void *)(uintptr_t)app32.payload_data; 1506 PR_PAYLOAD("sgfru:%s:: data %p hdl %lx cnt %d\n", 1507 f, app->payload_data, app->payload_hdl, app->payload_cnt); 1508 1509 } else 1510 #endif /* _MULTI_DATAMODEL */ 1511 if (ddi_copyin((void *)argp->argp, (void *)app, 1512 sizeof (append_info_t), argp->mode) != DDI_SUCCESS) { 1513 cmn_err(CE_WARN, 1514 "sgfru:%s: failed to copyin append_info_t struct", f); 1515 return (EFAULT); 1516 } 1517 PR_PAYLOAD("sgfru:%s: hdl %lx, cnt %d pkt hdl %lx " 1518 "tag %lx\n", f, app->payload_hdl, app->payload_cnt, 1519 app->packet.handle, app->packet.tag); 1520 return (0); 1521 } 1522 1523 /* 1524 * Used to copy in raw segment and payload data from user. 1525 */ 1526 static int 1527 sgfru_copyin_buffer(const sgfru_init_arg_t *argp, const caddr_t data, 1528 const int cnt, char *buffer) 1529 { 1530 static fn_t f = "sgfru_copyin_buffer"; 1531 1532 if (ddi_copyin((void *)data, (void *)buffer, cnt, argp->mode) 1533 != DDI_SUCCESS) { 1534 cmn_err(CE_WARN, "sgfru:%s: failed to copyin buffer", f); 1535 return (EFAULT); 1536 } 1537 return (0); 1538 } 1539 1540 /* 1541 * Used to copy out one fru_info_t to user. 1542 */ 1543 static int 1544 sgfru_copyout_fru(const sgfru_init_arg_t *argp, const fru_info_t *frup) 1545 { 1546 static fn_t f = "sgfru_copyout_fru"; 1547 1548 if (ddi_copyout((void *)frup, (void *)argp->argp, 1549 sizeof (fru_info_t), argp->mode) != DDI_SUCCESS) { 1550 cmn_err(CE_WARN, "sgfru:%s: failed to copyout fru", f); 1551 return (EFAULT); 1552 } 1553 return (0); 1554 } 1555 1556 /* 1557 * Used to copy out one fru_hdl_t to user. 1558 */ 1559 static int 1560 sgfru_copyout_handle(const sgfru_init_arg_t *argp, const void *addr, 1561 const fru_hdl_t *hdlp) 1562 { 1563 static fn_t f = "sgfru_copyout_handle"; 1564 1565 if (ddi_copyout((void *)hdlp, (void *)addr, sizeof (fru_hdl_t), 1566 argp->mode) != DDI_SUCCESS) { 1567 cmn_err(CE_WARN, "sgfru:%s: failed to copyout handle", f); 1568 return (EFAULT); 1569 } 1570 return (0); 1571 } 1572 1573 /* 1574 * Used to copy out an array of fru_hdl_t's to user. 1575 */ 1576 static int 1577 sgfru_copyout_handles(const sgfru_init_arg_t *argp, const frup_info_t *frup, 1578 const fru_hdl_t *hdlp) 1579 { 1580 static fn_t f = "sgfru_copyout_handles"; 1581 1582 size_t size = (size_t)(frup->fru_cnt * sizeof (fru_hdl_t)); 1583 /* copyout fru_hdl_t's */ 1584 if (ddi_copyout((void *)hdlp, (void *)frup->frus, size, argp->mode) 1585 != DDI_SUCCESS) { 1586 cmn_err(CE_WARN, "sgfru:%s: failed to copyout handles", f); 1587 return (EFAULT); 1588 } 1589 return (0); 1590 } 1591 1592 /* 1593 * Used to copy out one or more node_t's to user. 1594 */ 1595 static int 1596 sgfru_copyout_nodes(const sgfru_init_arg_t *argp, const frup_info_t *frup, 1597 const node_t *nodep) 1598 { 1599 static fn_t f = "sgfru_copyout_nodes"; 1600 1601 size_t size = (size_t)(frup->fru_cnt * sizeof (node_t)); 1602 /* copyout node_t's */ 1603 if (ddi_copyout((void *)nodep, (void *)frup->frus, size, argp->mode) 1604 != DDI_SUCCESS) { 1605 cmn_err(CE_WARN, "sgfru:%s: failed to copyout nodes", f); 1606 return (EFAULT); 1607 } 1608 return (0); 1609 } 1610 1611 /* 1612 * Used to copy out section_t's to user. 1613 */ 1614 static int 1615 sgfru_copyout_sections(const sgfru_init_arg_t *argp, const frup_info_t *frup, 1616 const section_t *sectp) 1617 { 1618 static fn_t f = "sgfru_copyout_sections"; 1619 1620 size_t size = (size_t)(frup->fru_cnt * sizeof (section_t)); 1621 /* copyout section_t's */ 1622 if (ddi_copyout((void *)sectp, (void *)frup->frus, size, argp->mode) 1623 != DDI_SUCCESS) { 1624 cmn_err(CE_WARN, "sgfru:%s: failed to copyout sections", f); 1625 return (EFAULT); 1626 } 1627 return (0); 1628 } 1629 1630 /* 1631 * Used to copy out segment_t's to user. 1632 */ 1633 static int 1634 sgfru_copyout_segments(const sgfru_init_arg_t *argp, const frup_info_t *frup, 1635 const segment_t *segp) 1636 { 1637 static fn_t f = "sgfru_copyout_segments"; 1638 1639 size_t size = (size_t)(frup->fru_cnt * sizeof (segment_t)); 1640 /* copyout segment_t's */ 1641 if (ddi_copyout((void *)segp, (void *)frup->frus, size, argp->mode) 1642 != DDI_SUCCESS) { 1643 cmn_err(CE_WARN, "sgfru:%s: failed to copyout segments", f); 1644 return (EFAULT); 1645 } 1646 return (0); 1647 } 1648 1649 /* 1650 * Used to copy out packet_t's to user. 1651 */ 1652 static int 1653 sgfru_copyout_packets(const sgfru_init_arg_t *argp, const frup_info_t *frup, 1654 const packet_t *packp) 1655 { 1656 static fn_t f = "sgfru_copyout_packets"; 1657 1658 size_t size = (size_t)(frup->fru_cnt * sizeof (packet_t)); 1659 /* copyout packet_t's */ 1660 if (ddi_copyout((void *)packp, (void *)frup->frus, size, argp->mode) 1661 != DDI_SUCCESS) { 1662 cmn_err(CE_WARN, "sgfru:%s: failed to copyout packets", f); 1663 return (EFAULT); 1664 } 1665 return (0); 1666 } 1667 1668 /* 1669 * Used to copy out raw segment and payload data to user. 1670 */ 1671 static int 1672 sgfru_copyout_buffer(const sgfru_init_arg_t *argp, const frup_info_t *frup, 1673 const char *buffer) 1674 { 1675 static fn_t f = "sgfru_copyout_buffer"; 1676 1677 size_t size = (size_t)(frup->fru_cnt); 1678 /* copyout packet_t */ 1679 if (ddi_copyout((void *)buffer, (void *)frup->frus, size, argp->mode) 1680 != DDI_SUCCESS) { 1681 cmn_err(CE_WARN, "sgfru:%s: failed to copyout buffer", f); 1682 return (EFAULT); 1683 } 1684 return (0); 1685 } 1686 1687 /* 1688 * Used to pad a Java (SCAPP) fru_info_t, in preparation for sending it to 1689 * C (Solaris). Assumes one fru_info_t. 1690 */ 1691 static caddr_t 1692 sgfru_fru_pad(const caddr_t datap, fru_info_t *fru) 1693 { 1694 caddr_t tdatap = datap; 1695 1696 bcopy(tdatap, (caddr_t)&fru->hdl, FRU_HDL_SIZE); 1697 tdatap += FRU_HDL_SIZE; 1698 bcopy(tdatap, (caddr_t)&fru->cnt, FRU_CNT_SIZE); 1699 tdatap += FRU_CNT_SIZE; 1700 return (tdatap); 1701 } 1702 1703 /* 1704 * Used to pad a Java (SCAPP) node_t, in preparation for sending it to 1705 * C (Solaris). Assumes a fru_info_t and one or more node_t's. 1706 */ 1707 static int 1708 sgfru_node_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru, 1709 node_t *nodep) 1710 { 1711 caddr_t tdatap = datap; 1712 node_t *np; 1713 int i, cnt = 1; 1714 1715 if (fru != NULL) { 1716 tdatap = sgfru_fru_pad(datap, fru); 1717 if (max_cnt < fru->cnt) { 1718 return (ENOMEM); 1719 } else { 1720 cnt = fru->cnt; 1721 } 1722 } 1723 for (i = 0, np = nodep; i < cnt; i++, np++) { 1724 bcopy(tdatap, (caddr_t)&np->handle, FRU_HDL_SIZE); 1725 tdatap += FRU_HDL_SIZE; 1726 bcopy(tdatap, (caddr_t)&np->nodename, NODENAME_SIZE); 1727 tdatap += NODENAME_SIZE; 1728 bcopy(tdatap, (caddr_t)&np->has_children, HASCHILDREN_SIZE); 1729 tdatap += HASCHILDREN_SIZE; 1730 bcopy(tdatap, (caddr_t)&np->class, CLASS_SIZE); 1731 tdatap += CLASS_SIZE; 1732 if (np->class == LOCATION_CLASS) { 1733 bcopy(tdatap, (caddr_t)&np->location_slot, SLOT_SIZE); 1734 tdatap += SLOT_SIZE; 1735 bcopy(tdatap, (caddr_t)&np->location_label, LABEL_SIZE); 1736 tdatap += LABEL_SIZE; 1737 } 1738 } 1739 return (0); 1740 } 1741 1742 /* 1743 * Used to pad a Java (SCAPP) section, in preparation for sending it to 1744 * C (Solaris). Assumes a fru_info_t and multiple section_t's. 1745 */ 1746 static int 1747 sgfru_section_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru, 1748 section_t *sectp) 1749 { 1750 caddr_t tdatap = datap; 1751 section_t *sp; 1752 int i; 1753 1754 tdatap = sgfru_fru_pad(datap, fru); 1755 if (max_cnt < fru->cnt) 1756 return (ENOMEM); 1757 for (i = 0, sp = sectp; i < fru->cnt; i++, sp++) { 1758 bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE); 1759 tdatap += FRU_HDL_SIZE; 1760 bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE); 1761 tdatap += OFFSET_SIZE; 1762 bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE); 1763 tdatap += LENGTH_SIZE; 1764 bcopy(tdatap, (caddr_t)&sp->protected, PROTECTED_SIZE); 1765 tdatap += PROTECTED_SIZE; 1766 bcopy(tdatap, (caddr_t)&sp->version, VERSION_SIZE); 1767 tdatap += VERSION_SIZE; 1768 } 1769 return (0); 1770 } 1771 1772 /* 1773 * Used to pad a Java (SCAPP) segment, in preparation for sending it to 1774 * C (Solaris). Assumes a fru_info_t and multiple segment_t's. 1775 */ 1776 static int 1777 sgfru_segment_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru, 1778 segment_t *segp) 1779 { 1780 caddr_t tdatap = datap; 1781 segment_t *sp; 1782 int i; 1783 1784 tdatap = sgfru_fru_pad(datap, fru); 1785 if (max_cnt < fru->cnt) 1786 return (ENOMEM); 1787 for (i = 0, sp = segp; i < fru->cnt; i++, sp++) { 1788 bcopy(tdatap, (caddr_t)&sp->handle, FRU_HDL_SIZE); 1789 tdatap += FRU_HDL_SIZE; 1790 bcopy(tdatap, (caddr_t)&sp->name, NAME_SIZE); 1791 tdatap += NAME_SIZE; 1792 bcopy(tdatap, (caddr_t)&sp->descriptor, DESCRIPTOR_SIZE); 1793 tdatap += DESCRIPTOR_SIZE; 1794 bcopy(tdatap, (caddr_t)&sp->offset, OFFSET_SIZE); 1795 tdatap += OFFSET_SIZE; 1796 bcopy(tdatap, (caddr_t)&sp->length, LENGTH_SIZE); 1797 tdatap += LENGTH_SIZE; 1798 } 1799 return (0); 1800 } 1801 1802 /* 1803 * Used to pad a Java (SCAPP) packet, in preparation for sending it to 1804 * C (Solaris). Assumes a fru_info_t and multiple packet_t's. 1805 */ 1806 static int 1807 sgfru_packet_pad(const caddr_t datap, const int max_cnt, fru_info_t *fru, 1808 packet_t *packp) 1809 { 1810 caddr_t tdatap = datap; 1811 packet_t *pp; 1812 int i; 1813 1814 tdatap = sgfru_fru_pad(datap, fru); 1815 if (max_cnt < fru->cnt) 1816 return (ENOMEM); 1817 for (i = 0, pp = packp; i < fru->cnt; i++, pp++) { 1818 bcopy(tdatap, (caddr_t)&pp->handle, FRU_HDL_SIZE); 1819 tdatap += FRU_HDL_SIZE; 1820 bcopy(tdatap, (caddr_t)&pp->tag, TAG_SIZE); 1821 tdatap += TAG_SIZE; 1822 } 1823 return (0); 1824 } 1825 1826 /* 1827 * Used to unpad a C (Solaris) fru_info_t, in preparation for sending it to 1828 * Java (SCAPP). Assumes a fru_info_t. 1829 */ 1830 static caddr_t 1831 sgfru_fru_unpad(const fru_info_t *fru, caddr_t datap) 1832 { 1833 caddr_t tdatap = datap; 1834 1835 bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE); 1836 tdatap += FRU_HDL_SIZE; 1837 bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE); 1838 tdatap += FRU_CNT_SIZE; 1839 return (tdatap); 1840 } 1841 1842 /* 1843 * Used to unpad a C (Solaris) segment, in preparation for sending it to 1844 * Java (SCAPP). Assumes a section_hdl_t and one segment_t. 1845 */ 1846 static void 1847 sgfru_segment_unpad(const fru_info_t *fru, const segment_t *segp, 1848 caddr_t datap) 1849 { 1850 caddr_t tdatap = datap; 1851 1852 bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE); 1853 tdatap += FRU_HDL_SIZE; 1854 bcopy((caddr_t)&segp->handle, tdatap, FRU_HDL_SIZE); 1855 tdatap += FRU_HDL_SIZE; 1856 bcopy((caddr_t)&segp->name, tdatap, NAME_SIZE); 1857 tdatap += NAME_SIZE; 1858 bcopy((caddr_t)&segp->descriptor, tdatap, DESCRIPTOR_SIZE); 1859 tdatap += DESCRIPTOR_SIZE; 1860 bcopy((caddr_t)&segp->offset, tdatap, OFFSET_SIZE); 1861 tdatap += OFFSET_SIZE; 1862 bcopy((caddr_t)&segp->length, tdatap, LENGTH_SIZE); 1863 } 1864 1865 /* 1866 * Used to unpad a C (Solaris) packet, in preparation for sending it to 1867 * Java (SCAPP). Assumes a fru_info_t and one packet_t. 1868 */ 1869 static caddr_t 1870 sgfru_packet_unpad(const fru_info_t *fru, const packet_t *packp, caddr_t datap) 1871 { 1872 caddr_t tdatap = datap; 1873 1874 bcopy((caddr_t)&fru->hdl, tdatap, FRU_HDL_SIZE); 1875 tdatap += FRU_HDL_SIZE; 1876 bcopy((caddr_t)&fru->cnt, tdatap, FRU_CNT_SIZE); 1877 tdatap += FRU_CNT_SIZE; 1878 bcopy((caddr_t)&packp->handle, tdatap, FRU_HDL_SIZE); 1879 tdatap += FRU_HDL_SIZE; 1880 bcopy((caddr_t)&packp->tag, tdatap, TAG_SIZE); 1881 tdatap += TAG_SIZE; 1882 return (tdatap); 1883 } 1884