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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 #ifndef	_PMCS_DEF_H
25 #define	_PMCS_DEF_H
26 #ifdef	__cplusplus
27 extern "C" {
28 #endif
29 
30 typedef enum {
31 	NOTHING,	/* nothing connected here */
32 	SATA,		/* SATA connection */
33 	SAS,		/* direct or indirect SAS connection */
34 	EXPANDER,	/* connection to an expander */
35 	NEW		/* Brand new device (pending state) */
36 } pmcs_dtype_t;
37 
38 /*
39  * This structure defines a PHY device that represents what we
40  * are connected to.
41  *
42  * The eight real physical PHYs that are in the PMC8X6G are represented
43  * as an array of eight of these structures which define what these
44  * real PHYs are connected to.
45  *
46  * Depending upon what is actually connected to each PHY, the
47  * type set will define what we're connected to. If it is
48  * a direct SATA connection, the phy will describe a SATA endpoint
49  * If it is a direct SAS connection, it will describe a SAS
50  * endpoint.
51  *
52  * If it is an EXPANDER, this will describe the edge of an expander.
53  * As we perform discovery on what is in an EXPANDER we define an
54  * additional list of phys that represent what the Expander is connected to.
55  */
56 #define	PMCS_HW_MIN_LINK_RATE	SAS_LINK_RATE_1_5GBIT
57 #define	PMCS_HW_MAX_LINK_RATE	SAS_LINK_RATE_6GBIT
58 
59 #define	PMCS_INVALID_DEVICE_ID		0xffffffff
60 #define	PMCS_PHY_INVALID_PORT_ID	0xf
61 
62 #define	PMCS_PM_MAX_NAMELEN	16
63 #define	PMCS_MAX_REENUMERATE	2	/* Maximum re-enumeration attempts */
64 
65 /*
66  * Number of usecs to wait after last noted activate/deactivate callback
67  * before possibly restarting discovery
68  */
69 #define	PMCS_REDISCOVERY_DELAY	(5 * MICROSEC)
70 
71 struct pmcs_phy {
72 	pmcs_phy_t	*sibling;	/* sibling phy */
73 	pmcs_phy_t 	*parent;	/* parent phy */
74 	pmcs_phy_t 	*children;	/* head of list of children */
75 	pmcs_phy_t 	*dead_next;	/* dead PHY list link */
76 	list_node_t	list_node;	/* list element */
77 	uint32_t	device_id;	/* PMC8X6G device handle */
78 	uint32_t
79 		ncphy 		: 8,	/* # of contained phys for expander */
80 		hw_event_ack	: 24;	/* XXX: first level phy event acked */
81 	uint8_t		phynum;		/* phy number on parent expander */
82 	uint8_t		width;		/* how many phys wide */
83 	uint8_t		ds_recovery_retries; /* # error retry attempts */
84 	uint8_t		ds_prev_good_recoveries; /* # successful recoveries */
85 	clock_t		prev_recovery;	/* previous successful recovery */
86 	clock_t		last_good_recovery; /* oldest successful recovery */
87 			/* within PMCS_MAX_DS_RECOVERY_TIME time frame */
88 	pmcs_dtype_t	dtype;		/* current dtype of the phy */
89 	pmcs_dtype_t	pend_dtype;	/* new dtype (pending change) */
90 	uint32_t
91 		level		: 8,	/* level in expander tree */
92 		tolerates_sas2	: 1,	/* tolerates SAS2 SMP */
93 		spinup_hold	: 1,	/* spinup hold needs releasing */
94 		atdt		: 3,	/* attached device type */
95 		portid		: 4,	/* PMC8X6G port context */
96 		link_rate   	: 4,	/* current supported speeds */
97 		valid_device_id	: 1,	/* device id is valid */
98 		abort_sent	: 1,	/* we've sent an abort */
99 		abort_pending	: 1,	/* we have an abort pending */
100 		need_rl_ext	: 1,	/* need SATA RL_EXT recocvery */
101 		subsidiary	: 1,	/* this is part of a wide phy */
102 		configured	: 1,	/* is configured */
103 		dead		: 1,	/* dead */
104 		changed		: 1,	/* this phy is changing */
105 		reenumerate	: 1,	/* attempt re-enumeration */
106 		virtual		: 1,	/* This is a virtual PHY */
107 		deregister_wait : 1;	/* phy waiting to get deregistered */
108 	clock_t		config_stop;	/* When config attempts will stop */
109 	hrtime_t	abort_all_start;
110 	kcondvar_t	abort_all_cv;	/* Wait for ABORT_ALL completion */
111 	kmutex_t	phy_lock;
112 	volatile uint32_t ref_count;	/* Targets & work on this PHY */
113 	uint32_t	enum_attempts;	/* # of enumeration attempts */
114 	uint8_t 	sas_address[8];	/* SAS address for this PHY */
115 	struct {
116 	uint32_t
117 		prog_min_rate	:4,
118 		hw_min_rate	:4,
119 		prog_max_rate	:4,
120 		hw_max_rate	:4,
121 		reserved	:16;
122 	} state;
123 	char		path[32];	/* path name for this phy */
124 	pmcs_hw_t	*pwp;		/* back ptr to hba struct */
125 	pmcs_iport_t	*iport;		/* back ptr to the iport handle */
126 	pmcs_iport_t	*last_iport;	/* last iport this PHY was on */
127 	pmcs_xscsi_t	*target;	/* back ptr to current target */
128 	kstat_t		*phy_stats;	/* kstats for this phy */
129 	/*
130 	 * Attached port phy mask and target port phymask.  With 16 bytes
131 	 * we can represent a phymask for anything with up to 64 ports
132 	 */
133 	uint64_t	att_port_pm;		/* att port pm for this PHY */
134 	uint64_t	att_port_pm_tmp;	/* Temp area for wide-ports */
135 	char		att_port_pm_str[PMCS_PM_MAX_NAMELEN + 1];
136 	uint64_t	tgt_port_pm;		/* tgt port pm for this PHY */
137 	uint64_t	tgt_port_pm_tmp;	/* Temp area for wide-ports */
138 	char		tgt_port_pm_str[PMCS_PM_MAX_NAMELEN + 1];
139 	smp_routing_attr_t routing_attr; /* Routing attr. from discover resp. */
140 	smp_routing_attr_t routing_method; /* Actual routing method used. */
141 	smp_report_general_resp_t rg_resp;	/* Response to REPORT_GENERAL */
142 	smp_discover_resp_t disc_resp;		/* Response to DISCOVER */
143 };
144 
145 /* maximum number of ds recovery retries (ds_recovery_retries) */
146 #define	PMCS_MAX_DS_RECOVERY_RETRIES	10
147 
148 /* max time allowed for successful recovery */
149 #define	PMCS_MAX_DS_RECOVERY_TIME	(60 * 1000000) /* 60 seconds */
150 
151 /* ds recovery on same same phy is not allowed within this interval */
152 #define	PMCS_DS_RECOVERY_INTERVAL	(1000000) /* 1 second */
153 
154 
155 /*
156  * Inbound and Outbound Queue Related Definitions.
157  *
158  * The PMC8X6G has a programmable number of inbound and outbound circular
159  * queues for use in message passing between the host and the PMC8X6G
160  * (up to 64 queues for the Rev C Chip). This driver does not use all
161  * possible queues.
162  *
163  * Each Queue is given 4K of consistent memory and we set a 64 byte size for
164  * the queue entry size (this gives us 256 queue entries per queue).
165  *
166  * This allocation then continues up a further PMCS_SCRATCH_SIZE bytes
167  * that the driver uses as a temporary scratch area for things like
168  * SMP discovery.
169  *
170  * This control area looks like this:
171  *
172  * Offset			What
173  * ------------------------------------------------
174  * 0					IQ 0 Consumer Index
175  * 4					IQ 1 Consumer Index
176  * 8..255				...
177  * 252..255				IQ 63 Consumer Index
178  * 256					OQ 0 Producer Index
179  * 260					OQ 1 Producer Index
180  * 264..259				....
181  * 508..511				OQ 63 Producer Index
182  * 512..512+PMCS_SCRATCH_SIZE-1		Scratch area.
183  */
184 #define	IQCI_BASE_OFFSET	0
185 #define	IQ_OFFSET(qnum)		(IQCI_BASE_OFFSET + (qnum << 2))
186 #define	OQPI_BASE_OFFSET	256
187 #define	OQ_OFFSET(qnum)		(OQPI_BASE_OFFSET + (qnum << 2))
188 
189 /*
190  * Work related structures. Each one of these structures is paired
191  * with *any* command that is fed to the PMC8X6G via one of the
192  * Inbound Queues. The work structure has a tag to compare with
193  * the message that comes back out of an Outbound Queue. The
194  * work structure also points to the phy which this command is
195  * tied to. It also has a pointer a callback function (if defined).
196  * See that TAG Architecture below for the various kinds of
197  * dispositions of a work structure.
198  */
199 
200 /*
201  * Work Structure States
202  *
203  * NIL			->	READY
204  * READY		->	NIL
205  * READY		->	ONCHIP
206  * ONCHIP		->	INTR
207  * INTR			->	READY
208  * INTR			->	NIL
209  * INTR			->	ABORTED
210  * INTR			->	TIMED_OUT
211  * ABORTED		->	NIL
212  * TIMED_OUT		->	NIL
213  */
214 typedef enum {
215 	PMCS_WORK_STATE_NIL = 0,
216 	PMCS_WORK_STATE_READY,
217 	PMCS_WORK_STATE_ONCHIP,
218 	PMCS_WORK_STATE_INTR,
219 	PMCS_WORK_STATE_IOCOMPQ,
220 	PMCS_WORK_STATE_ABORTED,
221 	PMCS_WORK_STATE_TIMED_OUT
222 } pmcs_work_state_t;
223 
224 struct pmcwork {
225 	STAILQ_ENTRY(pmcwork)	next;
226 	kmutex_t		lock;
227 	kcondvar_t		sleep_cv;
228 	void			*ptr;	/* linkage or callback function */
229 	void 			*arg;	/* command specific data */
230 	pmcs_phy_t 		*phy;	/* phy who owns this command */
231 	pmcs_xscsi_t		*xp;	/* Back pointer to xscsi struct */
232 	volatile uint32_t	htag;	/* tag for this structure */
233 	uint32_t		abt_htag; /* Tag of command to be aborted */
234 	uint32_t
235 			timer	:	27,
236 			onwire	:	1,
237 			dead	:	1,
238 			state	:	3;
239 	hrtime_t		start;	/* timestamp start */
240 	uint32_t		ssp_event; /* ssp event */
241 	pmcs_dtype_t		dtype;	/* stash, incase phy gets cleared */
242 
243 	void			*last_ptr;
244 	void			*last_arg;
245 	pmcs_phy_t		*last_phy;
246 	pmcs_xscsi_t		*last_xp;
247 	uint32_t		last_htag;
248 	pmcs_work_state_t	last_state;
249 	hrtime_t		finish;
250 };
251 #define	PMCS_ABT_HTAG_ALL	0xffffffff
252 
253 #define	PMCS_REC_EVENT	0xffffffff	/* event recovery */
254 
255 /*
256  * This structure defines a PMC-Sierra defined firmware header.
257  */
258 #pragma	pack(4)
259 typedef struct {
260 	char 		vendor_id[8];
261 	uint8_t		product_id;
262 	uint8_t		hwrev;
263 	uint8_t		destination_partition;
264 	uint8_t		reserved0;
265 	uint8_t		fwrev[4];
266 	uint32_t	firmware_length;
267 	uint32_t	crc;
268 	uint32_t	start_address;
269 	uint8_t		data[];
270 } pmcs_fw_hdr_t;
271 #pragma	pack()
272 
273 /*
274  * Offlevel work as a bit pattern.
275  */
276 #define	PMCS_WORK_DISCOVER		0
277 #define	PMCS_WORK_ABORT_HANDLE		3
278 #define	PMCS_WORK_SPINUP_RELEASE	4
279 #define	PMCS_WORK_SAS_HW_ACK		5
280 #define	PMCS_WORK_SATA_RUN		6
281 #define	PMCS_WORK_RUN_QUEUES		7
282 #define	PMCS_WORK_ADD_DMA_CHUNKS	8
283 #define	PMCS_WORK_DS_ERR_RECOVERY	9
284 #define	PMCS_WORK_SSP_EVT_RECOVERY	10
285 #define	PMCS_WORK_DEREGISTER_DEV	11
286 #define	PMCS_WORK_DUMP_REGS		12
287 
288 /*
289  * The actual values as they appear in work_flags
290  */
291 #define	PMCS_WORK_FLAG_DISCOVER		(1 << 0)
292 #define	PMCS_WORK_FLAG_ABORT_HANDLE	(1 << 3)
293 #define	PMCS_WORK_FLAG_SPINUP_RELEASE	(1 << 4)
294 #define	PMCS_WORK_FLAG_SAS_HW_ACK	(1 << 5)
295 #define	PMCS_WORK_FLAG_SATA_RUN		(1 << 6)
296 #define	PMCS_WORK_FLAG_RUN_QUEUES	(1 << 7)
297 #define	PMCS_WORK_FLAG_ADD_DMA_CHUNKS	(1 << 8)
298 #define	PMCS_WORK_FLAG_DS_ERR_RECOVERY	(1 << 9)
299 #define	PMCS_WORK_FLAG_SSP_EVT_RECOVERY (1 << 10)
300 #define	PMCS_WORK_FLAG_DEREGISTER_DEV   (1 << 11)
301 #define	PMCS_WORK_FLAG_DUMP_REGS	(1 << 12)
302 
303 /*
304  * This structure is used by this function to test MPI (and interrupts)
305  * after MPI has been started to make sure it's working reliably.
306  */
307 typedef struct {
308 	uint32_t signature;
309 	uint32_t count;
310 	uint32_t *ptr;
311 } echo_test_t;
312 #define	ECHO_SIGNATURE	0xbebebeef
313 
314 /*
315  * Tag Architecture. The PMC has 32 bit tags for MPI messages.
316  * We use this tag this way.
317  *
318  * bits		what
319  * ------------------------
320  * 31		done bit
321  * 30		non-io cmd bit
322  * 29..28	tag type
323  * 27..12	rolling serial number
324  * 11..0	index into work area to get pmcwork structure
325  *
326  * A tag type of NONE means that nobody is waiting on any results,
327  * so the interrupt code frees the work structure that has this
328  * tag.
329  *
330  * A tag type of CBACK means that the the interrupt handler
331  * takes the tag 'arg' in the work structure to be a callback
332  * function pointer (see pmcs_cb_t). The callee is responsible
333  * for freeing the work structure that has this tag.
334  *
335  * A tag type of WAIT means that the issuer of the work needs
336  * be woken up from interrupt level when the command completes
337  * (or times out). If work structure tag 'arg' is non-null,
338  * up to 2*PMCS_QENTRY_SIZE bits of data from the Outbound Queue
339  * entry may be copied to the area pointed to by 'arg'. This
340  * allows issuers to get directly at the results of the command
341  * they issed. The synchronization point for the issuer and the
342  * interrupt code for command done notification is the setting
343  * of the 'DONE' bit in the tag as stored in the work structure.
344  */
345 #define	PMCS_TAG_TYPE_FREE	0
346 #define	PMCS_TAG_TYPE_NONE	1
347 #define	PMCS_TAG_TYPE_CBACK  	2
348 #define	PMCS_TAG_TYPE_WAIT	3
349 #define	PMCS_TAG_TYPE_SHIFT	28
350 #define	PMCS_TAG_SERNO_SHIFT	12
351 #define	PMCS_TAG_INDEX_SHIFT	0
352 #define	PMCS_TAG_TYPE_MASK	0x30000000
353 #define	PMCS_TAG_NONIO_CMD	0x40000000
354 #define	PMCS_TAG_DONE		0x80000000
355 #define	PMCS_TAG_SERNO_MASK	0x0ffff000
356 #define	PMCS_TAG_INDEX_MASK	0x00000fff
357 #define	PMCS_TAG_TYPE(x)		\
358 	(((x) & PMCS_TAG_TYPE_MASK) >> PMCS_TAG_TYPE_SHIFT)
359 #define	PMCS_TAG_SERNO(x)	\
360 	(((x) & PMCS_TAG_SERNO_MASK) >> PMCS_TAG_SERNO_SHIFT)
361 #define	PMCS_TAG_INDEX(x)	\
362 	(((x) & PMCS_TAG_INDEX_MASK) >> PMCS_TAG_INDEX_SHIFT)
363 #define	PMCS_TAG_FREE		0
364 #define	PMCS_COMMAND_DONE(x)	\
365 	(((x)->htag == PMCS_TAG_FREE) || (((x)->htag & PMCS_TAG_DONE) != 0))
366 #define	PMCS_COMMAND_ACTIVE(x)	\
367 	((x)->htag != PMCS_TAG_FREE && (x)->state == PMCS_WORK_STATE_ONCHIP)
368 
369 /*
370  * Miscellaneous Definitions
371  */
372 #define	CLEAN_MESSAGE(m, x)	{	\
373 	int _j = x;			\
374 	while (_j < PMCS_MSG_SIZE) {	\
375 		m[_j++] = 0;		\
376 	}				\
377 }
378 
379 #define	COPY_MESSAGE(t, f, a)	{	\
380 	int _j;				\
381 	for (_j = 0; _j < a; _j++) {	\
382 		t[_j] = f[_j];		\
383 	}				\
384 	while (_j < PMCS_MSG_SIZE) {	\
385 		t[_j++] = 0;		\
386 	}				\
387 }
388 
389 #define	PMCS_PHY_ADDRESSABLE(pp)			\
390 	((pp)->level == 0 && (pp)->dtype == SATA &&	\
391 	    ((pp)->sas_address[0] >> 4) != 5)
392 
393 #define	RESTART_DISCOVERY(pwp)				\
394 	ASSERT(!mutex_owned(&pwp->config_lock));	\
395 	mutex_enter(&pwp->config_lock);			\
396 	pwp->config_changed = B_TRUE;			\
397 	mutex_exit(&pwp->config_lock);			\
398 	SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
399 
400 #define	RESTART_DISCOVERY_LOCKED(pwp)			\
401 	ASSERT(mutex_owned(&pwp->config_lock));		\
402 	pwp->config_changed = B_TRUE;			\
403 	SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
404 
405 #define	PHY_CHANGED(pwp, p)						\
406 	pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, p, NULL, "%s changed in "  \
407 	    "%s line %d", p->path, __func__, __LINE__); 		\
408 	p->changed = 1;							\
409 	p->enum_attempts = 0
410 
411 #define	PHY_CHANGED_AT_LOCATION(pwp, p, func, line)			\
412 	pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, p, NULL, "%s changed in "  \
413 	    "%s line %d", p->path, func, line);				\
414 	p->changed = 1;							\
415 	p->enum_attempts = 0
416 
417 #define	PHY_TYPE(pptr)					\
418 	(((pptr)->dtype == NOTHING)?  "NOTHING" :	\
419 	(((pptr)->dtype == SATA)? "SATA" :		\
420 	(((pptr)->dtype == SAS)? "SAS" : "EXPANDER")))
421 
422 #define	IS_ROOT_PHY(pptr)	(pptr->parent == NULL)
423 
424 #define	PMCS_HIPRI(pwp, oq, c)				\
425 	(pwp->hipri_queue & (1 << PMCS_IQ_OTHER)) ?	\
426 	(PMCS_IOMB_HIPRI | PMCS_IOMB_IN_SAS(oq, c)) :	\
427 	(PMCS_IOMB_IN_SAS(oq, c))
428 
429 #define	SCHEDULE_WORK(hwp, wrk)		\
430 	(void) atomic_set_long_excl(&hwp->work_flags, wrk)
431 
432 /*
433  * Check to see if the requested work bit is set.  Either way, the bit will
434  * be cleared upon return.
435  */
436 #define	WORK_SCHEDULED(hwp, wrk)	\
437 	(atomic_clear_long_excl(&hwp->work_flags, wrk) == 0)
438 
439 /*
440  * Check to see if the requested work bit is set.  The value will not be
441  * changed in this case.  The atomic_xx_nv operations can be quite expensive
442  * so this should not be used in non-DEBUG code.
443  */
444 #define	WORK_IS_SCHEDULED(hwp, wrk)	\
445 	((atomic_and_ulong_nv(&hwp->work_flags, (ulong_t)-1) & (1 << wrk)) != 0)
446 
447 #define	WAIT_FOR(p, t, r)					\
448 	clock_t	_lb = ddi_get_lbolt();				\
449 	r = 0;							\
450 	while (!PMCS_COMMAND_DONE(p)) {				\
451 		clock_t _ret = cv_timedwait(&p->sleep_cv,	\
452 		    &p->lock, _lb + drv_usectohz(t * 1000));	\
453 		if (!PMCS_COMMAND_DONE(p) && _ret < 0) {		\
454 			r = 1;					\
455 			break;					\
456 		}						\
457 	}
458 
459 /*
460  * Signal the next I/O completion thread to start running.
461  */
462 
463 #define	PMCS_CQ_RUN_LOCKED(hwp)						\
464 	if (!STAILQ_EMPTY(&hwp->cq) || hwp->iocomp_cb_head) {		\
465 		pmcs_cq_thr_info_t *cqti;				\
466 		cqti = &hwp->cq_info.cq_thr_info			\
467 		    [hwp->cq_info.cq_next_disp_thr];			\
468 		hwp->cq_info.cq_next_disp_thr++;			\
469 		if (hwp->cq_info.cq_next_disp_thr ==			\
470 		    hwp->cq_info.cq_threads) {				\
471 			hwp->cq_info.cq_next_disp_thr = 0;		\
472 		}							\
473 		mutex_enter(&cqti->cq_thr_lock);			\
474 		cv_signal(&cqti->cq_cv);				\
475 		mutex_exit(&cqti->cq_thr_lock);				\
476 	}
477 
478 #define	PMCS_CQ_RUN(hwp)						\
479 	mutex_enter(&hwp->cq_lock);					\
480 	PMCS_CQ_RUN_LOCKED(hwp);					\
481 	mutex_exit(&hwp->cq_lock);
482 
483 
484 /*
485  * Watchdog/SCSA timer definitions
486  */
487 /* usecs to SCSA watchdog ticks */
488 #define	US2WT(x)	(x)/10
489 
490 /*
491  * More misc
492  */
493 #define	BYTE0(x)	(((x) >>  0) & 0xff)
494 #define	BYTE1(x)	(((x) >>  8) & 0xff)
495 #define	BYTE2(x)	(((x) >> 16) & 0xff)
496 #define	BYTE3(x)	(((x) >> 24) & 0xff)
497 #define	BYTE4(x)	(((x) >> 32) & 0xff)
498 #define	BYTE5(x)	(((x) >> 40) & 0xff)
499 #define	BYTE6(x)	(((x) >> 48) & 0xff)
500 #define	BYTE7(x)	(((x) >> 56) & 0xff)
501 #define	WORD0(x)	(((x) >>  0) & 0xffff)
502 #define	WORD1(x)	(((x) >> 16) & 0xffff)
503 #define	WORD2(x)	(((x) >> 32) & 0xffff)
504 #define	WORD3(x)	(((x) >> 48) & 0xffff)
505 #define	DWORD0(x)	((uint32_t)(x))
506 #define	DWORD1(x)	((uint32_t)(((uint64_t)x) >> 32))
507 
508 #define	SAS_ADDR_FMT	"0x%02x%02x%02x%02x%02x%02x%02x%02x"
509 #define	SAS_ADDR_PRT(x)	x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]
510 
511 #define	PMCS_VALID_LINK_RATE(r) \
512 	((r == SAS_LINK_RATE_1_5GBIT) || (r == SAS_LINK_RATE_3GBIT) || \
513 	(r == SAS_LINK_RATE_6GBIT))
514 
515 /*
516  * This is here to avoid inclusion of <sys/ctype.h> which is not lint clean.
517  */
518 #define	HEXDIGIT(x)	(((x) >= '0' && (x) <= '9') || \
519 	((x) >= 'a' && (x) <= 'f') || ((x) >= 'A' && (x) <= 'F'))
520 
521 #define	NSECS_PER_SEC	1000000000UL
522 
523 
524 typedef void (*pmcs_cb_t) (pmcs_hw_t *, pmcwork_t *, uint32_t *);
525 
526 /*
527  * Defines and structure used for tracing/logging information
528  */
529 
530 #define	PMCS_TBUF_ELEM_SIZE	120
531 #define	PMCS_TBUF_NUM_ELEMS_DEF	100000
532 
533 #define	PMCS_TBUF_UA_MAX_SIZE	32
534 typedef struct {
535 	/* Target-specific data */
536 	uint16_t	target_num;
537 	char		target_ua[PMCS_TBUF_UA_MAX_SIZE];
538 	/* PHY-specific data */
539 	uint8_t 	phy_sas_address[8];
540 	char		phy_path[32];
541 	pmcs_dtype_t	phy_dtype;
542 	/* Log data */
543 	timespec_t	timestamp;
544 	uint64_t	fw_timestamp;
545 	char		buf[PMCS_TBUF_ELEM_SIZE];
546 } pmcs_tbuf_t;
547 
548 /*
549  * Firmware event log header format
550  */
551 typedef struct pmcs_fw_event_hdr_s {
552 	uint32_t	fw_el_signature;
553 	uint32_t	fw_el_entry_start_offset;
554 	uint32_t	fw_el_rsvd1;
555 	uint32_t	fw_el_buf_size;
556 	uint32_t	fw_el_rsvd2;
557 	uint32_t	fw_el_oldest_idx;
558 	uint32_t	fw_el_latest_idx;
559 	uint32_t	fw_el_entry_size;
560 } pmcs_fw_event_hdr_t;
561 
562 /*
563  * Firmware event log entry format
564  */
565 typedef struct pmcs_fw_event_entry_s {
566 	uint32_t	num_words : 3,
567 			reserved : 25,
568 			severity: 4;
569 	uint32_t	ts_upper;
570 	uint32_t	ts_lower;
571 	uint32_t	seq_num;
572 	uint32_t	logw0;
573 	uint32_t	logw1;
574 	uint32_t	logw2;
575 	uint32_t	logw3;
576 } pmcs_fw_event_entry_t;
577 
578 #define	PMCS_FWLOG_TIMER_DIV	8	/* fw timer has 8ns granularity */
579 #define	PMCS_FWLOG_AAP1_SIG	0x1234AAAA
580 #define	PMCS_FWLOG_IOP_SIG	0x5678CCCC
581 
582 /*
583  * Receptacle information
584  */
585 #define	PMCS_NUM_RECEPTACLES	2
586 
587 #define	PMCS_RECEPT_LABEL_0	"SAS0"
588 #define	PMCS_RECEPT_LABEL_1	"SAS1"
589 
590 #define	PMCS_RECEPT_PM_0	"f0"
591 #define	PMCS_RECEPT_PM_1	"f"
592 
593 #ifdef	__cplusplus
594 }
595 #endif
596 #endif	/* _PMCS_DEF_H */
597