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  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
  26  */
  27 
  28 
  29 #include <sys/types.h>
  30 #include <sys/conf.h>
  31 #include <sys/ddi.h>
  32 #include <sys/sunddi.h>
  33 #include <sys/ddi_impldefs.h>
  34 #include <sys/obpdefs.h>
  35 #include <sys/cmn_err.h>
  36 #include <sys/errno.h>
  37 #include <sys/kmem.h>
  38 #include <sys/debug.h>
  39 #include <sys/sysmacros.h>
  40 #include <sys/machsystm.h>
  41 #include <vm/hat_sfmmu.h>
  42 #include <sys/autoconf.h>
  43 #include <sys/open.h>
  44 #include <sys/stat.h>
  45 #include <sys/modctl.h>
  46 #include <sys/fhc.h>
  47 #include <sys/ac.h>
  48 #include <sys/cpu_module.h>
  49 #include <sys/x_call.h>
  50 #include <sys/fpu/fpusystm.h>
  51 #include <sys/lgrp.h>
  52 
  53 /* Useful debugging Stuff */
  54 #include <sys/nexusdebug.h>
  55 
  56 /*
  57  * Function prototypes
  58  */
  59 
  60 static int ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
  61                 void **result);
  62 static int ac_attach(dev_info_t *, ddi_attach_cmd_t);
  63 static int ac_detach(dev_info_t *, ddi_detach_cmd_t);
  64 static int ac_open(dev_t *, int, int, cred_t *);
  65 static int ac_close(dev_t, int, int, cred_t *);
  66 static int ac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  67 
  68 static void ac_add_kstats(struct ac_soft_state *);
  69 static void ac_del_kstats(struct ac_soft_state *);
  70 static int ac_misc_kstat_update(kstat_t *, int);
  71 static void ac_add_picN_kstats(dev_info_t *dip);
  72 static int ac_counters_kstat_update(kstat_t *, int);
  73 static void ac_get_memory_status(struct ac_soft_state *, enum ac_bank_id);
  74 static void ac_eval_memory_status(struct ac_soft_state *, enum ac_bank_id);
  75 static void ac_ecache_flush(uint64_t, uint64_t);
  76 static int ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
  77 static int ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag);
  78 static int ac_reset_timeout(int rw);
  79 static void ac_timeout(void *);
  80 static int ac_enter_transition(void);
  81 static void ac_exit_transition(void);
  82 
  83 
  84 int ac_add_memory(ac_cfga_pkt_t *);
  85 int ac_del_memory(ac_cfga_pkt_t *);
  86 int ac_mem_stat(ac_cfga_pkt_t *, int);
  87 int ac_mem_test_start(ac_cfga_pkt_t *, int);
  88 int ac_mem_test_stop(ac_cfga_pkt_t *, int);
  89 int ac_mem_test_read(ac_cfga_pkt_t *, int);
  90 int ac_mem_test_write(ac_cfga_pkt_t *, int);
  91 void ac_mem_test_stop_on_close(uint_t, uint_t);
  92 /*
  93  * ac audit message events
  94  */
  95 typedef enum {
  96         AC_AUDIT_OSTATE_CONFIGURE,
  97         AC_AUDIT_OSTATE_UNCONFIGURE,
  98         AC_AUDIT_OSTATE_SUCCEEDED,
  99         AC_AUDIT_OSTATE_CONFIGURE_FAILED,
 100         AC_AUDIT_OSTATE_UNCONFIGURE_FAILED
 101 } ac_audit_evt_t;
 102 static void ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt);
 103 static char *ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event);
 104 
 105 /* The memory ioctl interface version of this driver. */
 106 static ac_mem_version_t ac_mem_version = AC_MEM_ADMIN_VERSION;
 107 
 108 static int ac_mem_exercise(ac_cfga_pkt_t *, int);
 109 
 110 /*
 111  * Configuration data structures
 112  */
 113 static struct cb_ops ac_cb_ops = {
 114         ac_open,                        /* open */
 115         ac_close,                       /* close */
 116         nulldev,                        /* strategy */
 117         nulldev,                        /* print */
 118         nodev,                          /* dump */
 119         nulldev,                        /* read */
 120         nulldev,                        /* write */
 121         ac_ioctl,                       /* ioctl */
 122         nodev,                          /* devmap */
 123         nodev,                          /* mmap */
 124         nodev,                          /* segmap */
 125         nochpoll,                       /* poll */
 126         ddi_prop_op,                    /* cb_prop_op */
 127         0,                              /* streamtab */
 128         D_MP | D_NEW | D_HOTPLUG,       /* Driver compatibility flag */
 129         CB_REV,                         /* rev */
 130         nodev,                          /* cb_aread */
 131         nodev                           /* cb_awrite */
 132 };
 133 
 134 static struct dev_ops ac_ops = {
 135         DEVO_REV,                       /* devo_rev, */
 136         0,                              /* refcnt */
 137         ac_info,                        /* getinfo */
 138         nulldev,                        /* identify */
 139         nulldev,                        /* probe */
 140         ac_attach,                      /* attach */
 141         ac_detach,                      /* detach */
 142         nulldev,                        /* reset */
 143         &ac_cb_ops,                 /* cb_ops */
 144         (struct bus_ops *)0,            /* bus_ops */
 145         nulldev,                        /* power */
 146         ddi_quiesce_not_needed,                 /* quiesce */
 147 };
 148 
 149 /*
 150  * Driver globals
 151  */
 152 void *acp;                              /* ac soft state hook */
 153 static kstat_t  *ac_picN_ksp[AC_NUM_PICS];      /* performance picN kstats */
 154 static int      ac_attachcnt = 0;       /* number of instances attached */
 155 static kmutex_t ac_attachcnt_mutex;     /* ac_attachcnt lock - attach/detach */
 156 static kmutex_t ac_hot_plug_mode_mutex;
 157 static timeout_id_t     ac_hot_plug_timeout;
 158 static int              ac_hot_plug_timeout_interval = 10;
 159 
 160 #define AC_GETSOFTC(I) \
 161         ((struct ac_soft_state *)ddi_get_soft_state(acp, (I)))
 162 
 163 extern struct mod_ops mod_driverops;
 164 
 165 static struct modldrv modldrv = {
 166         &mod_driverops,             /* Type of module.  This one is a driver */
 167         "AC Leaf",              /* name of module */
 168         &ac_ops,            /* driver ops */
 169 };
 170 
 171 static struct modlinkage modlinkage = {
 172         MODREV_1,
 173         (void *)&modldrv,
 174         NULL
 175 };
 176 
 177 /*
 178  * These are the module initialization routines.
 179  */
 180 
 181 int
 182 _init(void)
 183 {
 184         int error;
 185 
 186         if ((error = ddi_soft_state_init(&acp, sizeof (struct ac_soft_state),
 187             1)) != 0)
 188                 return (error);
 189 
 190         if ((error = mod_install(&modlinkage)) != 0) {
 191                 ddi_soft_state_fini(&acp);
 192                 return (error);
 193         }
 194         /* Initialize global mutex */
 195         mutex_init(&ac_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL);
 196         mutex_init(&ac_hot_plug_mode_mutex, NULL, MUTEX_DRIVER, NULL);
 197         return (0);
 198 }
 199 
 200 int
 201 _fini(void)
 202 {
 203         int error;
 204 
 205         if ((error = mod_remove(&modlinkage)) == 0) {
 206                 ddi_soft_state_fini(&acp);
 207                 mutex_destroy(&ac_attachcnt_mutex);
 208                 mutex_destroy(&ac_hot_plug_mode_mutex);
 209         }
 210         return (error);
 211 }
 212 
 213 int
 214 _info(struct modinfo *modinfop)
 215 {
 216         return (mod_info(&modlinkage, modinfop));
 217 }
 218 
 219 /* ARGSUSED */
 220 static int
 221 ac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 222 {
 223         dev_t   dev;
 224         int     instance;
 225 
 226         if (infocmd == DDI_INFO_DEVT2INSTANCE) {
 227                 dev = (dev_t)arg;
 228                 instance = AC_GETINSTANCE(getminor(dev));
 229                 *result = (void *)(uintptr_t)instance;
 230                 return (DDI_SUCCESS);
 231         }
 232         return (DDI_FAILURE);
 233 }
 234 
 235 static int
 236 ac_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 237 {
 238         int instance;
 239         struct ac_soft_state *softsp;
 240         struct bd_list *list = NULL;
 241 
 242         switch (cmd) {
 243         case DDI_ATTACH:
 244                 break;
 245 
 246         case DDI_RESUME:
 247                 return (DDI_SUCCESS);
 248 
 249         default:
 250                 return (DDI_FAILURE);
 251         }
 252 
 253         instance = ddi_get_instance(devi);
 254 
 255         if (ddi_soft_state_zalloc(acp, instance) != DDI_SUCCESS) {
 256                 cmn_err(CE_WARN, "ddi_soft_state_zalloc failed for ac%d",
 257                     instance);
 258                 return (DDI_FAILURE);
 259         }
 260 
 261         softsp = ddi_get_soft_state(acp, instance);
 262 
 263         /* Set the dip in the soft state */
 264         softsp->dip = devi;
 265 
 266         /* Get the board number from this nodes parent */
 267         softsp->pdip = ddi_get_parent(softsp->dip);
 268         if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
 269             DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
 270                 cmn_err(CE_WARN, "ac%d: unable to retrieve %s property",
 271                     instance, OBP_BOARDNUM);
 272                 goto bad;
 273         }
 274 
 275         DPRINTF(AC_ATTACH_DEBUG, ("ac%d: devi= 0x%p\n,"
 276             " softsp=0x%p\n", instance, (void *)devi, (void *)softsp));
 277 
 278         /* map in the registers for this device. */
 279         if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0)) {
 280                 cmn_err(CE_WARN, "ac%d: unable to map registers", instance);
 281                 goto bad;
 282         }
 283 
 284         /* Setup the pointers to the hardware registers */
 285         softsp->ac_id = (uint32_t *)softsp->ac_base;
 286         softsp->ac_memctl = (uint64_t *)((char *)softsp->ac_base +
 287             AC_OFF_MEMCTL);
 288         softsp->ac_memdecode0 = (uint64_t *)((char *)softsp->ac_base +
 289             AC_OFF_MEMDEC0);
 290         softsp->ac_memdecode1 = (uint64_t *)((char *)softsp->ac_base +
 291             AC_OFF_MEMDEC1);
 292         softsp->ac_counter = (uint64_t *)((char *)softsp->ac_base +
 293             AC_OFF_CNTR);
 294         softsp->ac_mccr = (uint32_t *)((char *)softsp->ac_base +
 295             AC_OFF_MCCR);
 296 
 297         /* nothing to suspend/resume here */
 298         (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
 299             "pm-hardware-state", "no-suspend-resume");
 300 
 301         /* setup the the AC counter registers to allow for hotplug. */
 302         list = fhc_bdlist_lock(softsp->board);
 303 
 304         if (list == NULL) {
 305                 cmn_err(CE_PANIC, "ac%d: Board %d not found in database",
 306                     instance, softsp->board);
 307         }
 308 
 309         /* set the AC rev into the bd list structure */
 310         list->sc.ac_compid = *softsp->ac_id;
 311 
 312         list->ac_softsp = softsp;
 313 
 314         if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
 315                 /* Create the minor nodes */
 316                 if (ddi_create_minor_node(devi, NAME_BANK0, S_IFCHR,
 317                     (AC_PUTINSTANCE(instance) | 0),
 318                     DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
 319                         cmn_err(CE_WARN, "ac%d: \"%s\" "
 320                             "ddi_create_minor_node failed", instance,
 321                             NAME_BANK0);
 322                 }
 323                 if (ddi_create_minor_node(devi, NAME_BANK1, S_IFCHR,
 324                     (AC_PUTINSTANCE(instance) | 1),
 325                     DDI_NT_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
 326                         cmn_err(CE_WARN, "ac%d: \"%s\" "
 327                             "ddi_create_minor_node failed", instance,
 328                             NAME_BANK0);
 329                 }
 330 
 331                 /* purge previous fhc pa database entries */
 332                 fhc_del_memloc(softsp->board);
 333 
 334                 /* Inherit Memory Bank Status */
 335                 ac_get_memory_status(softsp, Bank0);
 336                 ac_get_memory_status(softsp, Bank1);
 337                 /* Final Memory Bank Status evaluation and messaging */
 338                 ac_eval_memory_status(softsp, Bank0);
 339                 ac_eval_memory_status(softsp, Bank1);
 340         }
 341 
 342         fhc_bdlist_unlock();
 343 
 344         /* create the kstats for this device. */
 345         ac_add_kstats(softsp);
 346 
 347         ddi_report_dev(devi);
 348 
 349         return (DDI_SUCCESS);
 350 
 351 bad:
 352         ddi_soft_state_free(acp, instance);
 353         return (DDI_FAILURE);
 354 }
 355 
 356 /* ARGSUSED */
 357 static int
 358 ac_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 359 {
 360         int instance;
 361         struct ac_soft_state *softsp;
 362         struct bd_list *list;
 363 
 364         /* get the instance of this devi */
 365         instance = ddi_get_instance(devi);
 366 
 367         /* get the soft state pointer for this device node */
 368         softsp = ddi_get_soft_state(acp, instance);
 369 
 370         switch (cmd) {
 371         case DDI_SUSPEND:
 372                 return (DDI_SUCCESS);
 373 
 374         case DDI_DETACH:
 375                 list = fhc_bdlist_lock(softsp->board);
 376 
 377                 if (fhc_bd_detachable(softsp->board))
 378                         break;
 379                 else
 380                         fhc_bdlist_unlock();
 381                 /* FALLTHROUGH */
 382 
 383         default:
 384                 return (DDI_FAILURE);
 385         }
 386 
 387         ASSERT(list->ac_softsp == softsp);
 388 
 389         if (list->sc.type == CPU_BOARD || list->sc.type == MEM_BOARD) {
 390                 int cpui;
 391 
 392                 /*
 393                  * Test to see if memory is in use on a CPU/MEM board.
 394                  * In the case of a DR operation this condition
 395                  * will have been assured when the board was unconfigured.
 396                  */
 397                 if (softsp->bank[Bank0].busy != 0 ||
 398                     softsp->bank[Bank0].ostate == SYSC_CFGA_OSTATE_CONFIGURED ||
 399                     softsp->bank[Bank1].busy != 0 ||
 400                     softsp->bank[Bank1].ostate == SYSC_CFGA_OSTATE_CONFIGURED) {
 401                         fhc_bdlist_unlock();
 402                         return (DDI_FAILURE);
 403                 }
 404                 /*
 405                  * CPU busy test is done by the DR sequencer before
 406                  * device detach called.
 407                  */
 408 
 409                 /*
 410                  * Flush all E-caches to remove references to this
 411                  * board's memory.
 412                  *
 413                  * Do this one CPU at a time to avoid stalls and timeouts
 414                  * due to all CPUs flushing concurrently.
 415                  * xc_one returns silently for non-existant CPUs.
 416                  */
 417                 for (cpui = 0; cpui < NCPU; cpui++)
 418                         xc_one(cpui, ac_ecache_flush, 0, 0);
 419         }
 420 
 421         list->ac_softsp = NULL;
 422 
 423         /* delete the kstat for this driver. */
 424         ac_del_kstats(softsp);
 425 
 426         /* unmap the registers */
 427         ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->ac_base, 0, 0);
 428 
 429         fhc_bdlist_unlock();
 430 
 431         /* Remove the minor nodes. */
 432         ddi_remove_minor_node(devi, NULL);
 433 
 434         /* free the soft state structure */
 435         ddi_soft_state_free(acp, instance);
 436         ddi_prop_remove_all(devi);
 437 
 438         return (DDI_SUCCESS);
 439 }
 440 
 441 /* ARGSUSED */
 442 static int
 443 ac_open(dev_t *devp, int flag, int otyp, cred_t *credp)
 444 {
 445         int instance;
 446         dev_t dev;
 447         struct ac_soft_state *softsp;
 448         struct bd_list *board;
 449         int vis;
 450 
 451         dev = *devp;
 452         instance = AC_GETINSTANCE(getminor(dev));
 453         softsp = AC_GETSOFTC(instance);
 454 
 455         /* Is the instance attached? */
 456         if (softsp == NULL) {
 457 #ifdef DEBUG
 458                 cmn_err(CE_WARN, "ac%d device not attached", instance);
 459 #endif /* DEBUG */
 460                 return (ENXIO);
 461         }
 462 
 463         /*
 464          * If the board is not configured, hide the memory APs
 465          */
 466         board = fhc_bdlist_lock(softsp->board);
 467         vis = (board != NULL) && MEM_BOARD_VISIBLE(board);
 468         fhc_bdlist_unlock();
 469 
 470         if (!vis)
 471                 return (ENXIO);
 472 
 473         /* verify that otyp is appropriate */
 474         if (otyp != OTYP_CHR) {
 475                 return (EINVAL);
 476         }
 477 
 478         return (DDI_SUCCESS);
 479 }
 480 
 481 /* ARGSUSED */
 482 static int
 483 ac_close(dev_t devt, int flag, int otyp, cred_t *credp)
 484 {
 485         struct ac_soft_state *softsp;
 486         int instance;
 487 
 488         instance = AC_GETINSTANCE(getminor(devt));
 489         softsp = AC_GETSOFTC(instance);
 490         ASSERT(softsp != NULL);
 491         ac_mem_test_stop_on_close(softsp->board, AC_GETBANK(getminor(devt)));
 492         return (DDI_SUCCESS);
 493 }
 494 
 495 static int
 496 ac_pkt_init(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
 497 {
 498 #ifdef _MULTI_DATAMODEL
 499         if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
 500                 ac_cfga_cmd32_t ac_cmd32;
 501 
 502                 if (ddi_copyin((void *)arg, &ac_cmd32,
 503                     sizeof (ac_cfga_cmd32_t), flag) != 0) {
 504                         return (EFAULT);
 505                 }
 506                 pkt->cmd_cfga.force = ac_cmd32.force;
 507                 pkt->cmd_cfga.test = ac_cmd32.test;
 508                 pkt->cmd_cfga.arg = ac_cmd32.arg;
 509                 pkt->cmd_cfga.errtype = ac_cmd32.errtype;
 510                 pkt->cmd_cfga.outputstr =
 511                     (char *)(uintptr_t)ac_cmd32.outputstr;
 512                 pkt->cmd_cfga.private =
 513                     (void *)(uintptr_t)ac_cmd32.private;
 514         } else
 515 #endif /* _MULTI_DATAMODEL */
 516         if (ddi_copyin((void *)arg, &(pkt->cmd_cfga),
 517             sizeof (ac_cfga_cmd_t), flag) != 0) {
 518                 return (EFAULT);
 519         }
 520         pkt->errbuf = kmem_zalloc(SYSC_OUTPUT_LEN, KM_SLEEP);
 521         return (0);
 522 }
 523 
 524 static int
 525 ac_pkt_fini(ac_cfga_pkt_t *pkt, intptr_t arg, int flag)
 526 {
 527         int ret = TRUE;
 528 
 529 #ifdef _MULTI_DATAMODEL
 530         if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) {
 531 
 532                 if (ddi_copyout(&(pkt->cmd_cfga.errtype),
 533                     (void *)&(((ac_cfga_cmd32_t *)arg)->errtype),
 534                     sizeof (ac_err_t), flag) != 0) {
 535                         ret = FALSE;
 536                 }
 537         } else
 538 #endif
 539         if (ddi_copyout(&(pkt->cmd_cfga.errtype),
 540             (void *)&(((ac_cfga_cmd_t *)arg)->errtype),
 541             sizeof (ac_err_t), flag) != 0) {
 542                 ret = FALSE;
 543         }
 544 
 545         if ((ret != FALSE) && ((pkt->cmd_cfga.outputstr != NULL) &&
 546             (ddi_copyout(pkt->errbuf, pkt->cmd_cfga.outputstr,
 547             SYSC_OUTPUT_LEN, flag) != 0))) {
 548                         ret = FALSE;
 549         }
 550 
 551         kmem_free(pkt->errbuf, SYSC_OUTPUT_LEN);
 552         return (ret);
 553 }
 554 
 555 /* ARGSUSED */
 556 static int
 557 ac_ioctl(
 558         dev_t devt,
 559         int cmd,
 560         intptr_t arg,
 561         int flag,
 562         cred_t *cred_p,
 563         int *rval_p)
 564 {
 565         struct ac_soft_state *softsp;
 566         ac_cfga_pkt_t cfga_pkt, *pkt;
 567         int instance;
 568         int retval;
 569 
 570         instance = AC_GETINSTANCE(getminor(devt));
 571         softsp = AC_GETSOFTC(instance);
 572         if (softsp == NULL) {
 573 #ifdef DEBUG
 574                 cmn_err(CE_NOTE, "ac%d device not attached", instance);
 575 #endif /* DEBUG */
 576                 return (ENXIO);
 577         }
 578 
 579         /*
 580          * Dispose of the easy ones first.
 581          */
 582         switch (cmd) {
 583         case AC_MEM_ADMIN_VER:
 584                 /*
 585                  * Specify the revision of this ioctl interface driver.
 586                  */
 587                 if (ddi_copyout(&ac_mem_version, (void *)arg,
 588                     sizeof (ac_mem_version_t), flag) != 0)
 589                         return (EFAULT);
 590                 return (DDI_SUCCESS);
 591 
 592         case AC_MEM_CONFIGURE:
 593         case AC_MEM_UNCONFIGURE:
 594         case AC_MEM_STAT:
 595         case AC_MEM_TEST_START:
 596         case AC_MEM_TEST_STOP:
 597         case AC_MEM_TEST_READ:
 598         case AC_MEM_TEST_WRITE:
 599         case AC_MEM_EXERCISE:
 600                 break;
 601 
 602         default:
 603                 return (ENOTTY);
 604         }
 605         if (cmd != AC_MEM_STAT && !fpu_exists) {
 606                 return (ENOTSUP);
 607         }
 608 
 609         pkt = &cfga_pkt;
 610         if ((retval = ac_pkt_init(pkt, arg, flag)) != 0)
 611                 return (retval);
 612         pkt->softsp = softsp;
 613         pkt->bank = AC_GETBANK(getminor(devt));
 614 
 615         switch (cmd) {
 616         case AC_MEM_CONFIGURE:
 617                 if ((flag & FWRITE) == 0) {
 618                         retval = EBADF;
 619                         break;
 620                 }
 621 
 622                 if (pkt->cmd_cfga.private != NULL) {
 623                         retval = EINVAL;
 624                         break;
 625                 }
 626                 ac_policy_audit_messages(AC_AUDIT_OSTATE_CONFIGURE, pkt);
 627                 retval = ac_add_memory(pkt);
 628                 if (!retval)
 629                         ac_policy_audit_messages(
 630                             AC_AUDIT_OSTATE_SUCCEEDED, pkt);
 631                 else
 632                         ac_policy_audit_messages(
 633                             AC_AUDIT_OSTATE_CONFIGURE_FAILED, pkt);
 634                 break;
 635 
 636         case AC_MEM_UNCONFIGURE:
 637                 if ((flag & FWRITE) == 0) {
 638                         retval = EBADF;
 639                         break;
 640                 }
 641 
 642                 if (pkt->cmd_cfga.private != NULL) {
 643                         retval = EINVAL;
 644                         break;
 645                 }
 646                 ac_policy_audit_messages(AC_AUDIT_OSTATE_UNCONFIGURE, pkt);
 647                 retval = ac_del_memory(pkt);
 648                 if (!retval) {
 649                         ac_policy_audit_messages(
 650                             AC_AUDIT_OSTATE_SUCCEEDED, pkt);
 651                 } else
 652                         ac_policy_audit_messages(
 653                             AC_AUDIT_OSTATE_UNCONFIGURE_FAILED, pkt);
 654                 break;
 655 
 656         case AC_MEM_STAT:
 657                 /*
 658                  * Query usage of a bank of memory.
 659                  */
 660                 retval = ac_mem_stat(pkt, flag);
 661                 break;
 662 
 663         case AC_MEM_TEST_START:
 664                 if ((flag & FWRITE) == 0) {
 665                         retval = EBADF;
 666                         break;
 667                 }
 668 
 669                 retval = ac_mem_test_start(pkt, flag);
 670                 break;
 671 
 672         case AC_MEM_TEST_STOP:
 673                 if ((flag & FWRITE) == 0) {
 674                         retval = EBADF;
 675                         break;
 676                 }
 677 
 678                 retval =  ac_mem_test_stop(pkt, flag);
 679                 break;
 680 
 681         case AC_MEM_TEST_READ:
 682                 /*
 683                  * read a 'page' (or less) of memory safely.
 684                  */
 685                 if ((flag & FWRITE) == 0) {
 686                         retval = EBADF;
 687                         break;
 688                 }
 689 
 690                 retval = ac_mem_test_read(pkt, flag);
 691                 break;
 692 
 693         case AC_MEM_TEST_WRITE:
 694                 /*
 695                  * write a 'page' (or less) of memory safely.
 696                  */
 697                 if ((flag & FWRITE) == 0) {
 698                         retval = EBADF;
 699                         break;
 700                 }
 701 
 702                 retval = ac_mem_test_write(pkt, flag);
 703                 break;
 704 
 705         case AC_MEM_EXERCISE:
 706                 retval = ac_mem_exercise(pkt, flag);
 707                 break;
 708 
 709         default:
 710                 ASSERT(0);
 711                 retval = ENOTTY;
 712                 break;
 713         }
 714 
 715         if (ac_pkt_fini(pkt, arg, flag) != TRUE)
 716                 retval = EFAULT;
 717 
 718         return (retval);
 719 }
 720 
 721 static void
 722 ac_add_kstats(struct ac_soft_state *softsp)
 723 {
 724         struct kstat *ac_ksp, *ac_counters_ksp;
 725         struct ac_kstat *ac_named_ksp;
 726         struct kstat_named *ac_counters_named_data;
 727 
 728         /*
 729          * create the unix-misc kstat for address controller
 730          * using the board number as the instance.
 731          */
 732         if ((ac_ksp = kstat_create("unix", softsp->board,
 733             AC_KSTAT_NAME, "misc", KSTAT_TYPE_NAMED,
 734             sizeof (struct ac_kstat) / sizeof (kstat_named_t),
 735             KSTAT_FLAG_PERSISTENT)) == NULL) {
 736                 cmn_err(CE_WARN, "ac%d: kstat_create failed",
 737                     ddi_get_instance(softsp->dip));
 738                 return;
 739         }
 740 
 741         ac_named_ksp = (struct ac_kstat *)(ac_ksp->ks_data);
 742 
 743         /* initialize the named kstats */
 744         kstat_named_init(&ac_named_ksp->ac_memctl,
 745             MEMCTL_KSTAT_NAMED,
 746             KSTAT_DATA_UINT64);
 747 
 748         kstat_named_init(&ac_named_ksp->ac_memdecode0,
 749             MEMDECODE0_KSTAT_NAMED,
 750             KSTAT_DATA_UINT64);
 751 
 752         kstat_named_init(&ac_named_ksp->ac_memdecode1,
 753             MEMDECODE1_KSTAT_NAMED,
 754             KSTAT_DATA_UINT64);
 755 
 756         kstat_named_init(&ac_named_ksp->ac_mccr,
 757             MCCR_KSTAT_NAMED,
 758             KSTAT_DATA_UINT32);
 759 
 760         kstat_named_init(&ac_named_ksp->ac_counter,
 761             CNTR_KSTAT_NAMED,
 762             KSTAT_DATA_UINT64);
 763 
 764         kstat_named_init(&ac_named_ksp->ac_bank0_status,
 765             BANK_0_KSTAT_NAMED,
 766             KSTAT_DATA_CHAR);
 767 
 768         kstat_named_init(&ac_named_ksp->ac_bank1_status,
 769             BANK_1_KSTAT_NAMED,
 770             KSTAT_DATA_CHAR);
 771 
 772         ac_ksp->ks_update = ac_misc_kstat_update;
 773         ac_ksp->ks_private = (void *)softsp;
 774         softsp->ac_ksp = ac_ksp;
 775         kstat_install(ac_ksp);
 776 
 777         /*
 778          * Create the picN kstats if we are the first instance
 779          * to attach. We use ac_attachcnt as a count of how
 780          * many instances have attached. This is protected by
 781          * a mutex.
 782          */
 783         mutex_enter(&ac_attachcnt_mutex);
 784         if (ac_attachcnt == 0)
 785                 ac_add_picN_kstats(softsp->dip);
 786 
 787         ac_attachcnt ++;
 788         mutex_exit(&ac_attachcnt_mutex);
 789 
 790         /*
 791          * Create the "counter" kstat for each AC instance.
 792          * This provides access to the %pcr and %pic
 793          * registers for that instance.
 794          *
 795          * The size of this kstat is AC_NUM_PICS + 1 for %pcr
 796          */
 797         if ((ac_counters_ksp = kstat_create("ac",
 798             ddi_get_instance(softsp->dip), "counters",
 799             "bus", KSTAT_TYPE_NAMED, AC_NUM_PICS + 1,
 800             KSTAT_FLAG_WRITABLE)) == NULL) {
 801 
 802                 cmn_err(CE_WARN, "ac%d counters: kstat_create failed",
 803                     ddi_get_instance(softsp->dip));
 804                 return;
 805         }
 806         ac_counters_named_data =
 807             (struct kstat_named *)(ac_counters_ksp->ks_data);
 808 
 809         /* initialize the named kstats */
 810         kstat_named_init(&ac_counters_named_data[0],
 811             "pcr", KSTAT_DATA_UINT64);
 812 
 813         kstat_named_init(&ac_counters_named_data[1],
 814             "pic0", KSTAT_DATA_UINT64);
 815 
 816         kstat_named_init(&ac_counters_named_data[2],
 817             "pic1", KSTAT_DATA_UINT64);
 818 
 819         ac_counters_ksp->ks_update = ac_counters_kstat_update;
 820         ac_counters_ksp->ks_private = (void *)softsp;
 821         kstat_install(ac_counters_ksp);
 822 
 823         /* update the sofstate */
 824         softsp->ac_counters_ksp = ac_counters_ksp;
 825 }
 826 
 827 /*
 828  * called from ac_add_kstats() to create a kstat for each %pic
 829  * that the AC supports. These (read-only) kstats export the
 830  * event names and %pcr masks that each %pic supports.
 831  *
 832  * if we fail to create any of these kstats we must remove any
 833  * that we have already created and return;
 834  *
 835  * NOTE: because all AC's use the same events we only need to
 836  *       create the picN kstats once. All instances can use
 837  *       the same picN kstats.
 838  *
 839  *       The flexibility exists to allow each device specify it's
 840  *       own events by creating picN kstats with the instance number
 841  *       set to ddi_get_instance(softsp->dip).
 842  *
 843  *       When searching for a picN kstat for a device you should
 844  *       first search for a picN kstat using the instance number
 845  *       of the device you are interested in. If that fails you
 846  *       should use the first picN kstat found for that device.
 847  */
 848 static void
 849 ac_add_picN_kstats(dev_info_t *dip)
 850 {
 851         typedef struct ac_event_mask {
 852                 char *event_name;
 853                 uint64_t pcr_mask;
 854         } ac_event_mask_t;
 855 
 856         /*
 857          * AC Performance Events.
 858          *
 859          * We declare an array of event-names and event-masks.
 860          */
 861         ac_event_mask_t ac_events_arr[] = {
 862                 {"mem_bank0_rds", 0x1}, {"mem_bank0_wrs", 0x2},
 863                 {"mem_bank0_stall", 0x3}, {"mem_bank1_rds", 0x4},
 864                 {"mem_bank1_wrs", 0x5}, {"mem_bank1_stall", 0x6},
 865                 {"clock_cycles", 0x7}, {"addr_pkts", 0x8},
 866                 {"data_pkts", 0x9}, {"flow_ctl_cyc", 0xa},
 867                 {"fast_arb_pkts", 0xb}, {"bus_cont_cyc", 0xc},
 868                 {"data_bus_can", 0xd}, {"ac_addr_pkts", 0xe},
 869                 {"ac_data_pkts", 0xf}, {"rts_pkts", 0x10},
 870                 {"rtsa_pkts", 0x11}, {"rto_pkts", 0x12},
 871                 {"rs_pkts", 0x13}, {"wb_pkts", 0x14},
 872                 {"ws_pkts", 0x15}, {"rio_pkts", 0x16},
 873                 {"rbio_pkts", 0x17}, {"wio_pkts", 0x18},
 874                 {"wbio_pkts", 0x19}, {"upa_a_rds_m", 0x1a},
 875                 {"upa_a_rdo_v", 0x1b}, {"upa_b_rds_m", 0x1c},
 876                 {"upa_b_rdo_v", 0x1d}, {"upa_a_preqs_fr", 0x20},
 877                 {"upa_a_sreqs_to", 0x21}, {"upa_a_preqs_to", 0x22},
 878                 {"upa_a_rds_fr", 0x23}, {"upa_a_rdsa_fr", 0x24},
 879                 {"upa_a_rdo_fr", 0x25}, {"upa_a_rdd_fr", 0x26},
 880                 {"upa_a_rio_rbio", 0x27}, {"upa_a_wio_wbio", 0x28},
 881                 {"upa_a_cpb_to", 0x29}, {"upa_a_inv_to", 0x2a},
 882                 {"upa_a_hits_buff", 0x2b}, {"upa_a_wb", 0x2c},
 883                 {"upa_a_wi", 0x2d}, {"upa_b_preqs_fr", 0x30},
 884                 {"upa_b_sreqs_to", 0x31}, {"upa_b_preqs_to", 0x32},
 885                 {"upa_b_rds_fr", 0x33}, {"upa_b_rdsa_fr", 0x34},
 886                 {"upa_b_rdo_fr", 0x35}, {"upa_b_rdd_fr", 0x36},
 887                 {"upa_b_rio_rbio", 0x37}, {"upa_b_wio_wbio", 0x38},
 888                 {"upa_b_cpb_to", 0x39}, {"upa_b_inv_to", 0x3a},
 889                 {"upa_b_hits_buff", 0x3b}, {"upa_b_wb", 0x3c},
 890                 {"upa_b_wi", 0x3d}
 891         };
 892 
 893 #define AC_NUM_EVENTS sizeof (ac_events_arr) / sizeof (ac_events_arr[0])
 894 
 895         /*
 896          * array of clear masks for each pic.
 897          * These masks are used to clear the %pcr bits for
 898          * each pic.
 899          */
 900         ac_event_mask_t ac_clear_pic[AC_NUM_PICS] = {
 901                 /* pic0 */
 902                 {"clear_pic", (uint64_t)~(0x3f)},
 903                 /* pic1 */
 904                 {"clear_pic", (uint64_t)~(0x3f << 8)}
 905         };
 906 
 907         struct kstat_named *ac_pic_named_data;
 908         int             event, pic;
 909         char            pic_name[30];
 910         int             instance = ddi_get_instance(dip);
 911         int             pic_shift = 0;
 912 
 913         for (pic = 0; pic < AC_NUM_PICS; pic++) {
 914                 /*
 915                  * create the picN kstat. The size of this kstat is
 916                  * AC_NUM_EVENTS + 1 for the clear_event_mask
 917                  */
 918                 (void) sprintf(pic_name, "pic%d", pic); /* pic0, pic1 ... */
 919                 if ((ac_picN_ksp[pic] = kstat_create("ac",
 920                     instance, pic_name, "bus", KSTAT_TYPE_NAMED,
 921                     AC_NUM_EVENTS + 1, NULL)) == NULL) {
 922 
 923                                 cmn_err(CE_WARN, "ac %s: kstat_create failed",
 924                                     pic_name);
 925 
 926                                 /* remove pic0 kstat if pic1 create fails */
 927                                 if (pic == 1) {
 928                                         kstat_delete(ac_picN_ksp[0]);
 929                                         ac_picN_ksp[0] = NULL;
 930                                 }
 931                                 return;
 932                 }
 933                 ac_pic_named_data =
 934                     (struct kstat_named *)(ac_picN_ksp[pic]->ks_data);
 935 
 936                 /*
 937                  * when we are storing pcr_masks we need to shift bits
 938                  * left by 8 for pic1 events.
 939                  */
 940                 if (pic == 1)
 941                         pic_shift = 8;
 942 
 943                 /*
 944                  * for each picN event we need to write a kstat record
 945                  * (name = EVENT, value.ui64 = PCR_MASK)
 946                  */
 947                 for (event = 0; event < AC_NUM_EVENTS; event ++) {
 948 
 949                         /* pcr_mask */
 950                         ac_pic_named_data[event].value.ui64 =
 951                             ac_events_arr[event].pcr_mask << pic_shift;
 952 
 953                         /* event-name */
 954                         kstat_named_init(&ac_pic_named_data[event],
 955                             ac_events_arr[event].event_name,
 956                             KSTAT_DATA_UINT64);
 957                 }
 958 
 959                 /*
 960                  * we add the clear_pic event and mask as the last
 961                  * record in the kstat
 962                  */
 963                 /* pcr mask */
 964                 ac_pic_named_data[AC_NUM_EVENTS].value.ui64 =
 965                     ac_clear_pic[pic].pcr_mask;
 966 
 967                 /* event-name */
 968                 kstat_named_init(&ac_pic_named_data[AC_NUM_EVENTS],
 969                     ac_clear_pic[pic].event_name,
 970                     KSTAT_DATA_UINT64);
 971 
 972                 kstat_install(ac_picN_ksp[pic]);
 973         }
 974 }
 975 
 976 
 977 static void
 978 ac_del_kstats(struct ac_soft_state *softsp)
 979 {
 980         struct kstat *ac_ksp;
 981         int pic;
 982 
 983         /* remove "misc" kstat */
 984         ac_ksp = softsp->ac_ksp;
 985         softsp->ac_ksp = NULL;
 986         if (ac_ksp != NULL) {
 987                 ASSERT(ac_ksp->ks_private == (void *)softsp);
 988                 kstat_delete(ac_ksp);
 989         }
 990 
 991         /* remove "bus" kstat */
 992         ac_ksp = softsp->ac_counters_ksp;
 993         softsp->ac_counters_ksp = NULL;
 994         if (ac_ksp != NULL) {
 995                 ASSERT(ac_ksp->ks_private == (void *)softsp);
 996                 kstat_delete(ac_ksp);
 997         }
 998 
 999         /*
1000          * if we are the last instance to detach we need to
1001          * remove the picN kstats. We use ac_attachcnt as a
1002          * count of how many instances are still attached. This
1003          * is protected by a mutex.
1004          */
1005         mutex_enter(&ac_attachcnt_mutex);
1006         ac_attachcnt --;
1007         if (ac_attachcnt == 0) {
1008                 for (pic = 0; pic < AC_NUM_PICS; pic++) {
1009                         if (ac_picN_ksp[pic] != (kstat_t *)NULL) {
1010                                 kstat_delete(ac_picN_ksp[pic]);
1011                                 ac_picN_ksp[pic] = NULL;
1012                         }
1013                 }
1014         }
1015         mutex_exit(&ac_attachcnt_mutex);
1016 }
1017 
1018 static enum ac_bank_status
1019 ac_kstat_stat(sysc_cfga_rstate_t rst, sysc_cfga_ostate_t ost)
1020 {
1021         switch (rst) {
1022         case SYSC_CFGA_RSTATE_EMPTY:
1023                 return (StNoMem);
1024         case SYSC_CFGA_RSTATE_DISCONNECTED:
1025                 return (StBad);
1026         case SYSC_CFGA_RSTATE_CONNECTED:
1027                 switch (ost) {
1028                 case SYSC_CFGA_OSTATE_UNCONFIGURED:
1029                         return (StSpare);
1030                 case SYSC_CFGA_OSTATE_CONFIGURED:
1031                         return (StActive);
1032                 default:
1033                         return (StUnknown);
1034                 }
1035         default:
1036                 return (StUnknown);
1037         }
1038 }
1039 
1040 static enum ac_bank_condition
1041 ac_kstat_cond(sysc_cfga_cond_t cond)
1042 {
1043         switch (cond) {
1044         case SYSC_CFGA_COND_UNKNOWN:
1045                 return (ConUnknown);
1046         case SYSC_CFGA_COND_OK:
1047                 return (ConOK);
1048         case SYSC_CFGA_COND_FAILING:
1049                 return (ConFailing);
1050         case SYSC_CFGA_COND_FAILED:
1051                 return (ConFailed);
1052         case SYSC_CFGA_COND_UNUSABLE:
1053                 return (ConBad);
1054         default:
1055                 return (ConUnknown);
1056         }
1057 }
1058 
1059 static int
1060 ac_misc_kstat_update(kstat_t *ksp, int rw)
1061 {
1062         struct ac_kstat *acksp;
1063         struct ac_soft_state *softsp;
1064 
1065         acksp = (struct ac_kstat *)ksp->ks_data;
1066         softsp = (struct ac_soft_state *)ksp->ks_private;
1067         /* Need the NULL check in case kstat is about to be deleted. */
1068         ASSERT(softsp->ac_ksp == NULL || ksp == softsp->ac_ksp);
1069 
1070         /* this is a read-only kstat. Bail out on a write */
1071         if (rw == KSTAT_WRITE) {
1072                 return (EACCES);
1073         } else {
1074                 /*
1075                  * copy the current state of the hardware into the
1076                  * kstat structure.
1077                  */
1078                 acksp->ac_memctl.value.ui64 = *softsp->ac_memctl;
1079                 acksp->ac_memdecode0.value.ui64 = *softsp->ac_memdecode0;
1080                 acksp->ac_memdecode1.value.ui64 = *softsp->ac_memdecode1;
1081                 acksp->ac_mccr.value.ui32 = *softsp->ac_mccr;
1082                 acksp->ac_counter.value.ui64 = *softsp->ac_counter;
1083                 acksp->ac_bank0_status.value.c[0] =
1084                     ac_kstat_stat(softsp->bank[0].rstate,
1085                     softsp->bank[0].ostate);
1086                 acksp->ac_bank0_status.value.c[1] =
1087                     ac_kstat_cond(softsp->bank[0].condition);
1088                 acksp->ac_bank1_status.value.c[0] =
1089                     ac_kstat_stat(softsp->bank[1].rstate,
1090                     softsp->bank[1].ostate);
1091                 acksp->ac_bank1_status.value.c[1] =
1092                     ac_kstat_cond(softsp->bank[1].condition);
1093         }
1094         return (0);
1095 }
1096 
1097 static int
1098 ac_counters_kstat_update(kstat_t *ksp, int rw)
1099 {
1100         struct kstat_named *ac_counters_data;
1101         struct ac_soft_state *softsp;
1102         uint64_t pic_register;
1103 
1104         ac_counters_data = (struct kstat_named *)ksp->ks_data;
1105         softsp = (struct ac_soft_state *)ksp->ks_private;
1106 
1107         /*
1108          * We need to start/restart the ac_timeout that will
1109          * return the AC counters to hot-plug mode after the
1110          * ac_hot_plug_timeout_interval has expired. We tell
1111          * ac_reset_timeout() whether this is a kstat_read or a
1112          * kstat_write call. If this fails we reject the kstat
1113          * operation.
1114          */
1115         if (ac_reset_timeout(rw) != 0)
1116                 return (-1);
1117 
1118 
1119         if (rw == KSTAT_WRITE) {
1120                 /*
1121                  * Write the %pcr value to the softsp->ac_mccr.
1122                  * This interface does not support writing to the
1123                  * %pic.
1124                  */
1125                 *softsp->ac_mccr =
1126                     (uint32_t)ac_counters_data[0].value.ui64;
1127         } else {
1128                 /*
1129                  * Read %pcr and %pic register values and write them
1130                  * into counters kstat.
1131                  */
1132 
1133                 /* pcr */
1134                 ac_counters_data[0].value.ui64 = *softsp->ac_mccr;
1135 
1136                 pic_register = *softsp->ac_counter;
1137                 /*
1138                  * ac pic register:
1139                  *  (63:32) = pic1
1140                  *  (31:00) = pic0
1141                  */
1142 
1143                 /* pic0 */
1144                 ac_counters_data[1].value.ui64 =
1145                     AC_COUNTER_TO_PIC0(pic_register);
1146                 /* pic1 */
1147                 ac_counters_data[2].value.ui64 =
1148                     AC_COUNTER_TO_PIC1(pic_register);
1149         }
1150         return (0);
1151 }
1152 
1153 /*
1154  * Decode the memory state given to us and plug it into the soft state
1155  */
1156 static void
1157 ac_get_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
1158 {
1159         char    *property = (id == Bank0) ? AC_BANK0_STATUS : AC_BANK1_STATUS;
1160         char    *propval;
1161         int     proplen;
1162         uint64_t memdec = (id == Bank0) ?
1163             *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
1164         uint_t          grp_size;
1165 
1166         softsp->bank[id].busy = 0;
1167         softsp->bank[id].status_change = ddi_get_time();
1168 
1169         if (GRP_SIZE_IS_SET(memdec)) {
1170                 grp_size = GRP_SPANMB(memdec);
1171 
1172                 /* determine the memory bank size (in MB) */
1173                 softsp->bank[id].real_size = softsp->bank[id].use_size =
1174                     (id == Bank0) ? (grp_size / INTLV0(*softsp->ac_memctl)) :
1175                     (grp_size / INTLV1(*softsp->ac_memctl));
1176         } else {
1177                 softsp->bank[id].real_size = softsp->bank[id].use_size = 0;
1178         }
1179 
1180         /*
1181          * decode the memory bank property.  set condition based
1182          * on the values.
1183          */
1184         if (ddi_prop_op(DDI_DEV_T_ANY, softsp->dip, PROP_LEN_AND_VAL_ALLOC,
1185             DDI_PROP_DONTPASS, property, (caddr_t)&propval, &proplen) ==
1186             DDI_PROP_SUCCESS) {
1187                 if (strcmp(propval, AC_BANK_NOMEM) == 0) {
1188                         softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
1189                         softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1190                         softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1191                 } else if (strcmp(propval, AC_BANK_OK) == 0) {
1192                         softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1193                         softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
1194                         softsp->bank[id].condition = SYSC_CFGA_COND_OK;
1195                 } else if (strcmp(propval, AC_BANK_SPARE) == 0) {
1196                         softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1197                         softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1198                         softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1199                 } else if (strcmp(propval, AC_BANK_FAILED) == 0) {
1200                         softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
1201                         softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1202                         softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
1203                 } else {
1204                         cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
1205                             "unknown %smemory state [%s]",
1206                             ddi_get_instance(softsp->dip), softsp->board, id,
1207                             (memdec & AC_MEM_VALID) ? "connected " : "",
1208                             propval);
1209                         if (memdec & AC_MEM_VALID) {
1210                                 softsp->bank[id].rstate =
1211                                     SYSC_CFGA_RSTATE_CONNECTED;
1212                                 softsp->bank[id].ostate =
1213                                     SYSC_CFGA_OSTATE_CONFIGURED;
1214                                 softsp->bank[id].condition =
1215                                     SYSC_CFGA_COND_OK;
1216                         } else {
1217                                 softsp->bank[id].rstate =
1218                                     SYSC_CFGA_RSTATE_DISCONNECTED;
1219                                 softsp->bank[id].ostate =
1220                                     SYSC_CFGA_OSTATE_UNCONFIGURED;
1221                                 softsp->bank[id].condition =
1222                                     SYSC_CFGA_COND_UNUSABLE;
1223                         }
1224                 }
1225 
1226                 kmem_free(propval, proplen);
1227         } else {
1228                 /* we don't have the property, deduce the state of memory */
1229                 if (memdec & AC_MEM_VALID) {
1230                         softsp->bank[id].rstate = SYSC_CFGA_RSTATE_CONNECTED;
1231                         softsp->bank[id].ostate = SYSC_CFGA_OSTATE_CONFIGURED;
1232                         softsp->bank[id].condition = SYSC_CFGA_COND_OK;
1233                 } else {
1234                         /* could be an i/o board... */
1235                         softsp->bank[id].rstate = SYSC_CFGA_RSTATE_EMPTY;
1236                         softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1237                         softsp->bank[id].condition = SYSC_CFGA_COND_UNKNOWN;
1238                 }
1239         }
1240 
1241         /* we assume that all other bank statuses are NOT valid */
1242         if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1243                 if ((memdec & AC_MEM_VALID) != 0) {
1244                         uint64_t        base_pa;
1245 
1246                         ASSERT((*softsp->ac_memctl & AC_CSR_REFEN) != 0);
1247                         /* register existence in the memloc database */
1248                         base_pa = GRP_REALBASE(memdec);
1249                         fhc_add_memloc(softsp->board, base_pa, grp_size);
1250                 }
1251         }
1252 }
1253 
1254 static void
1255 ac_eval_memory_status(struct ac_soft_state *softsp, enum ac_bank_id id)
1256 {
1257         uint64_t memdec = (id == Bank0) ?
1258             *(softsp->ac_memdecode0) : *(softsp->ac_memdecode1);
1259         uint64_t        base_pa;
1260 
1261         /*
1262          * Downgrade the status of any bank that did not get
1263          * programmed.
1264          */
1265         if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED &&
1266             softsp->bank[id].ostate == SYSC_CFGA_OSTATE_UNCONFIGURED &&
1267             (memdec & AC_MEM_VALID) == 0) {
1268                 cmn_err(CE_WARN, "ac%d: board %d, bank %d: "
1269                     "spare memory bank not valid - it was ",
1270                     ddi_get_instance(softsp->dip), softsp->board, id);
1271                 cmn_err(CE_WARN, "misconfigured by the system "
1272                     "firmware.  Disabling...");
1273                 softsp->bank[id].rstate = SYSC_CFGA_RSTATE_DISCONNECTED;
1274                 softsp->bank[id].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED;
1275                 softsp->bank[id].condition = SYSC_CFGA_COND_UNUSABLE;
1276         }
1277         /*
1278          * Log a message about good banks.
1279          */
1280         if (softsp->bank[id].rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1281                 ASSERT((memdec & AC_MEM_VALID) != 0);
1282                 base_pa = GRP_REALBASE(memdec);
1283 
1284                 cmn_err(CE_CONT, "?ac%d board %d bank %d: "
1285                     "base 0x%" PRIx64 " size %dmb rstate %d "
1286                     "ostate %d condition %d\n",
1287                     ddi_get_instance(softsp->dip),
1288                     softsp->board, id, base_pa, softsp->bank[id].real_size,
1289                     softsp->bank[id].rstate, softsp->bank[id].ostate,
1290                     softsp->bank[id].condition);
1291         }
1292 }
1293 
1294 /*ARGSUSED*/
1295 static void
1296 ac_ecache_flush(uint64_t a, uint64_t b)
1297 {
1298         cpu_flush_ecache();
1299 }
1300 
1301 static char *
1302 ac_ostate_typestr(sysc_cfga_ostate_t ostate, ac_audit_evt_t event)
1303 {
1304         char *type_str;
1305 
1306         switch (ostate) {
1307         case SYSC_CFGA_OSTATE_UNCONFIGURED:
1308                 switch (event) {
1309                 case AC_AUDIT_OSTATE_UNCONFIGURE:
1310                         type_str = "unconfiguring";
1311                         break;
1312                 case AC_AUDIT_OSTATE_SUCCEEDED:
1313                 case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1314                         type_str = "unconfigured";
1315                         break;
1316                 default:
1317                         type_str = "unconfigure?";
1318                         break;
1319                 }
1320                 break;
1321         case SYSC_CFGA_OSTATE_CONFIGURED:
1322                 switch (event) {
1323                 case AC_AUDIT_OSTATE_CONFIGURE:
1324                         type_str = "configuring";
1325                         break;
1326                 case AC_AUDIT_OSTATE_SUCCEEDED:
1327                 case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
1328                         type_str = "configured";
1329                         break;
1330                 default:
1331                         type_str = "configure?";
1332                         break;
1333                 }
1334                 break;
1335 
1336         default:
1337                 type_str = "undefined occupant state";
1338                 break;
1339         }
1340         return (type_str);
1341 }
1342 
1343 static void
1344 ac_policy_audit_messages(ac_audit_evt_t event, ac_cfga_pkt_t *pkt)
1345 {
1346         struct ac_soft_state *softsp = pkt->softsp;
1347 
1348         switch (event) {
1349                 case AC_AUDIT_OSTATE_CONFIGURE:
1350                         cmn_err(CE_NOTE,
1351                             "%s memory bank %d in slot %d",
1352                             ac_ostate_typestr(SYSC_CFGA_OSTATE_CONFIGURED,
1353                             event), pkt->bank,
1354                             softsp->board);
1355                         break;
1356                 case AC_AUDIT_OSTATE_UNCONFIGURE:
1357                         cmn_err(CE_NOTE,
1358                             "%s memory bank %d in slot %d",
1359                             ac_ostate_typestr(
1360                             SYSC_CFGA_OSTATE_UNCONFIGURED,
1361                             event), pkt->bank,
1362                             softsp->board);
1363                         break;
1364                 case AC_AUDIT_OSTATE_SUCCEEDED:
1365                         cmn_err(CE_NOTE,
1366                             "memory bank %d in slot %d is %s",
1367                             pkt->bank, softsp->board,
1368                             ac_ostate_typestr(
1369                             softsp->bank[pkt->bank].ostate,
1370                             event));
1371                         break;
1372                 case AC_AUDIT_OSTATE_CONFIGURE_FAILED:
1373                         cmn_err(CE_NOTE,
1374                         "memory bank %d in slot %d not %s",
1375                             pkt->bank,
1376                             softsp->board,
1377                             ac_ostate_typestr(
1378                             SYSC_CFGA_OSTATE_CONFIGURED,
1379                             event));
1380                         break;
1381                 case AC_AUDIT_OSTATE_UNCONFIGURE_FAILED:
1382                         cmn_err(CE_NOTE,
1383                             "memory bank %d in slot %d not %s",
1384                             pkt->bank,
1385                             softsp->board,
1386                             ac_ostate_typestr(
1387                             SYSC_CFGA_OSTATE_UNCONFIGURED,
1388                             event));
1389                         break;
1390                 default:
1391                         cmn_err(CE_NOTE,
1392                             "unknown audit of memory bank %d in slot %d",
1393                             pkt->bank, softsp->board);
1394                         break;
1395         }
1396 }
1397 
1398 #include <vm/page.h>
1399 #include <vm/hat.h>
1400 
1401 static int
1402 ac_mem_exercise(ac_cfga_pkt_t *pkt, int flag)
1403 {
1404         struct ac_mem_info *mem_info;
1405         pfn_t base;
1406         pgcnt_t npgs;
1407 
1408         mem_info = &pkt->softsp->bank[pkt->bank];
1409         if (mem_info->rstate == SYSC_CFGA_RSTATE_CONNECTED) {
1410                 uint64_t base_pa, bank_size;
1411                 uint64_t decode;
1412 
1413                 decode = (pkt->bank == Bank0) ?
1414                     *pkt->softsp->ac_memdecode0 : *pkt->softsp->ac_memdecode1;
1415                 base_pa = GRP_REALBASE(decode);
1416                 bank_size = GRP_UK2SPAN(decode);
1417 
1418                 base = base_pa >> PAGESHIFT;
1419                 npgs = bank_size >> PAGESHIFT;
1420         } else {
1421                 base = 0;
1422                 npgs = 0;
1423         }
1424         switch (pkt->cmd_cfga.arg) {
1425         case AC_MEMX_RELOCATE_ALL: {
1426                 pfn_t pfn, pglim;
1427                 struct ac_memx_relocate_stats rstat;
1428 
1429                 if (npgs == 0 ||
1430                     mem_info->ostate != SYSC_CFGA_OSTATE_CONFIGURED) {
1431                         return (EINVAL);
1432                 }
1433                 if (mem_info->busy != FALSE) {
1434                         return (EBUSY);
1435                 }
1436                 bzero(&rstat, sizeof (rstat));
1437                 rstat.base = (uint_t)base;
1438                 rstat.npgs = (uint_t)npgs;
1439                 pglim = base + npgs;
1440                 for (pfn = base; pfn < pglim; pfn++) {
1441                         page_t *pp, *pp_repl;
1442 
1443                 retry:
1444                         pp = page_numtopp_nolock(pfn);
1445                         if (pp != NULL) {
1446                                 if (!page_trylock(pp, SE_EXCL)) {
1447                                         pp = NULL;
1448                                         rstat.nolock++;
1449                                 }
1450                                 if (pp != NULL && page_pptonum(pp) != pfn) {
1451                                         page_unlock(pp);
1452                                         goto retry;
1453                                 }
1454                         } else {
1455                                 rstat.nopaget++;
1456                         }
1457                         if (pp != NULL && PP_ISFREE(pp)) {
1458                                 page_unlock(pp);
1459                                 rstat.isfree++;
1460                                 pp = NULL;
1461                         }
1462                         if (pp != NULL) {
1463                                 spgcnt_t npgs;
1464                                 int result;
1465 
1466                                 pp_repl = NULL;
1467                                 result = page_relocate(&pp, &pp_repl, 1, 1,
1468                                     &npgs, NULL);
1469                                 if (result == 0) {
1470                                         while (npgs-- > 0) {
1471                                                 page_t *tpp;
1472 
1473                                                 ASSERT(pp_repl != NULL);
1474                                                 tpp = pp_repl;
1475                                                 page_sub(&pp_repl, tpp);
1476                                                 page_unlock(tpp);
1477                                         }
1478 
1479                                         rstat.reloc++;
1480                                 } else {
1481                                         page_unlock(pp);
1482                                         rstat.noreloc++;
1483                                 }
1484                         }
1485                 }
1486                 if (pkt->cmd_cfga.private != NULL && ddi_copyout(&rstat,
1487                     pkt->cmd_cfga.private, sizeof (rstat), flag) != 0)
1488                         return (EFAULT);
1489                 return (DDI_SUCCESS);
1490         }
1491 
1492         default:
1493                 return (EINVAL);
1494         }
1495 }
1496 
1497 static int
1498 ac_reset_timeout(int rw)
1499 {
1500         mutex_enter(&ac_hot_plug_mode_mutex);
1501 
1502         if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
1503             (rw == KSTAT_READ)) {
1504                 /*
1505                  * We are in hot-plug mode. A kstat_read is not
1506                  * going to affect this. return 0 to allow the
1507                  * kstat_read to continue.
1508                  */
1509                 mutex_exit(&ac_hot_plug_mode_mutex);
1510                 return (0);
1511 
1512         } else if ((ac_hot_plug_timeout == (timeout_id_t)NULL) &&
1513             (rw == KSTAT_WRITE)) {
1514                 /*
1515                  * There are no pending timeouts and we have received a
1516                  * kstat_write request so we must be transitioning
1517                  * from "hot-plug" mode to non "hot-plug" mode.
1518                  * Try to lock all boards before allowing the kstat_write.
1519                  */
1520                 if (ac_enter_transition() == TRUE)
1521                         fhc_bdlist_unlock();
1522                 else {
1523                         /* cannot lock boards so fail */
1524                         mutex_exit(&ac_hot_plug_mode_mutex);
1525                         return (-1);
1526                 }
1527 
1528                 /*
1529                  * We need to display a Warning about hot-plugging any
1530                  * boards. This message is only needed when we are
1531                  * transitioning out of "hot-plug" mode.
1532                  */
1533                 cmn_err(CE_WARN, "This machine is being taken out of "
1534                     "hot-plug mode.");
1535                 cmn_err(CE_CONT, "Do not attempt to hot-plug boards "
1536                     "or power supplies in this system until further notice.");
1537 
1538         } else if (ac_hot_plug_timeout != (timeout_id_t)NULL) {
1539                 /*
1540                  * There is a pending timeout so we must already be
1541                  * in non "hot-plug" mode. It doesn't matter if the
1542                  * kstat request is a read or a write.
1543                  *
1544                  * We need to cancel the existing timeout.
1545                  */
1546                 (void) untimeout(ac_hot_plug_timeout);
1547                 ac_hot_plug_timeout = NULL;
1548         }
1549 
1550         /*
1551          * create a new timeout.
1552          */
1553         ac_hot_plug_timeout = timeout(ac_timeout, NULL,
1554             drv_sectohz(ac_hot_plug_timeout_interval));
1555 
1556         mutex_exit(&ac_hot_plug_mode_mutex);
1557         return (0);
1558 }
1559 
1560 static void
1561 ac_timeout(void *arg)
1562 {
1563         struct ac_soft_state *softsp;
1564         fhc_bd_t        *board;
1565 
1566 #ifdef lint
1567         arg = arg;
1568 #endif /* lint */
1569 
1570         ac_hot_plug_timeout = (timeout_id_t)NULL;
1571 
1572         (void) fhc_bdlist_lock(-1);
1573 
1574         /*
1575          * Foreach ac in the board list we need to
1576          * re-program the pcr into "hot-plug" mode.
1577          * We also program the pic register with the
1578          * bus pause timing
1579          */
1580         board = fhc_bd_first();
1581         while (board != NULL) {
1582                 softsp = board->ac_softsp;
1583                 if (softsp == NULL) {
1584                         /*
1585                          * This board must not have an AC.
1586                          * Skip it and move on.
1587                          */
1588                         board = fhc_bd_next(board);
1589                         continue;
1590                 }
1591                 /* program the pcr into hot-plug mode */
1592                 *softsp->ac_mccr = AC_CLEAR_PCR(*softsp->ac_mccr);
1593                 *softsp->ac_mccr = AC_SET_HOT_PLUG(*softsp->ac_mccr);
1594 
1595                 /* program the pic with the bus pause time value */
1596                 *softsp->ac_counter = AC_SET_PIC_BUS_PAUSE(softsp->board);
1597 
1598                 /* get the next board */
1599                 board = fhc_bd_next(board);
1600         }
1601 
1602         ac_exit_transition();
1603 
1604         fhc_bdlist_unlock();
1605 
1606         /*
1607          * It is now safe to start hot-plugging again. We need
1608          * to display a message.
1609          */
1610         cmn_err(CE_NOTE, "This machine is now in hot-plug mode.");
1611         cmn_err(CE_CONT, "Board and power supply hot-plug operations "
1612             "can be resumed.");
1613 }
1614 
1615 /*
1616  * This function will acquire the lock and set the in_transition
1617  * bit for all the slots.  If the slots are being used,
1618  * we return FALSE; else set in_transition and return TRUE.
1619  */
1620 static int
1621 ac_enter_transition(void)
1622 {
1623         fhc_bd_t        *list;
1624         sysc_cfga_stat_t *sysc_stat_lk;
1625 
1626         /* mutex lock the structure */
1627         (void) fhc_bdlist_lock(-1);
1628 
1629         list = fhc_bd_clock();
1630 
1631         /* change the in_transition bit */
1632         sysc_stat_lk = &list->sc;
1633         if (sysc_stat_lk->in_transition == TRUE) {
1634                 fhc_bdlist_unlock();
1635                 return (FALSE);
1636         } else {
1637                 sysc_stat_lk->in_transition = TRUE;
1638                 return (TRUE);
1639         }
1640 }
1641 
1642 /*
1643  * clear the in_transition bit for all the slots.
1644  */
1645 static void
1646 ac_exit_transition(void)
1647 {
1648         fhc_bd_t        *list;
1649         sysc_cfga_stat_t *sysc_stat_lk;
1650 
1651         ASSERT(fhc_bdlist_locked());
1652 
1653         list = fhc_bd_clock();
1654 
1655         sysc_stat_lk = &list->sc;
1656         ASSERT(sysc_stat_lk->in_transition == TRUE);
1657         sysc_stat_lk->in_transition = FALSE;
1658 }