pmcs_iomb.h revision 11980:1d26bfcee070
1234285Sdim/*
2234285Sdim * CDDL HEADER START
3234285Sdim *
4234285Sdim * The contents of this file are subject to the terms of the
5234285Sdim * Common Development and Distribution License (the "License").
6234285Sdim * You may not use this file except in compliance with the License.
7234285Sdim *
8234285Sdim * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9234285Sdim * or http://www.opensolaris.org/os/licensing.
10234285Sdim * See the License for the specific language governing permissions
11234285Sdim * and limitations under the License.
12234285Sdim *
13234285Sdim * When distributing Covered Code, include this CDDL HEADER in each
14234285Sdim * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15234285Sdim * If applicable, add the following below this CDDL HEADER, with the
16234285Sdim * fields enclosed by brackets "[]" replaced with your own identifying
17234285Sdim * information: Portions Copyright [yyyy] [name of copyright owner]
18234285Sdim *
19234285Sdim * CDDL HEADER END
20234285Sdim *
21234285Sdim *
22234285Sdim * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23234285Sdim * Use is subject to license terms.
24234285Sdim */
25234285Sdim/*
26234285Sdim * PMC 8x6G IOMB Definitions
27234285Sdim */
28234285Sdim#ifndef	_PMCS_IOMB_H
29234285Sdim#define	_PMCS_IOMB_H
30234285Sdim#ifdef	__cplusplus
31234285Sdimextern "C" {
32234285Sdim#endif
33234285Sdim
34234285Sdim/*
35234285Sdim * An IOMB (IO Message Buffer) is the principle means of communication
36234285Sdim * between the PMC and the HOST. The host places IOMBs on the Inbound
37234285Sdim * Queues (IQ) which are in HOST memory and updates a producer index
38234285Sdim * within the PMC. The PMC pulls the IOMB off the IQ and updates a
39234285Sdim * consumer index in HOST memory. If appropriate, when the PMC is
40234285Sdim * done with the action requested by the IOMB, the PMC writes a
41234285Sdim * reply IOMB to host memory and updates its producer index and
42234285Sdim * interrupts the HOST.
43234285Sdim */
44234285Sdim/*
45234285Sdim * The first word of all IOMBs is always laid out thusly:
46234285Sdim *
47234285Sdim * |Byte 3       |Byte 2       |Byte 1      |Byte 0   |
48234285Sdim * +-------------+-------------+----------------------+
49234285Sdim * |V Resvd    BC|Resvd  OBID  |CAT   |  OPCODE       |
50234285Sdim * +--------------------------------------------------+
51234285Sdim *
52234285Sdim * V == Valid
53234285Sdim * BC = Buffer Count
54234285Sdim * OBID = Outbound Queue ID
55234285Sdim * CAT = Category
56234285Sdim * OPCODE = Well, uh, OPCODE.
57234285Sdim */
58234285Sdim
59234285Sdim#define	PMCS_IOMB_VALID		(1U << 31)
60234285Sdim#define	PMCS_IOMB_HIPRI		(1U << 30)
61234285Sdim#define	PMCS_IOMB_BC_SHIFT	(24)
62234285Sdim#define	PMCS_IOMB_BC_MASK	(0xf << PMCS_IOMB_BC_SHIFT)
63234285Sdim#define	PMCS_IOMB_OBID_SHIFT	(16)
64234285Sdim#define	PMCS_IOMB_OBID_MASK	(0xf << PMCS_IOMB_OBID_SHIFT)
65234285Sdim#define	PMCS_IOMB_CAT_SHIFT	(12)
66234285Sdim#define	PMCS_IOMB_CAT_MASK	(0xf << PMCS_IOMB_CAT_SHIFT)
67234285Sdim#define	PMCS_IOMB_OPCODE_MASK	(0xfff)
68234285Sdim
69234285Sdim
70234285Sdim#define	PMCS_IOMB_CAT_NET	0
71234285Sdim#define	PMCS_IOMB_CAT_FC	1
72234285Sdim#define	PMCS_IOMB_CAT_SAS	2
73234285Sdim#define	PMCS_IOMB_CAT_SCSI	3
74234285Sdim
75234285Sdim/*
76234285Sdim * Shorthand
77234285Sdim */
78234285Sdim#define	PMCS_IOMB_IN_SAS(q, opcode)					\
79234285Sdim	(PMCS_IOMB_VALID | (1 << PMCS_IOMB_BC_SHIFT)		|	\
80234285Sdim	(PMCS_IOMB_CAT_SAS << PMCS_IOMB_CAT_SHIFT)		|	\
81234285Sdim	((q << PMCS_IOMB_OBID_SHIFT) & PMCS_IOMB_OBID_MASK)	|	\
82234285Sdim	(opcode & PMCS_IOMB_OPCODE_MASK))
83234285Sdim
84234285Sdim/*
85234285Sdim * PMC IOMB Inbound Queue Opcodes
86234285Sdim */
87234285Sdim#define	PMCIN_ECHO							0x01
88234285Sdim#define	PMCIN_GET_INFO							0x02
89234285Sdim#define	PMCIN_GET_VPD							0x03
90234285Sdim#define	PMCIN_PHY_START							0x04
91234285Sdim#define	PMCIN_PHY_STOP							0x05
92234285Sdim#define	PMCIN_SSP_INI_IO_START						0x06
93234285Sdim#define	PMCIN_SSP_INI_TM_START						0x07
94234285Sdim#define	PMCIN_SSP_INI_EXT_IO_START					0x08
95234285Sdim#define	PMCIN_DEVICE_HANDLE_ACCEPT					0x09
96234285Sdim#define	PMCIN_SSP_TGT_IO_START						0x0A
97234285Sdim#define	PMCIN_SSP_TGT_RESPONSE_START					0x0B
98234285Sdim#define	PMCIN_SSP_INI_EDC_EXT_IO_START					0x0C
99234285Sdim#define	PMCIN_SSP_INI_EDC_EXT_IO_START1					0x0D
100234285Sdim#define	PMCIN_SSP_TGT_EDC_IO_START					0x0E
101234285Sdim#define	PMCIN_SSP_ABORT							0x0F
102234285Sdim#define	PMCIN_DEREGISTER_DEVICE_HANDLE					0x10
103234285Sdim#define	PMCIN_GET_DEVICE_HANDLE						0x11
104234285Sdim#define	PMCIN_SMP_REQUEST						0x12
105234285Sdim#define	PMCIN_SMP_RESPONSE						0x13
106234285Sdim#define	PMCIN_SMP_ABORT							0x14
107234285Sdim#define	PMCIN_ASSISTED_DISCOVERY					0x15
108234285Sdim#define	PMCIN_REGISTER_DEVICE						0x16
109234285Sdim#define	PMCIN_SATA_HOST_IO_START					0x17
110234285Sdim#define	PMCIN_SATA_ABORT						0x18
111234285Sdim#define	PMCIN_LOCAL_PHY_CONTROL						0x19
112234285Sdim#define	PMCIN_GET_DEVICE_INFO						0x1A
113234285Sdim#define	PMCIN_TWI							0x1B
114234285Sdim#define	PMCIN_FW_FLASH_UPDATE						0x20
115234285Sdim#define	PMCIN_SET_VPD							0x21
116234285Sdim#define	PMCIN_GPIO							0x22
117234285Sdim#define	PMCIN_SAS_DIAG_MODE_START_END					0x23
118234285Sdim#define	PMCIN_SAS_DIAG_EXECUTE						0x24
119234285Sdim#define	PMCIN_SAW_HW_EVENT_ACK						0x25
120234285Sdim#define	PMCIN_GET_TIME_STAMP						0x26
121234285Sdim#define	PMCIN_PORT_CONTROL						0x27
122234285Sdim#define	PMCIN_GET_NVMD_DATA						0x28
123234285Sdim#define	PMCIN_SET_NVMD_DATA						0x29
124234285Sdim#define	PMCIN_SET_DEVICE_STATE						0x2A
125234285Sdim#define	PMCIN_GET_DEVICE_STATE						0x2B
126234285Sdim
127234285Sdim/*
128234285Sdim * General Inbound Queue related parameters (DWORD 4)
129234285Sdim */
130234285Sdim#define	PMCIN_MESSAGE_REPORT		(1 << 2)
131234285Sdim#define	PMCIN_DS_ABORT_TASK		(1 << 3)
132234285Sdim#define	PMCIN_DS_IN_RECOVERY		(1 << 4)
133234285Sdim#define	PMCIN_DATADIR_NONE		(0x00 << 8)
134234285Sdim#define	PMCIN_DATADIR_2_INI		(0x01 << 8)
135234285Sdim#define	PMCIN_DATADIR_2_DEV		(0x02 << 8)
136234285Sdim
137234285Sdim
138234285Sdim/*
139234285Sdim * SATA Host IO Start ATA Protocol Types
140234285Sdim * (placed into DWORD 4)
141234285Sdim */
142234285Sdim
143#define	SATA_PROTOCOL_SRST_ASSERT	(0x01 << 10)
144#define	SATA_PROTOCOL_SRT_DEASSERT	(0x02 << 10)
145#define	SATA_PROTOCOL_EXECDEVDIAG	(0x03 << 10)
146#define	SATA_PROTOCOL_NONDATA		(0x04 << 10)
147#define	SATA_PROTOCOL_PIO		(0x05 << 10)
148#define	SATA_PROTOCOL_DMA		(0x06 << 10)
149#define	SATA_PROTOCOL_FPDMA		(0x07 << 10)
150
151/*
152 * SAS Host IO Start TLR definitions
153 * (placed into DWORD 4)
154 */
155#define	SAS_TLR_ALL	0	/* SAS 1.1 and SAS 2.0 per device mode page */
156#define	SAS_TLR_ON	1	/* unconditionally on */
157#define	SAS_TLR_OFF	2	/* unconditionally off */
158#define	SAS_TLR_SAS2	3	/* SAS 2.0 per device mode page */
159
160/*
161 * IOP SMP Request Information
162 */
163#define	SMP_INDIRECT_RESPONSE		0x01
164#define	SMP_INDIRECT_REQUEST		0x02
165#define	SMP_PHY_OVERRIDE		0x04
166#define	SMP_REQUEST_LENGTH_SHIFT	16
167
168/*
169 * PHY Start related definitions
170 */
171#define	PHY_LINK_1_5			0x01
172#define	PHY_LINK_3			0x02
173#define	PHY_LINK_6			0x04
174#define	PHY_LINK_ALL			(PHY_LINK_1_5 | PHY_LINK_3 | PHY_LINK_6)
175#define	PHY_LINK_SHIFT			8
176
177#define	PHY_LM_SAS			1
178#define	PHY_LM_SATA			2
179#define	PHY_LM_AUTO			3
180#define	PHY_MODE_SHIFT			12
181
182#define	PHY_SPINUP_HOLD			(1 << 14)
183
184/*
185 * LOCAL PHY CONTROL related definitions
186 */
187
188/*
189 * Device Registration related definitions
190 */
191#define	PMCS_DEVREG_LINK_RATE_SHIFT	24
192#define	PMCS_DEVREG_TYPE_SATA		0
193#define	PMCS_DEVREG_TYPE_SAS		(1 << 28)
194#define	PMCS_DEVREG_TYPE_SATA_DIRECT	(1 << 29)
195
196#define	PMCS_PHYID_SHIFT		4	/* level 0 registration only */
197#define	PMCS_DEVREG_TLR			0x1	/* Transport Layer Retry */
198
199#define	PMCS_DEVREG_IT_NEXUS_TIMEOUT	2000U
200
201#define	PMCS_DEVREG_HA			0x2	/* Host Assigned upper 16 */
202						/* bits for device ID. */
203/*
204 * These are used for getting/setting data in the NVRAM (SEEPROM, VPD, etc.)
205 */
206
207typedef struct pmcs_get_nvmd_cmd_s {
208	uint32_t		header;		/* DWORD 0 */
209	uint32_t		htag;		/* DWORD 1 */
210	uint8_t			tdas_nvmd;	/* DWORD 2 */
211	uint8_t			tbn_tdps;
212	uint8_t			tda;
213	uint8_t			ip;
214	uint8_t			doa[3];		/* DWORD 3 Data Offset Addr */
215	uint8_t			d_len;		/* Direct Pld Data Len */
216	uint32_t		rsvd[8];	/* DWORDS 4-11 */
217	uint32_t		ipbal;		/* 12 - Ind Pld buf addr low */
218	uint32_t		ipbah;		/* 13 - Ind Pld buf addr high */
219	uint32_t		ipdl;		/* 14 - Ind Pld data length */
220	uint32_t		rsvd3;
221} pmcs_get_nvmd_cmd_t;
222
223typedef struct pmcs_set_nvmd_cmd_s {
224	uint32_t		header;		/* DWORD 0 */
225	uint32_t		htag;		/* DWORD 1 */
226	uint8_t			tdas_nvmd;	/* DWORD 2 */
227	uint8_t			tbn_tdps;
228	uint8_t			tda;
229	uint8_t			ip;
230	uint8_t			doa[3];		/* DWORD 3 Data Offset Addr */
231	uint8_t			d_len;		/* Direct Pld Data Len */
232	uint32_t		signature;	/* DWORD 4 */
233	uint32_t		rsvd[7];	/* DWORDS 5-11 */
234	uint32_t		ipbal;		/* 12 - Ind Pld buf addr low */
235	uint32_t		ipbah;		/* 13 - Ind Pld buf addr high */
236	uint32_t		ipdl;		/* 14 - Ind Pld data length */
237	uint32_t		rsvd2;
238} pmcs_set_nvmd_cmd_t;
239
240#define	PMCIN_NVMD_DIRECT_PLD		0x00
241#define	PMCIN_NVMD_INDIRECT_PLD		0x80
242
243/* TWI bus number is upper 4 bits of tbn_tdps */
244#define	PMCIN_NVMD_TBN(x)		(x << 4)
245
246/* TWI Device Page Size bits (lower 4 bits of tbn_tdps */
247#define	PMCIN_NVMD_TDPS_1		0	/* 1 byte */
248#define	PMCIN_NVMD_TDPS_8		1	/* 8 bytes */
249#define	PMCIN_NVMD_TDPS_16		2	/* 16 bytes */
250#define	PMCIN_NVMD_TDPS_32		3	/* 32 bytes */
251
252/* TWI Device Address Size (upper 4 bits of tdas_nvmd) */
253#define	PMCIN_NVMD_TDAS_1		(0 << 4)	/* 1 byte */
254#define	PMCIN_NVMD_TDAS_2		(1 << 4)	/* 2 bytes */
255
256/*
257 * TWI Device Address
258 * The address used to access TWI device for the 2Kb SEEPROM device is
259 * arranged as follows:
260 *	Bits 7-4 are fixed (0xA)
261 *	Bits 3-1 are page numbers for each 256 byte page
262 *	Bit 0: Set to "1" to read, "0" to write
263 * Bit 0 is set/reset by the firmware based on whether the command is a
264 * SET or a GET.
265 */
266#define	PMCIN_TDA_BASE			0xA0
267#define	PMCIN_TDA_PAGE(x)		(PMCIN_TDA_BASE | (x << 1))
268
269/* NVM Device bits (lower 4 bits of tdas_nvmd) */
270#define	PMCIN_NVMD_TWI			0	/* TWI Device */
271#define	PMCIN_NVMD_SEEPROM		1	/* SEEPROM Device */
272#define	PMCIN_NVMD_VPD			4	/* VPD Flash Memory */
273#define	PMCIN_NVMD_AAP1			5	/* AAP1 Register Dump */
274#define	PMCIN_NVMD_IOP			6	/* IOP Register Dump */
275
276#define	PMCS_SEEPROM_PAGE_SIZE		256
277
278/*
279 * Minimum and maximum sizes of SPCBoot image
280 */
281#define	PMCS_SPCBOOT_MIN_SIZE		64
282#define	PMCS_SPCBOOT_MAX_SIZE		512
283
284#define	PMCS_SEEPROM_SIGNATURE		0xFEDCBA98
285
286/*
287 * Register dump information
288 *
289 * There are two 16KB regions for register dump information
290 */
291
292#define	PMCS_REGISTER_DUMP_FLASH_SIZE	(1024 * 16)
293#define	PMCS_REGISTER_DUMP_BLOCK_SIZE	4096	/* Must be read 4K at a time */
294#define	PMCS_FLASH_CHUNK_SIZE		4096	/* Must be read 4K at a time */
295#define	PMCS_REG_DUMP_SIZE		(1024 * 1024 * 12)
296#define	PMCS_NVMD_EVENT_LOG_OFFSET	0x10000
297#define	PMCS_IQP_TRACE_BUFFER_SIZE	(1024 * 512)
298
299/*
300 * The list of items we can retrieve via the GET_NVMD_DATA command
301 */
302
303typedef enum {
304	PMCS_NVMD_VPD = 0,
305	PMCS_NVMD_REG_DUMP,
306	PMCS_NVMD_EVENT_LOG,
307	PMCS_NVMD_SPCBOOT
308} pmcs_nvmd_type_t;
309
310/*
311 * Command types, descriptors and offsets for SAS_DIAG_EXECUTE.
312 */
313#define	PMCS_DIAG_CMD_DESC_SHIFT	8
314#define	PMCS_DIAG_CMD_SHIFT		13
315#define	PMCS_DIAG_REPORT_GET		0x04	/* Get counters */
316#define	PMCS_ERR_CNT_RESET		0x05	/* Clear counters */
317#define	PMCS_DISPARITY_ERR_CNT		0x02	/* Disparity error count */
318#define	PMCS_LOST_DWORD_SYNC_CNT	0x05	/* Lost DWord sync count */
319#define	PMCS_INVALID_DWORD_CNT		0x06	/* Invalid DWord count */
320#define	PMCS_RESET_FAILED_CNT		0x0C	/* PHY reset failed count */
321
322/*
323 * VPD data layout
324 */
325
326#define	PMCS_VPD_DATA_PAGE	2	/* VPD starts at offset 512 */
327#define	PMCS_VPD_VERSION	2	/* Expected version number */
328#define	PMCS_VPD_RO_BYTE	0x90	/* Start of "read-only" data */
329#define	PMCS_VPD_START		0x82	/* VPD start byte */
330#define	PMCS_VPD_END		0x78	/* VPD end byte */
331
332/*
333 * This structure defines the "header" for the VPD data.  Everything
334 * following this structure is self-defining.  The consumer just needs
335 * to allocate a buffer large enough for vpd_length + 3 bytes of data.
336 */
337
338typedef struct {
339	uint8_t		eeprom_version;
340	uint8_t		vpd_length[2];	/* # bytes that follow, little-endian */
341	uint8_t		hba_sas_wwid[8];
342	uint8_t		subsys_pid[2];
343	uint8_t		subsys_vid[2];
344	uint8_t		vpd_start_byte;	/* 0x82 */
345	uint8_t		strid_length[2]; /* little-endian */
346	/* strid_length bytes follow */
347} pmcs_vpd_header_t;
348
349typedef struct {
350	char		keyword[2];
351	uint8_t		value_length;
352	char		value[1];	/* Length is actually value_length */
353} pmcs_vpd_kv_t;
354
355/*
356 * From here on out are definitions related to Outbound Queues
357 * (completions of Inbound Queue requests and async events)
358 */
359
360/*
361 * PMC IOMB Outbound Queue Opcodes
362 */
363#define	PMCOUT_ECHO							0x01
364#define	PMCOUT_GET_INFO							0x02
365#define	PMCOUT_GET_VPD							0x03
366#define	PMCOUT_SAS_HW_EVENT						0x04
367#define	PMCOUT_SSP_COMPLETION						0x05
368#define	PMCOUT_SMP_COMPLETION						0x06
369#define	PMCOUT_LOCAL_PHY_CONTROL					0x07
370#define	PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT				0x08
371#define	PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT				0x09
372#define	PMCOUT_DEVICE_REGISTRATION					0x0A
373#define	PMCOUT_DEREGISTER_DEVICE_HANDLE					0x0B
374#define	PMCOUT_GET_DEVICE_HANDLE					0x0C
375#define	PMCOUT_SATA_COMPLETION						0x0D
376#define	PMCOUT_SATA_EVENT						0x0E
377#define	PMCOUT_SSP_EVENT						0x0F
378#define	PMCOUT_DEVICE_HANDLE_ARRIVED					0x10
379#define	PMCOUT_SMP_REQUEST_RECEIVED					0x11
380#define	PMCOUT_SSP_REQUEST_RECEIVED					0x12
381#define	PMCOUT_DEVICE_INFO						0x13
382#define	PMCOUT_FW_FLASH_UPDATE						0x14
383#define	PMCOUT_SET_VPD							0x15
384#define	PMCOUT_GPIO							0x16
385#define	PMCOUT_GPIO_EVENT						0x17
386#define	PMCOUT_GENERAL_EVENT						0x18
387#define	PMCOUT_TWI							0x19
388#define	PMCOUT_SSP_ABORT						0x1A
389#define	PMCOUT_SATA_ABORT						0x1B
390#define	PMCOUT_SAS_DIAG_MODE_START_END					0x1C
391#define	PMCOUT_SAS_DIAG_EXECUTE						0x1D
392#define	PMCOUT_GET_TIME_STAMP						0x1E
393#define	PMCOUT_SAS_HW_EVENT_ACK_ACK					0x1F
394#define	PMCOUT_PORT_CONTROL						0x20
395#define	PMCOUT_SKIP_ENTRIES						0x21
396#define	PMCOUT_SMP_ABORT						0x22
397#define	PMCOUT_GET_NVMD_DATA						0x23
398#define	PMCOUT_SET_NVMD_DATA						0x24
399#define	PMCOUT_DEVICE_HANDLE_REMOVED					0x25
400#define	PMCOUT_SET_DEVICE_STATE						0x26
401#define	PMCOUT_GET_DEVICE_STATE						0x27
402#define	PMCOUT_SET_DEVICE_INFO						0x28
403
404/*
405 * General Outbound Status Definitions
406 */
407#define	PMCOUT_STATUS_OK						0x00
408#define	PMCOUT_STATUS_ABORTED						0x01
409#define	PMCOUT_STATUS_OVERFLOW						0x02
410#define	PMCOUT_STATUS_UNDERFLOW						0x03
411#define	PMCOUT_STATUS_FAILED						0x04
412#define	PMCOUT_STATUS_ABORT_RESET					0x05
413#define	PMCOUT_STATUS_IO_NOT_VALID					0x06
414#define	PMCOUT_STATUS_NO_DEVICE						0x07
415#define	PMCOUT_STATUS_ILLEGAL_PARAMETER					0x08
416#define	PMCOUT_STATUS_LINK_FAILURE					0x09
417#define	PMCOUT_STATUS_PROG_ERROR					0x0A
418#define	PMCOUT_STATUS_EDC_IN_ERROR					0x0B
419#define	PMCOUT_STATUS_EDC_OUT_ERROR					0x0C
420#define	PMCOUT_STATUS_ERROR_HW_TIMEOUT					0x0D
421#define	PMCOUT_STATUS_XFER_ERR_BREAK					0x0E
422#define	PMCOUT_STATUS_XFER_ERR_PHY_NOT_READY				0x0F
423#define	PMCOUT_STATUS_OPEN_CNX_PROTOCOL_NOT_SUPPORTED			0x10
424#define	PMCOUT_STATUS_OPEN_CNX_ERROR_ZONE_VIOLATION			0x11
425#define	PMCOUT_STATUS_OPEN_CNX_ERROR_BREAK				0x12
426#define	PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS			0x13
427#define	PMCOUT_STATUS_OPENCNX_ERROR_BAD_DESTINATION			0x14
428#define	PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED	0x15
429#define	PMCOUT_STATUS_OPEN_CNX_ERROR_STP_RESOURCES_BUSY			0x16
430#define	PMCOUT_STATUS_OPEN_CNX_ERROR_WRONG_DESTINATION			0x17
431#define	PMCOUT_STATUS_OPEN_CNX_ERROR_UNKNOWN_ERROR			0x18
432#define	PMCOUT_STATUS_IO_XFER_ERROR_NAK_RECEIVED			0x19
433#define	PMCOUT_STATUS_XFER_ERROR_ACK_NAK_TIMEOUT			0x1A
434#define	PMCOUT_STATUS_XFER_ERROR_PEER_ABORTED				0x1B
435#define	PMCOUT_STATUS_XFER_ERROR_RX_FRAME				0x1C
436#define	PMCOUT_STATUS_IO_XFER_ERROR_DMA					0x1D
437#define	PMCOUT_STATUS_XFER_ERROR_CREDIT_TIMEOUT				0x1E
438#define	PMCOUT_STATUS_XFER_ERROR_SATA_LINK_TIMEOUT			0x1F
439#define	PMCOUT_STATUS_XFER_ERROR_SATA					0x20
440#define	PMCOUT_STATUS_XFER_ERROR_REJECTED_NCQ_MODE			0x21
441#define	PMCOUT_STATUS_XFER_ERROR_ABORTED_DUE_TO_SRST			0x22
442#define	PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE			0x23
443#define	PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT			0x24
444#define	PMCOUT_STATUS_SMP_RESP_CONNECTION_ERROR				0x25
445#define	PMCOUT_STATUS_XFER_ERROR_UNEXPECTED_PHASE			0x26
446#define	PMCOUT_STATUS_XFER_ERROR_RDY_OVERRUN				0x27
447#define	PMCOUT_STATUS_XFER_ERROR_RDY_NOT_EXPECTED			0x28
448/* 0x29 */
449/* 0x2A */
450/* 0x2B */
451/* 0x2C */
452/* 0x2D */
453/* 0x2E */
454/* 0x2F */
455#define	PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT		0x30
456#define	PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK	0x31
457#define	PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK	0x32
458/* 0x33 */
459#define	PMCOUT_STATUS_XFER_ERROR_OFFSET_MISMATCH			0x34
460#define	PMCOUT_STATUS_XFER_ERROR_ZERO_DATA_LEN				0x35
461#define	PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED				0x36
462#define	PMCOUT_STATUS_ERROR_INTERNAL_SMP_RESOURCE			0x37
463#define	PMCOUT_STATUS_IO_PORT_IN_RESET					0x38
464#define	PMCOUT_STATUS_IO_DS_NON_OPERATIONAL				0x39
465#define	PMCOUT_STATUS_IO_DS_IN_RECOVERY					0x3A
466#define	PMCOUT_STATUS_IO_TM_TAG_NOT_FOUND				0x3B
467#define	PMCOUT_STATUS_IO_SSP_EXT_IU_ZERO_LEN_ERROR			0x3D
468#define	PMCOUT_STATUS_IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY		0x3F
469#define	PMCOUT_STATUS_IO_ABORT_IN_PROGRESS				0x40
470
471/*
472 * IOMB formats
473 *
474 * NOTE: All IOMBs are little-endian with exceptions to certain parts of
475 * some IOMBs.  For example, the SSP_RESPONSE_IU in the SSP_COMPLETION
476 * outbound IOMB is big-endian (SAS).
477 */
478
479/* Common IOMB header */
480
481typedef struct pmcs_iomb_header {
482	uint8_t		opcode_lo;
483	DECL_BITFIELD2(opcode_hi: 4,
484	    cat			: 4);
485	DECL_BITFIELD2(obid	: 6,
486	    rsvd1		: 2);
487	DECL_BITFIELD4(buf_count: 5,
488	    rsvd2		: 1,
489	    h_bit		: 1,
490	    v_bit		: 1);
491} pmcs_iomb_header_t;
492
493/* PMCOUT_SSP_COMPLETION */
494
495typedef struct pmcout_ssp_comp {
496	pmcs_iomb_header_t	header;
497	uint32_t		htag;
498	uint32_t		status;
499	uint32_t		param;
500	uint16_t		ssp_tag;
501	DECL_BITFIELD3(resc_v	: 1,
502	    resc_pad	: 2,
503	    rsvd1	: 5);
504	uint8_t			rsvd2;
505	/* SSP_RESPONSE_IU (if it exists) */
506	/* Residual count (if resc_v is set) */
507} pmcout_ssp_comp_t;
508
509
510/*
511 * Device State definitions
512 */
513#define	PMCS_DEVICE_STATE_NOT_AVAILABLE		0x0	/* Unconfigured tgt */
514#define	PMCS_DEVICE_STATE_OPERATIONAL		0x1
515#define	PMCS_DEVICE_STATE_PORT_IN_RESET		0x2
516#define	PMCS_DEVICE_STATE_IN_RECOVERY		0x3
517#define	PMCS_DEVICE_STATE_IN_ERROR		0x4
518#define	PMCS_DEVICE_STATE_NON_OPERATIONAL	0x7
519
520/*
521 * Reset Types
522 */
523#define	PMCS_SSP_LINK_RESET		0x1
524#define	PMCS_SSP_HARD_RESET		0x2
525#define	PMCS_SMP_HARD_RESET		0x3
526
527/*
528 * PHYOP for LOCAL_PHY_CONTROL Command
529 */
530#define	PMCS_PHYOP_LINK_RESET		0x01
531#define	PMCS_PHYOP_HARD_RESET		0x02
532
533/*
534 * Specialized status values
535 */
536/* PHY Stop Status Results */
537#define	IOP_PHY_STOP_OK		0x0
538#define	IOP_PHY_STOP_INVALID	0x1
539#define	IOP_PHY_STOP_ERROR	0x3
540#define	IOP_PHY_STOP_ALREADY	0x4
541
542/* PHY Start Status Results */
543#define	IOP_PHY_START_OK	0
544#define	IOP_PHY_START_INVALID	1
545#define	IOP_PHY_START_ALREADY	2
546#define	IOP_PHY_START_ERROR	3
547
548/* SET/GET_NVMD status results */
549#define	PMCS_NVMD_STAT_SUCCESS			0x0000
550#define	PMCS_NVMD_STAT_PLD_NVMD_COMB_ERR	0x0001
551#define	PMCS_NVMD_STAT_PLD_LEN_ERR		0x0002
552#define	PMCS_NVMD_STAT_TWI_DEV_NACK		0x2001
553#define	PMCS_NVMD_STAT_TWI_DEV_LOST_ARB		0x2002
554#define	PMCS_NVMD_STAT_TWI_TIMEOUT		0x2021
555#define	PMCS_NVMD_STAT_TWI_BUS_NACK		0x2081
556#define	PMCS_NVMD_STAT_TWI_DEV_ARB_FAIL		0x2082
557#define	PMCS_NVMD_STAT_TWI_BUS_SER_TIMEO	0x20FF
558#define	PMCS_NVMD_STAT_PART_NOT_IN_FLASH	0x9001
559#define	PMCS_NVMD_STAT_LEN_TOO_LARGE		0x9002
560#define	PMCS_NVMD_STAT_FLASH_PRGRM_FAIL		0x9003
561#define	PMCS_NVMD_STAT_DEVID_MATCH_FAIL		0x9004
562#define	PMCS_NVMD_STAT_VENDID_MATCH_FAIL	0x9005
563#define	PMCS_NVMD_STAT_SEC_ERASE_TIMEO		0x9006
564#define	PMCS_NVMD_STAT_SEC_ERASE_CWE		0x9007
565#define	PMCS_NVMD_STAT_FLASH_DEV_BUSY		0x9008
566#define	PMCS_NVMD_STAT_FLASH_DEV_NOT_SUP	0x9009
567#define	PMCS_NVMD_STAT_FLASH_NO_CFI		0x900A
568#define	PMCS_NVMD_STAT_ERASE_BLOCKS		0x900B
569#define	PMCS_NVMD_STAT_PART_READ_ONLY		0x900C
570#define	PMCS_NVMD_STAT_PART_INV_MAP_TYPE	0x900D
571#define	PMCS_NVMD_STAT_PART_INIT_STR_DIS	0x900E
572
573/*
574 * General Event Status Codes
575 */
576#define	INBOUND_IOMB_V_BIT_NOT_SET		0x1
577#define	INBOUND_IOMB_OPC_NOT_SUPPORTED		0x2
578
579/* Device Register Status Results */
580#define	PMCS_DEVREG_OK				0x0
581#define	PMCS_DEVREG_DEVICE_ALREADY_REGISTERED	0x2
582#define	PMCS_DEVREG_PHY_ALREADY_REGISTERED	0x4
583
584/*
585 * Flash Update responses
586 */
587#define	FLASH_UPDATE_COMPLETE_PENDING_REBOOT	0x0
588#define	FLASH_UPDATE_IN_PROGRESS		0x1
589#define	FLASH_UPDATE_HDR_ERR			0x2
590#define	FLASH_UPDATE_OFFSET_ERR			0x3
591#define	FLASH_UPDATE_UPDATE_CRC_ERR		0x4
592#define	FLASH_UPDATE_LENGTH_ERR			0x5
593#define	FLASH_UPDATE_HW_ERR			0x6
594#define	FLASH_UPDATE_DNLD_NOT_SUPPORTED		0x10
595#define	FLASH_UPDATE_DISABLED			0x11
596
597/*
598 * IOP SAS HW Event Related definitions
599 */
600
601#define	IOP_EVENT_LINK_RATE(x)		((x >> 28) & 0xf)
602#define	IOP_EVENT_STATUS(x) 		((x >> 24) & 0xf)
603#define	IOP_EVENT_EVENT(x)		((x >> 8) & 0xffff)
604#define	IOP_EVENT_PHYNUM(x)		((x >> 4) & 0xf)
605#define	IOP_EVENT_PORTID(x)		((x) & 0xf)
606
607
608#define	IOP_EVENT_PHY_STOP_STATUS		0x03
609#define	IOP_EVENT_SAS_PHY_UP			0x04
610#define	IOP_EVENT_SATA_PHY_UP			0x05
611#define	IOP_EVENT_SATA_SPINUP_HOLD		0x06
612#define	IOP_EVENT_PHY_DOWN			0x07
613#define	IOP_EVENT_PORT_INVALID			0x08	/* < fw 1.6 */
614#define	IOP_EVENT_BROADCAST_CHANGE		0x09
615#define	IOP_EVENT_BROADCAST_SES			0x0B
616#define	IOP_EVENT_PHY_ERR_INBOUND_CRC		0x0C
617#define	IOP_EVENT_HARD_RESET_RECEIVED		0x0D
618#define	IOP_EVENT_EVENT_ID_FRAME_TIMO		0x0F
619#define	IOP_EVENT_BROADCAST_EXP			0x10
620#define	IOP_EVENT_PHY_START_STATUS		0x11
621#define	IOP_EVENT_PHY_ERR_INVALID_DWORD		0x12
622#define	IOP_EVENT_PHY_ERR_DISPARITY_ERROR	0x13
623#define	IOP_EVENT_PHY_ERR_CODE_VIOLATION	0x14
624#define	IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN	0x15
625#define	IOP_EVENT_PHY_ERR_PHY_RESET_FAILD	0x16
626#define	IOP_EVENT_PORT_RECOVERY_TIMER_TMO	0x17
627#define	IOP_EVENT_PORT_RECOVER			0x18
628#define	IOP_EVENT_PORT_RESET_TIMER_TMO		0x19
629#define	IOP_EVENT_PORT_RESET_COMPLETE		0x20
630#define	IOP_EVENT_BROADCAST_ASYNC_EVENT		0x21
631#define	IOP_EVENT_IT_NEXUS_LOSS			0x22
632
633
634#define	IOP_EVENT_PORT_STATE(x)		((x) & 0xf)
635#define	IOP_EVENT_NPIP(x)		(((x) >> 4) & 0xf)
636
637#define	IOP_EVENT_PS_NIL		0x0	/* PORT_ID not valid yet */
638#define	IOP_EVENT_PS_VALID		0x1	/* PORT_ID now valid */
639#define	IOP_EVENT_PS_LOSTCOMM		0x2	/* Link temporarily down */
640#define	IOP_EVENT_PS_IN_RESET		0x4	/* Port in reset */
641#define	IOP_EVENT_PS_INVALID		0x8	/* PORT_ID now dead */
642
643/*
644 * HW Event Acknowledge Response Values
645 */
646#define	SAS_HW_EVENT_ACK_OK		0x0
647#define	SAS_HW_EVENT_ACK_INVALID_SEA	0x1
648#define	SAS_HW_EVENT_ACK_INVALID_PHY	0x2
649#define	SAS_HW_EVENT_ACK_INVALID_PORT	0x4
650#define	SAS_HW_EVENT_ACK_INVALID_PARAM	0x8
651
652/*
653 * IOMB Queue definitions and Macros
654 */
655
656#define	ADDQI(ix, n, qd)	((ix + n) & (qd - 1))
657#define	INCQI(ix, qd)		ix = ADDQI(ix, 1, qd)
658#define	QI2O(ix, n, qd)		(ADDQI(ix, n, qd) * PMCS_QENTRY_SIZE)
659
660/*
661 * Inbound Queue Producer Indices live inside the PMC card.
662 *
663 * Inbound Queue Consumer indices live in host memory. We use the Consumer
664 * Index to return a pointer to an Inbound Queue entry. We then can fill
665 * it with an IOMB. We then update the the Producer index which kicks
666 * card to read the IOMB we just wrote.
667 *
668 * There is one mutex for each inbound queue that is held from the time
669 * we get an entry until we increment the producer index, or released
670 * manually if we don't actually send the message.
671 */
672
673/*
674 * NB: the appropriate iqp_lock must be held
675 */
676#define	GET_IQ_ENTRY(hwp, qnum)	\
677	((ADDQI(hwp->shadow_iqpi[qnum], 1, hwp->ioq_depth) == \
678	pmcs_rd_iqci(hwp, qnum)) ? NULL : \
679	&hwp->iqp[qnum][hwp->shadow_iqpi[qnum] * (PMCS_QENTRY_SIZE >> 2)])
680
681/*
682 * NB: This releases the lock on the Inbound Queue that GET_IO_IQ_ENTRY
683 * acquired below.
684 */
685#ifdef	DEBUG
686#define	INC_IQ_ENTRY(hwp, qnum)						\
687{									\
688	uint32_t htag;							\
689	ASSERT(mutex_owned(&(hwp)->iqp_lock[qnum]));			\
690	htag = hwp->iqp[qnum][(hwp->shadow_iqpi[qnum] *			\
691	    (PMCS_QENTRY_SIZE >> 2)) + 1];				\
692	mutex_enter(&(hwp)->dbglock);					\
693	pmcs_iqp_trace(hwp, qnum);					\
694	mutex_exit(&(hwp)->dbglock);					\
695	INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth);			\
696	if (ddi_dma_sync(hwp->cip_handles, 0, 0,			\
697	    DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) {			\
698		pmcs_prt(hwp, PMCS_PRT_DEBUG, NULL, NULL, "Condition "	\
699		    "failed at %s():%d", __func__, __LINE__);		\
700	}								\
701	hwp->ftime[hwp->fti] = gethrtime();				\
702	pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]);		\
703	mutex_exit(&(hwp)->iqp_lock[qnum]);				\
704	mutex_enter(&(hwp)->dbglock);					\
705	hwp->ftag_lines[hwp->fti] = __LINE__;				\
706	hwp->ftags[hwp->fti++] = htag;					\
707	mutex_exit(&(hwp)->dbglock);					\
708}
709#else
710#define	INC_IQ_ENTRY(hwp, qnum)						\
711	INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth);			\
712	if (ddi_dma_sync(hwp->cip_handles, 0, 0,			\
713	    DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) {			\
714		pmcs_prt(hwp, PMCS_PRT_DEBUG, NULL, NULL, "Condition "	\
715		    "failed at %s():%d", __func__, __LINE__);		\
716	}								\
717	pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]);		\
718	mutex_exit(&(hwp)->iqp_lock[qnum])
719#endif
720
721
722/*
723 * NB: sucessfull acquisition of an IO Inbound Queue
724 * entry leaves the lock on that Inbound Queue held.
725 */
726#define	GET_IO_IQ_ENTRY(pwp, msg, did, iq)				\
727	iq = did & PMCS_IO_IQ_MASK;					\
728	mutex_enter(&(pwp)->iqp_lock[iq]);				\
729	msg = GET_IQ_ENTRY(pwp, iq);					\
730	if (msg == NULL) {						\
731		mutex_exit(&(pwp)->iqp_lock[iq]);			\
732		for (iq = 0; iq <= PMCS_NON_HIPRI_QUEUES; iq++) {	\
733			mutex_enter(&(pwp)->iqp_lock[iq]);		\
734			msg = GET_IQ_ENTRY(pwp, iq);			\
735			if (msg) {					\
736				break;					\
737			}						\
738			mutex_exit(&(pwp->iqp_lock[iq]));		\
739		}							\
740	}
741
742/*
743 * Outbound Queue Macros
744 *
745 * Outbound Queue Consumer indices live inside the card.
746 *
747 * Outbound Queue Producer indices live in host memory. When the card
748 * wants to send an IOMB, it uses the producer index to find the spot
749 * to write the IOMB. After it's done it updates the producer index
750 * and interrupts the host. The host reads the producer index (from
751 * host memory) and reads IOMBs up to but not including that index.
752 * It writes that index back to the consumer index on the card,
753 * signifying that it has read up to that which the card has sent.
754 */
755#define	GET_OQ_ENTRY(hwp, qn, ix, o) \
756	&hwp->oqp[qn][QI2O(ix, o, hwp->ioq_depth) >> 2]
757
758#define	STEP_OQ_ENTRY(hwp, qn, ix, n)	ix = ADDQI(ix, n, hwp->ioq_depth)
759
760#define	SYNC_OQ_ENTRY(hwp, qn, ci, pi) 		\
761	pmcs_wr_oqci(hwp, qn, ci);		\
762	(hwp)->oqci[qn] = ci;			\
763	(hwp)->oqpi[qn] = pi
764
765#ifdef	__cplusplus
766}
767#endif
768#endif	/* _PMCS_IOMB_H */
769