103831d35Sstevel /*
203831d35Sstevel * CDDL HEADER START
303831d35Sstevel *
403831d35Sstevel * The contents of this file are subject to the terms of the
5*cbcdac8fSmb91622 * Common Development and Distribution License (the "License").
6*cbcdac8fSmb91622 * You may not use this file except in compliance with the License.
703831d35Sstevel *
803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel * See the License for the specific language governing permissions
1103831d35Sstevel * and limitations under the License.
1203831d35Sstevel *
1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel *
1903831d35Sstevel * CDDL HEADER END
2003831d35Sstevel */
2103831d35Sstevel /*
22*cbcdac8fSmb91622 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2303831d35Sstevel * Use is subject to license terms.
2403831d35Sstevel */
2503831d35Sstevel
2603831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI"
2703831d35Sstevel
2803831d35Sstevel #include <sys/types.h>
2903831d35Sstevel #include <sys/serengeti.h>
3003831d35Sstevel #include <sys/errno.h>
3103831d35Sstevel #include <sys/systm.h>
3203831d35Sstevel #include <sys/cmn_err.h>
33*cbcdac8fSmb91622 #include <sys/cheetahregs.h>
34*cbcdac8fSmb91622 #include <sys/cpuvar.h>
3503831d35Sstevel
3603831d35Sstevel /*
3703831d35Sstevel * When an ECC error occurs on an E$ DIMM, the error handling code requests a
3803831d35Sstevel * unum to provide a human-readable physical location to the part that
3903831d35Sstevel * experienced the error.
4003831d35Sstevel *
4103831d35Sstevel * Previously, on Serengeti and LW8, a prom call was made to get this
4203831d35Sstevel * information. However, calling COBP to do a simple string format is
4303831d35Sstevel * inefficient. All the necessary information is now kept here.
4403831d35Sstevel *
4503831d35Sstevel * Since this data is now kept in two places (COBP and here), care must be
4603831d35Sstevel * taken so that the two locations are kept the same. Any changes to the
4703831d35Sstevel * jnumber array will require a change to COBP code so that the two arrays
4803831d35Sstevel * match. Any changes to the unum string format will require changes in both
4903831d35Sstevel * the COBP code (to match the code here) and plat_ecc_unum.c (to read the
5003831d35Sstevel * new format). These changes should not be necessary, except to reflect a
5103831d35Sstevel * new cpu or board type.
5203831d35Sstevel */
5303831d35Sstevel
5403831d35Sstevel /*
5503831d35Sstevel * The following array holds the jnumbers for Ecache DIMMs. The first index
5603831d35Sstevel * is the proc position on the board (0 through 3) and the second index is
5703831d35Sstevel * the DIMM number (0 or 1).
5803831d35Sstevel */
5903831d35Sstevel static int sg_j_number[SG_MAX_CMPS_PER_BD][SG_NUM_ECACHE_DIMMS_PER_CPU] = {
6003831d35Sstevel { 4400, 4300 },
6103831d35Sstevel { 5400, 5300 },
6203831d35Sstevel { 6400, 6300 },
6303831d35Sstevel { 7400, 7300 }
6403831d35Sstevel };
6503831d35Sstevel
6603831d35Sstevel /*
6703831d35Sstevel * Generate the unum for the specified cpuid and physical address. Put the
6803831d35Sstevel * unum in buf, which is of size buflen. Return the length of the string in
6903831d35Sstevel * lenp.
7003831d35Sstevel *
7103831d35Sstevel * Return 0 if successful, and an error number otherwise.
7203831d35Sstevel */
7303831d35Sstevel int
sg_get_ecacheunum(int cpuid,uint64_t physaddr,char * buf,uint_t buflen,int * lenp)7403831d35Sstevel sg_get_ecacheunum(int cpuid, uint64_t physaddr, char *buf, uint_t buflen,
7503831d35Sstevel int *lenp)
7603831d35Sstevel {
7703831d35Sstevel int node = SG_PORTID_TO_NODEID(cpuid);
7803831d35Sstevel int board = SG_CPU_BD_PORTID_TO_BD_NUM(cpuid);
7903831d35Sstevel int proc = SG_PORTID_TO_CPU_POSN(cpuid);
80*cbcdac8fSmb91622 int dimm;
8103831d35Sstevel
8203831d35Sstevel /*
8303831d35Sstevel * node and dimm will always be valid. board and proc may be -1 if
8403831d35Sstevel * an invalid cpuid is passed in.
8503831d35Sstevel */
8603831d35Sstevel if ((board == -1) || (proc == -1)) {
8703831d35Sstevel return (EINVAL);
8803831d35Sstevel }
8903831d35Sstevel
90*cbcdac8fSmb91622 /* Find the DIMM number (0 or 1) based on the value of physaddr bit 4 */
91*cbcdac8fSmb91622 if (IS_PANTHER(cpunodes[CPU->cpu_id].implementation) ||
92*cbcdac8fSmb91622 IS_JAGUAR(cpunodes[CPU->cpu_id].implementation))
93*cbcdac8fSmb91622 dimm = (physaddr & SG_ECACHE_DIMM_MASK) ? 0 : 1;
94*cbcdac8fSmb91622 else
95*cbcdac8fSmb91622 dimm = (physaddr & SG_ECACHE_DIMM_MASK) ? 1 : 0;
96*cbcdac8fSmb91622
9703831d35Sstevel *lenp = snprintf(buf, buflen, "/N%d/SB%d/P%d/E%d J%d",
9803831d35Sstevel node, board, proc, dimm, sg_j_number[proc][dimm]);
9903831d35Sstevel
10003831d35Sstevel return (0);
10103831d35Sstevel }
102