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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * IOSRAM leaf driver to SBBC nexus driver. This driver is used 29 * by Starcat Domain SW to read/write from/to the IO sram. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/conf.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/ddi_impldefs.h> 37 #include <sys/obpdefs.h> 38 #include <sys/promif.h> 39 #include <sys/prom_plat.h> 40 #include <sys/cmn_err.h> 41 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 42 #include <sys/modctl.h> /* for modldrv */ 43 #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */ 44 #include <sys/errno.h> 45 #include <sys/kmem.h> 46 #include <sys/kstat.h> 47 #include <sys/debug.h> 48 49 #include <sys/axq.h> 50 #include <sys/iosramreg.h> 51 #include <sys/iosramio.h> 52 #include <sys/iosramvar.h> 53 54 55 #if defined(DEBUG) 56 int iosram_debug = 0; 57 static void iosram_dprintf(const char *fmt, ...); 58 #define DPRINTF(level, arg) \ 59 { if (iosram_debug >= level) iosram_dprintf arg; } 60 #else /* !DEBUG */ 61 #define DPRINTF(level, arg) 62 #endif /* !DEBUG */ 63 64 65 /* 66 * IOSRAM module global state 67 */ 68 static void *iosramsoft_statep; /* IOSRAM state pointer */ 69 static kmutex_t iosram_mutex; /* mutex lock */ 70 71 static iosram_chunk_t *chunks = NULL; /* array of TOC entries */ 72 static int nchunks = 0; /* # of TOC entries */ 73 static iosram_chunk_t *iosram_hashtab[IOSRAM_HASHSZ]; /* key hash table */ 74 75 static kcondvar_t iosram_tswitch_wait; /* tunnel switch wait cv */ 76 static int iosram_tswitch_wakeup = 0; /* flag indicationg one or */ 77 /* more threads waiting on */ 78 /* iosram_tswitch_wait cv */ 79 static int iosram_tswitch_active = 0; /* tunnel switch active flag */ 80 static int iosram_tswitch_aborted = 0; /* tunnel switch abort flag */ 81 static clock_t iosram_tswitch_tstamp = 0; /* lbolt of last tswitch end */ 82 static kcondvar_t iosram_rw_wait; /* read/write wait cv */ 83 static int iosram_rw_wakeup = 0; /* flag indicationg one or */ 84 /* more threads waiting on */ 85 /* iosram_rw_wait cv */ 86 static int iosram_rw_active = 0; /* # threads accessing IOSRAM */ 87 #if defined(DEBUG) 88 static int iosram_rw_active_max = 0; 89 #endif 90 91 static struct iosramsoft *iosram_new_master = NULL; /* new tunnel target */ 92 static struct iosramsoft *iosram_master = NULL; /* master tunnel */ 93 static struct iosramsoft *iosram_instances = NULL; /* list of softstates */ 94 95 static ddi_acc_handle_t iosram_handle = NULL; /* master IOSRAM map handle */ 96 97 static void (*iosram_hdrchange_handler)() = NULL; 98 99 #if IOSRAM_STATS 100 static struct iosram_stat iosram_stats; /* IOSRAM statistics */ 101 static void iosram_print_stats(); /* forward declaration */ 102 #endif /* IOSRAM_STATS */ 103 104 105 #if IOSRAM_LOG 106 kmutex_t iosram_log_mutex; 107 int iosram_log_level = 1; 108 int iosram_log_print = 0; /* print log when recorded */ 109 uint32_t iosram_logseq; 110 iosram_log_t iosram_logbuf[IOSRAM_MAXLOG]; 111 static void iosram_print_log(int cnt); /* forward declaration */ 112 #endif /* IOSRAM_LOG */ 113 114 115 /* driver entry point fn definitions */ 116 static int iosram_open(dev_t *, int, int, cred_t *); 117 static int iosram_close(dev_t, int, int, cred_t *); 118 static int iosram_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 119 120 /* configuration entry point fn definitions */ 121 static int iosram_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 122 static int iosram_attach(dev_info_t *, ddi_attach_cmd_t); 123 static int iosram_detach(dev_info_t *, ddi_detach_cmd_t); 124 125 126 /* forward declaractions */ 127 static iosram_chunk_t *iosram_find_chunk(uint32_t key); 128 static void iosram_set_master(struct iosramsoft *softp); 129 static int iosram_is_chosen(struct iosramsoft *softp); 130 static int iosram_tunnel_capable(struct iosramsoft *softp); 131 static int iosram_read_toc(struct iosramsoft *softp); 132 static void iosram_init_hashtab(void); 133 static void iosram_update_addrs(struct iosramsoft *softp); 134 135 static int iosram_setup_map(struct iosramsoft *softp); 136 static void iosram_remove_map(struct iosramsoft *softp); 137 static int iosram_add_intr(iosramsoft_t *); 138 static int iosram_remove_intr(iosramsoft_t *); 139 140 static void iosram_add_instance(struct iosramsoft *softp); 141 static void iosram_remove_instance(int instance); 142 static int iosram_switch_tunnel(iosramsoft_t *softp); 143 static void iosram_abort_tswitch(); 144 145 #if defined(DEBUG) 146 /* forward declaractions for debugging */ 147 static int iosram_get_keys(iosram_toc_entry_t *buf, uint32_t *len); 148 static void iosram_print_cback(); 149 static void iosram_print_state(int); 150 static void iosram_print_flags(); 151 #endif 152 153 154 155 /* 156 * cb_ops 157 */ 158 static struct cb_ops iosram_cb_ops = { 159 iosram_open, /* cb_open */ 160 iosram_close, /* cb_close */ 161 nodev, /* cb_strategy */ 162 nodev, /* cb_print */ 163 nodev, /* cb_dump */ 164 nodev, /* cb_read */ 165 nodev, /* cb_write */ 166 iosram_ioctl, /* cb_ioctl */ 167 nodev, /* cb_devmap */ 168 nodev, /* cb_mmap */ 169 nodev, /* cb_segmap */ 170 nochpoll, /* cb_chpoll */ 171 ddi_prop_op, /* cb_prop_op */ 172 NULL, /* cb_stream */ 173 (int)(D_NEW | D_MP | D_HOTPLUG) /* cb_flag */ 174 }; 175 176 /* 177 * Declare ops vectors for auto configuration. 178 */ 179 struct dev_ops iosram_ops = { 180 DEVO_REV, /* devo_rev */ 181 0, /* devo_refcnt */ 182 iosram_getinfo, /* devo_getinfo */ 183 nulldev, /* devo_identify */ 184 nulldev, /* devo_probe */ 185 iosram_attach, /* devo_attach */ 186 iosram_detach, /* devo_detach */ 187 nodev, /* devo_reset */ 188 &iosram_cb_ops, /* devo_cb_ops */ 189 (struct bus_ops *)NULL, /* devo_bus_ops */ 190 nulldev, /* devo_power */ 191 ddi_quiesce_not_supported, /* devo_quiesce */ 192 }; 193 194 /* 195 * Loadable module support. 196 */ 197 extern struct mod_ops mod_driverops; 198 199 static struct modldrv iosrammodldrv = { 200 &mod_driverops, /* type of module - driver */ 201 "IOSRAM Leaf driver", 202 &iosram_ops, 203 }; 204 205 static struct modlinkage iosrammodlinkage = { 206 MODREV_1, 207 &iosrammodldrv, 208 NULL 209 }; 210 211 212 int 213 _init(void) 214 { 215 int error; 216 int i; 217 218 mutex_init(&iosram_mutex, NULL, MUTEX_DRIVER, (void *)NULL); 219 cv_init(&iosram_tswitch_wait, NULL, CV_DRIVER, NULL); 220 cv_init(&iosram_rw_wait, NULL, CV_DRIVER, NULL); 221 #if defined(IOSRAM_LOG) 222 mutex_init(&iosram_log_mutex, NULL, MUTEX_DRIVER, (void *)NULL); 223 #endif 224 225 DPRINTF(1, ("_init:IOSRAM\n")); 226 227 for (i = 0; i < IOSRAM_HASHSZ; i++) { 228 iosram_hashtab[i] = NULL; 229 } 230 231 if ((error = ddi_soft_state_init(&iosramsoft_statep, 232 sizeof (struct iosramsoft), 1)) != 0) { 233 goto failed; 234 } 235 if ((error = mod_install(&iosrammodlinkage)) != 0) { 236 ddi_soft_state_fini(&iosramsoft_statep); 237 goto failed; 238 } 239 240 IOSRAMLOG(0, "_init:IOSRAM ... error:%d statep:%p\n", 241 error, iosramsoft_statep, NULL, NULL); 242 243 return (error); 244 245 failed: 246 cv_destroy(&iosram_tswitch_wait); 247 cv_destroy(&iosram_rw_wait); 248 mutex_destroy(&iosram_mutex); 249 #if defined(IOSRAM_LOG) 250 mutex_destroy(&iosram_log_mutex); 251 #endif 252 IOSRAMLOG(0, "_init:IOSRAM ... error:%d statep:%p\n", 253 error, iosramsoft_statep, NULL, NULL); 254 255 return (error); 256 } 257 258 259 int 260 _fini(void) 261 { 262 #ifndef DEBUG 263 return (EBUSY); 264 #else /* !DEBUG */ 265 int error; 266 267 if ((error = mod_remove(&iosrammodlinkage)) == 0) { 268 ddi_soft_state_fini(&iosramsoft_statep); 269 270 cv_destroy(&iosram_tswitch_wait); 271 cv_destroy(&iosram_rw_wait); 272 mutex_destroy(&iosram_mutex); 273 #if defined(IOSRAM_LOG) 274 mutex_destroy(&iosram_log_mutex); 275 #endif 276 } 277 DPRINTF(1, ("_fini:IOSRAM error:%d\n", error)); 278 279 return (error); 280 #endif /* !DEBUG */ 281 } 282 283 284 int 285 _info(struct modinfo *modinfop) 286 { 287 return (mod_info(&iosrammodlinkage, modinfop)); 288 } 289 290 291 static int 292 iosram_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 293 { 294 int instance; 295 int propval; 296 int length; 297 char name[32]; 298 struct iosramsoft *softp; 299 300 instance = ddi_get_instance(dip); 301 302 DPRINTF(1, ("iosram(%d): attach dip:%p\n", instance)); 303 304 IOSRAMLOG(1, "ATTACH: dip:%p instance %d ... start\n", 305 dip, instance, NULL, NULL); 306 switch (cmd) { 307 case DDI_ATTACH: 308 break; 309 case DDI_RESUME: 310 if (!(softp = ddi_get_soft_state(iosramsoft_statep, 311 instance))) { 312 return (DDI_FAILURE); 313 } 314 mutex_enter(&iosram_mutex); 315 mutex_enter(&softp->intr_mutex); 316 if (!softp->suspended) { 317 mutex_exit(&softp->intr_mutex); 318 mutex_exit(&iosram_mutex); 319 return (DDI_FAILURE); 320 } 321 softp->suspended = 0; 322 323 /* 324 * enable SBBC interrupts if SBBC is mapped in 325 * restore the value saved during detach 326 */ 327 if (softp->sbbc_region) { 328 ddi_put32(softp->sbbc_handle, 329 &(softp->sbbc_region->int_enable.reg), 330 softp->int_enable_sav); 331 } 332 333 /* 334 * Trigger soft interrupt handler to process any pending 335 * interrupts. 336 */ 337 if (softp->intr_pending && !softp->intr_busy && 338 (softp->softintr_id != NULL)) { 339 ddi_trigger_softintr(softp->softintr_id); 340 } 341 342 mutex_exit(&softp->intr_mutex); 343 mutex_exit(&iosram_mutex); 344 345 return (DDI_SUCCESS); 346 347 default: 348 return (DDI_FAILURE); 349 } 350 351 if (ddi_soft_state_zalloc(iosramsoft_statep, instance) != 0) { 352 return (DDI_FAILURE); 353 } 354 355 if ((softp = ddi_get_soft_state(iosramsoft_statep, instance)) == NULL) { 356 return (DDI_FAILURE); 357 } 358 softp->dip = dip; 359 softp->instance = instance; 360 softp->sbbc_region = NULL; 361 362 /* 363 * If this instance is not tunnel capable, we don't attach it. 364 */ 365 if (iosram_tunnel_capable(softp) == 0) { 366 DPRINTF(1, ("iosram(%d): not tunnel_capable\n", instance)); 367 IOSRAMLOG(1, "ATTACH(%d): not tunnel_capable\n", instance, NULL, 368 NULL, NULL); 369 goto attach_fail; 370 } 371 372 /* 373 * Need to create an "interrupt-priorities" property to define the PIL 374 * to be used with the interrupt service routine. 375 */ 376 if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 377 "interrupt-priorities", &length) == DDI_PROP_NOT_FOUND) { 378 DPRINTF(1, ("iosram(%d): creating interrupt priority property", 379 instance)); 380 propval = IOSRAM_PIL; 381 if (ddi_prop_create(DDI_DEV_T_NONE, dip, 0, 382 "interrupt-priorities", (caddr_t)&propval, sizeof (propval)) 383 != DDI_PROP_SUCCESS) { 384 cmn_err(CE_WARN, 385 "iosram_attach: failed to create property"); 386 goto attach_fail; 387 } 388 } 389 390 /* 391 * Get interrupts cookies and initialize per-instance mutexes 392 */ 393 if (ddi_get_iblock_cookie(softp->dip, 0, &softp->real_iblk) 394 != DDI_SUCCESS) { 395 IOSRAMLOG(1, "ATTACH(%d): cannot get soft intr cookie\n", 396 instance, NULL, NULL, NULL); 397 goto attach_fail; 398 } 399 mutex_init(&softp->intr_mutex, NULL, MUTEX_DRIVER, 400 (void *)softp->real_iblk); 401 402 /* 403 * Add this instance to the iosram_instances list so that it can be used 404 * for tunnel in future. 405 */ 406 mutex_enter(&iosram_mutex); 407 softp->state = IOSRAM_STATE_INIT; 408 iosram_add_instance(softp); 409 410 /* 411 * If this is the chosen IOSRAM and there is no master IOSRAM yet, then 412 * let's set this instance as the master. 413 */ 414 if (iosram_master == NULL && iosram_is_chosen(softp)) { 415 iosram_switch_tunnel(softp); 416 417 /* 418 * XXX Do we need to panic if unable to setup master IOSRAM? 419 */ 420 if (iosram_master == NULL) { 421 cmn_err(CE_WARN, 422 "iosram(%d): can't setup master tunnel\n", 423 instance); 424 softp->state = 0; 425 iosram_remove_instance(softp->instance); 426 mutex_exit(&iosram_mutex); 427 mutex_destroy(&softp->intr_mutex); 428 goto attach_fail; 429 } 430 } 431 432 mutex_exit(&iosram_mutex); 433 434 /* 435 * Create minor node 436 */ 437 (void) sprintf(name, "iosram%d", instance); 438 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL, NULL) == 439 DDI_FAILURE) { 440 /* 441 * Minor node seems to be needed only for debugging purposes. 442 * Therefore, there is no need to fail this attach request. 443 * Simply print a message out. 444 */ 445 cmn_err(CE_NOTE, "!iosram(%d): can't create minor node\n", 446 instance); 447 } 448 ddi_report_dev(dip); 449 450 DPRINTF(1, ("iosram_attach(%d): success.\n", instance)); 451 IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... success softp:%p\n", 452 dip, instance, softp, NULL); 453 454 return (DDI_SUCCESS); 455 456 attach_fail: 457 DPRINTF(1, ("iosram_attach(%d):failed.\n", instance)); 458 IOSRAMLOG(1, "ATTACH: dip:%p instance:%d ... failed.\n", 459 dip, instance, NULL, NULL); 460 461 ddi_soft_state_free(iosramsoft_statep, instance); 462 return (DDI_FAILURE); 463 } 464 465 466 static int 467 iosram_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 468 { 469 int instance; 470 struct iosramsoft *softp; 471 472 instance = ddi_get_instance(dip); 473 if (!(softp = ddi_get_soft_state(iosramsoft_statep, instance))) { 474 return (DDI_FAILURE); 475 } 476 477 IOSRAMLOG(1, "DETACH: dip:%p instance %d softp:%p\n", 478 dip, instance, softp, NULL); 479 480 switch (cmd) { 481 case DDI_DETACH: 482 break; 483 case DDI_SUSPEND: 484 mutex_enter(&iosram_mutex); 485 mutex_enter(&softp->intr_mutex); 486 if (softp->suspended) { 487 mutex_exit(&softp->intr_mutex); 488 mutex_exit(&iosram_mutex); 489 return (DDI_FAILURE); 490 } 491 softp->suspended = 1; 492 /* 493 * Disable SBBC interrupts if SBBC is mapped in 494 */ 495 if (softp->sbbc_region) { 496 /* save current interrupt enable register */ 497 softp->int_enable_sav = ddi_get32(softp->sbbc_handle, 498 &(softp->sbbc_region->int_enable.reg)); 499 ddi_put32(softp->sbbc_handle, 500 &(softp->sbbc_region->int_enable.reg), 0x0); 501 } 502 mutex_exit(&softp->intr_mutex); 503 mutex_exit(&iosram_mutex); 504 return (DDI_SUCCESS); 505 506 default: 507 return (DDI_FAILURE); 508 } 509 510 511 /* 512 * Indicate that this instance is being detached so that this instance 513 * does not become a target for tunnel switch in future. 514 */ 515 mutex_enter(&iosram_mutex); 516 softp->state |= IOSRAM_STATE_DETACH; 517 518 /* 519 * If this instance is currently the master or the target of the tunnel 520 * switch, then we need to wait and switch tunnel, if necessary. 521 */ 522 if (iosram_master == softp || (softp->state & IOSRAM_STATE_TSWITCH)) { 523 mutex_exit(&iosram_mutex); 524 iosram_switchfrom(instance); 525 mutex_enter(&iosram_mutex); 526 } 527 528 /* 529 * If the tunnel switch is in progress and we are the master or target 530 * of tunnel relocation, then we can't detach this instance right now. 531 */ 532 if (softp->state & IOSRAM_STATE_TSWITCH) { 533 softp->state &= ~IOSRAM_STATE_DETACH; 534 mutex_exit(&iosram_mutex); 535 return (DDI_FAILURE); 536 } 537 538 /* 539 * We can't allow master IOSRAM to be detached as we won't be able to 540 * communicate otherwise. 541 */ 542 if (iosram_master == softp) { 543 softp->state &= ~IOSRAM_STATE_DETACH; 544 mutex_exit(&iosram_mutex); 545 return (DDI_FAILURE); 546 } 547 548 /* 549 * Now remove our instance from the iosram_instances list. 550 */ 551 iosram_remove_instance(instance); 552 mutex_exit(&iosram_mutex); 553 554 /* 555 * Instances should only ever be mapped if they are the master and/or 556 * participating in a tunnel switch. Neither should be the case here. 557 */ 558 ASSERT((softp->state & IOSRAM_STATE_MAPPED) == 0); 559 560 /* 561 * Destroy per-instance mutexes 562 */ 563 mutex_destroy(&softp->intr_mutex); 564 565 ddi_remove_minor_node(dip, NULL); 566 567 /* 568 * Finally remove our soft state structure 569 */ 570 ddi_soft_state_free(iosramsoft_statep, instance); 571 572 return (DDI_SUCCESS); 573 } 574 575 576 /* ARGSUSED0 */ 577 static int 578 iosram_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 579 void **result) 580 { 581 dev_t dev = (dev_t)arg; 582 struct iosramsoft *softp; 583 int instance, ret; 584 585 instance = getminor(dev); 586 587 IOSRAMLOG(2, "GETINFO: dip:%x instance %d dev:%x infocmd:%x\n", 588 dip, instance, dev, infocmd); 589 590 switch (infocmd) { 591 case DDI_INFO_DEVT2DEVINFO: 592 softp = ddi_get_soft_state(iosramsoft_statep, instance); 593 if (softp == NULL) { 594 *result = NULL; 595 ret = DDI_FAILURE; 596 } else { 597 *result = softp->dip; 598 ret = DDI_SUCCESS; 599 } 600 break; 601 case DDI_INFO_DEVT2INSTANCE: 602 *result = (void *)(uintptr_t)instance; 603 ret = DDI_SUCCESS; 604 break; 605 default: 606 ret = DDI_FAILURE; 607 break; 608 } 609 610 return (ret); 611 } 612 613 614 /*ARGSUSED1*/ 615 static int 616 iosram_open(dev_t *dev, int flag, int otype, cred_t *credp) 617 { 618 struct iosramsoft *softp; 619 int instance; 620 621 instance = getminor(*dev); 622 softp = ddi_get_soft_state(iosramsoft_statep, instance); 623 624 if (softp == NULL) { 625 return (ENXIO); 626 } 627 628 IOSRAMLOG(1, "OPEN: dev:%p otype:%x ... instance:%d softp:%p\n", 629 *dev, otype, softp->instance, softp); 630 631 return (0); 632 } 633 634 635 /*ARGSUSED1*/ 636 static int 637 iosram_close(dev_t dev, int flag, int otype, cred_t *credp) 638 { 639 struct iosramsoft *softp; 640 int instance; 641 642 instance = getminor(dev); 643 softp = ddi_get_soft_state(iosramsoft_statep, instance); 644 if (softp == NULL) { 645 return (ENXIO); 646 } 647 648 IOSRAMLOG(1, "CLOSE: dev:%p otype:%x ... instance:%d softp:%p\n", 649 dev, otype, softp->instance, softp); 650 651 return (0); 652 } 653 654 655 int 656 iosram_rd(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr) 657 { 658 iosram_chunk_t *chunkp; 659 uint32_t chunk_len; 660 uint8_t *iosramp; 661 ddi_acc_handle_t handle; 662 int boff; 663 union { 664 uchar_t cbuf[UINT32SZ]; 665 uint32_t data; 666 } word; 667 668 int error = 0; 669 uint8_t *buf = (uint8_t *)dptr; 670 671 /* 672 * We try to read from the IOSRAM using double word or word access 673 * provided both "off" and "buf" are (or can be) double word or word 674 * aligned. Othewise, we try to align the "off" to a word boundary and 675 * then try to read data from the IOSRAM using word access, but store it 676 * into buf buffer using byte access. 677 * 678 * If the leading/trailing portion of the IOSRAM data is not word 679 * aligned, it will always be copied using byte access. 680 */ 681 IOSRAMLOG(1, "RD: key: 0x%x off:%x len:%x buf:%p\n", 682 key, off, len, buf); 683 684 /* 685 * Acquire lock and look for the requested chunk. If it exists, make 686 * sure the requested read is within the chunk's bounds and no tunnel 687 * switch is active. 688 */ 689 mutex_enter(&iosram_mutex); 690 chunkp = iosram_find_chunk(key); 691 chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0; 692 693 if (iosram_master == NULL) { 694 error = EIO; 695 } else if (chunkp == NULL) { 696 error = EINVAL; 697 } else if ((off >= chunk_len) || (len > chunk_len) || 698 ((off + len) > chunk_len)) { 699 error = EMSGSIZE; 700 } else if (iosram_tswitch_active) { 701 error = EAGAIN; 702 } 703 704 if (error) { 705 mutex_exit(&iosram_mutex); 706 return (error); 707 } 708 709 /* 710 * Bump reference count to indicate #thread accessing IOSRAM and release 711 * the lock. 712 */ 713 iosram_rw_active++; 714 #if defined(DEBUG) 715 if (iosram_rw_active > iosram_rw_active_max) { 716 iosram_rw_active_max = iosram_rw_active; 717 } 718 #endif 719 mutex_exit(&iosram_mutex); 720 721 IOSRAM_STAT(read); 722 IOSRAM_STAT_ADD(bread, len); 723 724 /* Get starting address and map handle */ 725 iosramp = chunkp->basep + off; 726 handle = iosram_handle; 727 728 /* 729 * Align the off to word boundary and then try reading/writing data 730 * using double word or word access. 731 */ 732 if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) { 733 int cnt = UINT32SZ - boff; 734 735 if (cnt > len) { 736 cnt = len; 737 } 738 IOSRAMLOG(2, 739 "RD: align rep_get8(buf:%p sramp:%p cnt:%x) len:%x\n", 740 buf, iosramp, cnt, len); 741 ddi_rep_get8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR); 742 buf += cnt; 743 iosramp += cnt; 744 len -= cnt; 745 } 746 747 if ((len >= UINT64SZ) && 748 ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) { 749 /* 750 * Both source and destination are double word aligned 751 */ 752 int cnt = len/UINT64SZ; 753 754 IOSRAMLOG(2, 755 "RD: rep_get64(buf:%p sramp:%p cnt:%x) len:%x\n", 756 buf, iosramp, cnt, len); 757 ddi_rep_get64(handle, (uint64_t *)buf, (uint64_t *)iosramp, 758 cnt, DDI_DEV_AUTOINCR); 759 iosramp += cnt * UINT64SZ; 760 buf += cnt * UINT64SZ; 761 len -= cnt * UINT64SZ; 762 763 /* 764 * read remaining data using word and byte access 765 */ 766 if (len >= UINT32SZ) { 767 IOSRAMLOG(2, 768 "RD: get32(buf:%p sramp:%p) len:%x\n", 769 buf, iosramp, len, NULL); 770 *(uint32_t *)buf = ddi_get32(handle, 771 (uint32_t *)iosramp); 772 iosramp += UINT32SZ; 773 buf += UINT32SZ; 774 len -= UINT32SZ; 775 } 776 777 if (len != 0) { 778 ddi_rep_get8(handle, buf, iosramp, len, 779 DDI_DEV_AUTOINCR); 780 } 781 } else if ((len >= UINT32SZ) && 782 ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) { 783 /* 784 * Both source and destination are word aligned 785 */ 786 int cnt = len/UINT32SZ; 787 788 IOSRAMLOG(2, 789 "RD: rep_get32(buf:%p sramp:%p cnt:%x) len:%x\n", 790 buf, iosramp, cnt, len); 791 ddi_rep_get32(handle, (uint32_t *)buf, (uint32_t *)iosramp, 792 cnt, DDI_DEV_AUTOINCR); 793 iosramp += cnt * UINT32SZ; 794 buf += cnt * UINT32SZ; 795 len -= cnt * UINT32SZ; 796 797 /* 798 * copy the remainder using byte access 799 */ 800 if (len != 0) { 801 ddi_rep_get8(handle, buf, iosramp, len, 802 DDI_DEV_AUTOINCR); 803 } 804 } else if (len != 0) { 805 /* 806 * We know that the "off" (i.e. iosramp) is at least word 807 * aligned. We need to read IOSRAM word at a time and copy it 808 * byte at a time. 809 */ 810 ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0); 811 812 IOSRAMLOG(2, 813 "RD: unaligned get32(buf:%p sramp:%p) len:%x\n", 814 buf, iosramp, len, NULL); 815 for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) { 816 word.data = ddi_get32(handle, (uint32_t *)iosramp); 817 *buf++ = word.cbuf[0]; 818 *buf++ = word.cbuf[1]; 819 *buf++ = word.cbuf[2]; 820 *buf++ = word.cbuf[3]; 821 } 822 823 /* 824 * copy the remaining data using byte access 825 */ 826 if (len != 0) { 827 ddi_rep_get8(handle, buf, iosramp, len, 828 DDI_DEV_AUTOINCR); 829 } 830 } 831 832 /* 833 * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and any 834 * threads are waiting for r/w activity to complete, wake them up. 835 */ 836 mutex_enter(&iosram_mutex); 837 ASSERT(iosram_rw_active > 0); 838 839 if ((--iosram_rw_active == 0) && iosram_rw_wakeup) { 840 iosram_rw_wakeup = 0; 841 cv_broadcast(&iosram_rw_wait); 842 } 843 mutex_exit(&iosram_mutex); 844 845 return (error); 846 } 847 848 849 /* 850 * _iosram_write(key, off, len, dptr, force) 851 * Internal common routine to write to the IOSRAM. 852 */ 853 static int 854 _iosram_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr, int force) 855 { 856 iosram_chunk_t *chunkp; 857 uint32_t chunk_len; 858 uint8_t *iosramp; 859 ddi_acc_handle_t handle; 860 int boff; 861 union { 862 uint8_t cbuf[UINT32SZ]; 863 uint32_t data; 864 } word; 865 866 int error = 0; 867 uint8_t *buf = (uint8_t *)dptr; 868 869 /* 870 * We try to write to the IOSRAM using double word or word access 871 * provided both "off" and "buf" are (or can be) double word or word 872 * aligned. Othewise, we try to align the "off" to a word boundary and 873 * then try to write data to the IOSRAM using word access, but read data 874 * from the buf buffer using byte access. 875 * 876 * If the leading/trailing portion of the IOSRAM data is not word 877 * aligned, it will always be written using byte access. 878 */ 879 IOSRAMLOG(1, "WR: key: 0x%x off:%x len:%x buf:%p\n", 880 key, off, len, buf); 881 882 /* 883 * Acquire lock and look for the requested chunk. If it exists, make 884 * sure the requested write is within the chunk's bounds and no tunnel 885 * switch is active. 886 */ 887 mutex_enter(&iosram_mutex); 888 chunkp = iosram_find_chunk(key); 889 chunk_len = (chunkp != NULL) ? chunkp->toc_data.len : 0; 890 891 if (iosram_master == NULL) { 892 error = EIO; 893 } else if (chunkp == NULL) { 894 error = EINVAL; 895 } else if ((off >= chunk_len) || (len > chunk_len) || 896 ((off+len) > chunk_len)) { 897 error = EMSGSIZE; 898 } else if (iosram_tswitch_active && !force) { 899 error = EAGAIN; 900 } 901 902 if (error) { 903 mutex_exit(&iosram_mutex); 904 return (error); 905 } 906 907 /* 908 * If this is a forced write and there's a tunnel switch in progress, 909 * abort the switch. 910 */ 911 if (iosram_tswitch_active && force) { 912 cmn_err(CE_NOTE, "!iosram: Aborting tswitch on force_write"); 913 iosram_abort_tswitch(); 914 } 915 916 /* 917 * Bump reference count to indicate #thread accessing IOSRAM 918 * and release the lock. 919 */ 920 iosram_rw_active++; 921 #if defined(DEBUG) 922 if (iosram_rw_active > iosram_rw_active_max) { 923 iosram_rw_active_max = iosram_rw_active; 924 } 925 #endif 926 mutex_exit(&iosram_mutex); 927 928 929 IOSRAM_STAT(write); 930 IOSRAM_STAT_ADD(bwrite, len); 931 932 /* Get starting address and map handle */ 933 iosramp = chunkp->basep + off; 934 handle = iosram_handle; 935 936 /* 937 * Align the off to word boundary and then try reading/writing 938 * data using double word or word access. 939 */ 940 if ((boff = ((uintptr_t)iosramp & (UINT32SZ - 1))) != 0) { 941 int cnt = UINT32SZ - boff; 942 943 if (cnt > len) { 944 cnt = len; 945 } 946 IOSRAMLOG(2, 947 "WR: align rep_put8(buf:%p sramp:%p cnt:%x) len:%x\n", 948 buf, iosramp, cnt, len); 949 ddi_rep_put8(handle, buf, iosramp, cnt, DDI_DEV_AUTOINCR); 950 buf += cnt; 951 iosramp += cnt; 952 len -= cnt; 953 } 954 955 if ((len >= UINT64SZ) && 956 ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT64SZ - 1)) == 0)) { 957 /* 958 * Both source and destination are double word aligned 959 */ 960 int cnt = len/UINT64SZ; 961 962 IOSRAMLOG(2, 963 "WR: rep_put64(buf:%p sramp:%p cnt:%x) len:%x\n", 964 buf, iosramp, cnt, len); 965 ddi_rep_put64(handle, (uint64_t *)buf, (uint64_t *)iosramp, 966 cnt, DDI_DEV_AUTOINCR); 967 iosramp += cnt * UINT64SZ; 968 buf += cnt * UINT64SZ; 969 len -= cnt * UINT64SZ; 970 971 /* 972 * Copy the remaining data using word & byte access 973 */ 974 if (len >= UINT32SZ) { 975 IOSRAMLOG(2, 976 "WR: put32(buf:%p sramp:%p) len:%x\n", buf, iosramp, 977 len, NULL); 978 ddi_put32(handle, (uint32_t *)iosramp, 979 *(uint32_t *)buf); 980 iosramp += UINT32SZ; 981 buf += UINT32SZ; 982 len -= UINT32SZ; 983 } 984 985 if (len != 0) { 986 ddi_rep_put8(handle, buf, iosramp, len, 987 DDI_DEV_AUTOINCR); 988 } 989 } else if ((len >= UINT32SZ) && 990 ((((uintptr_t)iosramp | (uintptr_t)buf) & (UINT32SZ - 1)) == 0)) { 991 /* 992 * Both source and destination are word aligned 993 */ 994 int cnt = len/UINT32SZ; 995 996 IOSRAMLOG(2, 997 "WR: rep_put32(buf:%p sramp:%p cnt:%x) len:%x\n", 998 buf, iosramp, cnt, len); 999 ddi_rep_put32(handle, (uint32_t *)buf, (uint32_t *)iosramp, 1000 cnt, DDI_DEV_AUTOINCR); 1001 iosramp += cnt * UINT32SZ; 1002 buf += cnt * UINT32SZ; 1003 len -= cnt * UINT32SZ; 1004 1005 /* 1006 * copy the remainder using byte access 1007 */ 1008 if (len != 0) { 1009 ddi_rep_put8(handle, buf, iosramp, len, 1010 DDI_DEV_AUTOINCR); 1011 } 1012 } else if (len != 0) { 1013 /* 1014 * We know that the "off" is at least word aligned. We 1015 * need to read data from buf buffer byte at a time, and 1016 * write it to the IOSRAM word at a time. 1017 */ 1018 1019 ASSERT(((uintptr_t)iosramp & (UINT32SZ - 1)) == 0); 1020 1021 IOSRAMLOG(2, 1022 "WR: unaligned put32(buf:%p sramp:%p) len:%x\n", 1023 buf, iosramp, len, NULL); 1024 for (; len >= UINT32SZ; len -= UINT32SZ, iosramp += UINT32SZ) { 1025 word.cbuf[0] = *buf++; 1026 word.cbuf[1] = *buf++; 1027 word.cbuf[2] = *buf++; 1028 word.cbuf[3] = *buf++; 1029 ddi_put32(handle, (uint32_t *)iosramp, word.data); 1030 } 1031 1032 /* 1033 * copy the remaining data using byte access 1034 */ 1035 if (len != 0) { 1036 ddi_rep_put8(handle, buf, iosramp, 1037 len, DDI_DEV_AUTOINCR); 1038 } 1039 } 1040 1041 /* 1042 * Reacquire mutex lock, decrement refcnt and if refcnt is 0 and 1043 * any threads are waiting for r/w activity to complete, wake them up. 1044 */ 1045 mutex_enter(&iosram_mutex); 1046 ASSERT(iosram_rw_active > 0); 1047 1048 if ((--iosram_rw_active == 0) && iosram_rw_wakeup) { 1049 iosram_rw_wakeup = 0; 1050 cv_broadcast(&iosram_rw_wait); 1051 } 1052 mutex_exit(&iosram_mutex); 1053 1054 return (error); 1055 } 1056 1057 1058 int 1059 iosram_force_write(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr) 1060 { 1061 return (_iosram_write(key, off, len, dptr, 1 /* force */)); 1062 } 1063 1064 1065 int 1066 iosram_wr(uint32_t key, uint32_t off, uint32_t len, caddr_t dptr) 1067 { 1068 return (_iosram_write(key, off, len, dptr, 0)); 1069 } 1070 1071 1072 /* 1073 * iosram_register(key, handler, arg) 1074 * Register a handler and an arg for the specified chunk. This handler 1075 * will be invoked when an interrupt is received from the other side and 1076 * the int_pending flag for the corresponding key is marked 1077 * IOSRAM_INT_TO_DOM. 1078 */ 1079 /* ARGSUSED */ 1080 int 1081 iosram_register(uint32_t key, void (*handler)(), void *arg) 1082 { 1083 struct iosram_chunk *chunkp; 1084 int error = 0; 1085 1086 /* 1087 * Acquire lock and look for the requested chunk. If it exists, and no 1088 * other callback is registered, proceed with the registration. 1089 */ 1090 mutex_enter(&iosram_mutex); 1091 chunkp = iosram_find_chunk(key); 1092 1093 if (iosram_master == NULL) { 1094 error = EIO; 1095 } else if (chunkp == NULL) { 1096 error = EINVAL; 1097 } else if (chunkp->cback.handler != NULL) { 1098 error = EBUSY; 1099 } else { 1100 chunkp->cback.busy = 0; 1101 chunkp->cback.unregister = 0; 1102 chunkp->cback.handler = handler; 1103 chunkp->cback.arg = arg; 1104 } 1105 mutex_exit(&iosram_mutex); 1106 1107 IOSRAMLOG(1, "REG: key: 0x%x hdlr:%p arg:%p error:%d\n", 1108 key, handler, arg, error); 1109 1110 return (error); 1111 } 1112 1113 1114 /* 1115 * iosram_unregister() 1116 * Unregister handler associated with the specified chunk. 1117 */ 1118 int 1119 iosram_unregister(uint32_t key) 1120 { 1121 struct iosram_chunk *chunkp; 1122 int error = 0; 1123 1124 /* 1125 * Acquire lock and look for the requested chunk. If it exists and has 1126 * a callback registered, unregister it. 1127 */ 1128 mutex_enter(&iosram_mutex); 1129 chunkp = iosram_find_chunk(key); 1130 1131 if (iosram_master == NULL) { 1132 error = EIO; 1133 } else if (chunkp == NULL) { 1134 error = EINVAL; 1135 } else if (chunkp->cback.busy) { 1136 /* 1137 * If the handler is already busy (being invoked), then we flag 1138 * it so it will be unregistered after the invocation completes. 1139 */ 1140 DPRINTF(1, ("IOSRAM(%d): unregister: delaying unreg k:0x%08x\n", 1141 iosram_master->instance, key)); 1142 chunkp->cback.unregister = 1; 1143 } else if (chunkp->cback.handler != NULL) { 1144 chunkp->cback.handler = NULL; 1145 chunkp->cback.arg = NULL; 1146 } 1147 mutex_exit(&iosram_mutex); 1148 1149 IOSRAMLOG(1, "UNREG: key:%x error:%d\n", key, error, NULL, NULL); 1150 return (error); 1151 } 1152 1153 1154 /* 1155 * iosram_get_flag(): 1156 * Get data_valid and/or int_pending flags associated with the 1157 * specified key. 1158 */ 1159 int 1160 iosram_get_flag(uint32_t key, uint8_t *data_valid, uint8_t *int_pending) 1161 { 1162 iosram_chunk_t *chunkp; 1163 iosram_flags_t flags; 1164 int error = 0; 1165 1166 /* 1167 * Acquire lock and look for the requested chunk. If it exists, and no 1168 * tunnel switch is in progress, read the chunk's flags. 1169 */ 1170 mutex_enter(&iosram_mutex); 1171 chunkp = iosram_find_chunk(key); 1172 1173 if (iosram_master == NULL) { 1174 error = EIO; 1175 } else if (chunkp == NULL) { 1176 error = EINVAL; 1177 } else if (iosram_tswitch_active) { 1178 error = EAGAIN; 1179 } else { 1180 IOSRAM_STAT(getflag); 1181 1182 /* 1183 * Read the flags 1184 */ 1185 ddi_rep_get8(iosram_handle, (uint8_t *)&flags, 1186 (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t), 1187 DDI_DEV_AUTOINCR); 1188 1189 /* 1190 * Get each flag value that the caller is interested in. 1191 */ 1192 if (data_valid != NULL) { 1193 *data_valid = flags.data_valid; 1194 } 1195 1196 if (int_pending != NULL) { 1197 *int_pending = flags.int_pending; 1198 } 1199 } 1200 mutex_exit(&iosram_mutex); 1201 1202 IOSRAMLOG(1, "GetFlag key:%x data_valid:%x int_pending:%x error:%d\n", 1203 key, flags.data_valid, flags.int_pending, error); 1204 return (error); 1205 } 1206 1207 1208 /* 1209 * iosram_set_flag(): 1210 * Set data_valid and int_pending flags associated with the specified key. 1211 */ 1212 int 1213 iosram_set_flag(uint32_t key, uint8_t data_valid, uint8_t int_pending) 1214 { 1215 iosram_chunk_t *chunkp; 1216 iosram_flags_t flags; 1217 int error = 0; 1218 1219 /* 1220 * Acquire lock and look for the requested chunk. If it exists, and no 1221 * tunnel switch is in progress, write the chunk's flags. 1222 */ 1223 mutex_enter(&iosram_mutex); 1224 chunkp = iosram_find_chunk(key); 1225 1226 if (iosram_master == NULL) { 1227 error = EIO; 1228 } else if ((chunkp == NULL) || 1229 ((data_valid != IOSRAM_DATA_INVALID) && 1230 (data_valid != IOSRAM_DATA_VALID)) || 1231 ((int_pending != IOSRAM_INT_NONE) && 1232 (int_pending != IOSRAM_INT_TO_SSC) && 1233 (int_pending != IOSRAM_INT_TO_DOM))) { 1234 error = EINVAL; 1235 } else if (iosram_tswitch_active) { 1236 error = EAGAIN; 1237 } else { 1238 IOSRAM_STAT(setflag); 1239 flags.data_valid = data_valid; 1240 flags.int_pending = int_pending; 1241 ddi_rep_put8(iosram_handle, (uint8_t *)&flags, 1242 (uint8_t *)(chunkp->flagsp), sizeof (iosram_flags_t), 1243 DDI_DEV_AUTOINCR); 1244 } 1245 mutex_exit(&iosram_mutex); 1246 1247 IOSRAMLOG(1, "SetFlag key:%x data_valid:%x int_pending:%x error:%d\n", 1248 key, flags.data_valid, flags.int_pending, error); 1249 return (error); 1250 } 1251 1252 1253 /* 1254 * iosram_ctrl() 1255 * This function provides access to a variety of services not available 1256 * through the basic API. 1257 */ 1258 int 1259 iosram_ctrl(uint32_t key, uint32_t cmd, void *arg) 1260 { 1261 struct iosram_chunk *chunkp; 1262 int error = 0; 1263 1264 /* 1265 * Acquire lock and do some argument sanity checking. 1266 */ 1267 mutex_enter(&iosram_mutex); 1268 chunkp = iosram_find_chunk(key); 1269 1270 if (iosram_master == NULL) { 1271 error = EIO; 1272 } else if (chunkp == NULL) { 1273 error = EINVAL; 1274 } 1275 1276 if (error != 0) { 1277 mutex_exit(&iosram_mutex); 1278 return (error); 1279 } 1280 1281 /* 1282 * Arguments seem okay so far, so process the command. 1283 */ 1284 switch (cmd) { 1285 case IOSRAM_CMD_CHUNKLEN: 1286 /* 1287 * Return the length of the chunk indicated by the key. 1288 */ 1289 if (arg == NULL) { 1290 error = EINVAL; 1291 break; 1292 } 1293 1294 *(uint32_t *)arg = chunkp->toc_data.len; 1295 break; 1296 1297 default: 1298 error = ENOTSUP; 1299 break; 1300 } 1301 1302 mutex_exit(&iosram_mutex); 1303 return (error); 1304 } 1305 1306 1307 /* 1308 * iosram_hdr_ctrl() 1309 * This function provides an interface for the Mailbox Protocol 1310 * implementation to use when interacting with the IOSRAM header. 1311 */ 1312 int 1313 iosram_hdr_ctrl(uint32_t cmd, void *arg) 1314 { 1315 int error = 0; 1316 1317 /* 1318 * Acquire lock and do some argument sanity checking. 1319 */ 1320 mutex_enter(&iosram_mutex); 1321 1322 if (iosram_master == NULL) { 1323 error = EIO; 1324 } 1325 1326 if (error != 0) { 1327 mutex_exit(&iosram_mutex); 1328 return (error); 1329 } 1330 1331 switch (cmd) { 1332 case IOSRAM_HDRCMD_GET_SMS_MBOX_VER: 1333 /* 1334 * Return the value of the sms_mbox_version field. 1335 */ 1336 if (arg == NULL) { 1337 error = EINVAL; 1338 break; 1339 } 1340 1341 *(uint32_t *)arg = IOSRAM_GET_HDRFIELD32(iosram_master, 1342 sms_mbox_version); 1343 break; 1344 1345 case IOSRAM_HDRCMD_SET_OS_MBOX_VER: 1346 /* 1347 * Set the value of the os_mbox_version field. 1348 */ 1349 IOSRAM_SET_HDRFIELD32(iosram_master, os_mbox_version, 1350 (uint32_t)(uintptr_t)arg); 1351 IOSRAM_SET_HDRFIELD32(iosram_master, os_change_mask, 1352 IOSRAM_HDRFIELD_OS_MBOX_VER); 1353 iosram_send_intr(); 1354 break; 1355 1356 case IOSRAM_HDRCMD_REG_CALLBACK: 1357 iosram_hdrchange_handler = (void (*)())arg; 1358 break; 1359 1360 default: 1361 error = ENOTSUP; 1362 break; 1363 } 1364 1365 mutex_exit(&iosram_mutex); 1366 return (error); 1367 } 1368 1369 1370 /* 1371 * iosram_softintr() 1372 * IOSRAM soft interrupt handler 1373 */ 1374 static uint_t 1375 iosram_softintr(caddr_t arg) 1376 { 1377 uint32_t hdr_changes; 1378 iosramsoft_t *softp = (iosramsoft_t *)arg; 1379 iosram_chunk_t *chunkp; 1380 void (*handler)(); 1381 int i; 1382 uint8_t flag; 1383 1384 DPRINTF(1, ("iosram(%d): in iosram_softintr\n", softp->instance)); 1385 1386 IOSRAMLOG(2, "SINTR arg/softp:%p pending:%d busy:%d\n", 1387 arg, softp->intr_pending, softp->intr_busy, NULL); 1388 1389 mutex_enter(&iosram_mutex); 1390 mutex_enter(&softp->intr_mutex); 1391 1392 /* 1393 * Do not process interrupt if interrupt handler is already running or 1394 * no interrupts are pending. 1395 */ 1396 if (softp->intr_busy || !softp->intr_pending) { 1397 mutex_exit(&softp->intr_mutex); 1398 mutex_exit(&iosram_mutex); 1399 DPRINTF(1, ("IOSRAM(%d): softintr: busy=%d pending=%d\n", 1400 softp->instance, softp->intr_busy, softp->intr_pending)); 1401 return (softp->intr_pending ? DDI_INTR_CLAIMED : 1402 DDI_INTR_UNCLAIMED); 1403 } 1404 1405 /* 1406 * It's possible for the SC to send an interrupt on the new master 1407 * before we are able to set our internal state. If so, we'll retrigger 1408 * soft interrupt right after tunnel switch completion. 1409 */ 1410 if (softp->state & IOSRAM_STATE_TSWITCH) { 1411 mutex_exit(&softp->intr_mutex); 1412 mutex_exit(&iosram_mutex); 1413 DPRINTF(1, ("IOSRAM(%d): softintr: doing switch " 1414 "state=0x%x\n", softp->instance, softp->state)); 1415 return (DDI_INTR_CLAIMED); 1416 } 1417 1418 /* 1419 * Do not process interrupt if we are not the master. 1420 */ 1421 if (!(softp->state & IOSRAM_STATE_MASTER)) { 1422 mutex_exit(&softp->intr_mutex); 1423 mutex_exit(&iosram_mutex); 1424 DPRINTF(1, ("IOSRAM(%d): softintr: no master state=0x%x\n ", 1425 softp->instance, softp->state)); 1426 return (DDI_INTR_CLAIMED); 1427 } 1428 1429 IOSRAM_STAT(sintr_recv); 1430 1431 /* 1432 * If the driver is suspended, then we should not process any 1433 * interrupts. Instead, we trigger a soft interrupt when the driver 1434 * resumes. 1435 */ 1436 if (softp->suspended) { 1437 mutex_exit(&softp->intr_mutex); 1438 mutex_exit(&iosram_mutex); 1439 DPRINTF(1, ("IOSRAM(%d): softintr: suspended\n", 1440 softp->instance)); 1441 return (DDI_INTR_CLAIMED); 1442 } 1443 1444 /* 1445 * Indicate that the IOSRAM interrupt handler is busy. Note that this 1446 * includes incrementing the reader/writer count, since we don't want 1447 * any tunnel switches to start up while we're processing callbacks. 1448 */ 1449 softp->intr_busy = 1; 1450 iosram_rw_active++; 1451 #if defined(DEBUG) 1452 if (iosram_rw_active > iosram_rw_active_max) { 1453 iosram_rw_active_max = iosram_rw_active; 1454 } 1455 #endif 1456 1457 do { 1458 DPRINTF(1, ("IOSRAM(%d): softintr: processing interrupt\n", 1459 softp->instance)); 1460 1461 softp->intr_pending = 0; 1462 1463 mutex_exit(&softp->intr_mutex); 1464 1465 /* 1466 * Process changes to the IOSRAM header. 1467 */ 1468 hdr_changes = IOSRAM_GET_HDRFIELD32(iosram_master, 1469 sms_change_mask); 1470 if (hdr_changes != 0) { 1471 int error; 1472 1473 IOSRAM_SET_HDRFIELD32(iosram_master, sms_change_mask, 1474 0); 1475 if (hdr_changes & IOSRAM_HDRFIELD_TOC_INDEX) { 1476 /* 1477 * XXX is it safe to temporarily release the 1478 * iosram_mutex here? 1479 */ 1480 mutex_exit(&iosram_mutex); 1481 error = iosram_read_toc(iosram_master); 1482 mutex_enter(&iosram_mutex); 1483 if (error) { 1484 cmn_err(CE_WARN, "iosram_read_toc: new" 1485 " TOC invalid; using old TOC."); 1486 } 1487 iosram_update_addrs(iosram_master); 1488 } 1489 1490 if (iosram_hdrchange_handler != NULL) { 1491 mutex_exit(&iosram_mutex); 1492 iosram_hdrchange_handler(); 1493 mutex_enter(&iosram_mutex); 1494 } 1495 } 1496 1497 /* 1498 * Get data_valid/int_pending flags and generate a callback if 1499 * applicable. For now, we read only those flags for which a 1500 * callback has been registered. We can optimize reading of 1501 * flags by reading them all at once and then process them 1502 * later. 1503 */ 1504 for (i = 0, chunkp = chunks; i < nchunks; i++, 1505 chunkp++) { 1506 #if DEBUG 1507 flag = ddi_get8(iosram_handle, 1508 &(chunkp->flagsp->int_pending)); 1509 DPRINTF(1, ("IOSRAM(%d): softintr chunk #%d " 1510 "flag=0x%x handler=%p\n", 1511 softp->instance, i, (int)flag, 1512 chunkp->cback.handler)); 1513 #endif 1514 if ((handler = chunkp->cback.handler) == NULL) { 1515 continue; 1516 } 1517 flag = ddi_get8(iosram_handle, 1518 &(chunkp->flagsp->int_pending)); 1519 if (flag == IOSRAM_INT_TO_DOM) { 1520 DPRINTF(1, 1521 ("IOSRAM(%d): softintr: invoking handler\n", 1522 softp->instance)); 1523 IOSRAMLOG(1, 1524 "SINTR invoking hdlr:%p arg:%p index:%d\n", 1525 handler, chunkp->cback.arg, i, NULL); 1526 IOSRAM_STAT(callbacks); 1527 1528 ddi_put8(iosram_handle, 1529 &(chunkp->flagsp->int_pending), 1530 IOSRAM_INT_NONE); 1531 chunkp->cback.busy = 1; 1532 mutex_exit(&iosram_mutex); 1533 (*handler)(chunkp->cback.arg); 1534 mutex_enter(&iosram_mutex); 1535 chunkp->cback.busy = 0; 1536 1537 /* 1538 * If iosram_unregister was called while the 1539 * callback was being invoked, complete the 1540 * unregistration here. 1541 */ 1542 if (chunkp->cback.unregister) { 1543 DPRINTF(1, ("IOSRAM(%d): softintr: " 1544 "delayed unreg k:0x%08x\n", 1545 softp->instance, 1546 chunkp->toc_data.key)); 1547 chunkp->cback.handler = NULL; 1548 chunkp->cback.arg = NULL; 1549 chunkp->cback.unregister = 0; 1550 } 1551 } 1552 1553 /* 1554 * If there's a tunnel switch waiting to run, give it 1555 * higher priority than these callbacks by bailing out. 1556 * They'll still be invoked on the new master iosram 1557 * when the tunnel switch is done. 1558 */ 1559 if (iosram_tswitch_active) { 1560 break; 1561 } 1562 } 1563 1564 mutex_enter(&softp->intr_mutex); 1565 1566 } while (softp->intr_pending && !softp->suspended && 1567 !iosram_tswitch_active); 1568 1569 /* 1570 * Indicate IOSRAM interrupt handler is not BUSY any more 1571 */ 1572 softp->intr_busy = 0; 1573 1574 ASSERT(iosram_rw_active > 0); 1575 if ((--iosram_rw_active == 0) && iosram_rw_wakeup) { 1576 iosram_rw_wakeup = 0; 1577 cv_broadcast(&iosram_rw_wait); 1578 } 1579 1580 mutex_exit(&softp->intr_mutex); 1581 mutex_exit(&iosram_mutex); 1582 1583 DPRINTF(1, ("iosram(%d): softintr exit\n", softp->instance)); 1584 1585 return (DDI_INTR_CLAIMED); 1586 } 1587 1588 1589 /* 1590 * iosram_intr() 1591 * IOSRAM real interrupt handler 1592 */ 1593 static uint_t 1594 iosram_intr(caddr_t arg) 1595 { 1596 iosramsoft_t *softp = (iosramsoft_t *)arg; 1597 int result = DDI_INTR_UNCLAIMED; 1598 uint32_t int_status; 1599 1600 DPRINTF(2, ("iosram(%d): in iosram_intr\n", softp->instance)); 1601 1602 mutex_enter(&softp->intr_mutex); 1603 1604 if (softp->sbbc_handle == NULL) { 1605 /* 1606 * The SBBC registers region is not mapped in. 1607 * Set the interrupt pending flag here, and process the 1608 * interrupt after the tunnel switch. 1609 */ 1610 DPRINTF(1, ("IOSRAM(%d): iosram_intr: SBBC not mapped\n", 1611 softp->instance)); 1612 softp->intr_pending = 1; 1613 mutex_exit(&softp->intr_mutex); 1614 return (DDI_INTR_UNCLAIMED); 1615 } 1616 1617 int_status = ddi_get32(softp->sbbc_handle, 1618 &(softp->sbbc_region->int_status.reg)); 1619 DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n", int_status)); 1620 1621 if (int_status & IOSRAM_SBBC_INT0) { 1622 result = DDI_INTR_CLAIMED; 1623 DPRINTF(1, ("iosram_intr: int0 detected!\n")); 1624 } 1625 1626 if (int_status & IOSRAM_SBBC_INT1) { 1627 result = DDI_INTR_CLAIMED; 1628 DPRINTF(1, ("iosram_intr: int1 detected!\n")); 1629 } 1630 1631 if (result == DDI_INTR_CLAIMED) { 1632 ddi_put32(softp->sbbc_handle, 1633 &(softp->sbbc_region->int_status.reg), int_status); 1634 int_status = ddi_get32(softp->sbbc_handle, 1635 &(softp->sbbc_region->int_status.reg)); 1636 DPRINTF(1, ("iosram_intr: int_status = 0x%08x\n", 1637 int_status)); 1638 1639 softp->intr_pending = 1; 1640 /* 1641 * Trigger soft interrupt if not executing and 1642 * not suspended. 1643 */ 1644 if (!softp->intr_busy && !softp->suspended && 1645 (softp->softintr_id != NULL)) { 1646 DPRINTF(1, ("iosram(%d): trigger softint\n", 1647 softp->instance)); 1648 ddi_trigger_softintr(softp->softintr_id); 1649 } 1650 } 1651 1652 IOSRAM_STAT(intr_recv); 1653 1654 mutex_exit(&softp->intr_mutex); 1655 1656 IOSRAMLOG(2, "INTR arg/softp:%p pending:%d busy:%d\n", 1657 arg, softp->intr_pending, softp->intr_busy, NULL); 1658 DPRINTF(1, ("iosram(%d): iosram_intr exit\n", softp->instance)); 1659 1660 return (result); 1661 } 1662 1663 1664 /* 1665 * iosram_send_intr() 1666 * Send an interrupt to the SSP side via AXQ driver 1667 */ 1668 int 1669 iosram_send_intr() 1670 { 1671 IOSRAMLOG(1, "SendIntr called\n", NULL, NULL, NULL, NULL); 1672 IOSRAM_STAT(intr_send); 1673 DPRINTF(1, ("iosram iosram_send_intr invoked\n")); 1674 1675 return (axq_cpu2ssc_intr(0)); 1676 } 1677 1678 1679 #if defined(DEBUG) 1680 static void 1681 iosram_dummy_cback(void *arg) 1682 { 1683 DPRINTF(1, ("iosram_dummy_cback invoked arg:%p\n", arg)); 1684 } 1685 #endif /* DEBUG */ 1686 1687 1688 /*ARGSUSED1*/ 1689 static int 1690 iosram_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1691 int *rvalp) 1692 { 1693 struct iosramsoft *softp; 1694 int error = DDI_SUCCESS; 1695 1696 softp = ddi_get_soft_state(iosramsoft_statep, getminor(dev)); 1697 if (softp == NULL) { 1698 return (ENXIO); 1699 } 1700 IOSRAMLOG(1, "IOCTL: dev:%p cmd:%x arg:%p ... instance %d\n", 1701 dev, cmd, arg, softp->instance); 1702 1703 switch (cmd) { 1704 #if defined(DEBUG) 1705 case IOSRAM_GET_FLAG: 1706 { 1707 iosram_io_t req; 1708 uint8_t data_valid, int_pending; 1709 1710 if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 1711 return (EFAULT); 1712 } 1713 1714 DPRINTF(2, ("IOSRAM_GET_FLAG(key:%x\n", req.key)); 1715 1716 req.retval = iosram_get_flag(req.key, &data_valid, 1717 &int_pending); 1718 req.data_valid = (uint32_t)data_valid; 1719 req.int_pending = (uint32_t)int_pending; 1720 1721 if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 1722 DPRINTF(1, 1723 ("IOSRAM_GET_FLAG: can't copyout req.retval (%x)", 1724 req.retval)); 1725 error = EFAULT; 1726 } 1727 1728 return (error); 1729 } 1730 1731 case IOSRAM_SET_FLAG: 1732 { 1733 iosram_io_t req; 1734 1735 if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 1736 return (EFAULT); 1737 } 1738 1739 DPRINTF(2, ("IOSRAM_SET_FLAG(key:%x data_valid:%x " 1740 "int_pending:%x\n", req.key, req.data_valid, 1741 req.int_pending)); 1742 1743 req.retval = iosram_set_flag(req.key, req.data_valid, 1744 req.int_pending); 1745 1746 if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 1747 DPRINTF(1, ("IOSRAM_SET_FLAG: can't copyout req.retval" 1748 " (%x)\n", req.retval)); 1749 error = EFAULT; 1750 } 1751 1752 return (error); 1753 } 1754 1755 case IOSRAM_RD: 1756 { 1757 caddr_t bufp; 1758 int len; 1759 iosram_io_t req; 1760 1761 if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 1762 return (EFAULT); 1763 } 1764 1765 DPRINTF(2, ("IOSRAM_RD(k:%x o:%x len:%x bufp:%p\n", req.key, 1766 req.off, req.len, (void *)(uintptr_t)req.bufp)); 1767 1768 len = req.len; 1769 bufp = kmem_alloc(len, KM_SLEEP); 1770 1771 req.retval = iosram_rd(req.key, req.off, req.len, bufp); 1772 1773 if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, len, mode)) { 1774 DPRINTF(1, ("IOSRAM_RD: copyout(%p, %p,%x,%x) failed\n", 1775 bufp, (void *)(uintptr_t)req.bufp, len, mode)); 1776 error = EFAULT; 1777 } else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 1778 DPRINTF(1, ("IOSRAM_RD: can't copyout retval (%x)\n", 1779 req.retval)); 1780 error = EFAULT; 1781 } 1782 1783 kmem_free(bufp, len); 1784 return (error); 1785 } 1786 1787 case IOSRAM_WR: 1788 { 1789 caddr_t bufp; 1790 iosram_io_t req; 1791 int len; 1792 1793 if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 1794 return (EFAULT); 1795 } 1796 1797 DPRINTF(2, ("IOSRAM_WR(k:%x o:%x len:%x bufp:%p\n", 1798 req.key, req.off, req.len, req.bufp)); 1799 len = req.len; 1800 bufp = kmem_alloc(len, KM_SLEEP); 1801 if (ddi_copyin((void *)(uintptr_t)req.bufp, bufp, len, mode)) { 1802 error = EFAULT; 1803 } else { 1804 req.retval = iosram_wr(req.key, req.off, req.len, 1805 bufp); 1806 1807 if (ddi_copyout(&req, (void *)arg, sizeof (req), 1808 mode)) { 1809 error = EFAULT; 1810 } 1811 } 1812 kmem_free(bufp, len); 1813 return (error); 1814 } 1815 1816 case IOSRAM_TOC: 1817 { 1818 caddr_t bufp; 1819 int len; 1820 iosram_io_t req; 1821 1822 if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 1823 return (EFAULT); 1824 } 1825 1826 DPRINTF(2, ("IOSRAM_TOC (req.bufp:%x req.len:%x) \n", 1827 req.bufp, req.len)); 1828 1829 len = req.len; 1830 bufp = kmem_alloc(len, KM_SLEEP); 1831 1832 req.retval = iosram_get_keys((iosram_toc_entry_t *)bufp, 1833 &req.len); 1834 1835 if (ddi_copyout(bufp, (void *)(uintptr_t)req.bufp, req.len, 1836 mode)) { 1837 DPRINTF(1, 1838 ("IOSRAM_TOC: copyout(%p, %p,%x,%x) failed\n", 1839 bufp, (void *)(uintptr_t)req.bufp, req.len, mode)); 1840 error = EFAULT; 1841 } else if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 1842 DPRINTF(1, ("IOSRAM_TOC: can't copyout retval (%x)\n", 1843 req.retval)); 1844 error = EFAULT; 1845 } 1846 kmem_free(bufp, len); 1847 return (error); 1848 } 1849 1850 case IOSRAM_SEND_INTR: 1851 { 1852 DPRINTF(2, ("IOSRAM_SEND_INTR\n")); 1853 1854 switch ((int)arg) { 1855 case 0x11: 1856 case 0x22: 1857 case 0x44: 1858 case 0x88: 1859 ddi_put32(softp->sbbc_handle, 1860 &(softp->sbbc_region->int_enable.reg), (int)arg); 1861 DPRINTF(1, ("Wrote 0x%x to int_enable.reg\n", 1862 (int)arg)); 1863 break; 1864 case 0xBB: 1865 ddi_put32(softp->sbbc_handle, 1866 &(softp->sbbc_region->p0_int_gen.reg), 1); 1867 DPRINTF(1, ("Wrote 1 to p0_int_gen.reg\n")); 1868 break; 1869 default: 1870 error = iosram_send_intr(); 1871 } 1872 1873 return (error); 1874 } 1875 1876 case IOSRAM_PRINT_CBACK: 1877 iosram_print_cback(); 1878 break; 1879 1880 case IOSRAM_PRINT_STATE: 1881 iosram_print_state((int)arg); 1882 break; 1883 1884 #if IOSRAM_STATS 1885 case IOSRAM_PRINT_STATS: 1886 iosram_print_stats(); 1887 break; 1888 #endif 1889 1890 #if IOSRAM_LOG 1891 case IOSRAM_PRINT_LOG: 1892 iosram_print_log((int)arg); 1893 break; 1894 #endif 1895 1896 case IOSRAM_TUNNEL_SWITCH: 1897 error = iosram_switchfrom((int)arg); 1898 break; 1899 1900 case IOSRAM_PRINT_FLAGS: 1901 iosram_print_flags(); 1902 break; 1903 1904 case IOSRAM_REG_CBACK: 1905 { 1906 iosram_io_t req; 1907 1908 if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 1909 return (EFAULT); 1910 } 1911 1912 DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key)); 1913 1914 req.retval = iosram_register(req.key, iosram_dummy_cback, 1915 (void *)(uintptr_t)req.key); 1916 if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 1917 error = EFAULT; 1918 } 1919 1920 return (error); 1921 } 1922 1923 case IOSRAM_UNREG_CBACK: 1924 { 1925 iosram_io_t req; 1926 1927 if (ddi_copyin((void *)arg, &req, sizeof (req), mode)) { 1928 return (EFAULT); 1929 } 1930 1931 DPRINTF(2, ("IOSRAM_REG_CBACK(k:%x)\n", req.key)); 1932 1933 req.retval = iosram_unregister(req.key); 1934 if (ddi_copyout(&req, (void *)arg, sizeof (req), mode)) { 1935 error = EFAULT; 1936 } 1937 1938 return (error); 1939 } 1940 1941 case IOSRAM_SEMA_ACQUIRE: 1942 { 1943 DPRINTF(1, ("IOSRAM_SEMA_ACQUIRE\n")); 1944 error = iosram_sema_acquire(NULL); 1945 return (error); 1946 } 1947 1948 case IOSRAM_SEMA_RELEASE: 1949 { 1950 DPRINTF(1, ("IOSRAM_SEMA_RELEASE\n")); 1951 error = iosram_sema_release(); 1952 return (error); 1953 } 1954 1955 #endif /* DEBUG */ 1956 1957 default: 1958 DPRINTF(1, ("iosram_ioctl: Illegal command %x\n", cmd)); 1959 error = ENOTTY; 1960 } 1961 1962 return (error); 1963 } 1964 1965 1966 /* 1967 * iosram_switch_tunnel(softp) 1968 * Switch master tunnel to the specified instance 1969 * Must be called while holding iosram_mutex 1970 */ 1971 /*ARGSUSED*/ 1972 static int 1973 iosram_switch_tunnel(iosramsoft_t *softp) 1974 { 1975 #ifdef DEBUG 1976 int instance = softp->instance; 1977 #endif 1978 int error = 0; 1979 iosramsoft_t *prev_master; 1980 1981 ASSERT(mutex_owned(&iosram_mutex)); 1982 1983 DPRINTF(1, ("tunnel switch new master:%p (%d) current master:%p (%d)\n", 1984 softp, instance, iosram_master, 1985 ((iosram_master) ? iosram_master->instance : -1))); 1986 IOSRAMLOG(1, "TSWTCH: new_master:%p (%p) iosram_master:%p (%d)\n", 1987 softp, instance, iosram_master, 1988 ((iosram_master) ? iosram_master->instance : -1)); 1989 1990 if (softp == NULL || (softp->state & IOSRAM_STATE_DETACH)) { 1991 return (ENXIO); 1992 } 1993 if (iosram_master == softp) { 1994 return (0); 1995 } 1996 1997 1998 /* 1999 * We protect against the softp structure being deallocated by setting 2000 * the IOSRAM_STATE_TSWITCH state flag. The detach routine will check 2001 * for this flag and if set, it will wait for this flag to be reset or 2002 * refuse the detach operation. 2003 */ 2004 iosram_new_master = softp; 2005 softp->state |= IOSRAM_STATE_TSWITCH; 2006 prev_master = iosram_master; 2007 if (prev_master) { 2008 prev_master->state |= IOSRAM_STATE_TSWITCH; 2009 } 2010 mutex_exit(&iosram_mutex); 2011 2012 /* 2013 * Map the target IOSRAM, read the TOC, and register interrupts if not 2014 * already done. 2015 */ 2016 DPRINTF(1, ("iosram(%d): mapping IOSRAM and SBBC\n", 2017 softp->instance)); 2018 IOSRAMLOG(1, "TSWTCH: mapping instance:%d softp:%p\n", 2019 instance, softp, NULL, NULL); 2020 2021 if (iosram_setup_map(softp) != DDI_SUCCESS) { 2022 error = ENXIO; 2023 } else if ((chunks == NULL) && (iosram_read_toc(softp) != 0)) { 2024 iosram_remove_map(softp); 2025 error = EINVAL; 2026 } else if (iosram_add_intr(softp) != DDI_SUCCESS) { 2027 /* 2028 * If there was no previous master, purge the TOC data that 2029 * iosram_read_toc() created. 2030 */ 2031 if ((prev_master == NULL) && (chunks != NULL)) { 2032 kmem_free(chunks, nchunks * sizeof (iosram_chunk_t)); 2033 chunks = NULL; 2034 nchunks = 0; 2035 iosram_init_hashtab(); 2036 } 2037 iosram_remove_map(softp); 2038 error = ENXIO; 2039 } 2040 2041 /* 2042 * If we are asked to abort tunnel switch, do so now, before invoking 2043 * the OBP callback. 2044 */ 2045 if (iosram_tswitch_aborted) { 2046 2047 /* 2048 * Once the tunnel switch is aborted, this thread should not 2049 * resume. If it does, we simply log a message. We can't unmap 2050 * the new master IOSRAM as it may be accessed in 2051 * iosram_abort_tswitch(). It will be unmapped when it is 2052 * detached. 2053 */ 2054 IOSRAMLOG(1, 2055 "TSWTCH: aborted (pre OBP cback). Thread resumed.\n", 2056 NULL, NULL, NULL, NULL); 2057 error = EIO; 2058 } 2059 2060 if (error) { 2061 IOSRAMLOG(1, 2062 "TSWTCH: map failed instance:%d softp:%p error:%x\n", 2063 instance, softp, error, NULL); 2064 goto done; 2065 } 2066 2067 if (prev_master != NULL) { 2068 int result; 2069 2070 /* 2071 * Now invoke the OBP interface to do the tunnel switch. 2072 */ 2073 result = prom_starcat_switch_tunnel(softp->portid, 2074 OBP_TSWITCH_REQREPLY); 2075 if (result != 0) { 2076 error = EIO; 2077 } 2078 IOSRAMLOG(1, 2079 "TSWTCH: OBP tswitch portid:%x result:%x error:%x\n", 2080 softp->portid, result, error, NULL); 2081 IOSRAM_STAT(tswitch); 2082 iosram_tswitch_tstamp = ddi_get_lbolt(); 2083 } 2084 2085 mutex_enter(&iosram_mutex); 2086 if (iosram_tswitch_aborted) { 2087 /* 2088 * Tunnel switch aborted. This thread should not resume. 2089 * For now, we simply log a message, but don't unmap any 2090 * IOSRAM at this stage as it may be accessed within the 2091 * isoram_abort_tswitch(). The IOSRAM will be unmapped 2092 * when that instance is detached. 2093 */ 2094 if (iosram_tswitch_aborted) { 2095 IOSRAMLOG(1, 2096 "TSWTCH: aborted (post OBP cback). Thread" 2097 " resumed.\n", NULL, NULL, NULL, NULL); 2098 error = EIO; 2099 mutex_exit(&iosram_mutex); 2100 } 2101 } else if (error) { 2102 /* 2103 * Tunnel switch failed. Continue using previous tunnel. 2104 * However, unmap new (target) IOSRAM. 2105 */ 2106 iosram_new_master = NULL; 2107 mutex_exit(&iosram_mutex); 2108 iosram_remove_intr(softp); 2109 iosram_remove_map(softp); 2110 } else { 2111 /* 2112 * Tunnel switch was successful. Set the new master. 2113 * Also unmap old master IOSRAM and remove any interrupts 2114 * associated with that. 2115 * 2116 * Note that a call to iosram_force_write() allows access 2117 * to the IOSRAM while tunnel switch is in progress. That 2118 * means we need to set the new master before unmapping 2119 * the old master. 2120 */ 2121 iosram_set_master(softp); 2122 iosram_new_master = NULL; 2123 mutex_exit(&iosram_mutex); 2124 2125 if (prev_master) { 2126 IOSRAMLOG(1, "TSWTCH: unmapping prev_master:%p (%d)\n", 2127 prev_master, prev_master->instance, NULL, NULL); 2128 iosram_remove_intr(prev_master); 2129 iosram_remove_map(prev_master); 2130 } 2131 } 2132 2133 done: 2134 mutex_enter(&iosram_mutex); 2135 2136 /* 2137 * Clear the tunnel switch flag on the source and destination 2138 * instances. 2139 */ 2140 if (prev_master) { 2141 prev_master->state &= ~IOSRAM_STATE_TSWITCH; 2142 } 2143 softp->state &= ~IOSRAM_STATE_TSWITCH; 2144 2145 /* 2146 * Since incoming interrupts could get lost during a tunnel switch, 2147 * trigger a soft interrupt just in case. No harm other than a bit 2148 * of wasted effort will be caused if no interrupts were dropped. 2149 */ 2150 mutex_enter(&softp->intr_mutex); 2151 iosram_master->intr_pending = 1; 2152 if ((iosram_master->softintr_id != NULL) && 2153 (iosram_master->intr_busy == 0)) { 2154 ddi_trigger_softintr(iosram_master->softintr_id); 2155 } 2156 mutex_exit(&softp->intr_mutex); 2157 2158 IOSRAMLOG(1, "TSWTCH: done error:%d iosram_master:%p instance:%d\n", 2159 error, iosram_master, 2160 (iosram_master) ? iosram_master->instance : -1, NULL); 2161 2162 return (error); 2163 } 2164 2165 2166 /* 2167 * iosram_abort_tswitch() 2168 * Must be called while holding iosram_mutex. 2169 */ 2170 static void 2171 iosram_abort_tswitch() 2172 { 2173 uint32_t master_valid, new_master_valid; 2174 2175 ASSERT(mutex_owned(&iosram_mutex)); 2176 2177 if ((!iosram_tswitch_active) || iosram_tswitch_aborted) { 2178 return; 2179 } 2180 2181 ASSERT(iosram_master != NULL); 2182 2183 IOSRAMLOG(1, "ABORT: iosram_master:%p (%d) iosram_new_master:%p (%d)\n", 2184 iosram_master, iosram_master->instance, iosram_new_master, 2185 (iosram_new_master == NULL) ? -1 : iosram_new_master->instance); 2186 2187 /* 2188 * The first call to iosram_force_write() in the middle of tunnel switch 2189 * will get here. We lookup IOSRAM VALID location and setup appropriate 2190 * master, if one is still valid. We also set iosram_tswitch_aborted to 2191 * prevent reentering this code and to catch if the OBP callback thread 2192 * somehow resumes. 2193 */ 2194 iosram_tswitch_aborted = 1; 2195 2196 if ((iosram_new_master == NULL) || 2197 (iosram_new_master = iosram_master)) { 2198 /* 2199 * New master hasn't been selected yet, or OBP callback 2200 * succeeded and we already selected new IOSRAM as master, but 2201 * system crashed in the middle of unmapping previous master or 2202 * cleaning up state. Use the existing master. 2203 */ 2204 ASSERT(iosram_master->iosramp != NULL); 2205 ASSERT(IOSRAM_GET_HDRFIELD32(iosram_master, status) == 2206 IOSRAM_VALID); 2207 IOSRAMLOG(1, "ABORT: master (%d) already determined.\n", 2208 iosram_master->instance, NULL, NULL, NULL); 2209 2210 return; 2211 } 2212 2213 /* 2214 * System crashed in the middle of tunnel switch and we know that the 2215 * new target has not been marked master yet. That means, the old 2216 * master should still be mapped. We need to abort the tunnel switch 2217 * and setup a valid master, if possible, so that we can write to the 2218 * IOSRAM. 2219 * 2220 * We select a new master based upon the IOSRAM header status fields in 2221 * the previous master IOSRAM and the target IOSRAM as follows: 2222 * 2223 * iosram_master iosram-tswitch 2224 * (Prev Master) (New Target) Decision 2225 * --------------- --------------- ----------- 2226 * VALID don't care prev master 2227 * INTRANSIT INVALID prev master 2228 * INTRANSIT INTRANSIT prev master 2229 * INTRANSIT VALID new target 2230 * INVALID INVALID shouldn't ever happen 2231 * INVALID INTRANSIT shouldn't ever happen 2232 * INVALID VALID new target 2233 */ 2234 2235 master_valid = (iosram_master->iosramp != NULL) ? 2236 IOSRAM_GET_HDRFIELD32(iosram_master, status) : IOSRAM_INVALID; 2237 new_master_valid = (iosram_new_master->iosramp != NULL) ? 2238 IOSRAM_GET_HDRFIELD32(iosram_new_master, status) : IOSRAM_INVALID; 2239 2240 if (master_valid == IOSRAM_VALID) { 2241 /* EMPTY */ 2242 /* 2243 * OBP hasn't been called yet or, if it has, it hasn't started 2244 * copying yet. Use the existing master. Note that the new 2245 * master may not be mapped yet. 2246 */ 2247 IOSRAMLOG(1, "ABORT: prev master(%d) is VALID\n", 2248 iosram_master->instance, NULL, NULL, NULL); 2249 } else if (master_valid == IOSRAM_INTRANSIT) { 2250 /* 2251 * The system crashed after OBP started processing the tunnel 2252 * switch but before the iosram driver determined that it was 2253 * complete. Use the new master if it has been marked valid, 2254 * meaning that OBP finished copying data to it, or the old 2255 * master otherwise. 2256 */ 2257 IOSRAMLOG(1, "ABORT: prev master(%d) is INTRANSIT\n", 2258 iosram_master->instance, NULL, NULL, NULL); 2259 2260 if (new_master_valid == IOSRAM_VALID) { 2261 iosram_set_master(iosram_new_master); 2262 IOSRAMLOG(1, "ABORT: new master(%d) is VALID\n", 2263 iosram_new_master->instance, NULL, NULL, 2264 NULL); 2265 } else { 2266 prom_starcat_switch_tunnel(iosram_master->portid, 2267 OBP_TSWITCH_NOREPLY); 2268 2269 IOSRAMLOG(1, "ABORT: new master(%d) is INVALID\n", 2270 iosram_new_master->instance, NULL, NULL, 2271 NULL); 2272 } 2273 } else { 2274 /* 2275 * The system crashed after OBP marked the old master INVALID, 2276 * which means the new master is the way to go. 2277 */ 2278 IOSRAMLOG(1, "ABORT: prev master(%d) is INVALID\n", 2279 iosram_master->instance, NULL, NULL, NULL); 2280 2281 ASSERT(new_master_valid == IOSRAM_VALID); 2282 2283 iosram_set_master(iosram_new_master); 2284 } 2285 2286 IOSRAMLOG(1, "ABORT: Instance %d selected as master\n", 2287 iosram_master->instance, NULL, NULL, NULL); 2288 } 2289 2290 2291 /* 2292 * iosram_switchfrom(instance) 2293 * Switch master tunnel away from the specified instance 2294 */ 2295 /*ARGSUSED*/ 2296 int 2297 iosram_switchfrom(int instance) 2298 { 2299 struct iosramsoft *softp; 2300 int error = 0; 2301 int count; 2302 clock_t current_tstamp; 2303 clock_t tstamp_interval; 2304 struct iosramsoft *last_master = NULL; 2305 static int last_master_instance = -1; 2306 2307 IOSRAMLOG(1, "SwtchFrom: instance:%d iosram_master:%p (%d)\n", 2308 instance, iosram_master, 2309 ((iosram_master) ? iosram_master->instance : -1), NULL); 2310 2311 mutex_enter(&iosram_mutex); 2312 2313 /* 2314 * Wait if another tunnel switch is in progress 2315 */ 2316 for (count = 0; iosram_tswitch_active && count < IOSRAM_TSWITCH_RETRY; 2317 count++) { 2318 iosram_tswitch_wakeup = 1; 2319 cv_wait(&iosram_tswitch_wait, &iosram_mutex); 2320 } 2321 2322 if (iosram_tswitch_active) { 2323 mutex_exit(&iosram_mutex); 2324 return (EAGAIN); 2325 } 2326 2327 /* 2328 * Check if the specified instance holds the tunnel. If not, 2329 * then we are done. 2330 */ 2331 if ((iosram_master == NULL) || (iosram_master->instance != instance)) { 2332 mutex_exit(&iosram_mutex); 2333 return (0); 2334 } 2335 2336 /* 2337 * Before beginning the tunnel switch process, wait for any outstanding 2338 * read/write activity to complete. 2339 */ 2340 iosram_tswitch_active = 1; 2341 while (iosram_rw_active) { 2342 iosram_rw_wakeup = 1; 2343 cv_wait(&iosram_rw_wait, &iosram_mutex); 2344 } 2345 2346 /* 2347 * If a previous tunnel switch just completed, we have to make sure 2348 * HWAD has enough time to find the new tunnel before we switch 2349 * away from it. Otherwise, OBP's mailbox message to OSD will never 2350 * get through. Just to be paranoid about synchronization of lbolt 2351 * across different CPUs, make sure the current attempt isn't noted 2352 * as starting _before_ the last tunnel switch completed. 2353 */ 2354 current_tstamp = ddi_get_lbolt(); 2355 if (current_tstamp > iosram_tswitch_tstamp) { 2356 tstamp_interval = current_tstamp - iosram_tswitch_tstamp; 2357 } else { 2358 tstamp_interval = 0; 2359 } 2360 if (drv_hztousec(tstamp_interval) < IOSRAM_TSWITCH_DELAY_US) { 2361 mutex_exit(&iosram_mutex); 2362 delay(drv_usectohz(IOSRAM_TSWITCH_DELAY_US) - tstamp_interval); 2363 mutex_enter(&iosram_mutex); 2364 } 2365 2366 /* 2367 * The specified instance holds the tunnel. We need to move it to some 2368 * other IOSRAM. Try out all possible IOSRAMs listed in 2369 * iosram_instances. For now, we always search from the first entry. 2370 * In future, it may be desirable to start where we left off. 2371 */ 2372 for (softp = iosram_instances; softp != NULL; softp = softp->next) { 2373 if (iosram_tswitch_aborted) { 2374 break; 2375 } 2376 2377 /* we can't switch _to_ the instance we're switching _from_ */ 2378 if (softp->instance == instance) { 2379 continue; 2380 } 2381 2382 /* skip over instances being detached */ 2383 if (softp->state & IOSRAM_STATE_DETACH) { 2384 continue; 2385 } 2386 2387 /* 2388 * Try to avoid reverting to the last instance we switched away 2389 * from, as we expect that one to be detached eventually. Keep 2390 * track of it, though, so we can go ahead and try switching to 2391 * it if no other viable candidates are found. 2392 */ 2393 if (softp->instance == last_master_instance) { 2394 last_master = softp; 2395 continue; 2396 } 2397 2398 /* 2399 * Do the tunnel switch. If successful, record the instance of 2400 * the master we just left behind so we can try to avoid 2401 * reverting to it next time. 2402 */ 2403 if (iosram_switch_tunnel(softp) == 0) { 2404 last_master_instance = instance; 2405 break; 2406 } 2407 } 2408 2409 /* 2410 * If we failed to switch the tunnel, but we skipped over an instance 2411 * that had previously been switched out of because we expected it to be 2412 * detached, go ahead and try it anyway (unless the tswitch was aborted 2413 * or the instance we skipped is finally being detached). 2414 */ 2415 if ((softp == NULL) && (last_master != NULL) && 2416 !iosram_tswitch_aborted && 2417 !(last_master->state & IOSRAM_STATE_DETACH)) { 2418 if (iosram_switch_tunnel(last_master) == 0) { 2419 softp = last_master; 2420 last_master_instance = instance; 2421 } 2422 } 2423 2424 if ((softp == NULL) || (iosram_tswitch_aborted)) { 2425 error = EIO; 2426 } 2427 2428 /* 2429 * If there are additional tunnel switches queued up waiting for this 2430 * one to complete, wake them up. 2431 */ 2432 if (iosram_tswitch_wakeup) { 2433 iosram_tswitch_wakeup = 0; 2434 cv_broadcast(&iosram_tswitch_wait); 2435 } 2436 iosram_tswitch_active = 0; 2437 mutex_exit(&iosram_mutex); 2438 return (error); 2439 } 2440 2441 2442 /* 2443 * iosram_tunnel_capable(softp) 2444 * Check if this IOSRAM instance is tunnel-capable by looing at 2445 * "tunnel-capable" property. 2446 */ 2447 static int 2448 iosram_tunnel_capable(struct iosramsoft *softp) 2449 { 2450 int proplen; 2451 int tunnel_capable; 2452 2453 /* 2454 * Look up IOSRAM_TUNNELOK_PROP property, if any. 2455 */ 2456 proplen = sizeof (tunnel_capable); 2457 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, softp->dip, 2458 DDI_PROP_DONTPASS, IOSRAM_TUNNELOK_PROP, (caddr_t)&tunnel_capable, 2459 &proplen) != DDI_PROP_SUCCESS) { 2460 tunnel_capable = 0; 2461 } 2462 return (tunnel_capable); 2463 } 2464 2465 2466 static int 2467 iosram_sbbc_setup_map(struct iosramsoft *softp) 2468 { 2469 int rv; 2470 struct ddi_device_acc_attr attr; 2471 dev_info_t *dip = softp->dip; 2472 uint32_t sema_val; 2473 2474 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 2475 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 2476 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 2477 2478 mutex_enter(&iosram_mutex); 2479 mutex_enter(&softp->intr_mutex); 2480 2481 /* 2482 * Map SBBC region in 2483 */ 2484 if ((rv = ddi_regs_map_setup(dip, IOSRAM_SBBC_MAP_INDEX, 2485 (caddr_t *)&softp->sbbc_region, 2486 IOSRAM_SBBC_MAP_OFFSET, sizeof (iosram_sbbc_region_t), 2487 &attr, &softp->sbbc_handle)) != DDI_SUCCESS) { 2488 DPRINTF(1, ("Failed to map SBBC region.\n")); 2489 mutex_exit(&softp->intr_mutex); 2490 mutex_exit(&iosram_mutex); 2491 return (rv); 2492 } 2493 2494 /* 2495 * Disable SBBC interrupts. SBBC interrupts are enabled 2496 * once the interrupt handler is registered. 2497 */ 2498 ddi_put32(softp->sbbc_handle, 2499 &(softp->sbbc_region->int_enable.reg), 0x0); 2500 2501 /* 2502 * Clear hardware semaphore value if appropriate. 2503 * When the first SBBC is mapped in by the IOSRAM driver, 2504 * the value of the semaphore should be initialized only 2505 * if it is not held by SMS. For subsequent SBBC's, the 2506 * semaphore will be always initialized. 2507 */ 2508 sema_val = IOSRAM_SEMA_RD(softp); 2509 2510 if (!iosram_master) { 2511 /* the first SBBC is being mapped in */ 2512 if (!(IOSRAM_SEMA_IS_HELD(sema_val) && 2513 IOSRAM_SEMA_GET_IDX(sema_val) == IOSRAM_SEMA_SMS_IDX)) { 2514 /* not held by SMS, we clear the semaphore */ 2515 IOSRAM_SEMA_WR(softp, 0); 2516 } 2517 } else { 2518 /* not the first SBBC, we clear the semaphore */ 2519 IOSRAM_SEMA_WR(softp, 0); 2520 } 2521 2522 mutex_exit(&softp->intr_mutex); 2523 mutex_exit(&iosram_mutex); 2524 return (0); 2525 } 2526 2527 2528 static int 2529 iosram_setup_map(struct iosramsoft *softp) 2530 { 2531 int instance = softp->instance; 2532 dev_info_t *dip = softp->dip; 2533 int portid; 2534 int proplen; 2535 caddr_t propvalue; 2536 struct ddi_device_acc_attr attr; 2537 2538 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 2539 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 2540 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 2541 2542 /* 2543 * Lookup IOSRAM_REG_PROP property to find out our IOSRAM length 2544 */ 2545 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 2546 DDI_PROP_DONTPASS, IOSRAM_REG_PROP, (caddr_t)&propvalue, 2547 &proplen) != DDI_PROP_SUCCESS) { 2548 cmn_err(CE_WARN, "iosram(%d): can't find register property.\n", 2549 instance); 2550 return (DDI_FAILURE); 2551 } else { 2552 iosram_reg_t *regprop = (iosram_reg_t *)propvalue; 2553 2554 DPRINTF(1, ("SetupMap(%d): Got reg prop: %x %x %x\n", 2555 instance, regprop->addr_hi, 2556 regprop->addr_lo, regprop->size)); 2557 2558 softp->iosramlen = regprop->size; 2559 2560 kmem_free(propvalue, proplen); 2561 } 2562 DPRINTF(1, ("SetupMap(%d): IOSRAM length: 0x%x\n", instance, 2563 softp->iosramlen)); 2564 softp->handle = NULL; 2565 2566 /* 2567 * To minimize boot time, we map the entire IOSRAM as opposed to 2568 * mapping individual chunk via ddi_regs_map_setup() call. 2569 */ 2570 if (ddi_regs_map_setup(dip, 0, (caddr_t *)&softp->iosramp, 2571 0x0, softp->iosramlen, &attr, &softp->handle) != DDI_SUCCESS) { 2572 cmn_err(CE_WARN, "iosram(%d): failed to map IOSRAM len:%x\n", 2573 instance, softp->iosramlen); 2574 iosram_remove_map(softp); 2575 return (DDI_FAILURE); 2576 } 2577 2578 /* 2579 * Lookup PORTID property on my parent hierarchy 2580 */ 2581 proplen = sizeof (portid); 2582 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 2583 0, IOSRAM_PORTID_PROP, (caddr_t)&portid, 2584 &proplen) != DDI_PROP_SUCCESS) { 2585 cmn_err(CE_WARN, "iosram(%d): can't find portid property.\n", 2586 instance); 2587 iosram_remove_map(softp); 2588 return (DDI_FAILURE); 2589 } 2590 softp->portid = portid; 2591 2592 if (iosram_sbbc_setup_map(softp) != DDI_SUCCESS) { 2593 cmn_err(CE_WARN, "iosram(%d): can't map SBBC region.\n", 2594 instance); 2595 iosram_remove_map(softp); 2596 return (DDI_FAILURE); 2597 } 2598 2599 mutex_enter(&iosram_mutex); 2600 softp->state |= IOSRAM_STATE_MAPPED; 2601 mutex_exit(&iosram_mutex); 2602 2603 return (DDI_SUCCESS); 2604 } 2605 2606 2607 static void 2608 iosram_remove_map(struct iosramsoft *softp) 2609 { 2610 mutex_enter(&iosram_mutex); 2611 2612 ASSERT((softp->state & IOSRAM_STATE_MASTER) == 0); 2613 2614 if (softp->handle) { 2615 ddi_regs_map_free(&softp->handle); 2616 softp->handle = NULL; 2617 } 2618 softp->iosramp = NULL; 2619 2620 /* 2621 * Umap SBBC registers region. Shared with handler for SBBC 2622 * interrupts, take intr_mutex. 2623 */ 2624 mutex_enter(&softp->intr_mutex); 2625 if (softp->sbbc_region) { 2626 ddi_regs_map_free(&softp->sbbc_handle); 2627 softp->sbbc_region = NULL; 2628 } 2629 mutex_exit(&softp->intr_mutex); 2630 2631 softp->state &= ~IOSRAM_STATE_MAPPED; 2632 2633 mutex_exit(&iosram_mutex); 2634 } 2635 2636 2637 /* 2638 * iosram_is_chosen(struct iosramsoft *softp) 2639 * 2640 * Looks up "chosen" node property to 2641 * determine if it is the chosen IOSRAM. 2642 */ 2643 static int 2644 iosram_is_chosen(struct iosramsoft *softp) 2645 { 2646 char chosen_iosram[MAXNAMELEN]; 2647 char pn[MAXNAMELEN]; 2648 int nodeid; 2649 int chosen; 2650 pnode_t dnode; 2651 2652 /* 2653 * Get /chosen node info. prom interface will handle errors. 2654 */ 2655 dnode = prom_chosennode(); 2656 2657 /* 2658 * Look for the "iosram" property on the chosen node with a prom 2659 * interface as ddi_find_devinfo() couldn't be used (calls 2660 * ddi_walk_devs() that creates one extra lock on the device tree). 2661 */ 2662 if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) { 2663 /* 2664 * Can't find IOSRAM_CHOSEN_PROP property under chosen node 2665 */ 2666 cmn_err(CE_WARN, 2667 "iosram(%d): can't find chosen iosram property\n", 2668 softp->instance); 2669 return (0); 2670 } 2671 2672 DPRINTF(1, ("iosram(%d): Got '%x' for chosen '%s' property\n", 2673 softp->instance, nodeid, IOSRAM_CHOSEN_PROP)); 2674 2675 /* 2676 * get the full OBP pathname of this node 2677 */ 2678 if (prom_phandle_to_path((phandle_t)nodeid, chosen_iosram, 2679 sizeof (chosen_iosram)) < 0) { 2680 cmn_err(CE_NOTE, "prom_phandle_to_path(%x) failed\n", nodeid); 2681 return (0); 2682 } 2683 DPRINTF(1, ("iosram(%d): prom_phandle_to_path(%x) is '%s'\n", 2684 softp->instance, nodeid, chosen_iosram)); 2685 2686 (void) ddi_pathname(softp->dip, pn); 2687 DPRINTF(1, ("iosram(%d): ddi_pathname(%p) is '%s'\n", 2688 softp->instance, softp->dip, pn)); 2689 2690 chosen = (strcmp(chosen_iosram, pn) == 0) ? 1 : 0; 2691 DPRINTF(1, ("iosram(%d): ... %s\n", softp->instance, 2692 chosen ? "MASTER" : "SLAVE")); 2693 IOSRAMLOG(1, "iosram(%d): ... %s\n", softp->instance, 2694 (chosen ? "MASTER" : "SLAVE"), NULL, NULL); 2695 2696 return (chosen); 2697 } 2698 2699 2700 /* 2701 * iosram_set_master(struct iosramsoft *softp) 2702 * 2703 * Set master tunnel to the specified IOSRAM 2704 * Must be called while holding iosram_mutex. 2705 */ 2706 static void 2707 iosram_set_master(struct iosramsoft *softp) 2708 { 2709 ASSERT(mutex_owned(&iosram_mutex)); 2710 ASSERT(softp != NULL); 2711 ASSERT(softp->state & IOSRAM_STATE_MAPPED); 2712 ASSERT(IOSRAM_GET_HDRFIELD32(softp, status) == IOSRAM_VALID); 2713 2714 /* 2715 * Clear MASTER flag on any previous IOSRAM master, if any 2716 */ 2717 if (iosram_master && (iosram_master != softp)) { 2718 iosram_master->state &= ~IOSRAM_STATE_MASTER; 2719 } 2720 2721 /* 2722 * Setup new IOSRAM master 2723 */ 2724 iosram_update_addrs(softp); 2725 iosram_handle = softp->handle; 2726 softp->state |= IOSRAM_STATE_MASTER; 2727 softp->tswitch_ok++; 2728 iosram_master = softp; 2729 2730 IOSRAMLOG(1, "SETMASTER: softp:%p instance:%d\n", softp, 2731 softp->instance, NULL, NULL); 2732 } 2733 2734 2735 /* 2736 * iosram_read_toc() 2737 * 2738 * Read the TOC from an IOSRAM instance that has been mapped in. 2739 * If the TOC is flawed or the IOSRAM isn't valid, return an error. 2740 */ 2741 static int 2742 iosram_read_toc(struct iosramsoft *softp) 2743 { 2744 int i; 2745 int instance = softp->instance; 2746 uint8_t *toc_entryp; 2747 iosram_flags_t *flagsp = NULL; 2748 int new_nchunks; 2749 iosram_chunk_t *new_chunks; 2750 iosram_chunk_t *chunkp; 2751 iosram_chunk_t *old_chunkp; 2752 iosram_toc_entry_t index; 2753 2754 /* 2755 * Never try to read the TOC out of an unmapped IOSRAM. 2756 */ 2757 ASSERT(softp->state & IOSRAM_STATE_MAPPED); 2758 2759 mutex_enter(&iosram_mutex); 2760 2761 /* 2762 * Check to make sure this IOSRAM is marked valid. Return 2763 * an error if it isn't. 2764 */ 2765 if (IOSRAM_GET_HDRFIELD32(softp, status) != IOSRAM_VALID) { 2766 DPRINTF(1, ("iosram_read_toc(%d): IOSRAM not flagged valid\n", 2767 instance)); 2768 mutex_exit(&iosram_mutex); 2769 return (EINVAL); 2770 } 2771 2772 /* 2773 * Get the location of the TOC. 2774 */ 2775 toc_entryp = softp->iosramp + IOSRAM_GET_HDRFIELD32(softp, toc_offset); 2776 2777 /* 2778 * Read the index entry from the TOC and make sure it looks correct. 2779 */ 2780 ddi_rep_get8(softp->handle, (uint8_t *)&index, toc_entryp, 2781 sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR); 2782 if ((index.key != IOSRAM_INDEX_KEY) || 2783 (index.off != IOSRAM_INDEX_OFF)) { 2784 cmn_err(CE_WARN, "iosram(%d): invalid TOC index.\n", instance); 2785 mutex_exit(&iosram_mutex); 2786 return (EINVAL); 2787 } 2788 2789 /* 2790 * Allocate storage for the new chunks array and initialize it with data 2791 * from the TOC and callback data from the corresponding old chunk, if 2792 * it exists. 2793 */ 2794 new_nchunks = index.len - 1; 2795 new_chunks = (iosram_chunk_t *)kmem_zalloc(new_nchunks * 2796 sizeof (iosram_chunk_t), KM_SLEEP); 2797 for (i = 0, chunkp = new_chunks; i < new_nchunks; i++, chunkp++) { 2798 toc_entryp += sizeof (iosram_toc_entry_t); 2799 ddi_rep_get8(softp->handle, (uint8_t *)&(chunkp->toc_data), 2800 toc_entryp, sizeof (iosram_toc_entry_t), DDI_DEV_AUTOINCR); 2801 chunkp->hash = NULL; 2802 if ((chunkp->toc_data.off < softp->iosramlen) && 2803 (chunkp->toc_data.len <= softp->iosramlen) && 2804 ((chunkp->toc_data.off + chunkp->toc_data.len) <= 2805 softp->iosramlen)) { 2806 chunkp->basep = softp->iosramp + chunkp->toc_data.off; 2807 DPRINTF(1, 2808 ("iosram_read_toc(%d): k:%x o:%x l:%x p:%x\n", 2809 instance, chunkp->toc_data.key, 2810 chunkp->toc_data.off, chunkp->toc_data.len, 2811 chunkp->basep)); 2812 } else { 2813 cmn_err(CE_WARN, "iosram(%d): TOC entry %d" 2814 "out of range... off:%x len:%x\n", 2815 instance, i + 1, chunkp->toc_data.off, 2816 chunkp->toc_data.len); 2817 kmem_free(new_chunks, new_nchunks * 2818 sizeof (iosram_chunk_t)); 2819 mutex_exit(&iosram_mutex); 2820 return (EINVAL); 2821 } 2822 2823 /* 2824 * Note the existence of the flags chunk, which is required in 2825 * a correct TOC. 2826 */ 2827 if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) { 2828 flagsp = (iosram_flags_t *)chunkp->basep; 2829 } 2830 2831 /* 2832 * If there was an entry for this chunk in the old list, copy 2833 * the callback data from old to new storage. 2834 */ 2835 if ((nchunks > 0) && 2836 ((old_chunkp = iosram_find_chunk(chunkp->toc_data.key)) != 2837 NULL)) { 2838 bcopy(&(old_chunkp->cback), &(chunkp->cback), 2839 sizeof (iosram_cback_t)); 2840 } 2841 } 2842 /* 2843 * The TOC is malformed if there is no entry for the flags chunk. 2844 */ 2845 if (flagsp == NULL) { 2846 kmem_free(new_chunks, new_nchunks * sizeof (iosram_chunk_t)); 2847 mutex_exit(&iosram_mutex); 2848 return (EINVAL); 2849 } 2850 2851 /* 2852 * Free any memory that is no longer needed and install the new data 2853 * as current data. 2854 */ 2855 if (chunks != NULL) { 2856 kmem_free(chunks, nchunks * sizeof (iosram_chunk_t)); 2857 } 2858 chunks = new_chunks; 2859 nchunks = new_nchunks; 2860 iosram_init_hashtab(); 2861 2862 mutex_exit(&iosram_mutex); 2863 return (0); 2864 } 2865 2866 2867 /* 2868 * iosram_init_hashtab() 2869 * 2870 * Initialize the hash table and populate it with the IOSRAM 2871 * chunks previously read from the TOC. The caller must hold the 2872 * ioram_mutex lock. 2873 */ 2874 static void 2875 iosram_init_hashtab(void) 2876 { 2877 int i, bucket; 2878 iosram_chunk_t *chunkp; 2879 2880 ASSERT(mutex_owned(&iosram_mutex)); 2881 2882 for (i = 0; i < IOSRAM_HASHSZ; i++) { 2883 iosram_hashtab[i] = NULL; 2884 } 2885 2886 if (chunks) { 2887 for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 2888 /* 2889 * Hide the flags chunk by leaving it out of the hash 2890 * table. 2891 */ 2892 if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) { 2893 continue; 2894 } 2895 2896 /* 2897 * Add the current chunk to the hash table. 2898 */ 2899 bucket = IOSRAM_HASH(chunkp->toc_data.key); 2900 chunkp->hash = iosram_hashtab[bucket]; 2901 iosram_hashtab[bucket] = chunkp; 2902 } 2903 } 2904 } 2905 2906 2907 /* 2908 * iosram_update_addrs() 2909 * 2910 * Process the chunk list, updating each chunk's basep, which is a pointer 2911 * to the beginning of the chunk's memory in kvaddr space. Record the 2912 * basep value of the flags chunk to speed up flag access. The caller 2913 * must hold the iosram_mutex lock. 2914 */ 2915 static void 2916 iosram_update_addrs(struct iosramsoft *softp) 2917 { 2918 int i; 2919 iosram_flags_t *flagsp; 2920 iosram_chunk_t *chunkp; 2921 2922 ASSERT(mutex_owned(&iosram_mutex)); 2923 2924 /* 2925 * First go through all of the chunks updating their base pointers and 2926 * looking for the flags chunk. 2927 */ 2928 for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 2929 chunkp->basep = softp->iosramp + chunkp->toc_data.off; 2930 if (chunkp->toc_data.key == IOSRAM_FLAGS_KEY) { 2931 flagsp = (iosram_flags_t *)(chunkp->basep); 2932 DPRINTF(1, 2933 ("iosram_update_addrs flags: o:0x%08x p:%p", 2934 chunkp->toc_data.off, flagsp)); 2935 } 2936 } 2937 2938 /* 2939 * Now, go through and update each chunk's flags pointer. This can't be 2940 * done in the first loop because we don't have the address of the flags 2941 * chunk yet. 2942 */ 2943 for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 2944 chunkp->flagsp = flagsp++; 2945 DPRINTF(1, ("iosram_update_addrs: k:0x%x f:%p\n", 2946 chunkp->toc_data.key, chunkp->flagsp)); 2947 } 2948 } 2949 2950 /* 2951 * iosram_find_chunk(key) 2952 * 2953 * Return a pointer to iosram_chunk structure corresponding to the 2954 * "key" IOSRAM chunk. The caller must hold the iosram_mutex lock. 2955 */ 2956 static iosram_chunk_t * 2957 iosram_find_chunk(uint32_t key) 2958 { 2959 iosram_chunk_t *chunkp; 2960 int index = IOSRAM_HASH(key); 2961 2962 ASSERT(mutex_owned(&iosram_mutex)); 2963 2964 for (chunkp = iosram_hashtab[index]; chunkp; chunkp = chunkp->hash) { 2965 if (chunkp->toc_data.key == key) { 2966 break; 2967 } 2968 } 2969 2970 return (chunkp); 2971 } 2972 2973 2974 /* 2975 * iosram_add_intr(iosramsoft_t *) 2976 */ 2977 static int 2978 iosram_add_intr(iosramsoft_t *softp) 2979 { 2980 IOSRAMLOG(2, "ADDINTR: softp:%p instance:%d\n", 2981 softp, softp->instance, NULL, NULL); 2982 2983 if (ddi_add_softintr(softp->dip, DDI_SOFTINT_MED, 2984 &softp->softintr_id, &softp->soft_iblk, NULL, 2985 iosram_softintr, (caddr_t)softp) != DDI_SUCCESS) { 2986 cmn_err(CE_WARN, 2987 "iosram(%d): Can't register softintr.\n", 2988 softp->instance); 2989 return (DDI_FAILURE); 2990 } 2991 2992 if (ddi_add_intr(softp->dip, 0, &softp->real_iblk, NULL, 2993 iosram_intr, (caddr_t)softp) != DDI_SUCCESS) { 2994 cmn_err(CE_WARN, 2995 "iosram(%d): Can't register intr" 2996 " handler.\n", softp->instance); 2997 ddi_remove_softintr(softp->softintr_id); 2998 return (DDI_FAILURE); 2999 } 3000 3001 /* 3002 * Enable SBBC interrupts 3003 */ 3004 ddi_put32(softp->sbbc_handle, &(softp->sbbc_region->int_enable.reg), 3005 IOSRAM_SBBC_INT0|IOSRAM_SBBC_INT1); 3006 3007 return (DDI_SUCCESS); 3008 } 3009 3010 3011 /* 3012 * iosram_remove_intr(iosramsoft_t *) 3013 */ 3014 static int 3015 iosram_remove_intr(iosramsoft_t *softp) 3016 { 3017 IOSRAMLOG(2, "REMINTR: softp:%p instance:%d\n", 3018 softp, softp->instance, NULL, NULL); 3019 3020 /* 3021 * Disable SBBC interrupts if SBBC is mapped in 3022 */ 3023 if (softp->sbbc_region) { 3024 ddi_put32(softp->sbbc_handle, 3025 &(softp->sbbc_region->int_enable.reg), 0); 3026 } 3027 3028 /* 3029 * Remove SBBC interrupt handler 3030 */ 3031 ddi_remove_intr(softp->dip, 0, softp->real_iblk); 3032 3033 /* 3034 * Remove soft interrupt handler 3035 */ 3036 mutex_enter(&iosram_mutex); 3037 if (softp->softintr_id != NULL) { 3038 ddi_remove_softintr(softp->softintr_id); 3039 softp->softintr_id = NULL; 3040 } 3041 mutex_exit(&iosram_mutex); 3042 3043 return (0); 3044 } 3045 3046 3047 /* 3048 * iosram_add_instance(iosramsoft_t *) 3049 * Must be called while holding iosram_mutex 3050 */ 3051 static void 3052 iosram_add_instance(iosramsoft_t *new_softp) 3053 { 3054 #ifdef DEBUG 3055 int instance = new_softp->instance; 3056 iosramsoft_t *softp; 3057 #endif 3058 3059 ASSERT(mutex_owned(&iosram_mutex)); 3060 3061 #if defined(DEBUG) 3062 /* Verify that this instance is not in the list */ 3063 for (softp = iosram_instances; softp != NULL; softp = softp->next) { 3064 ASSERT(softp->instance != instance); 3065 } 3066 #endif 3067 3068 /* 3069 * Add this instance to the list 3070 */ 3071 if (iosram_instances != NULL) { 3072 iosram_instances->prev = new_softp; 3073 } 3074 new_softp->next = iosram_instances; 3075 new_softp->prev = NULL; 3076 iosram_instances = new_softp; 3077 } 3078 3079 3080 /* 3081 * iosram_remove_instance(int instance) 3082 * Must be called while holding iosram_mutex 3083 */ 3084 static void 3085 iosram_remove_instance(int instance) 3086 { 3087 iosramsoft_t *softp; 3088 3089 /* 3090 * Remove specified instance from the iosram_instances list so that 3091 * it can't be chosen for tunnel in future. 3092 */ 3093 ASSERT(mutex_owned(&iosram_mutex)); 3094 3095 for (softp = iosram_instances; softp != NULL; softp = softp->next) { 3096 if (softp->instance == instance) { 3097 if (softp->next != NULL) { 3098 softp->next->prev = softp->prev; 3099 } 3100 if (softp->prev != NULL) { 3101 softp->prev->next = softp->next; 3102 } 3103 if (iosram_instances == softp) { 3104 iosram_instances = softp->next; 3105 } 3106 3107 return; 3108 } 3109 } 3110 } 3111 3112 3113 /* 3114 * iosram_sema_acquire: Acquire hardware semaphore. 3115 * Return 0 if the semaphore could be acquired, or one of the following 3116 * possible values: 3117 * EAGAIN: there is a tunnel switch in progress 3118 * EBUSY: the semaphore was already "held" 3119 * ENXIO: an IO error occured (e.g. SBBC not mapped) 3120 * If old_value is not NULL, the location it points to will be updated 3121 * with the semaphore value read when attempting to acquire it. 3122 */ 3123 int 3124 iosram_sema_acquire(uint32_t *old_value) 3125 { 3126 struct iosramsoft *softp; 3127 int rv; 3128 uint32_t sema_val; 3129 3130 DPRINTF(2, ("IOSRAM: in iosram_sema_acquire\n")); 3131 3132 mutex_enter(&iosram_mutex); 3133 3134 /* 3135 * Disallow access if there is a tunnel switch in progress. 3136 */ 3137 if (iosram_tswitch_active) { 3138 mutex_exit(&iosram_mutex); 3139 return (EAGAIN); 3140 } 3141 3142 /* 3143 * Use current master IOSRAM for operation, fail if none is 3144 * currently active. 3145 */ 3146 if ((softp = iosram_master) == NULL) { 3147 mutex_exit(&iosram_mutex); 3148 DPRINTF(1, ("IOSRAM: iosram_sema_acquire: no master\n")); 3149 return (ENXIO); 3150 } 3151 3152 mutex_enter(&softp->intr_mutex); 3153 3154 /* 3155 * Fail if SBBC region has not been mapped. This shouldn't 3156 * happen if we have a master IOSRAM, but we double-check. 3157 */ 3158 if (softp->sbbc_region == NULL) { 3159 mutex_exit(&softp->intr_mutex); 3160 mutex_exit(&iosram_mutex); 3161 DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: " 3162 "SBBC not mapped\n", softp->instance)); 3163 return (ENXIO); 3164 } 3165 3166 /* read semaphore value */ 3167 sema_val = IOSRAM_SEMA_RD(softp); 3168 if (old_value != NULL) 3169 *old_value = sema_val; 3170 3171 if (IOSRAM_SEMA_IS_HELD(sema_val)) { 3172 /* semaphore was held by someone else */ 3173 rv = EBUSY; 3174 } else { 3175 /* semaphore was not held, we just acquired it */ 3176 rv = 0; 3177 } 3178 3179 mutex_exit(&softp->intr_mutex); 3180 mutex_exit(&iosram_mutex); 3181 3182 DPRINTF(1, ("IOSRAM(%d): iosram_sema_acquire: " 3183 "old value=0x%x rv=%d\n", softp->instance, sema_val, rv)); 3184 3185 return (rv); 3186 } 3187 3188 3189 /* 3190 * iosram_sema_release: Release hardware semaphore. 3191 * This function will "release" the hardware semaphore, and return 0 on 3192 * success. If an error occured, one of the following values will be 3193 * returned: 3194 * EAGAIN: there is a tunnel switch in progress 3195 * ENXIO: an IO error occured (e.g. SBBC not mapped) 3196 */ 3197 int 3198 iosram_sema_release(void) 3199 { 3200 struct iosramsoft *softp; 3201 3202 DPRINTF(2, ("IOSRAM: in iosram_sema_release\n")); 3203 3204 mutex_enter(&iosram_mutex); 3205 3206 /* 3207 * Disallow access if there is a tunnel switch in progress. 3208 */ 3209 if (iosram_tswitch_active) { 3210 mutex_exit(&iosram_mutex); 3211 return (EAGAIN); 3212 } 3213 3214 /* 3215 * Use current master IOSRAM for operation, fail if none is 3216 * currently active. 3217 */ 3218 if ((softp = iosram_master) == NULL) { 3219 mutex_exit(&iosram_mutex); 3220 DPRINTF(1, ("IOSRAM: iosram_sema_release: no master\n")); 3221 return (ENXIO); 3222 } 3223 3224 mutex_enter(&softp->intr_mutex); 3225 3226 /* 3227 * Fail if SBBC region has not been mapped in. This shouldn't 3228 * happen if we have a master IOSRAM, but we double-check. 3229 */ 3230 if (softp->sbbc_region == NULL) { 3231 mutex_exit(&softp->intr_mutex); 3232 mutex_exit(&iosram_mutex); 3233 DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: " 3234 "SBBC not mapped\n", softp->instance)); 3235 return (ENXIO); 3236 } 3237 3238 /* Release semaphore by clearing our semaphore register */ 3239 IOSRAM_SEMA_WR(softp, 0); 3240 3241 mutex_exit(&softp->intr_mutex); 3242 mutex_exit(&iosram_mutex); 3243 3244 DPRINTF(1, ("IOSRAM(%d): iosram_sema_release: success\n", 3245 softp->instance)); 3246 3247 return (0); 3248 } 3249 3250 3251 #if defined(IOSRAM_LOG) 3252 void 3253 iosram_log(caddr_t fmt, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4) 3254 { 3255 uint32_t seq; 3256 iosram_log_t *logp; 3257 3258 mutex_enter(&iosram_log_mutex); 3259 3260 seq = iosram_logseq++; 3261 logp = &iosram_logbuf[seq % IOSRAM_MAXLOG]; 3262 logp->seq = seq; 3263 logp->tstamp = ddi_get_lbolt(); 3264 logp->fmt = fmt; 3265 logp->arg1 = a1; 3266 logp->arg2 = a2; 3267 logp->arg3 = a3; 3268 logp->arg4 = a4; 3269 3270 mutex_exit(&iosram_log_mutex); 3271 3272 if (iosram_log_print) { 3273 cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp); 3274 if (logp->fmt) { 3275 cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2, 3276 logp->arg3, logp->arg4); 3277 if (logp->fmt[strlen(logp->fmt)-1] != '\n') { 3278 cmn_err(CE_CONT, "\n"); 3279 } 3280 } else { 3281 cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n", 3282 logp->fmt, logp->arg1, logp->arg2, logp->arg3, 3283 logp->arg4); 3284 } 3285 } 3286 } 3287 #endif /* IOSRAM_LOG */ 3288 3289 3290 #if defined(DEBUG) 3291 /* 3292 * iosram_get_keys(buf, len) 3293 * Return IOSRAM TOC in the specified buffer 3294 */ 3295 static int 3296 iosram_get_keys(iosram_toc_entry_t *bufp, uint32_t *len) 3297 { 3298 struct iosram_chunk *chunkp; 3299 int error = 0; 3300 int i; 3301 int cnt = (*len) / sizeof (iosram_toc_entry_t); 3302 3303 IOSRAMLOG(2, "iosram_get_keys(bufp:%p *len:%x)\n", bufp, *len, NULL, 3304 NULL); 3305 3306 /* 3307 * Copy data while holding the lock to prevent any data 3308 * corruption or invalid pointer dereferencing. 3309 */ 3310 mutex_enter(&iosram_mutex); 3311 3312 if (iosram_master == NULL) { 3313 error = EIO; 3314 } else { 3315 for (i = 0, chunkp = chunks; i < nchunks && i < cnt; 3316 i++, chunkp++) { 3317 bufp[i].key = chunkp->toc_data.key; 3318 bufp[i].off = chunkp->toc_data.off; 3319 bufp[i].len = chunkp->toc_data.len; 3320 bufp[i].unused = chunkp->toc_data.unused; 3321 } 3322 *len = i * sizeof (iosram_toc_entry_t); 3323 } 3324 3325 mutex_exit(&iosram_mutex); 3326 return (error); 3327 } 3328 3329 3330 /* 3331 * iosram_print_state(instance) 3332 */ 3333 static void 3334 iosram_print_state(int instance) 3335 { 3336 struct iosramsoft *softp; 3337 char pn[MAXNAMELEN]; 3338 3339 if (instance < 0) { 3340 softp = iosram_master; 3341 } else { 3342 softp = ddi_get_soft_state(iosramsoft_statep, instance); 3343 } 3344 3345 if (softp == NULL) { 3346 cmn_err(CE_CONT, "iosram_print_state: Can't find instance %d\n", 3347 instance); 3348 return; 3349 } 3350 instance = softp->instance; 3351 3352 mutex_enter(&iosram_mutex); 3353 mutex_enter(&softp->intr_mutex); 3354 3355 cmn_err(CE_CONT, "iosram_print_state(%d): ... %s\n", instance, 3356 ((softp == iosram_master) ? "MASTER" : "SLAVE")); 3357 3358 (void) ddi_pathname(softp->dip, pn); 3359 cmn_err(CE_CONT, " pathname:%s\n", pn); 3360 cmn_err(CE_CONT, " instance:%d portid:%d iosramlen:0x%x\n", 3361 softp->instance, softp->portid, softp->iosramlen); 3362 cmn_err(CE_CONT, " softp:%p handle:%p iosramp:%p\n", softp, 3363 softp->handle, softp->iosramp); 3364 cmn_err(CE_CONT, " state:0x%x tswitch_ok:%x tswitch_fail:%x\n", 3365 softp->state, softp->tswitch_ok, softp->tswitch_fail); 3366 cmn_err(CE_CONT, " softintr_id:%p intr_busy:%x intr_pending:%x\n", 3367 softp->softintr_id, softp->intr_busy, softp->intr_pending); 3368 3369 mutex_exit(&softp->intr_mutex); 3370 mutex_exit(&iosram_mutex); 3371 } 3372 3373 3374 /* 3375 * iosram_print_stats() 3376 */ 3377 static void 3378 iosram_print_stats() 3379 { 3380 uint32_t calls; 3381 3382 cmn_err(CE_CONT, "iosram_stats:\n"); 3383 calls = iosram_stats.read; 3384 cmn_err(CE_CONT, " read ... calls:%x bytes:%lx avg_sz:%x\n", 3385 calls, iosram_stats.bread, 3386 (uint32_t)((calls != 0) ? (iosram_stats.bread/calls) : 0)); 3387 3388 calls = iosram_stats.write; 3389 cmn_err(CE_CONT, " write ... calls:%x bytes:%lx avg_sz:%x\n", 3390 calls, iosram_stats.bwrite, 3391 (uint32_t)((calls != 0) ? (iosram_stats.bwrite/calls) : 0)); 3392 3393 cmn_err(CE_CONT, " intr recv (real:%x soft:%x) sent:%x cback:%x\n", 3394 iosram_stats.intr_recv, iosram_stats.sintr_recv, 3395 iosram_stats.intr_send, iosram_stats.callbacks); 3396 3397 cmn_err(CE_CONT, " tswitch: %x getflag:%x setflag:%x\n", 3398 iosram_stats.tswitch, iosram_stats.getflag, 3399 iosram_stats.setflag); 3400 3401 cmn_err(CE_CONT, " iosram_rw_active_max: %x\n", iosram_rw_active_max); 3402 } 3403 3404 3405 static void 3406 iosram_print_cback() 3407 { 3408 iosram_chunk_t *chunkp; 3409 int i; 3410 3411 /* 3412 * Print callback handlers 3413 */ 3414 mutex_enter(&iosram_mutex); 3415 3416 cmn_err(CE_CONT, "IOSRAM callbacks:\n"); 3417 for (i = 0, chunkp = chunks; i < nchunks; i++, chunkp++) { 3418 if (chunkp->cback.handler) { 3419 cmn_err(CE_CONT, " %2d: key:0x%x hdlr:%p arg:%p " 3420 "busy:%d unreg:%d\n", i, chunkp->toc_data.key, 3421 chunkp->cback.handler, chunkp->cback.arg, 3422 chunkp->cback.busy, chunkp->cback.unregister); 3423 } 3424 } 3425 mutex_exit(&iosram_mutex); 3426 } 3427 3428 3429 static void 3430 iosram_print_flags() 3431 { 3432 int i; 3433 uint32_t *keys; 3434 iosram_flags_t *flags; 3435 3436 mutex_enter(&iosram_mutex); 3437 3438 if (iosram_master == NULL) { 3439 mutex_exit(&iosram_mutex); 3440 cmn_err(CE_CONT, "IOSRAM Flags: not accessible\n"); 3441 return; 3442 } 3443 3444 keys = kmem_alloc(nchunks * sizeof (uint32_t), KM_SLEEP); 3445 flags = kmem_alloc(nchunks * sizeof (iosram_flags_t), KM_SLEEP); 3446 3447 for (i = 0; i < nchunks; i++) { 3448 keys[i] = chunks[i].toc_data.key; 3449 ddi_rep_get8(iosram_handle, (uint8_t *)&(flags[i]), 3450 (uint8_t *)(chunks[i].flagsp), sizeof (iosram_flags_t), 3451 DDI_DEV_AUTOINCR); 3452 } 3453 3454 mutex_exit(&iosram_mutex); 3455 3456 cmn_err(CE_CONT, "IOSRAM Flags:\n"); 3457 for (i = 0; i < nchunks; i++) { 3458 cmn_err(CE_CONT, 3459 " %2d: key: 0x%x data_valid:%x int_pending:%x\n", 3460 i, keys[i], flags[i].data_valid, flags[i].int_pending); 3461 } 3462 3463 kmem_free(keys, nchunks * sizeof (uint32_t)); 3464 kmem_free(flags, nchunks * sizeof (iosram_flags_t)); 3465 } 3466 3467 3468 /*PRINTFLIKE1*/ 3469 static void 3470 iosram_dprintf(const char *fmt, ...) 3471 { 3472 char msg_buf[256]; 3473 va_list adx; 3474 3475 va_start(adx, fmt); 3476 vsprintf(msg_buf, fmt, adx); 3477 va_end(adx); 3478 3479 cmn_err(CE_CONT, "%s", msg_buf); 3480 } 3481 #endif /* DEBUG */ 3482 3483 3484 #if IOSRAM_LOG 3485 /* 3486 * iosram_print_log(int cnt) 3487 * Print last few entries of the IOSRAM log in reverse order 3488 */ 3489 static void 3490 iosram_print_log(int cnt) 3491 { 3492 int i; 3493 3494 if (cnt <= 0) { 3495 cnt = 20; 3496 } else if (cnt > IOSRAM_MAXLOG) { 3497 cnt = IOSRAM_MAXLOG; 3498 } 3499 3500 3501 cmn_err(CE_CONT, 3502 "\niosram_logseq: 0x%x lbolt: %lx iosram_log_level:%x\n", 3503 iosram_logseq, ddi_get_lbolt(), iosram_log_level); 3504 cmn_err(CE_CONT, "iosram_logbuf: %p max entries:0x%x\n", 3505 iosram_logbuf, IOSRAM_MAXLOG); 3506 for (i = iosram_logseq; --i >= 0 && --cnt >= 0; ) { 3507 iosram_log_t *logp; 3508 3509 mutex_enter(&iosram_log_mutex); 3510 3511 logp = &iosram_logbuf[i %IOSRAM_MAXLOG]; 3512 cmn_err(CE_CONT, "#%x @%lx ", logp->seq, logp->tstamp); 3513 3514 if (logp->fmt) { 3515 cmn_err(CE_CONT, logp->fmt, logp->arg1, logp->arg2, 3516 logp->arg3, logp->arg4); 3517 if (logp->fmt[strlen(logp->fmt)-1] != '\n') { 3518 cmn_err(CE_CONT, "\n"); 3519 } 3520 } else { 3521 cmn_err(CE_CONT, "fmt:%p args: %lx %lx %lx %lx\n", 3522 logp->fmt, logp->arg1, logp->arg2, 3523 logp->arg3, logp->arg4); 3524 } 3525 3526 mutex_exit(&iosram_log_mutex); 3527 } 3528 } 3529 #endif /* IOSRAM_LOG */ 3530