xref: /illumos-gate/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h (revision 4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6)
1*4c06356bSdh /*
2*4c06356bSdh  * CDDL HEADER START
3*4c06356bSdh  *
4*4c06356bSdh  * The contents of this file are subject to the terms of the
5*4c06356bSdh  * Common Development and Distribution License (the "License").
6*4c06356bSdh  * You may not use this file except in compliance with the License.
7*4c06356bSdh  *
8*4c06356bSdh  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4c06356bSdh  * or http://www.opensolaris.org/os/licensing.
10*4c06356bSdh  * See the License for the specific language governing permissions
11*4c06356bSdh  * and limitations under the License.
12*4c06356bSdh  *
13*4c06356bSdh  * When distributing Covered Code, include this CDDL HEADER in each
14*4c06356bSdh  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4c06356bSdh  * If applicable, add the following below this CDDL HEADER, with the
16*4c06356bSdh  * fields enclosed by brackets "[]" replaced with your own identifying
17*4c06356bSdh  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4c06356bSdh  *
19*4c06356bSdh  * CDDL HEADER END
20*4c06356bSdh  *
21*4c06356bSdh  *
22*4c06356bSdh  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*4c06356bSdh  * Use is subject to license terms.
24*4c06356bSdh  */
25*4c06356bSdh #ifndef	_PMCS_DEF_H
26*4c06356bSdh #define	_PMCS_DEF_H
27*4c06356bSdh #ifdef	__cplusplus
28*4c06356bSdh extern "C" {
29*4c06356bSdh #endif
30*4c06356bSdh 
31*4c06356bSdh typedef enum {
32*4c06356bSdh 	NOTHING,	/* nothing connected here */
33*4c06356bSdh 	SATA,		/* SATA connection */
34*4c06356bSdh 	SAS,		/* direct or indirect SAS connection */
35*4c06356bSdh 	EXPANDER,	/* connection to an expander */
36*4c06356bSdh 	NEW		/* Brand new device (pending state) */
37*4c06356bSdh } pmcs_dtype_t;
38*4c06356bSdh 
39*4c06356bSdh /*
40*4c06356bSdh  * This structure defines a PHY device that represents what we
41*4c06356bSdh  * are connected to.
42*4c06356bSdh  *
43*4c06356bSdh  * The eight real physical PHYs that are in the PMC8X6G are represented
44*4c06356bSdh  * as an array of eight of these structures which define what these
45*4c06356bSdh  * real PHYs are connected to.
46*4c06356bSdh  *
47*4c06356bSdh  * Depending upon what is actually connected to each PHY, the
48*4c06356bSdh  * type set will define what we're connected to. If it is
49*4c06356bSdh  * a direct SATA connection, the phy will describe a SATA endpoint
50*4c06356bSdh  * If it is a direct SAS connection, it will describe a SAS
51*4c06356bSdh  * endpoint.
52*4c06356bSdh  *
53*4c06356bSdh  * If it is an EXPANDER, this will describe the edge of an expander.
54*4c06356bSdh  * As we perform discovery on what is in an EXPANDER we define an
55*4c06356bSdh  * additional list of phys that represent what the Expander is connected to.
56*4c06356bSdh  */
57*4c06356bSdh #define	PMCS_HW_MIN_LINK_RATE	SAS_LINK_RATE_1_5GBIT
58*4c06356bSdh #define	PMCS_HW_MAX_LINK_RATE	SAS_LINK_RATE_6GBIT
59*4c06356bSdh 
60*4c06356bSdh #define	PMCS_INVALID_DEVICE_ID	0xffffffff
61*4c06356bSdh 
62*4c06356bSdh struct pmcs_phy {
63*4c06356bSdh 	pmcs_phy_t	*sibling;	/* sibling phy */
64*4c06356bSdh 	pmcs_phy_t 	*parent;	/* parent phy */
65*4c06356bSdh 	pmcs_phy_t 	*children;	/* head of list of children */
66*4c06356bSdh 	pmcs_phy_t 	*dead_next;	/* dead PHY list link */
67*4c06356bSdh 	list_node_t	list_node;	/* list element */
68*4c06356bSdh 	uint32_t	device_id;	/* PMC8X6G device handle */
69*4c06356bSdh 	uint32_t
70*4c06356bSdh 		ncphy 		: 8,	/* # of contained phys for expander */
71*4c06356bSdh 		hw_event_ack	: 24;	/* XXX: first level phy event acked */
72*4c06356bSdh 	uint8_t		phynum;		/* phy number on parent expander */
73*4c06356bSdh 	uint8_t		width;		/* how many phys wide */
74*4c06356bSdh 	uint8_t		ds_recovery_retries; /* # error retry attempts */
75*4c06356bSdh 	pmcs_dtype_t	dtype;		/* current dtype of the phy */
76*4c06356bSdh 	pmcs_dtype_t	pend_dtype;	/* new dtype (pending change) */
77*4c06356bSdh 	uint32_t
78*4c06356bSdh 		level		: 8,	/* level in expander tree */
79*4c06356bSdh 		tolerates_sas2	: 1,	/* tolerates SAS2 SMP */
80*4c06356bSdh 		spinup_hold	: 1,	/* spinup hold needs releasing */
81*4c06356bSdh 		atdt		: 3,	/* attached device type */
82*4c06356bSdh 		portid		: 4,	/* PMC8X6G port context */
83*4c06356bSdh 		link_rate   	: 4,	/* current supported speeds */
84*4c06356bSdh 		valid_device_id	: 1,	/* device id is valid */
85*4c06356bSdh 		abort_sent	: 1,	/* we've sent an abort */
86*4c06356bSdh 		abort_pending	: 1,	/* we have an abort pending */
87*4c06356bSdh 		need_rl_ext	: 1,	/* need SATA RL_EXT recocvery */
88*4c06356bSdh 		subsidiary	: 1,	/* this is part of a wide phy */
89*4c06356bSdh 		configured	: 1,	/* is configured */
90*4c06356bSdh 		dead		: 1,	/* dead */
91*4c06356bSdh 		changed		: 1;	/* this phy is changing */
92*4c06356bSdh 	clock_t		config_stop;	/* When config attempts will stop */
93*4c06356bSdh 	hrtime_t	abort_all_start;
94*4c06356bSdh 	kcondvar_t	abort_all_cv;	/* Wait for ABORT_ALL completion */
95*4c06356bSdh 	kmutex_t	phy_lock;
96*4c06356bSdh 	volatile uint32_t ref_count;	/* Targets & work on this PHY */
97*4c06356bSdh 	uint8_t 	sas_address[8];	/* SAS address for this PHY */
98*4c06356bSdh 	struct {
99*4c06356bSdh 	uint32_t
100*4c06356bSdh 		prog_min_rate	:4,
101*4c06356bSdh 		hw_min_rate	:4,
102*4c06356bSdh 		prog_max_rate	:4,
103*4c06356bSdh 		hw_max_rate	:4,
104*4c06356bSdh 		reserved	:16;
105*4c06356bSdh 	} state;
106*4c06356bSdh 	char		path[32];	/* path name for this phy */
107*4c06356bSdh 	pmcs_hw_t	*pwp;		/* back ptr to hba struct */
108*4c06356bSdh 	pmcs_iport_t	*iport;		/* back ptr to the iport handle */
109*4c06356bSdh 	pmcs_xscsi_t	*target;	/* back ptr to current target */
110*4c06356bSdh 	kstat_t		*phy_stats;	/* kstats for this phy */
111*4c06356bSdh };
112*4c06356bSdh 
113*4c06356bSdh /* maximum number of ds recovery retries (ds_recovery_retries) */
114*4c06356bSdh #define	PMCS_MAX_DS_RECOVERY_RETRIES	4
115*4c06356bSdh 
116*4c06356bSdh 
117*4c06356bSdh /*
118*4c06356bSdh  * Inbound and Outbound Queue Related Definitions.
119*4c06356bSdh  *
120*4c06356bSdh  * The PMC8X6G has a programmable number of inbound and outbound circular
121*4c06356bSdh  * queues for use in message passing between the host and the PMC8X6G
122*4c06356bSdh  * (up to 64 queues for the Rev C Chip). This driver does not use all
123*4c06356bSdh  * possible queues.
124*4c06356bSdh  *
125*4c06356bSdh  * Each Queue is given 4K of consistent memory and we set a 64 byte size for
126*4c06356bSdh  * the queue entry size (this gives us 256 queue entries per queue).
127*4c06356bSdh  *
128*4c06356bSdh  * This allocation then continues up a further PMCS_SCRATCH_SIZE bytes
129*4c06356bSdh  * that the driver uses as a temporary scratch area for things like
130*4c06356bSdh  * SMP discovery.
131*4c06356bSdh  *
132*4c06356bSdh  * This control area looks like this:
133*4c06356bSdh  *
134*4c06356bSdh  * Offset			What
135*4c06356bSdh  * ------------------------------------------------
136*4c06356bSdh  * 0					IQ 0 Consumer Index
137*4c06356bSdh  * 4					IQ 1 Consumer Index
138*4c06356bSdh  * 8..255				...
139*4c06356bSdh  * 252..255				IQ 63 Consumer Index
140*4c06356bSdh  * 256					OQ 0 Producer Index
141*4c06356bSdh  * 260					OQ 1 Producer Index
142*4c06356bSdh  * 264..259				....
143*4c06356bSdh  * 508..511				OQ 63 Producer Index
144*4c06356bSdh  * 512..512+PMCS_SCRATCH_SIZE-1		Scratch area.
145*4c06356bSdh  */
146*4c06356bSdh #define	IQCI_BASE_OFFSET	0
147*4c06356bSdh #define	IQ_OFFSET(qnum)		(IQCI_BASE_OFFSET + (qnum << 2))
148*4c06356bSdh #define	OQPI_BASE_OFFSET	256
149*4c06356bSdh #define	OQ_OFFSET(qnum)		(OQPI_BASE_OFFSET + (qnum << 2))
150*4c06356bSdh 
151*4c06356bSdh /*
152*4c06356bSdh  * Work related structures. Each one of these structures is paired
153*4c06356bSdh  * with *any* command that is fed to the PMC8X6G via one of the
154*4c06356bSdh  * Inbound Queues. The work structure has a tag to compare with
155*4c06356bSdh  * the message that comes back out of an Outbound Queue. The
156*4c06356bSdh  * work structure also points to the phy which this command is
157*4c06356bSdh  * tied to. It also has a pointer a callback function (if defined).
158*4c06356bSdh  * See that TAG Architecture below for the various kinds of
159*4c06356bSdh  * dispositions of a work structure.
160*4c06356bSdh  */
161*4c06356bSdh 
162*4c06356bSdh /*
163*4c06356bSdh  * Work Structure States
164*4c06356bSdh  *
165*4c06356bSdh  * NIL			->	READY
166*4c06356bSdh  * READY		->	NIL
167*4c06356bSdh  * READY		->	ONCHIP
168*4c06356bSdh  * ONCHIP		->	INTR
169*4c06356bSdh  * INTR			->	READY
170*4c06356bSdh  * INTR			->	NIL
171*4c06356bSdh  * INTR			->	ABORTED
172*4c06356bSdh  * INTR			->	TIMED_OUT
173*4c06356bSdh  * ABORTED		->	NIL
174*4c06356bSdh  * TIMED_OUT		->	NIL
175*4c06356bSdh  */
176*4c06356bSdh typedef enum {
177*4c06356bSdh 	PMCS_WORK_STATE_NIL = 0,
178*4c06356bSdh 	PMCS_WORK_STATE_READY,
179*4c06356bSdh 	PMCS_WORK_STATE_ONCHIP,
180*4c06356bSdh 	PMCS_WORK_STATE_INTR,
181*4c06356bSdh 	PMCS_WORK_STATE_IOCOMPQ,
182*4c06356bSdh 	PMCS_WORK_STATE_ABORTED,
183*4c06356bSdh 	PMCS_WORK_STATE_TIMED_OUT
184*4c06356bSdh } pmcs_work_state_t;
185*4c06356bSdh 
186*4c06356bSdh struct pmcwork {
187*4c06356bSdh 	STAILQ_ENTRY(pmcwork)	next;
188*4c06356bSdh 	kmutex_t		lock;
189*4c06356bSdh 	kcondvar_t		sleep_cv;
190*4c06356bSdh 	void			*ptr;	/* linkage or callback function */
191*4c06356bSdh 	void 			*arg;	/* command specific data */
192*4c06356bSdh 	pmcs_phy_t 		*phy;	/* phy who owns this command */
193*4c06356bSdh 	pmcs_xscsi_t		*xp;	/* Back pointer to xscsi struct */
194*4c06356bSdh 	volatile uint32_t	htag;	/* tag for this structure */
195*4c06356bSdh 	uint32_t
196*4c06356bSdh 			timer	:	27,
197*4c06356bSdh 			onwire	:	1,
198*4c06356bSdh 			dead	:	1,
199*4c06356bSdh 			state	:	3;
200*4c06356bSdh 	hrtime_t		start;	/* timestamp start */
201*4c06356bSdh 	uint32_t		ssp_event; /* ssp event */
202*4c06356bSdh 	pmcs_dtype_t		dtype;	/* stash, incase phy gets cleared */
203*4c06356bSdh 
204*4c06356bSdh 	/* DEBUG-only fields from here on */
205*4c06356bSdh 	void			*last_ptr;
206*4c06356bSdh 	void			*last_arg;
207*4c06356bSdh 	pmcs_phy_t		*last_phy;
208*4c06356bSdh 	pmcs_xscsi_t		*last_xp;
209*4c06356bSdh 	uint32_t		last_htag;
210*4c06356bSdh 	pmcs_work_state_t	last_state;
211*4c06356bSdh 	hrtime_t		finish;
212*4c06356bSdh };
213*4c06356bSdh 
214*4c06356bSdh #define	PMCS_REC_EVENT	0xffffffff	/* event recovery */
215*4c06356bSdh 
216*4c06356bSdh /*
217*4c06356bSdh  * This structure defines a PMC-Sierra defined firmware header.
218*4c06356bSdh  */
219*4c06356bSdh #pragma	pack(4)
220*4c06356bSdh typedef struct {
221*4c06356bSdh 	char 		vendor_id[8];
222*4c06356bSdh 	uint8_t		product_id;
223*4c06356bSdh 	uint8_t		hwrev;
224*4c06356bSdh 	uint8_t		destination_partition;
225*4c06356bSdh 	uint8_t		reserved0;
226*4c06356bSdh 	uint8_t		fwrev[4];
227*4c06356bSdh 	uint32_t	firmware_length;
228*4c06356bSdh 	uint32_t	crc;
229*4c06356bSdh 	uint32_t	start_address;
230*4c06356bSdh 	uint8_t		data[];
231*4c06356bSdh } pmcs_fw_hdr_t;
232*4c06356bSdh #pragma	pack()
233*4c06356bSdh 
234*4c06356bSdh /*
235*4c06356bSdh  * Offlevel work as a bit pattern.
236*4c06356bSdh  */
237*4c06356bSdh #define	PMCS_WORK_DISCOVER		0
238*4c06356bSdh #define	PMCS_WORK_REM_DEVICES		2
239*4c06356bSdh #define	PMCS_WORK_ABORT_HANDLE		3
240*4c06356bSdh #define	PMCS_WORK_SPINUP_RELEASE	4
241*4c06356bSdh #define	PMCS_WORK_SAS_HW_ACK		5
242*4c06356bSdh #define	PMCS_WORK_SATA_RUN		6
243*4c06356bSdh #define	PMCS_WORK_RUN_QUEUES		7
244*4c06356bSdh #define	PMCS_WORK_ADD_DMA_CHUNKS	8
245*4c06356bSdh #define	PMCS_WORK_DS_ERR_RECOVERY	9
246*4c06356bSdh #define	PMCS_WORK_SSP_EVT_RECOVERY	10
247*4c06356bSdh 
248*4c06356bSdh /*
249*4c06356bSdh  * The actual values as they appear in work_flags
250*4c06356bSdh  */
251*4c06356bSdh #define	PMCS_WORK_FLAG_DISCOVER		(1 << 0)
252*4c06356bSdh #define	PMCS_WORK_FLAG_REM_DEVICES	(1 << 2)
253*4c06356bSdh #define	PMCS_WORK_FLAG_ABORT_HANDLE	(1 << 3)
254*4c06356bSdh #define	PMCS_WORK_FLAG_SPINUP_RELEASE	(1 << 4)
255*4c06356bSdh #define	PMCS_WORK_FLAG_SAS_HW_ACK	(1 << 5)
256*4c06356bSdh #define	PMCS_WORK_FLAG_SATA_RUN		(1 << 6)
257*4c06356bSdh #define	PMCS_WORK_FLAG_RUN_QUEUES	(1 << 7)
258*4c06356bSdh #define	PMCS_WORK_FLAG_ADD_DMA_CHUNKS	(1 << 8)
259*4c06356bSdh #define	PMCS_WORK_FLAG_DS_ERR_RECOVERY	(1 << 9)
260*4c06356bSdh #define	PMCS_WORK_FLAG_SSP_EVT_RECOVERY (1 << 10)
261*4c06356bSdh 
262*4c06356bSdh /*
263*4c06356bSdh  * This structure is used by this function to test MPI (and interrupts)
264*4c06356bSdh  * after MPI has been started to make sure it's working reliably.
265*4c06356bSdh  */
266*4c06356bSdh typedef struct {
267*4c06356bSdh 	uint32_t signature;
268*4c06356bSdh 	uint32_t count;
269*4c06356bSdh 	uint32_t *ptr;
270*4c06356bSdh } echo_test_t;
271*4c06356bSdh #define	ECHO_SIGNATURE	0xbebebeef
272*4c06356bSdh 
273*4c06356bSdh /*
274*4c06356bSdh  * Tag Architecture. The PMC has 32 bit tags for MPI messages.
275*4c06356bSdh  * We use this tag this way.
276*4c06356bSdh  *
277*4c06356bSdh  * bits		what
278*4c06356bSdh  * ------------------------
279*4c06356bSdh  * 31		done bit
280*4c06356bSdh  * 30..28	tag type
281*4c06356bSdh  * 27..12	rolling serial number
282*4c06356bSdh  * 11..0	index into work area to get pmcwork structure
283*4c06356bSdh  *
284*4c06356bSdh  * A tag type of NONE means that nobody is waiting on any results,
285*4c06356bSdh  * so the interrupt code frees the work structure that has this
286*4c06356bSdh  * tag.
287*4c06356bSdh  *
288*4c06356bSdh  * A tag type of CBACK means that the the interrupt handler
289*4c06356bSdh  * takes the tag 'arg' in the work structure to be a callback
290*4c06356bSdh  * function pointer (see pmcs_cb_t). The callee is responsible
291*4c06356bSdh  * for freeing the work structure that has this tag.
292*4c06356bSdh  *
293*4c06356bSdh  * A tag type of WAIT means that the issuer of the work needs
294*4c06356bSdh  * be woken up from interrupt level when the command completes
295*4c06356bSdh  * (or times out). If work structure tag 'arg' is non-null,
296*4c06356bSdh  * up to 2*PMCS_QENTRY_SIZE bits of data from the Outbound Queue
297*4c06356bSdh  * entry may be copied to the area pointed to by 'arg'. This
298*4c06356bSdh  * allows issuers to get directly at the results of the command
299*4c06356bSdh  * they issed. The synchronization point for the issuer and the
300*4c06356bSdh  * interrupt code for command done notification is the setting
301*4c06356bSdh  * of the 'DONE' bit in the tag as stored in the work structure.
302*4c06356bSdh  */
303*4c06356bSdh #define	PMCS_TAG_TYPE_FREE	0
304*4c06356bSdh #define	PMCS_TAG_TYPE_NONE	1
305*4c06356bSdh #define	PMCS_TAG_TYPE_CBACK  	2
306*4c06356bSdh #define	PMCS_TAG_TYPE_WAIT	3
307*4c06356bSdh #define	PMCS_TAG_TYPE_SHIFT	28
308*4c06356bSdh #define	PMCS_TAG_SERNO_SHIFT	12
309*4c06356bSdh #define	PMCS_TAG_INDEX_SHIFT	0
310*4c06356bSdh #define	PMCS_TAG_TYPE_MASK	0x70000000
311*4c06356bSdh #define	PMCS_TAG_DONE		0x80000000
312*4c06356bSdh #define	PMCS_TAG_SERNO_MASK	0x0ffff000
313*4c06356bSdh #define	PMCS_TAG_INDEX_MASK	0x00000fff
314*4c06356bSdh #define	PMCS_TAG_TYPE(x)		\
315*4c06356bSdh 	(((x) & PMCS_TAG_TYPE_MASK) >> PMCS_TAG_TYPE_SHIFT)
316*4c06356bSdh #define	PMCS_TAG_SERNO(x)	\
317*4c06356bSdh 	(((x) & PMCS_TAG_SERNO_MASK) >> PMCS_TAG_SERNO_SHIFT)
318*4c06356bSdh #define	PMCS_TAG_INDEX(x)	\
319*4c06356bSdh 	(((x) & PMCS_TAG_INDEX_MASK) >> PMCS_TAG_INDEX_SHIFT)
320*4c06356bSdh #define	PMCS_TAG_FREE		0
321*4c06356bSdh #define	PMCS_COMMAND_DONE(x)	\
322*4c06356bSdh 	(((x)->htag == PMCS_TAG_FREE) || (((x)->htag & PMCS_TAG_DONE) != 0))
323*4c06356bSdh #define	PMCS_COMMAND_ACTIVE(x)	\
324*4c06356bSdh 	((x)->htag != PMCS_TAG_FREE && (x)->state == PMCS_WORK_STATE_ONCHIP)
325*4c06356bSdh 
326*4c06356bSdh /*
327*4c06356bSdh  * Miscellaneous Definitions
328*4c06356bSdh  */
329*4c06356bSdh #define	CLEAN_MESSAGE(m, x)	{	\
330*4c06356bSdh 	int _j = x;			\
331*4c06356bSdh 	while (_j < PMCS_MSG_SIZE) {	\
332*4c06356bSdh 		m[_j++] = 0;		\
333*4c06356bSdh 	}				\
334*4c06356bSdh }
335*4c06356bSdh 
336*4c06356bSdh #define	COPY_MESSAGE(t, f, a)	{	\
337*4c06356bSdh 	int _j;				\
338*4c06356bSdh 	for (_j = 0; _j < a; _j++) {	\
339*4c06356bSdh 		t[_j] = f[_j];		\
340*4c06356bSdh 	}				\
341*4c06356bSdh 	while (_j < PMCS_MSG_SIZE) {	\
342*4c06356bSdh 		t[_j++] = 0;		\
343*4c06356bSdh 	}				\
344*4c06356bSdh }
345*4c06356bSdh 
346*4c06356bSdh #define	PMCS_PHY_ADDRESSABLE(pp)			\
347*4c06356bSdh 	((pp)->level == 0 && (pp)->dtype == SATA &&	\
348*4c06356bSdh 	    ((pp)->sas_address[0] >> 4) != 5)
349*4c06356bSdh 
350*4c06356bSdh #define	RESTART_DISCOVERY(pwp)				\
351*4c06356bSdh 	ASSERT(!mutex_owned(&pwp->config_lock));	\
352*4c06356bSdh 	mutex_enter(&pwp->config_lock);			\
353*4c06356bSdh 	pwp->config_changed = B_TRUE;			\
354*4c06356bSdh 	mutex_exit(&pwp->config_lock);			\
355*4c06356bSdh 	SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
356*4c06356bSdh 
357*4c06356bSdh #define	RESTART_DISCOVERY_LOCKED(pwp)			\
358*4c06356bSdh 	ASSERT(mutex_owned(&pwp->config_lock));		\
359*4c06356bSdh 	pwp->config_changed = B_TRUE;			\
360*4c06356bSdh 	SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
361*4c06356bSdh 
362*4c06356bSdh #define	PHY_CHANGED(pwp, p)						\
363*4c06356bSdh 	pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "%s changed in %s line %d", \
364*4c06356bSdh 	    p->path, __func__, __LINE__);				\
365*4c06356bSdh 	p->changed = 1
366*4c06356bSdh 
367*4c06356bSdh #define	PHY_CHANGED_AT_LOCATION(pwp, p, func, line)			\
368*4c06356bSdh 	pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "%s changed in %s line %d", \
369*4c06356bSdh 	    p->path, func, line);					\
370*4c06356bSdh 	p->changed = 1
371*4c06356bSdh 
372*4c06356bSdh #define	PHY_TYPE(pptr)					\
373*4c06356bSdh 	(((pptr)->dtype == NOTHING)?  "NOTHING" :	\
374*4c06356bSdh 	(((pptr)->dtype == SATA)? "SATA" :		\
375*4c06356bSdh 	(((pptr)->dtype == SAS)? "SAS" : "EXPANDER")))
376*4c06356bSdh 
377*4c06356bSdh #define	IS_ROOT_PHY(pptr)	(pptr->parent == NULL)
378*4c06356bSdh 
379*4c06356bSdh #define	PMCS_HIPRI(pwp, oq, c)				\
380*4c06356bSdh 	(pwp->hipri_queue & (1 << PMCS_IQ_OTHER)) ?	\
381*4c06356bSdh 	(PMCS_IOMB_HIPRI | PMCS_IOMB_IN_SAS(oq, c)) :	\
382*4c06356bSdh 	(PMCS_IOMB_IN_SAS(oq, c))
383*4c06356bSdh 
384*4c06356bSdh #define	SCHEDULE_WORK(hwp, wrk)		\
385*4c06356bSdh 	(void) atomic_set_long_excl(&hwp->work_flags, wrk)
386*4c06356bSdh 
387*4c06356bSdh /*
388*4c06356bSdh  * Check to see if the requested work bit is set.  Either way, the bit will
389*4c06356bSdh  * be cleared upon return.
390*4c06356bSdh  */
391*4c06356bSdh #define	WORK_SCHEDULED(hwp, wrk)	\
392*4c06356bSdh 	(atomic_clear_long_excl(&hwp->work_flags, wrk) == 0)
393*4c06356bSdh 
394*4c06356bSdh /*
395*4c06356bSdh  * Check to see if the requested work bit is set.  The value will not be
396*4c06356bSdh  * changed in this case.  The atomic_xx_nv operations can be quite expensive
397*4c06356bSdh  * so this should not be used in non-DEBUG code.
398*4c06356bSdh  */
399*4c06356bSdh #define	WORK_IS_SCHEDULED(hwp, wrk)	\
400*4c06356bSdh 	((atomic_and_ulong_nv(&hwp->work_flags, (ulong_t)-1) & (1 << wrk)) != 0)
401*4c06356bSdh 
402*4c06356bSdh #define	WAIT_FOR(p, t, r)					\
403*4c06356bSdh 	r = 0;							\
404*4c06356bSdh 	while (!PMCS_COMMAND_DONE(p)) {				\
405*4c06356bSdh 		clock_t tmp = cv_timedwait(&p->sleep_cv,	\
406*4c06356bSdh 		    &p->lock, ddi_get_lbolt() +			\
407*4c06356bSdh 		    drv_usectohz(t * 1000));			\
408*4c06356bSdh 		if (!PMCS_COMMAND_DONE(p) && tmp < 0) {		\
409*4c06356bSdh 			r = 1;					\
410*4c06356bSdh 			break;					\
411*4c06356bSdh 		}						\
412*4c06356bSdh 	}
413*4c06356bSdh 
414*4c06356bSdh /*
415*4c06356bSdh  * Signal the next I/O completion thread to start running.
416*4c06356bSdh  */
417*4c06356bSdh 
418*4c06356bSdh #define	PMCS_CQ_RUN_LOCKED(hwp)						\
419*4c06356bSdh 	if (!STAILQ_EMPTY(&hwp->cq) || hwp->iocomp_cb_head) {		\
420*4c06356bSdh 		pmcs_cq_thr_info_t *cqti;				\
421*4c06356bSdh 		cqti = &hwp->cq_info.cq_thr_info			\
422*4c06356bSdh 		    [hwp->cq_info.cq_next_disp_thr];			\
423*4c06356bSdh 		hwp->cq_info.cq_next_disp_thr++;			\
424*4c06356bSdh 		if (hwp->cq_info.cq_next_disp_thr ==			\
425*4c06356bSdh 		    hwp->cq_info.cq_threads) {				\
426*4c06356bSdh 			hwp->cq_info.cq_next_disp_thr = 0;		\
427*4c06356bSdh 		}							\
428*4c06356bSdh 		mutex_enter(&cqti->cq_thr_lock);			\
429*4c06356bSdh 		cv_signal(&cqti->cq_cv);				\
430*4c06356bSdh 		mutex_exit(&cqti->cq_thr_lock);				\
431*4c06356bSdh 	}								\
432*4c06356bSdh 
433*4c06356bSdh #define	PMCS_CQ_RUN(hwp)						\
434*4c06356bSdh 	mutex_enter(&hwp->cq_lock);					\
435*4c06356bSdh 	PMCS_CQ_RUN_LOCKED(hwp);					\
436*4c06356bSdh 	mutex_exit(&hwp->cq_lock);
437*4c06356bSdh 
438*4c06356bSdh 
439*4c06356bSdh /*
440*4c06356bSdh  * Watchdog/SCSA timer definitions
441*4c06356bSdh  */
442*4c06356bSdh /* usecs to SCSA watchdog ticks */
443*4c06356bSdh #define	US2WT(x)	(x)/10
444*4c06356bSdh 
445*4c06356bSdh /*
446*4c06356bSdh  * More misc
447*4c06356bSdh  */
448*4c06356bSdh #define	BYTE0(x)	(((x) >>  0) & 0xff)
449*4c06356bSdh #define	BYTE1(x)	(((x) >>  8) & 0xff)
450*4c06356bSdh #define	BYTE2(x)	(((x) >> 16) & 0xff)
451*4c06356bSdh #define	BYTE3(x)	(((x) >> 24) & 0xff)
452*4c06356bSdh #define	BYTE4(x)	(((x) >> 32) & 0xff)
453*4c06356bSdh #define	BYTE5(x)	(((x) >> 40) & 0xff)
454*4c06356bSdh #define	BYTE6(x)	(((x) >> 48) & 0xff)
455*4c06356bSdh #define	BYTE7(x)	(((x) >> 56) & 0xff)
456*4c06356bSdh #define	WORD0(x)	(((x) >>  0) & 0xffff)
457*4c06356bSdh #define	WORD1(x)	(((x) >> 16) & 0xffff)
458*4c06356bSdh #define	WORD2(x)	(((x) >> 32) & 0xffff)
459*4c06356bSdh #define	WORD3(x)	(((x) >> 48) & 0xffff)
460*4c06356bSdh #define	DWORD0(x)	((uint32_t)(x))
461*4c06356bSdh #define	DWORD1(x)	((uint32_t)(((uint64_t)x) >> 32))
462*4c06356bSdh 
463*4c06356bSdh #define	SAS_ADDR_FMT	"0x%02x%02x%02x%02x%02x%02x%02x%02x"
464*4c06356bSdh #define	SAS_ADDR_PRT(x)	x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]
465*4c06356bSdh 
466*4c06356bSdh #define	PMCS_VALID_LINK_RATE(r) \
467*4c06356bSdh 	((r == SAS_LINK_RATE_1_5GBIT) || (r == SAS_LINK_RATE_3GBIT) || \
468*4c06356bSdh 	(r == SAS_LINK_RATE_6GBIT))
469*4c06356bSdh 
470*4c06356bSdh /*
471*4c06356bSdh  * This is here to avoid inclusion of <sys/ctype.h> which is not lint clean.
472*4c06356bSdh  */
473*4c06356bSdh #define	HEXDIGIT(x)	(((x) >= '0' && (x) <= '9') || \
474*4c06356bSdh 	((x) >= 'a' && (x) <= 'f') || ((x) >= 'A' && (x) <= 'F'))
475*4c06356bSdh 
476*4c06356bSdh 
477*4c06356bSdh typedef void (*pmcs_cb_t) (pmcs_hw_t *, pmcwork_t *, uint32_t *);
478*4c06356bSdh 
479*4c06356bSdh /*
480*4c06356bSdh  * Defines and structure used for tracing/logging information
481*4c06356bSdh  */
482*4c06356bSdh 
483*4c06356bSdh #define	PMCS_TBUF_ELEM_SIZE	120
484*4c06356bSdh 
485*4c06356bSdh #ifdef DEBUG
486*4c06356bSdh #define	PMCS_TBUF_NUM_ELEMS_DEF	100000
487*4c06356bSdh #else
488*4c06356bSdh #define	PMCS_TBUF_NUM_ELEMS_DEF	15000
489*4c06356bSdh #endif
490*4c06356bSdh 
491*4c06356bSdh typedef struct {
492*4c06356bSdh 	timespec_t	timestamp;
493*4c06356bSdh 	char		buf[PMCS_TBUF_ELEM_SIZE];
494*4c06356bSdh } pmcs_tbuf_t;
495*4c06356bSdh 
496*4c06356bSdh /*
497*4c06356bSdh  * Firmware event log header format
498*4c06356bSdh  */
499*4c06356bSdh 
500*4c06356bSdh typedef struct pmcs_fw_event_hdr_s {
501*4c06356bSdh 	uint32_t	fw_el_signature;
502*4c06356bSdh 	uint32_t	fw_el_entry_start_offset;
503*4c06356bSdh 	uint32_t	fw_el_rsvd1;
504*4c06356bSdh 	uint32_t	fw_el_buf_size;
505*4c06356bSdh 	uint32_t	fw_el_rsvd2;
506*4c06356bSdh 	uint32_t	fw_el_oldest_idx;
507*4c06356bSdh 	uint32_t	fw_el_latest_idx;
508*4c06356bSdh 	uint32_t	fw_el_entry_size;
509*4c06356bSdh } pmcs_fw_event_hdr_t;
510*4c06356bSdh 
511*4c06356bSdh #ifdef	__cplusplus
512*4c06356bSdh }
513*4c06356bSdh #endif
514*4c06356bSdh #endif	/* _PMCS_DEF_H */
515