xref: /illumos-gate/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h (revision 188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9a)
14c06356bSdh /*
24c06356bSdh  * CDDL HEADER START
34c06356bSdh  *
44c06356bSdh  * The contents of this file are subject to the terms of the
54c06356bSdh  * Common Development and Distribution License (the "License").
64c06356bSdh  * You may not use this file except in compliance with the License.
74c06356bSdh  *
84c06356bSdh  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c06356bSdh  * or http://www.opensolaris.org/os/licensing.
104c06356bSdh  * See the License for the specific language governing permissions
114c06356bSdh  * and limitations under the License.
124c06356bSdh  *
134c06356bSdh  * When distributing Covered Code, include this CDDL HEADER in each
144c06356bSdh  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c06356bSdh  * If applicable, add the following below this CDDL HEADER, with the
164c06356bSdh  * fields enclosed by brackets "[]" replaced with your own identifying
174c06356bSdh  * information: Portions Copyright [yyyy] [name of copyright owner]
184c06356bSdh  *
194c06356bSdh  * CDDL HEADER END
20658280b6SDavid Hollister  */
21658280b6SDavid Hollister /*
22658280b6SDavid Hollister  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
234c06356bSdh  */
244c06356bSdh #ifndef	_PMCS_DEF_H
254c06356bSdh #define	_PMCS_DEF_H
264c06356bSdh #ifdef	__cplusplus
274c06356bSdh extern "C" {
284c06356bSdh #endif
294c06356bSdh 
304c06356bSdh typedef enum {
314c06356bSdh 	NOTHING,	/* nothing connected here */
324c06356bSdh 	SATA,		/* SATA connection */
334c06356bSdh 	SAS,		/* direct or indirect SAS connection */
344c06356bSdh 	EXPANDER,	/* connection to an expander */
354c06356bSdh 	NEW		/* Brand new device (pending state) */
364c06356bSdh } pmcs_dtype_t;
374c06356bSdh 
384c06356bSdh /*
394c06356bSdh  * This structure defines a PHY device that represents what we
404c06356bSdh  * are connected to.
414c06356bSdh  *
424c06356bSdh  * The eight real physical PHYs that are in the PMC8X6G are represented
434c06356bSdh  * as an array of eight of these structures which define what these
444c06356bSdh  * real PHYs are connected to.
454c06356bSdh  *
464c06356bSdh  * Depending upon what is actually connected to each PHY, the
474c06356bSdh  * type set will define what we're connected to. If it is
484c06356bSdh  * a direct SATA connection, the phy will describe a SATA endpoint
494c06356bSdh  * If it is a direct SAS connection, it will describe a SAS
504c06356bSdh  * endpoint.
514c06356bSdh  *
524c06356bSdh  * If it is an EXPANDER, this will describe the edge of an expander.
534c06356bSdh  * As we perform discovery on what is in an EXPANDER we define an
544c06356bSdh  * additional list of phys that represent what the Expander is connected to.
554c06356bSdh  */
564c06356bSdh #define	PMCS_HW_MIN_LINK_RATE	SAS_LINK_RATE_1_5GBIT
574c06356bSdh #define	PMCS_HW_MAX_LINK_RATE	SAS_LINK_RATE_6GBIT
584c06356bSdh 
59601c90f1SSrikanth, Ramana #define	PMCS_INVALID_DEVICE_ID		0xffffffff
60601c90f1SSrikanth, Ramana #define	PMCS_PHY_INVALID_PORT_ID	0xf
614c06356bSdh 
62499cfd15SDavid Hollister #define	PMCS_PM_MAX_NAMELEN	16
639aed1621SDavid Hollister #define	PMCS_MAX_REENUMERATE	2	/* Maximum re-enumeration attempts */
649aed1621SDavid Hollister 
659aed1621SDavid Hollister /*
669aed1621SDavid Hollister  * Number of usecs to wait after last noted activate/deactivate callback
679aed1621SDavid Hollister  * before possibly restarting discovery
689aed1621SDavid Hollister  */
699aed1621SDavid Hollister #define	PMCS_REDISCOVERY_DELAY	(5 * MICROSEC)
70499cfd15SDavid Hollister 
714c06356bSdh struct pmcs_phy {
724c06356bSdh 	pmcs_phy_t	*sibling;	/* sibling phy */
734c06356bSdh 	pmcs_phy_t 	*parent;	/* parent phy */
744c06356bSdh 	pmcs_phy_t 	*children;	/* head of list of children */
754c06356bSdh 	pmcs_phy_t 	*dead_next;	/* dead PHY list link */
764c06356bSdh 	list_node_t	list_node;	/* list element */
774c06356bSdh 	uint32_t	device_id;	/* PMC8X6G device handle */
784c06356bSdh 	uint32_t
794c06356bSdh 		ncphy 		: 8,	/* # of contained phys for expander */
804c06356bSdh 		hw_event_ack	: 24;	/* XXX: first level phy event acked */
814c06356bSdh 	uint8_t		phynum;		/* phy number on parent expander */
824c06356bSdh 	uint8_t		width;		/* how many phys wide */
834c06356bSdh 	uint8_t		ds_recovery_retries; /* # error retry attempts */
84af685682SSrikanth, Ramana 	uint8_t		ds_prev_good_recoveries; /* # successful recoveries */
85af685682SSrikanth, Ramana 	clock_t		prev_recovery;	/* previous successful recovery */
86af685682SSrikanth, Ramana 	clock_t		last_good_recovery; /* oldest successful recovery */
87af685682SSrikanth, Ramana 			/* within PMCS_MAX_DS_RECOVERY_TIME time frame */
884c06356bSdh 	pmcs_dtype_t	dtype;		/* current dtype of the phy */
894c06356bSdh 	pmcs_dtype_t	pend_dtype;	/* new dtype (pending change) */
904c06356bSdh 	uint32_t
914c06356bSdh 		level		: 8,	/* level in expander tree */
924c06356bSdh 		tolerates_sas2	: 1,	/* tolerates SAS2 SMP */
934c06356bSdh 		spinup_hold	: 1,	/* spinup hold needs releasing */
944c06356bSdh 		atdt		: 3,	/* attached device type */
954c06356bSdh 		portid		: 4,	/* PMC8X6G port context */
964c06356bSdh 		link_rate   	: 4,	/* current supported speeds */
974c06356bSdh 		valid_device_id	: 1,	/* device id is valid */
984c06356bSdh 		abort_sent	: 1,	/* we've sent an abort */
994c06356bSdh 		abort_pending	: 1,	/* we have an abort pending */
1004c06356bSdh 		need_rl_ext	: 1,	/* need SATA RL_EXT recocvery */
1014c06356bSdh 		subsidiary	: 1,	/* this is part of a wide phy */
1024c06356bSdh 		configured	: 1,	/* is configured */
1034c06356bSdh 		dead		: 1,	/* dead */
104601c90f1SSrikanth, Ramana 		changed		: 1,	/* this phy is changing */
1059aed1621SDavid Hollister 		reenumerate	: 1,	/* attempt re-enumeration */
106c80dec56SDavid Hollister 		virtual		: 1,	/* This is a virtual PHY */
107601c90f1SSrikanth, Ramana 		deregister_wait : 1;	/* phy waiting to get deregistered */
1084c06356bSdh 	clock_t		config_stop;	/* When config attempts will stop */
1094c06356bSdh 	hrtime_t	abort_all_start;
1104c06356bSdh 	kcondvar_t	abort_all_cv;	/* Wait for ABORT_ALL completion */
1114c06356bSdh 	kmutex_t	phy_lock;
1124c06356bSdh 	volatile uint32_t ref_count;	/* Targets & work on this PHY */
1139aed1621SDavid Hollister 	uint32_t	enum_attempts;	/* # of enumeration attempts */
1144c06356bSdh 	uint8_t 	sas_address[8];	/* SAS address for this PHY */
1154c06356bSdh 	struct {
1164c06356bSdh 	uint32_t
1174c06356bSdh 		prog_min_rate	:4,
1184c06356bSdh 		hw_min_rate	:4,
1194c06356bSdh 		prog_max_rate	:4,
1204c06356bSdh 		hw_max_rate	:4,
1214c06356bSdh 		reserved	:16;
1224c06356bSdh 	} state;
1234c06356bSdh 	char		path[32];	/* path name for this phy */
1244c06356bSdh 	pmcs_hw_t	*pwp;		/* back ptr to hba struct */
1254c06356bSdh 	pmcs_iport_t	*iport;		/* back ptr to the iport handle */
12673a3eccdSDavid Hollister 	pmcs_iport_t	*last_iport;	/* last iport this PHY was on */
1274c06356bSdh 	pmcs_xscsi_t	*target;	/* back ptr to current target */
128*188eaed9SSrikanth Suravajhala 	pmcs_xscsi_t	**target_addr;	/* address of real target pointer */
1294c06356bSdh 	kstat_t		*phy_stats;	/* kstats for this phy */
130499cfd15SDavid Hollister 	/*
131499cfd15SDavid Hollister 	 * Attached port phy mask and target port phymask.  With 16 bytes
132499cfd15SDavid Hollister 	 * we can represent a phymask for anything with up to 64 ports
133499cfd15SDavid Hollister 	 */
134499cfd15SDavid Hollister 	uint64_t	att_port_pm;		/* att port pm for this PHY */
135499cfd15SDavid Hollister 	uint64_t	att_port_pm_tmp;	/* Temp area for wide-ports */
136499cfd15SDavid Hollister 	char		att_port_pm_str[PMCS_PM_MAX_NAMELEN + 1];
137499cfd15SDavid Hollister 	uint64_t	tgt_port_pm;		/* tgt port pm for this PHY */
138499cfd15SDavid Hollister 	uint64_t	tgt_port_pm_tmp;	/* Temp area for wide-ports */
139499cfd15SDavid Hollister 	char		tgt_port_pm_str[PMCS_PM_MAX_NAMELEN + 1];
1409aed1621SDavid Hollister 	smp_routing_attr_t routing_attr; /* Routing attr. from discover resp. */
1419aed1621SDavid Hollister 	smp_routing_attr_t routing_method; /* Actual routing method used. */
1429aed1621SDavid Hollister 	smp_report_general_resp_t rg_resp;	/* Response to REPORT_GENERAL */
1439aed1621SDavid Hollister 	smp_discover_resp_t disc_resp;		/* Response to DISCOVER */
1444c06356bSdh };
1454c06356bSdh 
1464c06356bSdh /* maximum number of ds recovery retries (ds_recovery_retries) */
147601c90f1SSrikanth, Ramana #define	PMCS_MAX_DS_RECOVERY_RETRIES	10
1484c06356bSdh 
149af685682SSrikanth, Ramana /* max time allowed for successful recovery */
150af685682SSrikanth, Ramana #define	PMCS_MAX_DS_RECOVERY_TIME	(60 * 1000000) /* 60 seconds */
151af685682SSrikanth, Ramana 
152af685682SSrikanth, Ramana /* ds recovery on same same phy is not allowed within this interval */
153af685682SSrikanth, Ramana #define	PMCS_DS_RECOVERY_INTERVAL	(1000000) /* 1 second */
154af685682SSrikanth, Ramana 
1554c06356bSdh 
1564c06356bSdh /*
1574c06356bSdh  * Inbound and Outbound Queue Related Definitions.
1584c06356bSdh  *
1594c06356bSdh  * The PMC8X6G has a programmable number of inbound and outbound circular
1604c06356bSdh  * queues for use in message passing between the host and the PMC8X6G
1614c06356bSdh  * (up to 64 queues for the Rev C Chip). This driver does not use all
1624c06356bSdh  * possible queues.
1634c06356bSdh  *
1644c06356bSdh  * Each Queue is given 4K of consistent memory and we set a 64 byte size for
1654c06356bSdh  * the queue entry size (this gives us 256 queue entries per queue).
1664c06356bSdh  *
1674c06356bSdh  * This allocation then continues up a further PMCS_SCRATCH_SIZE bytes
1684c06356bSdh  * that the driver uses as a temporary scratch area for things like
1694c06356bSdh  * SMP discovery.
1704c06356bSdh  *
1714c06356bSdh  * This control area looks like this:
1724c06356bSdh  *
1734c06356bSdh  * Offset			What
1744c06356bSdh  * ------------------------------------------------
1754c06356bSdh  * 0					IQ 0 Consumer Index
1764c06356bSdh  * 4					IQ 1 Consumer Index
1774c06356bSdh  * 8..255				...
1784c06356bSdh  * 252..255				IQ 63 Consumer Index
1794c06356bSdh  * 256					OQ 0 Producer Index
1804c06356bSdh  * 260					OQ 1 Producer Index
1814c06356bSdh  * 264..259				....
1824c06356bSdh  * 508..511				OQ 63 Producer Index
1834c06356bSdh  * 512..512+PMCS_SCRATCH_SIZE-1		Scratch area.
1844c06356bSdh  */
1854c06356bSdh #define	IQCI_BASE_OFFSET	0
1864c06356bSdh #define	IQ_OFFSET(qnum)		(IQCI_BASE_OFFSET + (qnum << 2))
1874c06356bSdh #define	OQPI_BASE_OFFSET	256
1884c06356bSdh #define	OQ_OFFSET(qnum)		(OQPI_BASE_OFFSET + (qnum << 2))
1894c06356bSdh 
1904c06356bSdh /*
1914c06356bSdh  * Work related structures. Each one of these structures is paired
1924c06356bSdh  * with *any* command that is fed to the PMC8X6G via one of the
1934c06356bSdh  * Inbound Queues. The work structure has a tag to compare with
1944c06356bSdh  * the message that comes back out of an Outbound Queue. The
1954c06356bSdh  * work structure also points to the phy which this command is
1964c06356bSdh  * tied to. It also has a pointer a callback function (if defined).
1974c06356bSdh  * See that TAG Architecture below for the various kinds of
1984c06356bSdh  * dispositions of a work structure.
1994c06356bSdh  */
2004c06356bSdh 
2014c06356bSdh /*
2024c06356bSdh  * Work Structure States
2034c06356bSdh  *
2044c06356bSdh  * NIL			->	READY
2054c06356bSdh  * READY		->	NIL
2064c06356bSdh  * READY		->	ONCHIP
2074c06356bSdh  * ONCHIP		->	INTR
2084c06356bSdh  * INTR			->	READY
2094c06356bSdh  * INTR			->	NIL
2104c06356bSdh  * INTR			->	ABORTED
2114c06356bSdh  * INTR			->	TIMED_OUT
2124c06356bSdh  * ABORTED		->	NIL
2134c06356bSdh  * TIMED_OUT		->	NIL
2144c06356bSdh  */
2154c06356bSdh typedef enum {
2164c06356bSdh 	PMCS_WORK_STATE_NIL = 0,
2174c06356bSdh 	PMCS_WORK_STATE_READY,
2184c06356bSdh 	PMCS_WORK_STATE_ONCHIP,
2194c06356bSdh 	PMCS_WORK_STATE_INTR,
2204c06356bSdh 	PMCS_WORK_STATE_IOCOMPQ,
2214c06356bSdh 	PMCS_WORK_STATE_ABORTED,
2224c06356bSdh 	PMCS_WORK_STATE_TIMED_OUT
2234c06356bSdh } pmcs_work_state_t;
2244c06356bSdh 
2254c06356bSdh struct pmcwork {
2264c06356bSdh 	STAILQ_ENTRY(pmcwork)	next;
2274c06356bSdh 	kmutex_t		lock;
2284c06356bSdh 	kcondvar_t		sleep_cv;
2294c06356bSdh 	void			*ptr;	/* linkage or callback function */
2304c06356bSdh 	void 			*arg;	/* command specific data */
2314c06356bSdh 	pmcs_phy_t 		*phy;	/* phy who owns this command */
2324c06356bSdh 	pmcs_xscsi_t		*xp;	/* Back pointer to xscsi struct */
2334c06356bSdh 	volatile uint32_t	htag;	/* tag for this structure */
234c3bc407cSdh 	uint32_t		abt_htag; /* Tag of command to be aborted */
2354c06356bSdh 	uint32_t
2364c06356bSdh 			timer	:	27,
2374c06356bSdh 			onwire	:	1,
2384c06356bSdh 			dead	:	1,
2394c06356bSdh 			state	:	3;
2404c06356bSdh 	hrtime_t		start;	/* timestamp start */
2414c06356bSdh 	uint32_t		ssp_event; /* ssp event */
2424c06356bSdh 	pmcs_dtype_t		dtype;	/* stash, incase phy gets cleared */
2434c06356bSdh 
2444c06356bSdh 	void			*last_ptr;
2454c06356bSdh 	void			*last_arg;
2464c06356bSdh 	pmcs_phy_t		*last_phy;
2474c06356bSdh 	pmcs_xscsi_t		*last_xp;
2484c06356bSdh 	uint32_t		last_htag;
2494c06356bSdh 	pmcs_work_state_t	last_state;
2504c06356bSdh 	hrtime_t		finish;
2514c06356bSdh };
25239cd77a0SJesse Butler #define	PMCS_ABT_HTAG_ALL	0xffffffff
2534c06356bSdh 
2544c06356bSdh #define	PMCS_REC_EVENT	0xffffffff	/* event recovery */
2554c06356bSdh 
2564c06356bSdh /*
2574c06356bSdh  * This structure defines a PMC-Sierra defined firmware header.
2584c06356bSdh  */
2594c06356bSdh #pragma	pack(4)
2604c06356bSdh typedef struct {
2614c06356bSdh 	char 		vendor_id[8];
2624c06356bSdh 	uint8_t		product_id;
2634c06356bSdh 	uint8_t		hwrev;
2644c06356bSdh 	uint8_t		destination_partition;
2654c06356bSdh 	uint8_t		reserved0;
2664c06356bSdh 	uint8_t		fwrev[4];
2674c06356bSdh 	uint32_t	firmware_length;
2684c06356bSdh 	uint32_t	crc;
2694c06356bSdh 	uint32_t	start_address;
2704c06356bSdh 	uint8_t		data[];
2714c06356bSdh } pmcs_fw_hdr_t;
2724c06356bSdh #pragma	pack()
2734c06356bSdh 
2744c06356bSdh /*
2754c06356bSdh  * Offlevel work as a bit pattern.
2764c06356bSdh  */
2774c06356bSdh #define	PMCS_WORK_DISCOVER		0
2784c06356bSdh #define	PMCS_WORK_ABORT_HANDLE		3
2794c06356bSdh #define	PMCS_WORK_SPINUP_RELEASE	4
2804c06356bSdh #define	PMCS_WORK_SAS_HW_ACK		5
2814c06356bSdh #define	PMCS_WORK_SATA_RUN		6
2824c06356bSdh #define	PMCS_WORK_RUN_QUEUES		7
2834c06356bSdh #define	PMCS_WORK_ADD_DMA_CHUNKS	8
2844c06356bSdh #define	PMCS_WORK_DS_ERR_RECOVERY	9
2854c06356bSdh #define	PMCS_WORK_SSP_EVT_RECOVERY	10
286601c90f1SSrikanth, Ramana #define	PMCS_WORK_DEREGISTER_DEV	11
287c280a92bSDavid Hollister #define	PMCS_WORK_DUMP_REGS		12
2884c06356bSdh 
2894c06356bSdh /*
2904c06356bSdh  * The actual values as they appear in work_flags
2914c06356bSdh  */
2924c06356bSdh #define	PMCS_WORK_FLAG_DISCOVER		(1 << 0)
2934c06356bSdh #define	PMCS_WORK_FLAG_ABORT_HANDLE	(1 << 3)
2944c06356bSdh #define	PMCS_WORK_FLAG_SPINUP_RELEASE	(1 << 4)
2954c06356bSdh #define	PMCS_WORK_FLAG_SAS_HW_ACK	(1 << 5)
2964c06356bSdh #define	PMCS_WORK_FLAG_SATA_RUN		(1 << 6)
2974c06356bSdh #define	PMCS_WORK_FLAG_RUN_QUEUES	(1 << 7)
2984c06356bSdh #define	PMCS_WORK_FLAG_ADD_DMA_CHUNKS	(1 << 8)
2994c06356bSdh #define	PMCS_WORK_FLAG_DS_ERR_RECOVERY	(1 << 9)
3004c06356bSdh #define	PMCS_WORK_FLAG_SSP_EVT_RECOVERY (1 << 10)
301601c90f1SSrikanth, Ramana #define	PMCS_WORK_FLAG_DEREGISTER_DEV   (1 << 11)
302c280a92bSDavid Hollister #define	PMCS_WORK_FLAG_DUMP_REGS	(1 << 12)
3034c06356bSdh 
3044c06356bSdh /*
3054c06356bSdh  * This structure is used by this function to test MPI (and interrupts)
3064c06356bSdh  * after MPI has been started to make sure it's working reliably.
3074c06356bSdh  */
3084c06356bSdh typedef struct {
3094c06356bSdh 	uint32_t signature;
3104c06356bSdh 	uint32_t count;
3114c06356bSdh 	uint32_t *ptr;
3124c06356bSdh } echo_test_t;
3134c06356bSdh #define	ECHO_SIGNATURE	0xbebebeef
3144c06356bSdh 
3154c06356bSdh /*
3164c06356bSdh  * Tag Architecture. The PMC has 32 bit tags for MPI messages.
3174c06356bSdh  * We use this tag this way.
3184c06356bSdh  *
3194c06356bSdh  * bits		what
3204c06356bSdh  * ------------------------
3214c06356bSdh  * 31		done bit
322978d7443SSrikanth Suravajhala  * 30		non-io cmd bit
323978d7443SSrikanth Suravajhala  * 29..28	tag type
3244c06356bSdh  * 27..12	rolling serial number
3254c06356bSdh  * 11..0	index into work area to get pmcwork structure
3264c06356bSdh  *
3274c06356bSdh  * A tag type of NONE means that nobody is waiting on any results,
3284c06356bSdh  * so the interrupt code frees the work structure that has this
3294c06356bSdh  * tag.
3304c06356bSdh  *
3314c06356bSdh  * A tag type of CBACK means that the the interrupt handler
3324c06356bSdh  * takes the tag 'arg' in the work structure to be a callback
3334c06356bSdh  * function pointer (see pmcs_cb_t). The callee is responsible
3344c06356bSdh  * for freeing the work structure that has this tag.
3354c06356bSdh  *
3364c06356bSdh  * A tag type of WAIT means that the issuer of the work needs
3374c06356bSdh  * be woken up from interrupt level when the command completes
3384c06356bSdh  * (or times out). If work structure tag 'arg' is non-null,
3394c06356bSdh  * up to 2*PMCS_QENTRY_SIZE bits of data from the Outbound Queue
3404c06356bSdh  * entry may be copied to the area pointed to by 'arg'. This
3414c06356bSdh  * allows issuers to get directly at the results of the command
3424c06356bSdh  * they issed. The synchronization point for the issuer and the
3434c06356bSdh  * interrupt code for command done notification is the setting
3444c06356bSdh  * of the 'DONE' bit in the tag as stored in the work structure.
3454c06356bSdh  */
3464c06356bSdh #define	PMCS_TAG_TYPE_FREE	0
3474c06356bSdh #define	PMCS_TAG_TYPE_NONE	1
3484c06356bSdh #define	PMCS_TAG_TYPE_CBACK  	2
3494c06356bSdh #define	PMCS_TAG_TYPE_WAIT	3
3504c06356bSdh #define	PMCS_TAG_TYPE_SHIFT	28
3514c06356bSdh #define	PMCS_TAG_SERNO_SHIFT	12
3524c06356bSdh #define	PMCS_TAG_INDEX_SHIFT	0
353978d7443SSrikanth Suravajhala #define	PMCS_TAG_TYPE_MASK	0x30000000
354978d7443SSrikanth Suravajhala #define	PMCS_TAG_NONIO_CMD	0x40000000
3554c06356bSdh #define	PMCS_TAG_DONE		0x80000000
3564c06356bSdh #define	PMCS_TAG_SERNO_MASK	0x0ffff000
3574c06356bSdh #define	PMCS_TAG_INDEX_MASK	0x00000fff
3584c06356bSdh #define	PMCS_TAG_TYPE(x)		\
3594c06356bSdh 	(((x) & PMCS_TAG_TYPE_MASK) >> PMCS_TAG_TYPE_SHIFT)
3604c06356bSdh #define	PMCS_TAG_SERNO(x)	\
3614c06356bSdh 	(((x) & PMCS_TAG_SERNO_MASK) >> PMCS_TAG_SERNO_SHIFT)
3624c06356bSdh #define	PMCS_TAG_INDEX(x)	\
3634c06356bSdh 	(((x) & PMCS_TAG_INDEX_MASK) >> PMCS_TAG_INDEX_SHIFT)
3644c06356bSdh #define	PMCS_TAG_FREE		0
3654c06356bSdh #define	PMCS_COMMAND_DONE(x)	\
3664c06356bSdh 	(((x)->htag == PMCS_TAG_FREE) || (((x)->htag & PMCS_TAG_DONE) != 0))
3674c06356bSdh #define	PMCS_COMMAND_ACTIVE(x)	\
3684c06356bSdh 	((x)->htag != PMCS_TAG_FREE && (x)->state == PMCS_WORK_STATE_ONCHIP)
3694c06356bSdh 
3704c06356bSdh /*
3714c06356bSdh  * Miscellaneous Definitions
3724c06356bSdh  */
3734c06356bSdh #define	CLEAN_MESSAGE(m, x)	{	\
3744c06356bSdh 	int _j = x;			\
3754c06356bSdh 	while (_j < PMCS_MSG_SIZE) {	\
3764c06356bSdh 		m[_j++] = 0;		\
3774c06356bSdh 	}				\
3784c06356bSdh }
3794c06356bSdh 
3804c06356bSdh #define	COPY_MESSAGE(t, f, a)	{	\
3814c06356bSdh 	int _j;				\
3824c06356bSdh 	for (_j = 0; _j < a; _j++) {	\
3834c06356bSdh 		t[_j] = f[_j];		\
3844c06356bSdh 	}				\
3854c06356bSdh 	while (_j < PMCS_MSG_SIZE) {	\
3864c06356bSdh 		t[_j++] = 0;		\
3874c06356bSdh 	}				\
3884c06356bSdh }
3894c06356bSdh 
3904c06356bSdh #define	PMCS_PHY_ADDRESSABLE(pp)			\
3914c06356bSdh 	((pp)->level == 0 && (pp)->dtype == SATA &&	\
3924c06356bSdh 	    ((pp)->sas_address[0] >> 4) != 5)
3934c06356bSdh 
3944c06356bSdh #define	RESTART_DISCOVERY(pwp)				\
3954c06356bSdh 	ASSERT(!mutex_owned(&pwp->config_lock));	\
3964c06356bSdh 	mutex_enter(&pwp->config_lock);			\
3974c06356bSdh 	pwp->config_changed = B_TRUE;			\
3984c06356bSdh 	mutex_exit(&pwp->config_lock);			\
3994c06356bSdh 	SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
4004c06356bSdh 
4014c06356bSdh #define	RESTART_DISCOVERY_LOCKED(pwp)			\
4024c06356bSdh 	ASSERT(mutex_owned(&pwp->config_lock));		\
4034c06356bSdh 	pwp->config_changed = B_TRUE;			\
4044c06356bSdh 	SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
4054c06356bSdh 
4064c06356bSdh #define	PHY_CHANGED(pwp, p)						\
407c3bc407cSdh 	pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, p, NULL, "%s changed in "  \
408c3bc407cSdh 	    "%s line %d", p->path, __func__, __LINE__); 		\
4099aed1621SDavid Hollister 	p->changed = 1;							\
4109aed1621SDavid Hollister 	p->enum_attempts = 0
4114c06356bSdh 
4124c06356bSdh #define	PHY_CHANGED_AT_LOCATION(pwp, p, func, line)			\
413c3bc407cSdh 	pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, p, NULL, "%s changed in "  \
414c3bc407cSdh 	    "%s line %d", p->path, func, line);				\
4159aed1621SDavid Hollister 	p->changed = 1;							\
4169aed1621SDavid Hollister 	p->enum_attempts = 0
4174c06356bSdh 
4184c06356bSdh #define	PHY_TYPE(pptr)					\
4194c06356bSdh 	(((pptr)->dtype == NOTHING)?  "NOTHING" :	\
4204c06356bSdh 	(((pptr)->dtype == SATA)? "SATA" :		\
4214c06356bSdh 	(((pptr)->dtype == SAS)? "SAS" : "EXPANDER")))
4224c06356bSdh 
4234c06356bSdh #define	IS_ROOT_PHY(pptr)	(pptr->parent == NULL)
4244c06356bSdh 
4254c06356bSdh #define	PMCS_HIPRI(pwp, oq, c)				\
4264c06356bSdh 	(pwp->hipri_queue & (1 << PMCS_IQ_OTHER)) ?	\
4274c06356bSdh 	(PMCS_IOMB_HIPRI | PMCS_IOMB_IN_SAS(oq, c)) :	\
4284c06356bSdh 	(PMCS_IOMB_IN_SAS(oq, c))
4294c06356bSdh 
4304c06356bSdh #define	SCHEDULE_WORK(hwp, wrk)		\
4314c06356bSdh 	(void) atomic_set_long_excl(&hwp->work_flags, wrk)
4324c06356bSdh 
4334c06356bSdh /*
4344c06356bSdh  * Check to see if the requested work bit is set.  Either way, the bit will
4354c06356bSdh  * be cleared upon return.
4364c06356bSdh  */
4374c06356bSdh #define	WORK_SCHEDULED(hwp, wrk)	\
4384c06356bSdh 	(atomic_clear_long_excl(&hwp->work_flags, wrk) == 0)
4394c06356bSdh 
4404c06356bSdh /*
4414c06356bSdh  * Check to see if the requested work bit is set.  The value will not be
4424c06356bSdh  * changed in this case.  The atomic_xx_nv operations can be quite expensive
4434c06356bSdh  * so this should not be used in non-DEBUG code.
4444c06356bSdh  */
4454c06356bSdh #define	WORK_IS_SCHEDULED(hwp, wrk)	\
4464c06356bSdh 	((atomic_and_ulong_nv(&hwp->work_flags, (ulong_t)-1) & (1 << wrk)) != 0)
4474c06356bSdh 
4484c06356bSdh #define	WAIT_FOR(p, t, r)					\
44932b54db7SJesse Butler 	clock_t	_lb = ddi_get_lbolt();				\
4504c06356bSdh 	r = 0;							\
4514c06356bSdh 	while (!PMCS_COMMAND_DONE(p)) {				\
45232b54db7SJesse Butler 		clock_t _ret = cv_timedwait(&p->sleep_cv,	\
45332b54db7SJesse Butler 		    &p->lock, _lb + drv_usectohz(t * 1000));	\
45432b54db7SJesse Butler 		if (!PMCS_COMMAND_DONE(p) && _ret < 0) {		\
4554c06356bSdh 			r = 1;					\
4564c06356bSdh 			break;					\
4574c06356bSdh 		}						\
4584c06356bSdh 	}
4594c06356bSdh 
4604c06356bSdh /*
4614c06356bSdh  * Signal the next I/O completion thread to start running.
4624c06356bSdh  */
4634c06356bSdh 
4644c06356bSdh #define	PMCS_CQ_RUN_LOCKED(hwp)						\
4654c06356bSdh 	if (!STAILQ_EMPTY(&hwp->cq) || hwp->iocomp_cb_head) {		\
4664c06356bSdh 		pmcs_cq_thr_info_t *cqti;				\
4674c06356bSdh 		cqti = &hwp->cq_info.cq_thr_info			\
4684c06356bSdh 		    [hwp->cq_info.cq_next_disp_thr];			\
4694c06356bSdh 		hwp->cq_info.cq_next_disp_thr++;			\
4704c06356bSdh 		if (hwp->cq_info.cq_next_disp_thr ==			\
4714c06356bSdh 		    hwp->cq_info.cq_threads) {				\
4724c06356bSdh 			hwp->cq_info.cq_next_disp_thr = 0;		\
4734c06356bSdh 		}							\
4744c06356bSdh 		mutex_enter(&cqti->cq_thr_lock);			\
4754c06356bSdh 		cv_signal(&cqti->cq_cv);				\
4764c06356bSdh 		mutex_exit(&cqti->cq_thr_lock);				\
4778f514e74SDavid Hollister 	}
4784c06356bSdh 
4794c06356bSdh #define	PMCS_CQ_RUN(hwp)						\
4804c06356bSdh 	mutex_enter(&hwp->cq_lock);					\
4814c06356bSdh 	PMCS_CQ_RUN_LOCKED(hwp);					\
4824c06356bSdh 	mutex_exit(&hwp->cq_lock);
4834c06356bSdh 
4844c06356bSdh 
4854c06356bSdh /*
4864c06356bSdh  * Watchdog/SCSA timer definitions
4874c06356bSdh  */
4884c06356bSdh /* usecs to SCSA watchdog ticks */
4894c06356bSdh #define	US2WT(x)	(x)/10
4904c06356bSdh 
4914c06356bSdh /*
4924c06356bSdh  * More misc
4934c06356bSdh  */
4944c06356bSdh #define	BYTE0(x)	(((x) >>  0) & 0xff)
4954c06356bSdh #define	BYTE1(x)	(((x) >>  8) & 0xff)
4964c06356bSdh #define	BYTE2(x)	(((x) >> 16) & 0xff)
4974c06356bSdh #define	BYTE3(x)	(((x) >> 24) & 0xff)
4984c06356bSdh #define	BYTE4(x)	(((x) >> 32) & 0xff)
4994c06356bSdh #define	BYTE5(x)	(((x) >> 40) & 0xff)
5004c06356bSdh #define	BYTE6(x)	(((x) >> 48) & 0xff)
5014c06356bSdh #define	BYTE7(x)	(((x) >> 56) & 0xff)
5024c06356bSdh #define	WORD0(x)	(((x) >>  0) & 0xffff)
5034c06356bSdh #define	WORD1(x)	(((x) >> 16) & 0xffff)
5044c06356bSdh #define	WORD2(x)	(((x) >> 32) & 0xffff)
5054c06356bSdh #define	WORD3(x)	(((x) >> 48) & 0xffff)
5064c06356bSdh #define	DWORD0(x)	((uint32_t)(x))
5074c06356bSdh #define	DWORD1(x)	((uint32_t)(((uint64_t)x) >> 32))
5084c06356bSdh 
5094c06356bSdh #define	SAS_ADDR_FMT	"0x%02x%02x%02x%02x%02x%02x%02x%02x"
5104c06356bSdh #define	SAS_ADDR_PRT(x)	x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]
5114c06356bSdh 
5124c06356bSdh #define	PMCS_VALID_LINK_RATE(r) \
5134c06356bSdh 	((r == SAS_LINK_RATE_1_5GBIT) || (r == SAS_LINK_RATE_3GBIT) || \
5144c06356bSdh 	(r == SAS_LINK_RATE_6GBIT))
5154c06356bSdh 
5164c06356bSdh /*
5174c06356bSdh  * This is here to avoid inclusion of <sys/ctype.h> which is not lint clean.
5184c06356bSdh  */
5194c06356bSdh #define	HEXDIGIT(x)	(((x) >= '0' && (x) <= '9') || \
5204c06356bSdh 	((x) >= 'a' && (x) <= 'f') || ((x) >= 'A' && (x) <= 'F'))
5214c06356bSdh 
5221f81b464SDavid Hollister #define	NSECS_PER_SEC	1000000000UL
5231f81b464SDavid Hollister 
5244c06356bSdh 
5254c06356bSdh typedef void (*pmcs_cb_t) (pmcs_hw_t *, pmcwork_t *, uint32_t *);
5264c06356bSdh 
5274c06356bSdh /*
5284c06356bSdh  * Defines and structure used for tracing/logging information
5294c06356bSdh  */
5304c06356bSdh 
5314c06356bSdh #define	PMCS_TBUF_ELEM_SIZE	120
5324c06356bSdh #define	PMCS_TBUF_NUM_ELEMS_DEF	100000
5334c06356bSdh 
534c3bc407cSdh #define	PMCS_TBUF_UA_MAX_SIZE	32
5354c06356bSdh typedef struct {
536c3bc407cSdh 	/* Target-specific data */
537c3bc407cSdh 	uint16_t	target_num;
538c3bc407cSdh 	char		target_ua[PMCS_TBUF_UA_MAX_SIZE];
539c3bc407cSdh 	/* PHY-specific data */
540c3bc407cSdh 	uint8_t 	phy_sas_address[8];
541c3bc407cSdh 	char		phy_path[32];
542c3bc407cSdh 	pmcs_dtype_t	phy_dtype;
543c3bc407cSdh 	/* Log data */
5444c06356bSdh 	timespec_t	timestamp;
5451f81b464SDavid Hollister 	uint64_t	fw_timestamp;
5464c06356bSdh 	char		buf[PMCS_TBUF_ELEM_SIZE];
5474c06356bSdh } pmcs_tbuf_t;
5484c06356bSdh 
5494c06356bSdh /*
5504c06356bSdh  * Firmware event log header format
5514c06356bSdh  */
5524c06356bSdh typedef struct pmcs_fw_event_hdr_s {
5534c06356bSdh 	uint32_t	fw_el_signature;
5544c06356bSdh 	uint32_t	fw_el_entry_start_offset;
5554c06356bSdh 	uint32_t	fw_el_rsvd1;
5564c06356bSdh 	uint32_t	fw_el_buf_size;
5574c06356bSdh 	uint32_t	fw_el_rsvd2;
5584c06356bSdh 	uint32_t	fw_el_oldest_idx;
5594c06356bSdh 	uint32_t	fw_el_latest_idx;
5604c06356bSdh 	uint32_t	fw_el_entry_size;
5614c06356bSdh } pmcs_fw_event_hdr_t;
5624c06356bSdh 
5631f81b464SDavid Hollister /*
5641f81b464SDavid Hollister  * Firmware event log entry format
5651f81b464SDavid Hollister  */
5661f81b464SDavid Hollister typedef struct pmcs_fw_event_entry_s {
5671f81b464SDavid Hollister 	uint32_t	num_words : 3,
5681f81b464SDavid Hollister 			reserved : 25,
5691f81b464SDavid Hollister 			severity: 4;
5701f81b464SDavid Hollister 	uint32_t	ts_upper;
5711f81b464SDavid Hollister 	uint32_t	ts_lower;
5721f81b464SDavid Hollister 	uint32_t	seq_num;
5731f81b464SDavid Hollister 	uint32_t	logw0;
5741f81b464SDavid Hollister 	uint32_t	logw1;
5751f81b464SDavid Hollister 	uint32_t	logw2;
5761f81b464SDavid Hollister 	uint32_t	logw3;
5771f81b464SDavid Hollister } pmcs_fw_event_entry_t;
5781f81b464SDavid Hollister 
5791f81b464SDavid Hollister #define	PMCS_FWLOG_TIMER_DIV	8	/* fw timer has 8ns granularity */
5801f81b464SDavid Hollister #define	PMCS_FWLOG_AAP1_SIG	0x1234AAAA
5811f81b464SDavid Hollister #define	PMCS_FWLOG_IOP_SIG	0x5678CCCC
5821f81b464SDavid Hollister 
583658280b6SDavid Hollister /*
584658280b6SDavid Hollister  * Receptacle information
585658280b6SDavid Hollister  */
586658280b6SDavid Hollister #define	PMCS_NUM_RECEPTACLES	2
587658280b6SDavid Hollister 
588658280b6SDavid Hollister #define	PMCS_RECEPT_LABEL_0	"SAS0"
589658280b6SDavid Hollister #define	PMCS_RECEPT_LABEL_1	"SAS1"
590658280b6SDavid Hollister 
5911f81b464SDavid Hollister #define	PMCS_RECEPT_PM_0	"f0"
5921f81b464SDavid Hollister #define	PMCS_RECEPT_PM_1	"f"
593658280b6SDavid Hollister 
5944c06356bSdh #ifdef	__cplusplus
5954c06356bSdh }
5964c06356bSdh #endif
5974c06356bSdh #endif	/* _PMCS_DEF_H */
598