103831d3stevel/*
203831d3stevel * CDDL HEADER START
303831d3stevel *
403831d3stevel * The contents of this file are subject to the terms of the
503831d3stevel * Common Development and Distribution License (the "License").
603831d3stevel * You may not use this file except in compliance with the License.
703831d3stevel *
803831d3stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d3stevel * or http://www.opensolaris.org/os/licensing.
1003831d3stevel * See the License for the specific language governing permissions
1103831d3stevel * and limitations under the License.
1203831d3stevel *
1303831d3stevel * When distributing Covered Code, include this CDDL HEADER in each
1403831d3stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d3stevel * If applicable, add the following below this CDDL HEADER, with the
1603831d3stevel * fields enclosed by brackets "[]" replaced with your own identifying
1703831d3stevel * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d3stevel *
1903831d3stevel * CDDL HEADER END
2003831d3stevel */
2103831d3stevel
2203831d3stevel/*
2307d06daSurya Prakki * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d3stevel * Use is subject to license terms.
2503831d3stevel */
2603831d3stevel
2703831d3stevel/*
2803831d3stevel * Interface for Serengeti IOSRAM mailbox
2903831d3stevel * OS <-> SC communication protocol
3003831d3stevel */
3103831d3stevel
3203831d3stevel#include <sys/types.h>
3303831d3stevel#include <sys/systm.h>
3403831d3stevel#include <sys/ddi.h>
3503831d3stevel#include <sys/sunddi.h>
3603831d3stevel#include <sys/kmem.h>
3703831d3stevel#include <sys/uadmin.h>
3803831d3stevel#include <sys/machsystm.h>
3903831d3stevel#include <sys/disp.h>
4003831d3stevel#include <sys/taskq.h>
4103831d3stevel
4203831d3stevel#include <sys/sgevents.h>
4303831d3stevel#include <sys/sgsbbc_priv.h>
4403831d3stevel#include <sys/sgsbbc_iosram_priv.h>
4503831d3stevel#include <sys/sgsbbc_mailbox_priv.h>
4603831d3stevel#include <sys/plat_ecc_unum.h>
4703831d3stevel#include <sys/plat_ecc_dimm.h>
4803831d3stevel#include <sys/serengeti.h>
4903831d3stevel#include <sys/fm/util.h>
5003831d3stevel#include <sys/promif.h>
5103831d3stevel#include <sys/plat_datapath.h>
5203831d3stevel
5303831d3stevelsbbc_mailbox_t	*master_mbox = NULL;
5403831d3stevel
5503831d3stevel/*
5603831d3stevel * Panic Shutdown event support
5703831d3stevel */
5803831d3stevelstatic	kmutex_t	panic_hdlr_lock;
5903831d3stevel
6003831d3stevel/*
6103831d3stevel * The ID of the soft interrupt which triggers the bringing down of a Domain
6203831d3stevel * when a PANIC_SHUTDOWN event is received.
6303831d3stevel */
6403831d3stevelstatic ddi_softintr_t	panic_softintr_id = 0;
6503831d3stevel
6603831d3stevelstatic sg_panic_shutdown_t	panic_payload;
6703831d3stevelstatic sbbc_msg_t		panic_payload_msg;
6803831d3stevel
6903831d3stevel/*
7003831d3stevel * A queue for making sure outgoing messages are in order as ScApp
7103831d3stevel * does not support interleaving messages.
7203831d3stevel */
7303831d3stevelstatic kcondvar_t	outbox_queue;
7403831d3stevelstatic kmutex_t		outbox_queue_lock;
7503831d3stevel
7603831d3stevel/*
7703831d3stevel * Handle unsolicited capability message.
7803831d3stevel */
7903831d3stevelstatic plat_capability_data_t	cap_payload;
8003831d3stevelstatic sbbc_msg_t		cap_payload_msg;
8103831d3stevelstatic kmutex_t			cap_msg_hdlr_lock;
8203831d3stevel
8303831d3stevel/*
8403831d3stevel * Datapath error and fault messages arrive unsolicited.  The message data
8503831d3stevel * is contained in a plat_datapath_info_t structure.
8603831d3stevel */
8703831d3steveltypedef struct {
8803831d3stevel	uint8_t		type;		/* CDS, DX, CP */
8903831d3stevel	uint8_t		pad;		/* for alignment */
9003831d3stevel	uint16_t	cpuid;		/* Safari ID of base CPU */
9103831d3stevel	uint32_t	t_value;	/* SERD timeout threshold (seconds) */
9203831d3stevel} plat_datapath_info_t;
9303831d3stevel
9403831d3stevel/*
9503831d3stevel * Unsolicited datapath error messages are processed via a soft interrupt,
9603831d3stevel * triggered in unsolicited interrupt processing.
9703831d3stevel */
9803831d3stevelstatic	ddi_softintr_t		dp_softintr_id = 0;
9903831d3stevelstatic	kmutex_t		dp_hdlr_lock;
10003831d3stevel
10103831d3stevelstatic	plat_datapath_info_t	dp_payload;
10203831d3stevelstatic	sbbc_msg_t		dp_payload_msg;
10303831d3stevel
10403831d3stevelstatic char *dperrtype[] = {
10503831d3stevel	DP_ERROR_CDS,
10603831d3stevel	DP_ERROR_DX,
10703831d3stevel	DP_ERROR_RP
10803831d3stevel};
10903831d3stevel
11003831d3stevel/*
11103831d3stevel * Variable indicating if we are already processing requests.
11203831d3stevel * Setting this value must be protected by outbox_queue_lock.
11303831d3stevel */
11403831d3stevelstatic int		outbox_busy = 0;
11503831d3stevel
11603831d3stevel/*
11703831d3stevel * local stuff
11803831d3stevel */
11903831d3stevelstatic int sbbc_mbox_send_msg(sbbc_msg_t *, int, uint_t, time_t, clock_t);
12003831d3stevelstatic int sbbc_mbox_recv_msg();
12103831d3stevelstatic int mbox_write(struct sbbc_mbox_header *,
12203831d3stevel	struct sbbc_fragment *, sbbc_msg_t *);
12303831d3stevelstatic int mbox_read(struct sbbc_mbox_header *, struct sbbc_fragment *,
12403831d3stevel	sbbc_msg_t *);
12503831d3stevelstatic int mbox_has_free_space(struct sbbc_mbox_header *);
12603831d3stevelstatic void mbox_skip_next_msg(struct sbbc_mbox_header *);
12703831d3stevelstatic int mbox_read_header(uint32_t, struct sbbc_mbox_header *);
12803831d3stevelstatic void mbox_update_header(uint32_t, struct sbbc_mbox_header *);
12903831d3stevelstatic int mbox_read_frag(struct sbbc_mbox_header *, struct sbbc_fragment *);
13003831d3stevelstatic struct sbbc_msg_waiter *mbox_find_waiter(uint16_t, uint32_t);
13103831d3stevelstatic void wakeup_next(void);
13203831d3stevelstatic uint_t sbbc_panic_shutdown_handler(char *arg);
13303831d3stevelstatic uint_t sbbc_do_fast_shutdown(char *arg);
13403831d3stevelstatic void sbbc_mbox_post_reg(sbbc_softstate_t *softsp);
13503831d3stevelstatic uint_t cap_ecc_msg_handler(char *);
13603831d3stevelstatic uint_t sbbc_datapath_error_msg_handler(char *arg);
13703831d3stevelstatic uint_t sbbc_datapath_fault_msg_handler(char *arg);
13803831d3stevelstatic uint_t sbbc_dp_trans_event(char *arg);
13903831d3stevel
14003831d3stevel
14103831d3stevel/*
14203831d3stevel * Interrupt handlers
14303831d3stevel */
14403831d3stevelstatic int sbbc_mbox_msgin(void);
14503831d3stevelstatic int sbbc_mbox_msgout(void);
14603831d3stevelstatic int sbbc_mbox_spacein(void);
14703831d3stevelstatic int sbbc_mbox_spaceout(void);
14803831d3stevel
14903831d3stevel/*
15003831d3stevel * ECC event mailbox message taskq and parameters
15103831d3stevel */
15203831d3stevelstatic taskq_t	*sbbc_ecc_mbox_taskq = NULL;
15303831d3stevelstatic int	sbbc_ecc_mbox_taskq_errs = 0;
15403831d3stevelstatic int	sbbc_ecc_mbox_send_errs = 0;
15503831d3stevelstatic int	sbbc_ecc_mbox_inval_errs = 0;
15603831d3stevelstatic int	sbbc_ecc_mbox_other_errs = 0;
15703831d3stevelint	sbbc_ecc_mbox_err_throttle = ECC_MBOX_TASKQ_ERR_THROTTLE;
15803831d3stevel
15903831d3stevel/*
16003831d3stevel * Called when SBBC driver is loaded
16103831d3stevel * Initialise global mailbox stuff, etc
16203831d3stevel */
16303831d3stevelvoid
16403831d3stevelsbbc_mbox_init()
16503831d3stevel{
16603831d3stevel	int	i;
16703831d3stevel
16803831d3stevel	master_mbox = kmem_zalloc(sizeof (sbbc_mailbox_t), KM_NOSLEEP);
16903831d3stevel	if (master_mbox == NULL) {
17003831d3stevel		cmn_err(CE_PANIC, "Can't allocate memory for mailbox\n");
17103831d3stevel	}
17203831d3stevel
17303831d3stevel	/*
17403831d3stevel	 * mutex'es for the wait-lists
17503831d3stevel	 */
17603831d3stevel	for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) {
17703831d3stevel		mutex_init(&master_mbox->mbox_wait_lock[i],
17803831d3stevel			NULL, MUTEX_DEFAULT, NULL);
17903831d3stevel		master_mbox->mbox_wait_list[i] = NULL;
18003831d3stevel	}
18103831d3stevel
18203831d3stevel	for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++)
18303831d3stevel		master_mbox->intrs[i] = NULL;
18403831d3stevel
18503831d3stevel	/*
18603831d3stevel	 * Two mailbox channels SC -> OS , read-only
18703831d3stevel	 *			OS -> SC, read/write
18803831d3stevel	 */
18903831d3stevel	master_mbox->mbox_in = kmem_zalloc(sizeof (sbbc_mbox_t), KM_NOSLEEP);
19003831d3stevel	if (master_mbox->mbox_in == NULL) {
19103831d3stevel		cmn_err(CE_PANIC,
19203831d3stevel			"Can't allocate memory for inbound mailbox\n");
19303831d3stevel	}
19403831d3stevel
19503831d3stevel	master_mbox->mbox_out = kmem_zalloc(sizeof (sbbc_mbox_t), KM_NOSLEEP);
19603831d3stevel	if (master_mbox->mbox_out == NULL) {
19703831d3stevel		cmn_err(CE_PANIC,
19803831d3stevel			"Can't allocate memory for outbound mailbox\n");
19903831d3stevel	}
20003831d3stevel
20103831d3stevel	mutex_init(&master_mbox->mbox_in->mb_lock, NULL,
20203831d3stevel		MUTEX_DEFAULT, NULL);
20303831d3stevel	mutex_init(&master_mbox->mbox_out->mb_lock, NULL,
20403831d3stevel		MUTEX_DEFAULT, NULL);
20503831d3stevel
20603831d3stevel	/*
20703831d3stevel	 * Add PANIC_SHUTDOWN Event mutex
20803831d3stevel	 */
20903831d3stevel	mutex_init(&panic_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
21003831d3stevel
21103831d3stevel	/* Initialize datapath error message handler mutex */
21203831d3stevel	mutex_init(&dp_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
21303831d3stevel
21403831d3stevel	/* Initialize capability message handler event mutex */
21503831d3stevel	mutex_init(&cap_msg_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
21603831d3stevel
21703831d3stevel	/*
21803831d3stevel	 * NOT USED YET
21903831d3stevel	 */
22003831d3stevel	master_mbox->mbox_in->mb_type =
22103831d3stevel		master_mbox->mbox_out->mb_type = 0;
22203831d3stevel
22303831d3stevel	cv_init(&outbox_queue, NULL, CV_DEFAULT, NULL);
22403831d3stevel	mutex_init(&outbox_queue_lock, NULL, MUTEX_DEFAULT, NULL);
22503831d3stevel
22603831d3stevel}
22703831d3stevel
22803831d3stevel/*
22903831d3stevel * called when the SBBC driver is unloaded
23003831d3stevel */
23103831d3stevelvoid
23203831d3stevelsbbc_mbox_fini()
23303831d3stevel{
23403831d3stevel	int	i;
23503831d3stevel	int	err;
23603831d3stevel
23703831d3stevel	/*
23803831d3stevel	 * destroy ECC event mailbox taskq
23903831d3stevel	 */
24003831d3stevel	if (sbbc_ecc_mbox_taskq != NULL) {
24103831d3stevel		taskq_destroy(sbbc_ecc_mbox_taskq);
24203831d3stevel		sbbc_ecc_mbox_taskq = NULL;
24303831d3stevel		sbbc_ecc_mbox_taskq_errs = 0;
24403831d3stevel	}
24503831d3stevel
24603831d3stevel	/*
24703831d3stevel	 * unregister interrupts
24803831d3stevel	 */
24903831d3stevel	(void) iosram_unreg_intr(SBBC_MAILBOX_IN);
25003831d3stevel	(void) iosram_unreg_intr(SBBC_MAILBOX_IN);
25103831d3stevel	(void) iosram_unreg_intr(SBBC_MAILBOX_SPACE_IN);
25203831d3stevel	(void) iosram_unreg_intr(SBBC_MAILBOX_SPACE_OUT);
25303831d3stevel
25403831d3stevel	/*
25503831d3stevel	 * Remove Panic Shutdown and Datapath Error event support.
25603831d3stevel	 *
25703831d3stevel	 * NOTE: If we have not added the soft interrupt handlers for these
25803831d3stevel	 * then we know that we have not registered the event handlers either.
25903831d3stevel	 */
26003831d3stevel	if (panic_softintr_id != 0) {
26103831d3stevel		ddi_remove_softintr(panic_softintr_id);
26203831d3stevel
26303831d3stevel		err = sbbc_mbox_unreg_intr(MBOX_EVENT_PANIC_SHUTDOWN,
26403831d3stevel			sbbc_panic_shutdown_handler);
26503831d3stevel		if (err != 0) {
26603831d3stevel			cmn_err(CE_WARN, "Failed to unreg Panic Shutdown "
26703831d3stevel				"handler. Err=%d", err);
26803831d3stevel		}
26903831d3stevel	}
27003831d3stevel	if (dp_softintr_id != 0) {
27103831d3stevel		ddi_remove_softintr(dp_softintr_id);
27203831d3stevel
27303831d3stevel		err = sbbc_mbox_unreg_intr(MBOX_EVENT_DP_ERROR,
27403831d3stevel			sbbc_datapath_error_msg_handler);
27503831d3stevel		err |= sbbc_mbox_unreg_intr(MBOX_EVENT_DP_FAULT,
27603831d3stevel			sbbc_datapath_fault_msg_handler);
27703831d3stevel		if (err != 0) {
27803831d3stevel			cmn_err(CE_WARN, "Failed to unreg Datapath Error "
27903831d3stevel				"handler. Err=%d", err);
28003831d3stevel		}
28103831d3stevel	}
28203831d3stevel
28303831d3stevel	/*
28403831d3stevel	 * destroy all its mutex'es, lists etc
28503831d3stevel	 */
28603831d3stevel
28703831d3stevel	/*
28803831d3stevel	 * mutex'es for the wait-lists
28903831d3stevel	 */
29003831d3stevel	for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) {
291