xref: /titanic_50/usr/src/uts/sun4u/io/mem_cache.c (revision 0b5ce10aee80822ecc7df77df92a5e24078ba196)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Driver to retire/unretire L2/L3 cachelines on panther
28  */
29 #include <sys/types.h>
30 #include <sys/types32.h>
31 #include <sys/time.h>
32 #include <sys/errno.h>
33 #include <sys/cmn_err.h>
34 #include <sys/param.h>
35 #include <sys/modctl.h>
36 #include <sys/conf.h>
37 #include <sys/open.h>
38 #include <sys/stat.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
41 #include <sys/file.h>
42 #include <sys/cpuvar.h>
43 #include <sys/x_call.h>
44 #include <sys/cheetahregs.h>
45 #include <sys/mem_cache.h>
46 #include <sys/mem_cache_ioctl.h>
47 
48 extern int	retire_l2(uint64_t, uint64_t);
49 extern int	retire_l2_alternate(uint64_t, uint64_t);
50 extern int	unretire_l2(uint64_t, uint64_t);
51 extern int	unretire_l2_alternate(uint64_t, uint64_t);
52 extern int	retire_l3(uint64_t, uint64_t);
53 extern int	retire_l3_alternate(uint64_t, uint64_t);
54 extern int	unretire_l3(uint64_t, uint64_t);
55 extern int	unretire_l3_alternate(uint64_t, uint64_t);
56 
57 extern void	retire_l2_start(uint64_t, uint64_t);
58 extern void	retire_l2_end(uint64_t, uint64_t);
59 extern void	unretire_l2_start(uint64_t, uint64_t);
60 extern void	unretire_l2_end(uint64_t, uint64_t);
61 extern void	retire_l3_start(uint64_t, uint64_t);
62 extern void	retire_l3_end(uint64_t, uint64_t);
63 extern void	unretire_l3_start(uint64_t, uint64_t);
64 extern void	unretire_l3_end(uint64_t, uint64_t);
65 
66 extern void	get_ecache_dtags_tl1(uint64_t, ch_cpu_logout_t *);
67 extern void	get_l2_tag_tl1(uint64_t, uint64_t);
68 extern void	get_l3_tag_tl1(uint64_t, uint64_t);
69 extern const int _ncpu;
70 
71 /* Macro for putting 64-bit onto stack as two 32-bit ints */
72 #define	PRTF_64_TO_32(x)	(uint32_t)((x)>>32), (uint32_t)(x)
73 
74 
75 uint_t l2_flush_retries_done = 0;
76 int mem_cache_debug = 0x0;
77 uint64_t pattern = 0;
78 uint32_t retire_failures = 0;
79 #ifdef DEBUG
80 int	inject_anonymous_tag_error = 0;
81 int32_t last_error_injected_way = 0;
82 uint8_t last_error_injected_bit = 0;
83 int32_t last_l3tag_error_injected_way;
84 uint8_t last_l3tag_error_injected_bit;
85 int32_t last_l2tag_error_injected_way;
86 uint8_t last_l2tag_error_injected_bit;
87 #endif
88 
89 /* dev_ops and cb_ops entry point function declarations */
90 static int	mem_cache_attach(dev_info_t *, ddi_attach_cmd_t);
91 static int	mem_cache_detach(dev_info_t *, ddi_detach_cmd_t);
92 static int	mem_cache_getinfo(dev_info_t *, ddi_info_cmd_t, void *,
93 				void **);
94 static int	mem_cache_open(dev_t *, int, int, cred_t *);
95 static int	mem_cache_close(dev_t, int, int, cred_t *);
96 static int	mem_cache_ioctl_ops(int, int, cache_info_t *);
97 static int	mem_cache_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
98 
99 struct cb_ops mem_cache_cb_ops = {
100 	mem_cache_open,
101 	mem_cache_close,
102 	nodev,
103 	nodev,
104 	nodev,			/* dump */
105 	nodev,
106 	nodev,
107 	mem_cache_ioctl,
108 	nodev,			/* devmap */
109 	nodev,
110 	ddi_segmap,		/* segmap */
111 	nochpoll,
112 	ddi_prop_op,
113 	NULL,			/* for STREAMS drivers */
114 	D_NEW | D_MP		/* driver compatibility flag */
115 };
116 
117 static struct dev_ops mem_cache_dev_ops = {
118 	DEVO_REV,		/* driver build version */
119 	0,			/* device reference count */
120 	mem_cache_getinfo,
121 	nulldev,
122 	nulldev,		/* probe */
123 	mem_cache_attach,
124 	mem_cache_detach,
125 	nulldev,		/* reset */
126 	&mem_cache_cb_ops,
127 	(struct bus_ops *)NULL,
128 	nulldev,			/* power */
129 	ddi_quiesce_not_needed,		/* quiesce */
130 };
131 
132 /*
133  * Soft state
134  */
135 struct mem_cache_softc {
136 	dev_info_t	*dip;
137 	kmutex_t	mutex;
138 };
139 #define	getsoftc(inst)	((struct mem_cache_softc *)ddi_get_soft_state(statep,\
140 			(inst)))
141 
142 /* module configuration stuff */
143 static void *statep;
144 extern struct mod_ops mod_driverops;
145 
146 static struct modldrv modldrv = {
147 	&mod_driverops,
148 	"mem_cache_driver (08/01/30) ",
149 	&mem_cache_dev_ops
150 };
151 
152 static struct modlinkage modlinkage = {
153 	MODREV_1,
154 	&modldrv,
155 	0
156 };
157 
158 extern const int _ncpu; /* Pull the kernel's global _ncpu definition */
159 
160 int
161 _init(void)
162 {
163 	int e;
164 
165 	if (e = ddi_soft_state_init(&statep, sizeof (struct mem_cache_softc),
166 	    MAX_MEM_CACHE_INSTANCES)) {
167 		return (e);
168 	}
169 
170 	if ((e = mod_install(&modlinkage)) != 0)
171 		ddi_soft_state_fini(&statep);
172 
173 	return (e);
174 }
175 
176 int
177 _fini(void)
178 {
179 	int e;
180 
181 	if ((e = mod_remove(&modlinkage)) != 0)
182 		return (e);
183 
184 	ddi_soft_state_fini(&statep);
185 
186 	return (DDI_SUCCESS);
187 }
188 
189 int
190 _info(struct modinfo *modinfop)
191 {
192 	return (mod_info(&modlinkage, modinfop));
193 }
194 
195 /*ARGSUSED*/
196 static int
197 mem_cache_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
198 {
199 	int	inst;
200 	int	retval = DDI_SUCCESS;
201 	struct mem_cache_softc *softc;
202 
203 	inst = getminor((dev_t)arg);
204 
205 	switch (cmd) {
206 	case DDI_INFO_DEVT2DEVINFO:
207 		if ((softc = getsoftc(inst)) == NULL) {
208 			*result = (void *)NULL;
209 			retval = DDI_FAILURE;
210 		} else
211 			*result = (void *)softc->dip;
212 		break;
213 
214 	case DDI_INFO_DEVT2INSTANCE:
215 		*result = (void *)((uintptr_t)inst);
216 		break;
217 
218 	default:
219 		retval = DDI_FAILURE;
220 	}
221 
222 	return (retval);
223 }
224 
225 static int
226 mem_cache_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
227 {
228 	int inst;
229 	struct mem_cache_softc *softc = NULL;
230 	char name[80];
231 
232 	switch (cmd) {
233 	case DDI_ATTACH:
234 		inst = ddi_get_instance(dip);
235 		if (inst >= MAX_MEM_CACHE_INSTANCES) {
236 			cmn_err(CE_WARN, "attach failed, too many instances\n");
237 			return (DDI_FAILURE);
238 		}
239 		(void) sprintf(name, MEM_CACHE_DRIVER_NAME"%d", inst);
240 		if (ddi_create_priv_minor_node(dip, name,
241 		    S_IFCHR,
242 		    inst,
243 		    DDI_PSEUDO,
244 		    0, NULL, "all", 0640) ==
245 		    DDI_FAILURE) {
246 			ddi_remove_minor_node(dip, NULL);
247 			return (DDI_FAILURE);
248 		}
249 
250 		/* Allocate a soft state structure for this instance */
251 		if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS) {
252 			cmn_err(CE_WARN, " ddi_soft_state_zalloc() failed "
253 			    "for inst %d\n", inst);
254 			goto attach_failed;
255 		}
256 
257 		/* Setup soft state */
258 		softc = getsoftc(inst);
259 		softc->dip = dip;
260 		mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL);
261 
262 		/* Create main environmental node */
263 		ddi_report_dev(dip);
264 
265 		return (DDI_SUCCESS);
266 
267 	case DDI_RESUME:
268 		return (DDI_SUCCESS);
269 
270 	default:
271 		return (DDI_FAILURE);
272 	}
273 
274 attach_failed:
275 
276 	/* Free soft state, if allocated. remove minor node if added earlier */
277 	if (softc)
278 		ddi_soft_state_free(statep, inst);
279 
280 	ddi_remove_minor_node(dip, NULL);
281 
282 	return (DDI_FAILURE);
283 }
284 
285 static int
286 mem_cache_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
287 {
288 	int inst;
289 	struct mem_cache_softc *softc;
290 
291 	switch (cmd) {
292 	case DDI_DETACH:
293 		inst = ddi_get_instance(dip);
294 		if ((softc = getsoftc(inst)) == NULL)
295 			return (ENXIO);
296 
297 		/* Free the soft state and remove minor node added earlier */
298 		mutex_destroy(&softc->mutex);
299 		ddi_soft_state_free(statep, inst);
300 		ddi_remove_minor_node(dip, NULL);
301 		return (DDI_SUCCESS);
302 
303 	case DDI_SUSPEND:
304 		return (DDI_SUCCESS);
305 
306 	default:
307 		return (DDI_FAILURE);
308 	}
309 }
310 
311 /*ARGSUSED*/
312 static int
313 mem_cache_open(dev_t *devp, int flag, int otyp, cred_t *credp)
314 {
315 	int	inst = getminor(*devp);
316 
317 	return (getsoftc(inst) == NULL ? ENXIO : 0);
318 }
319 
320 /*ARGSUSED*/
321 static int
322 mem_cache_close(dev_t dev, int flag, int otyp, cred_t *credp)
323 {
324 	int	inst = getminor(dev);
325 
326 	return (getsoftc(inst) == NULL ? ENXIO : 0);
327 }
328 
329 static char *tstate_to_desc[] = {
330 	"Invalid",			/* 0 */
331 	"Shared",			/* 1 */
332 	"Exclusive",			/* 2 */
333 	"Owner",			/* 3 */
334 	"Modified",			/* 4 */
335 	"NA",				/* 5 */
336 	"Owner/Shared",			/* 6 */
337 	"Reserved(7)",			/* 7 */
338 };
339 
340 static char *
341 tag_state_to_desc(uint8_t tagstate)
342 {
343 	return (tstate_to_desc[tagstate & CH_ECSTATE_MASK]);
344 }
345 
346 void
347 print_l2_tag(uint64_t tag_addr, uint64_t l2_tag)
348 {
349 	uint64_t l2_subaddr;
350 	uint8_t	l2_state;
351 
352 	l2_subaddr = PN_L2TAG_TO_PA(l2_tag);
353 	l2_subaddr |= (tag_addr & PN_L2_INDEX_MASK);
354 
355 	l2_state = (l2_tag & CH_ECSTATE_MASK);
356 	cmn_err(CE_CONT,
357 	    "PA=0x%08x.%08x E$tag 0x%08x.%08x E$state %s\n",
358 	    PRTF_64_TO_32(l2_subaddr),
359 	    PRTF_64_TO_32(l2_tag),
360 	    tag_state_to_desc(l2_state));
361 }
362 
363 void
364 print_l2cache_line(ch_cpu_logout_t *clop)
365 {
366 	uint64_t l2_subaddr;
367 	int i, offset;
368 	uint8_t	way, l2_state;
369 	ch_ec_data_t *ecp;
370 
371 
372 	for (way = 0; way < PN_CACHE_NWAYS; way++) {
373 		ecp = &clop->clo_data.chd_l2_data[way];
374 		l2_subaddr = PN_L2TAG_TO_PA(ecp->ec_tag);
375 		l2_subaddr |= (ecp->ec_idx & PN_L2_INDEX_MASK);
376 
377 		l2_state = (ecp->ec_tag & CH_ECSTATE_MASK);
378 		cmn_err(CE_CONT,
379 		    "\nWAY = %d index = 0x%08x PA=0x%08x.%08x\n"
380 		    "E$tag 0x%08x.%08x E$state %s",
381 		    way, (uint32_t)ecp->ec_idx, PRTF_64_TO_32(l2_subaddr),
382 		    PRTF_64_TO_32(ecp->ec_tag),
383 		    tag_state_to_desc(l2_state));
384 		/*
385 		 * Dump out Ecache subblock data captured.
386 		 * For Cheetah, we need to compute the ECC for each 16-byte
387 		 * chunk and compare it with the captured chunk ECC to figure
388 		 * out which chunk is bad.
389 		 */
390 		for (i = 0; i < (CH_ECACHE_SUBBLK_SIZE/16); i++) {
391 			ec_data_elm_t *ecdptr;
392 			uint64_t d_low, d_high;
393 			uint32_t ecc;
394 			int l2_data_idx = (i/2);
395 
396 			offset = i * 16;
397 			ecdptr = &clop->clo_data.chd_l2_data[way].ec_data
398 			    [l2_data_idx];
399 			if ((i & 1) == 0) {
400 				ecc = (ecdptr->ec_eccd >> 9) & 0x1ff;
401 				d_high = ecdptr->ec_d8[0];
402 				d_low  = ecdptr->ec_d8[1];
403 			} else {
404 				ecc = ecdptr->ec_eccd & 0x1ff;
405 				d_high = ecdptr->ec_d8[2];
406 				d_low  = ecdptr->ec_d8[3];
407 			}
408 
409 			cmn_err(CE_CONT,
410 			    "\nE$Data (0x%02x) 0x%08x.%08x 0x%08x.%08x"
411 			    " ECC 0x%03x",
412 			    offset, PRTF_64_TO_32(d_high),
413 			    PRTF_64_TO_32(d_low), ecc);
414 		}
415 	}	/* end of for way loop */
416 }
417 
418 void
419 print_ecache_line(ch_cpu_logout_t *clop)
420 {
421 	uint64_t ec_subaddr;
422 	int i, offset;
423 	uint8_t	way, ec_state;
424 	ch_ec_data_t *ecp;
425 
426 
427 	for (way = 0; way < PN_CACHE_NWAYS; way++) {
428 		ecp = &clop->clo_data.chd_ec_data[way];
429 		ec_subaddr = PN_L3TAG_TO_PA(ecp->ec_tag);
430 		ec_subaddr |= (ecp->ec_idx & PN_L3_TAG_RD_MASK);
431 
432 		ec_state = (ecp->ec_tag & CH_ECSTATE_MASK);
433 		cmn_err(CE_CONT,
434 		    "\nWAY = %d index = 0x%08x PA=0x%08x.%08x\n"
435 		    "E$tag 0x%08x.%08x E$state %s",
436 		    way, (uint32_t)ecp->ec_idx, PRTF_64_TO_32(ec_subaddr),
437 		    PRTF_64_TO_32(ecp->ec_tag),
438 		    tag_state_to_desc(ec_state));
439 		/*
440 		 * Dump out Ecache subblock data captured.
441 		 * For Cheetah, we need to compute the ECC for each 16-byte
442 		 * chunk and compare it with the captured chunk ECC to figure
443 		 * out which chunk is bad.
444 		 */
445 		for (i = 0; i < (CH_ECACHE_SUBBLK_SIZE/16); i++) {
446 			ec_data_elm_t *ecdptr;
447 			uint64_t d_low, d_high;
448 			uint32_t ecc;
449 			int ec_data_idx = (i/2);
450 
451 			offset = i * 16;
452 			ecdptr =
453 			    &clop->clo_data.chd_ec_data[way].ec_data
454 			    [ec_data_idx];
455 			if ((i & 1) == 0) {
456 				ecc = (ecdptr->ec_eccd >> 9) & 0x1ff;
457 				d_high = ecdptr->ec_d8[0];
458 				d_low  = ecdptr->ec_d8[1];
459 			} else {
460 				ecc = ecdptr->ec_eccd & 0x1ff;
461 				d_high = ecdptr->ec_d8[2];
462 				d_low  = ecdptr->ec_d8[3];
463 			}
464 
465 			cmn_err(CE_CONT,
466 			    "\nE$Data (0x%02x) 0x%08x.%08x 0x%08x.%08x"
467 			    " ECC 0x%03x",
468 			    offset, PRTF_64_TO_32(d_high),
469 			    PRTF_64_TO_32(d_low), ecc);
470 		}
471 	}
472 }
473 
474 static boolean_t
475 tag_addr_collides(uint64_t tag_addr, cache_id_t type,
476     retire_func_t start_of_func, retire_func_t end_of_func)
477 {
478 	uint64_t start_paddr, end_paddr;
479 	char *type_str;
480 
481 	start_paddr = va_to_pa((void *)start_of_func);
482 	end_paddr = va_to_pa((void *)end_of_func);
483 	switch (type) {
484 		case L2_CACHE_TAG:
485 		case L2_CACHE_DATA:
486 			tag_addr &= PN_L2_INDEX_MASK;
487 			start_paddr &= PN_L2_INDEX_MASK;
488 			end_paddr &= PN_L2_INDEX_MASK;
489 			type_str = "L2:";
490 			break;
491 		case L3_CACHE_TAG:
492 		case L3_CACHE_DATA:
493 			tag_addr &= PN_L3_TAG_RD_MASK;
494 			start_paddr &= PN_L3_TAG_RD_MASK;
495 			end_paddr &= PN_L3_TAG_RD_MASK;
496 			type_str = "L3:";
497 			break;
498 		default:
499 			/*
500 			 * Should never reach here.
501 			 */
502 			ASSERT(0);
503 			return (B_FALSE);
504 	}
505 	if ((tag_addr > (start_paddr - 0x100)) &&
506 	    (tag_addr < (end_paddr + 0x100))) {
507 		if (mem_cache_debug & 0x1)
508 			cmn_err(CE_CONT,
509 			    "%s collision detected tag_addr = 0x%08x"
510 			    " start_paddr = 0x%08x end_paddr = 0x%08x\n",
511 			    type_str, (uint32_t)tag_addr, (uint32_t)start_paddr,
512 			    (uint32_t)end_paddr);
513 		return (B_TRUE);
514 	}
515 	else
516 		return (B_FALSE);
517 }
518 
519 static uint64_t
520 get_tag_addr(cache_info_t *cache_info)
521 {
522 	uint64_t tag_addr, scratch;
523 
524 	switch (cache_info->cache) {
525 		case L2_CACHE_TAG:
526 		case L2_CACHE_DATA:
527 			tag_addr = (uint64_t)(cache_info->index <<
528 			    PN_CACHE_LINE_SHIFT);
529 			scratch = (uint64_t)(cache_info->way <<
530 			    PN_L2_WAY_SHIFT);
531 			tag_addr |= scratch;
532 			tag_addr |= PN_L2_IDX_HW_ECC_EN;
533 			break;
534 		case L3_CACHE_TAG:
535 		case L3_CACHE_DATA:
536 			tag_addr = (uint64_t)(cache_info->index <<
537 			    PN_CACHE_LINE_SHIFT);
538 			scratch = (uint64_t)(cache_info->way <<
539 			    PN_L3_WAY_SHIFT);
540 			tag_addr |= scratch;
541 			tag_addr |= PN_L3_IDX_HW_ECC_EN;
542 			break;
543 		default:
544 			/*
545 			 * Should never reach here.
546 			 */
547 			ASSERT(0);
548 			return (uint64_t)(0);
549 	}
550 	return (tag_addr);
551 }
552 
553 static int
554 mem_cache_ioctl_ops(int cmd, int mode, cache_info_t *cache_info)
555 {
556 	int	ret_val = 0;
557 	uint64_t afar, tag_addr;
558 	ch_cpu_logout_t clop;
559 	uint64_t Lxcache_tag_data[PN_CACHE_NWAYS];
560 	int	i, retire_retry_count;
561 	cpu_t	*cpu;
562 	uint64_t tag_data;
563 	uint8_t state;
564 
565 	if (cache_info->way >= PN_CACHE_NWAYS)
566 		return (EINVAL);
567 	switch (cache_info->cache) {
568 		case L2_CACHE_TAG:
569 		case L2_CACHE_DATA:
570 			if (cache_info->index >=
571 			    (PN_L2_SET_SIZE/PN_L2_LINESIZE))
572 				return (EINVAL);
573 			break;
574 		case L3_CACHE_TAG:
575 		case L3_CACHE_DATA:
576 			if (cache_info->index >=
577 			    (PN_L3_SET_SIZE/PN_L3_LINESIZE))
578 				return (EINVAL);
579 			break;
580 		default:
581 			return (ENOTSUP);
582 	}
583 	/*
584 	 * Check if we have a valid cpu ID and that
585 	 * CPU is ONLINE.
586 	 */
587 	mutex_enter(&cpu_lock);
588 	cpu = cpu_get(cache_info->cpu_id);
589 	if ((cpu == NULL) || (!cpu_is_online(cpu))) {
590 		mutex_exit(&cpu_lock);
591 		return (EINVAL);
592 	}
593 	mutex_exit(&cpu_lock);
594 	pattern = 0;	/* default value of TAG PA when cacheline is retired. */
595 	switch (cmd) {
596 		case MEM_CACHE_RETIRE:
597 			tag_addr = get_tag_addr(cache_info);
598 			pattern |= PN_ECSTATE_NA;
599 			retire_retry_count = 0;
600 			affinity_set(cache_info->cpu_id);
601 			switch (cache_info->cache) {
602 				case L2_CACHE_DATA:
603 				case L2_CACHE_TAG:
604 					if ((cache_info->bit & MSB_BIT_MASK) ==
605 					    MSB_BIT_MASK)
606 						pattern |= PN_L2TAG_PA_MASK;
607 retry_l2_retire:
608 					if (tag_addr_collides(tag_addr,
609 					    cache_info->cache,
610 					    retire_l2_start, retire_l2_end))
611 						ret_val =
612 						    retire_l2_alternate(
613 						    tag_addr, pattern);
614 					else
615 						ret_val = retire_l2(tag_addr,
616 						    pattern);
617 					if (ret_val == 1) {
618 						/*
619 						 * cacheline was in retired
620 						 * STATE already.
621 						 * so return success.
622 						 */
623 						ret_val = 0;
624 					}
625 					if (ret_val < 0) {
626 						cmn_err(CE_WARN,
627 		"retire_l2() failed. index = 0x%x way %d. Retrying...\n",
628 						    cache_info->index,
629 						    cache_info->way);
630 						if (retire_retry_count >= 2) {
631 							retire_failures++;
632 							affinity_clear();
633 							return (EIO);
634 						}
635 						retire_retry_count++;
636 						goto retry_l2_retire;
637 					}
638 					if (ret_val == 2)
639 						l2_flush_retries_done++;
640 			/*
641 			 * We bind ourself to a CPU and send cross trap to
642 			 * ourself. On return from xt_one we can rely on the
643 			 * data in tag_data being filled in. Normally one would
644 			 * do a xt_sync to make sure that the CPU has completed
645 			 * the cross trap call xt_one.
646 			 */
647 					xt_one(cache_info->cpu_id,
648 					    (xcfunc_t *)(get_l2_tag_tl1),
649 					    tag_addr, (uint64_t)(&tag_data));
650 					state = tag_data & CH_ECSTATE_MASK;
651 					if (state != PN_ECSTATE_NA) {
652 						retire_failures++;
653 						print_l2_tag(tag_addr,
654 						    tag_data);
655 						cmn_err(CE_WARN,
656 		"L2 RETIRE:failed for index 0x%x way %d. Retrying...\n",
657 						    cache_info->index,
658 						    cache_info->way);
659 						if (retire_retry_count >= 2) {
660 							retire_failures++;
661 							affinity_clear();
662 							return (EIO);
663 						}
664 						retire_retry_count++;
665 						goto retry_l2_retire;
666 					}
667 					break;
668 				case L3_CACHE_TAG:
669 				case L3_CACHE_DATA:
670 					if ((cache_info->bit & MSB_BIT_MASK) ==
671 					    MSB_BIT_MASK)
672 						pattern |= PN_L3TAG_PA_MASK;
673 					if (tag_addr_collides(tag_addr,
674 					    cache_info->cache,
675 					    retire_l3_start, retire_l3_end))
676 						ret_val =
677 						    retire_l3_alternate(
678 						    tag_addr, pattern);
679 					else
680 						ret_val = retire_l3(tag_addr,
681 						    pattern);
682 					if (ret_val == 1) {
683 						/*
684 						 * cacheline was in retired
685 						 * STATE already.
686 						 * so return success.
687 						 */
688 						ret_val = 0;
689 					}
690 					if (ret_val < 0) {
691 						cmn_err(CE_WARN,
692 			"retire_l3() failed. ret_val = %d index = 0x%x\n",
693 						    ret_val,
694 						    cache_info->index);
695 						retire_failures++;
696 						affinity_clear();
697 						return (EIO);
698 					}
699 			/*
700 			 * We bind ourself to a CPU and send cross trap to
701 			 * ourself. On return from xt_one we can rely on the
702 			 * data in tag_data being filled in. Normally one would
703 			 * do a xt_sync to make sure that the CPU has completed
704 			 * the cross trap call xt_one.
705 			 */
706 					xt_one(cache_info->cpu_id,
707 					    (xcfunc_t *)(get_l3_tag_tl1),
708 					    tag_addr, (uint64_t)(&tag_data));
709 					state = tag_data & CH_ECSTATE_MASK;
710 					if (state != PN_ECSTATE_NA) {
711 						cmn_err(CE_WARN,
712 					"L3 RETIRE failed for index 0x%x\n",
713 						    cache_info->index);
714 						retire_failures++;
715 						affinity_clear();
716 						return (EIO);
717 					}
718 
719 					break;
720 			}
721 			affinity_clear();
722 			break;
723 		case MEM_CACHE_UNRETIRE:
724 			tag_addr = get_tag_addr(cache_info);
725 			pattern = PN_ECSTATE_INV;
726 			affinity_set(cache_info->cpu_id);
727 			switch (cache_info->cache) {
728 				case L2_CACHE_DATA:
729 				case L2_CACHE_TAG:
730 			/*
731 			 * We bind ourself to a CPU and send cross trap to
732 			 * ourself. On return from xt_one we can rely on the
733 			 * data in tag_data being filled in. Normally one would
734 			 * do a xt_sync to make sure that the CPU has completed
735 			 * the cross trap call xt_one.
736 			 */
737 					xt_one(cache_info->cpu_id,
738 					    (xcfunc_t *)(get_l2_tag_tl1),
739 					    tag_addr, (uint64_t)(&tag_data));
740 					state = tag_data & CH_ECSTATE_MASK;
741 					if (state != PN_ECSTATE_NA) {
742 						affinity_clear();
743 						return (EINVAL);
744 					}
745 					if (tag_addr_collides(tag_addr,
746 					    cache_info->cache,
747 					    unretire_l2_start, unretire_l2_end))
748 						ret_val =
749 						    unretire_l2_alternate(
750 						    tag_addr, pattern);
751 					else
752 						ret_val =
753 						    unretire_l2(tag_addr,
754 						    pattern);
755 					if (ret_val != 0) {
756 						cmn_err(CE_WARN,
757 			"unretire_l2() failed. ret_val = %d index = 0x%x\n",
758 						    ret_val,
759 						    cache_info->index);
760 						retire_failures++;
761 						affinity_clear();
762 						return (EIO);
763 					}
764 					break;
765 				case L3_CACHE_TAG:
766 				case L3_CACHE_DATA:
767 			/*
768 			 * We bind ourself to a CPU and send cross trap to
769 			 * ourself. On return from xt_one we can rely on the
770 			 * data in tag_data being filled in. Normally one would
771 			 * do a xt_sync to make sure that the CPU has completed
772 			 * the cross trap call xt_one.
773 			 */
774 					xt_one(cache_info->cpu_id,
775 					    (xcfunc_t *)(get_l3_tag_tl1),
776 					    tag_addr, (uint64_t)(&tag_data));
777 					state = tag_data & CH_ECSTATE_MASK;
778 					if (state != PN_ECSTATE_NA) {
779 						affinity_clear();
780 						return (EINVAL);
781 					}
782 					if (tag_addr_collides(tag_addr,
783 					    cache_info->cache,
784 					    unretire_l3_start, unretire_l3_end))
785 						ret_val =
786 						    unretire_l3_alternate(
787 						    tag_addr, pattern);
788 					else
789 						ret_val =
790 						    unretire_l3(tag_addr,
791 						    pattern);
792 					if (ret_val != 0) {
793 						cmn_err(CE_WARN,
794 			"unretire_l3() failed. ret_val = %d index = 0x%x\n",
795 						    ret_val,
796 						    cache_info->index);
797 						affinity_clear();
798 						return (EIO);
799 					}
800 					break;
801 			}
802 			affinity_clear();
803 			break;
804 		case MEM_CACHE_ISRETIRED:
805 		case MEM_CACHE_STATE:
806 			return (ENOTSUP);
807 		case MEM_CACHE_READ_TAGS:
808 #ifdef DEBUG
809 		case MEM_CACHE_READ_ERROR_INJECTED_TAGS:
810 #endif
811 			/*
812 			 * Read tag and data for all the ways at a given afar
813 			 */
814 			afar = (uint64_t)(cache_info->index
815 			    << PN_CACHE_LINE_SHIFT);
816 			mutex_enter(&cpu_lock);
817 			affinity_set(cache_info->cpu_id);
818 			(void) pause_cpus(NULL);
819 			mutex_exit(&cpu_lock);
820 			/*
821 			 * We bind ourself to a CPU and send cross trap to
822 			 * ourself. On return from xt_one we can rely on the
823 			 * data in clop being filled in. Normally one would
824 			 * do a xt_sync to make sure that the CPU has completed
825 			 * the cross trap call xt_one.
826 			 */
827 			xt_one(cache_info->cpu_id,
828 			    (xcfunc_t *)(get_ecache_dtags_tl1),
829 			    afar, (uint64_t)(&clop));
830 			mutex_enter(&cpu_lock);
831 			(void) start_cpus();
832 			mutex_exit(&cpu_lock);
833 			affinity_clear();
834 			switch (cache_info->cache) {
835 				case L2_CACHE_TAG:
836 					for (i = 0; i < PN_CACHE_NWAYS; i++) {
837 						Lxcache_tag_data[i] =
838 						    clop.clo_data.chd_l2_data
839 						    [i].ec_tag;
840 					}
841 #ifdef DEBUG
842 					last_error_injected_bit =
843 					    last_l2tag_error_injected_bit;
844 					last_error_injected_way =
845 					    last_l2tag_error_injected_way;
846 #endif
847 					break;
848 				case L3_CACHE_TAG:
849 					for (i = 0; i < PN_CACHE_NWAYS; i++) {
850 						Lxcache_tag_data[i] =
851 						    clop.clo_data.chd_ec_data
852 						    [i].ec_tag;
853 					}
854 #ifdef DEBUG
855 					last_error_injected_bit =
856 					    last_l3tag_error_injected_bit;
857 					last_error_injected_way =
858 					    last_l3tag_error_injected_way;
859 #endif
860 					break;
861 				default:
862 					return (ENOTSUP);
863 			}	/* end if switch(cache) */
864 #ifdef DEBUG
865 			if ((cmd == MEM_CACHE_READ_ERROR_INJECTED_TAGS) &&
866 			    (inject_anonymous_tag_error == 0) &&
867 			    (last_error_injected_way >= 0) &&
868 			    (last_error_injected_way <= 3)) {
869 				pattern = ((uint64_t)1 <<
870 				    last_error_injected_bit);
871 				/*
872 				 * If error bit is ECC we need to make sure
873 				 * ECC on all all WAYS are corrupted.
874 				 */
875 				if ((last_error_injected_bit >= 6) &&
876 				    (last_error_injected_bit <= 14)) {
877 					for (i = 0; i < PN_CACHE_NWAYS; i++)
878 						Lxcache_tag_data[i] ^=
879 						    pattern;
880 				} else
881 					Lxcache_tag_data
882 					    [last_error_injected_way] ^=
883 					    pattern;
884 			}
885 #endif
886 			if (ddi_copyout((caddr_t)Lxcache_tag_data,
887 			    (caddr_t)cache_info->datap,
888 			    sizeof (Lxcache_tag_data), mode)
889 			    != DDI_SUCCESS) {
890 				return (EFAULT);
891 			}
892 			break;	/* end of READ_TAGS */
893 		default:
894 			return (ENOTSUP);
895 	}	/* end if switch(cmd) */
896 	return (ret_val);
897 }
898 
899 /*ARGSUSED*/
900 static int
901 mem_cache_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
902 		int *rvalp)
903 {
904 	int	inst;
905 	struct mem_cache_softc *softc;
906 	cache_info_t	cache_info;
907 	cache_info32_t	cache_info32;
908 	int	ret_val;
909 	int	is_panther;
910 
911 	inst = getminor(dev);
912 	if ((softc = getsoftc(inst)) == NULL)
913 		return (ENXIO);
914 
915 	mutex_enter(&softc->mutex);
916 
917 #ifdef _MULTI_DATAMODEL
918 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
919 		if (ddi_copyin((cache_info32_t *)arg, &cache_info32,
920 		    sizeof (cache_info32), mode) != DDI_SUCCESS) {
921 			mutex_exit(&softc->mutex);
922 			return (EFAULT);
923 		}
924 		cache_info.cache = cache_info32.cache;
925 		cache_info.index = cache_info32.index;
926 		cache_info.way = cache_info32.way;
927 		cache_info.cpu_id = cache_info32.cpu_id;
928 		cache_info.bit = cache_info32.bit;
929 		cache_info.datap = (void *)((uint64_t)cache_info32.datap);
930 	} else
931 #endif
932 	if (ddi_copyin((cache_info_t *)arg, &cache_info,
933 	    sizeof (cache_info), mode) != DDI_SUCCESS) {
934 		mutex_exit(&softc->mutex);
935 		return (EFAULT);
936 	}
937 
938 	if ((cache_info.cpu_id < 0) || (cache_info.cpu_id >= _ncpu)) {
939 		mutex_exit(&softc->mutex);
940 		return (EINVAL);
941 	}
942 	is_panther = IS_PANTHER(cpunodes[cache_info.cpu_id].implementation);
943 	if (!is_panther) {
944 		mutex_exit(&softc->mutex);
945 		return (ENOTSUP);
946 	}
947 	switch (cmd) {
948 		case MEM_CACHE_RETIRE:
949 		case MEM_CACHE_UNRETIRE:
950 			if ((mode & FWRITE) == 0) {
951 				ret_val = EBADF;
952 				break;
953 			}
954 		/*FALLTHROUGH*/
955 		case MEM_CACHE_ISRETIRED:
956 		case MEM_CACHE_STATE:
957 		case MEM_CACHE_READ_TAGS:
958 #ifdef DEBUG
959 		case MEM_CACHE_READ_ERROR_INJECTED_TAGS:
960 #endif
961 			ret_val =  mem_cache_ioctl_ops(cmd, mode, &cache_info);
962 			break;
963 		default:
964 			ret_val = ENOTSUP;
965 			break;
966 	}
967 	mutex_exit(&softc->mutex);
968 	return (ret_val);
969 }
970