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 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