xref: /illumos-gate/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h (revision 8d0c3d29bb99f6521f2dc5058a7e4debebad7899)
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 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 /*
26  * PMC 8x6G IOMB Definitions
27  */
28 #ifndef	_PMCS_IOMB_H
29 #define	_PMCS_IOMB_H
30 #ifdef	__cplusplus
31 extern "C" {
32 #endif
33 
34 /*
35  * An IOMB (IO Message Buffer) is the principle means of communication
36  * between the PMC and the HOST. The host places IOMBs on the Inbound
37  * Queues (IQ) which are in HOST memory and updates a producer index
38  * within the PMC. The PMC pulls the IOMB off the IQ and updates a
39  * consumer index in HOST memory. If appropriate, when the PMC is
40  * done with the action requested by the IOMB, the PMC writes a
41  * reply IOMB to host memory and updates its producer index and
42  * interrupts the HOST.
43  */
44 /*
45  * The first word of all IOMBs is always laid out thusly:
46  *
47  * |Byte 3       |Byte 2       |Byte 1      |Byte 0   |
48  * +-------------+-------------+----------------------+
49  * |V Resvd    BC|Resvd  OBID  |CAT   |  OPCODE       |
50  * +--------------------------------------------------+
51  *
52  * V == Valid
53  * BC = Buffer Count
54  * OBID = Outbound Queue ID
55  * CAT = Category
56  * OPCODE = Well, uh, OPCODE.
57  */
58 
59 #define	PMCS_IOMB_VALID		(1U << 31)
60 #define	PMCS_IOMB_HIPRI		(1U << 30)
61 #define	PMCS_IOMB_BC_SHIFT	(24)
62 #define	PMCS_IOMB_BC_MASK	(0xf << PMCS_IOMB_BC_SHIFT)
63 #define	PMCS_IOMB_OBID_SHIFT	(16)
64 #define	PMCS_IOMB_OBID_MASK	(0xf << PMCS_IOMB_OBID_SHIFT)
65 #define	PMCS_IOMB_CAT_SHIFT	(12)
66 #define	PMCS_IOMB_CAT_MASK	(0xf << PMCS_IOMB_CAT_SHIFT)
67 #define	PMCS_IOMB_OPCODE_MASK	(0xfff)
68 
69 
70 #define	PMCS_IOMB_CAT_NET	0
71 #define	PMCS_IOMB_CAT_FC	1
72 #define	PMCS_IOMB_CAT_SAS	2
73 #define	PMCS_IOMB_CAT_SCSI	3
74 
75 /*
76  * Shorthand
77  */
78 #define	PMCS_IOMB_IN_SAS(q, opcode)					\
79 	(PMCS_IOMB_VALID | (1 << PMCS_IOMB_BC_SHIFT)		|	\
80 	(PMCS_IOMB_CAT_SAS << PMCS_IOMB_CAT_SHIFT)		|	\
81 	((q << PMCS_IOMB_OBID_SHIFT) & PMCS_IOMB_OBID_MASK)	|	\
82 	(opcode & PMCS_IOMB_OPCODE_MASK))
83 
84 /*
85  * PMC IOMB Inbound Queue Opcodes
86  */
87 #define	PMCIN_ECHO							0x01
88 #define	PMCIN_GET_INFO							0x02
89 #define	PMCIN_GET_VPD							0x03
90 #define	PMCIN_PHY_START							0x04
91 #define	PMCIN_PHY_STOP							0x05
92 #define	PMCIN_SSP_INI_IO_START						0x06
93 #define	PMCIN_SSP_INI_TM_START						0x07
94 #define	PMCIN_SSP_INI_EXT_IO_START					0x08
95 #define	PMCIN_DEVICE_HANDLE_ACCEPT					0x09
96 #define	PMCIN_SSP_TGT_IO_START						0x0A
97 #define	PMCIN_SSP_TGT_RESPONSE_START					0x0B
98 #define	PMCIN_SSP_INI_EDC_EXT_IO_START					0x0C
99 #define	PMCIN_SSP_INI_EDC_EXT_IO_START1					0x0D
100 #define	PMCIN_SSP_TGT_EDC_IO_START					0x0E
101 #define	PMCIN_SSP_ABORT							0x0F
102 #define	PMCIN_DEREGISTER_DEVICE_HANDLE					0x10
103 #define	PMCIN_GET_DEVICE_HANDLE						0x11
104 #define	PMCIN_SMP_REQUEST						0x12
105 #define	PMCIN_SMP_RESPONSE						0x13
106 #define	PMCIN_SMP_ABORT							0x14
107 #define	PMCIN_ASSISTED_DISCOVERY					0x15
108 #define	PMCIN_REGISTER_DEVICE						0x16
109 #define	PMCIN_SATA_HOST_IO_START					0x17
110 #define	PMCIN_SATA_ABORT						0x18
111 #define	PMCIN_LOCAL_PHY_CONTROL						0x19
112 #define	PMCIN_GET_DEVICE_INFO						0x1A
113 #define	PMCIN_TWI							0x1B
114 #define	PMCIN_FW_FLASH_UPDATE						0x20
115 #define	PMCIN_SET_VPD							0x21
116 #define	PMCIN_GPIO							0x22
117 #define	PMCIN_SAS_DIAG_MODE_START_END					0x23
118 #define	PMCIN_SAS_DIAG_EXECUTE						0x24
119 #define	PMCIN_SAS_HW_EVENT_ACK						0x25
120 #define	PMCIN_GET_TIME_STAMP						0x26
121 #define	PMCIN_PORT_CONTROL						0x27
122 #define	PMCIN_GET_NVMD_DATA						0x28
123 #define	PMCIN_SET_NVMD_DATA						0x29
124 #define	PMCIN_SET_DEVICE_STATE						0x2A
125 #define	PMCIN_GET_DEVICE_STATE						0x2B
126 
127 /*
128  * General Inbound Queue related parameters (DWORD 4)
129  */
130 #define	PMCIN_MESSAGE_REPORT		(1 << 2)
131 #define	PMCIN_DS_ABORT_TASK		(1 << 3)
132 #define	PMCIN_DS_IN_RECOVERY		(1 << 4)
133 #define	PMCIN_DATADIR_NONE		(0x00 << 8)
134 #define	PMCIN_DATADIR_2_INI		(0x01 << 8)
135 #define	PMCIN_DATADIR_2_DEV		(0x02 << 8)
136 
137 
138 /*
139  * SATA Host IO Start ATA Protocol Types
140  * (placed into DWORD 4)
141  */
142 
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 
207 typedef 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 
223 typedef 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 
303 typedef 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_EEPROM_INT_VERSION	1	/* supported version for Thebe INT */
327 #define	PMCS_EEPROM_EXT_VERSION	2	/* supported version for Thebe EXT */
328 #define	PMCS_VPD_DATA_PAGE	2	/* VPD starts at offset 512 */
329 #define	PMCS_VPD_RO_BYTE	0x90	/* Start of "read-only" data */
330 #define	PMCS_VPD_START		0x82	/* VPD start byte */
331 #define	PMCS_VPD_END		0x78	/* VPD end byte */
332 
333 #define	PMCS_EEPROM_INT_SSID_BYTE1	0x02	/* Byte 1 of Thebe INT SSID */
334 #define	PMCS_EEPROM_INT_SSID_BYTE2	0x02	/* Byte 2 of Thebe INT SSID */
335 #define	PMCS_EEPROM_EXT_SSID_BYTE1	0x00	/* Byte 1 of Thebe EXT SSID */
336 #define	PMCS_EEPROM_EXT_SSID_BYTE2	0x22	/* Byte 2 of Thebe EXT SSID */
337 
338 /*
339  * This structure defines the "header" for the VPD data.  Everything
340  * following this structure is self-defining.  The consumer just needs
341  * to allocate a buffer large enough for vpd_length + 3 bytes of data.
342  */
343 
344 typedef struct {
345 	uint8_t		eeprom_version;
346 	uint8_t		vpd_length[2];	/* # bytes that follow, little-endian */
347 	uint8_t		hba_sas_wwid[8];
348 	uint8_t		subsys_pid[2];
349 	uint8_t		subsys_vid[2];
350 	uint8_t		vpd_start_byte;	/* 0x82 */
351 	uint8_t		strid_length[2]; /* little-endian */
352 	/* strid_length bytes follow */
353 } pmcs_vpd_header_t;
354 
355 typedef struct {
356 	char		keyword[2];
357 	uint8_t		value_length;
358 	char		value[1];	/* Length is actually value_length */
359 } pmcs_vpd_kv_t;
360 
361 /*
362  * From here on out are definitions related to Outbound Queues
363  * (completions of Inbound Queue requests and async events)
364  */
365 
366 /*
367  * PMC IOMB Outbound Queue Opcodes
368  */
369 #define	PMCOUT_ECHO							0x01
370 #define	PMCOUT_GET_INFO							0x02
371 #define	PMCOUT_GET_VPD							0x03
372 #define	PMCOUT_SAS_HW_EVENT						0x04
373 #define	PMCOUT_SSP_COMPLETION						0x05
374 #define	PMCOUT_SMP_COMPLETION						0x06
375 #define	PMCOUT_LOCAL_PHY_CONTROL					0x07
376 #define	PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT				0x08
377 #define	PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT				0x09
378 #define	PMCOUT_DEVICE_REGISTRATION					0x0A
379 #define	PMCOUT_DEREGISTER_DEVICE_HANDLE					0x0B
380 #define	PMCOUT_GET_DEVICE_HANDLE					0x0C
381 #define	PMCOUT_SATA_COMPLETION						0x0D
382 #define	PMCOUT_SATA_EVENT						0x0E
383 #define	PMCOUT_SSP_EVENT						0x0F
384 #define	PMCOUT_DEVICE_HANDLE_ARRIVED					0x10
385 #define	PMCOUT_SMP_REQUEST_RECEIVED					0x11
386 #define	PMCOUT_SSP_REQUEST_RECEIVED					0x12
387 #define	PMCOUT_DEVICE_INFO						0x13
388 #define	PMCOUT_FW_FLASH_UPDATE						0x14
389 #define	PMCOUT_SET_VPD							0x15
390 #define	PMCOUT_GPIO							0x16
391 #define	PMCOUT_GPIO_EVENT						0x17
392 #define	PMCOUT_GENERAL_EVENT						0x18
393 #define	PMCOUT_TWI							0x19
394 #define	PMCOUT_SSP_ABORT						0x1A
395 #define	PMCOUT_SATA_ABORT						0x1B
396 #define	PMCOUT_SAS_DIAG_MODE_START_END					0x1C
397 #define	PMCOUT_SAS_DIAG_EXECUTE						0x1D
398 #define	PMCOUT_GET_TIME_STAMP						0x1E
399 #define	PMCOUT_SAS_HW_EVENT_ACK_ACK					0x1F
400 #define	PMCOUT_PORT_CONTROL						0x20
401 #define	PMCOUT_SKIP_ENTRIES						0x21
402 #define	PMCOUT_SMP_ABORT						0x22
403 #define	PMCOUT_GET_NVMD_DATA						0x23
404 #define	PMCOUT_SET_NVMD_DATA						0x24
405 #define	PMCOUT_DEVICE_HANDLE_REMOVED					0x25
406 #define	PMCOUT_SET_DEVICE_STATE						0x26
407 #define	PMCOUT_GET_DEVICE_STATE						0x27
408 #define	PMCOUT_SET_DEVICE_INFO						0x28
409 
410 /*
411  * General Outbound Status Definitions
412  */
413 #define	PMCOUT_STATUS_OK						0x00
414 #define	PMCOUT_STATUS_ABORTED						0x01
415 #define	PMCOUT_STATUS_OVERFLOW						0x02
416 #define	PMCOUT_STATUS_UNDERFLOW						0x03
417 #define	PMCOUT_STATUS_FAILED						0x04
418 #define	PMCOUT_STATUS_ABORT_RESET					0x05
419 #define	PMCOUT_STATUS_IO_NOT_VALID					0x06
420 #define	PMCOUT_STATUS_NO_DEVICE						0x07
421 #define	PMCOUT_STATUS_ILLEGAL_PARAMETER					0x08
422 #define	PMCOUT_STATUS_LINK_FAILURE					0x09
423 #define	PMCOUT_STATUS_PROG_ERROR					0x0A
424 #define	PMCOUT_STATUS_EDC_IN_ERROR					0x0B
425 #define	PMCOUT_STATUS_EDC_OUT_ERROR					0x0C
426 #define	PMCOUT_STATUS_ERROR_HW_TIMEOUT					0x0D
427 #define	PMCOUT_STATUS_XFER_ERR_BREAK					0x0E
428 #define	PMCOUT_STATUS_XFER_ERR_PHY_NOT_READY				0x0F
429 #define	PMCOUT_STATUS_OPEN_CNX_PROTOCOL_NOT_SUPPORTED			0x10
430 #define	PMCOUT_STATUS_OPEN_CNX_ERROR_ZONE_VIOLATION			0x11
431 #define	PMCOUT_STATUS_OPEN_CNX_ERROR_BREAK				0x12
432 #define	PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS			0x13
433 #define	PMCOUT_STATUS_OPENCNX_ERROR_BAD_DESTINATION			0x14
434 #define	PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED	0x15
435 #define	PMCOUT_STATUS_OPEN_CNX_ERROR_STP_RESOURCES_BUSY			0x16
436 #define	PMCOUT_STATUS_OPEN_CNX_ERROR_WRONG_DESTINATION			0x17
437 #define	PMCOUT_STATUS_OPEN_CNX_ERROR_UNKNOWN_ERROR			0x18
438 #define	PMCOUT_STATUS_IO_XFER_ERROR_NAK_RECEIVED			0x19
439 #define	PMCOUT_STATUS_XFER_ERROR_ACK_NAK_TIMEOUT			0x1A
440 #define	PMCOUT_STATUS_XFER_ERROR_PEER_ABORTED				0x1B
441 #define	PMCOUT_STATUS_XFER_ERROR_RX_FRAME				0x1C
442 #define	PMCOUT_STATUS_IO_XFER_ERROR_DMA					0x1D
443 #define	PMCOUT_STATUS_XFER_ERROR_CREDIT_TIMEOUT				0x1E
444 #define	PMCOUT_STATUS_XFER_ERROR_SATA_LINK_TIMEOUT			0x1F
445 #define	PMCOUT_STATUS_XFER_ERROR_SATA					0x20
446 #define	PMCOUT_STATUS_XFER_ERROR_REJECTED_NCQ_MODE			0x21
447 #define	PMCOUT_STATUS_XFER_ERROR_ABORTED_DUE_TO_SRST			0x22
448 #define	PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE			0x23
449 #define	PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT			0x24
450 #define	PMCOUT_STATUS_SMP_RESP_CONNECTION_ERROR				0x25
451 #define	PMCOUT_STATUS_XFER_ERROR_UNEXPECTED_PHASE			0x26
452 #define	PMCOUT_STATUS_XFER_ERROR_RDY_OVERRUN				0x27
453 #define	PMCOUT_STATUS_XFER_ERROR_RDY_NOT_EXPECTED			0x28
454 /* 0x29 */
455 /* 0x2A */
456 /* 0x2B */
457 /* 0x2C */
458 /* 0x2D */
459 /* 0x2E */
460 /* 0x2F */
461 #define	PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT		0x30
462 #define	PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK	0x31
463 #define	PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK	0x32
464 /* 0x33 */
465 #define	PMCOUT_STATUS_XFER_ERROR_OFFSET_MISMATCH			0x34
466 #define	PMCOUT_STATUS_XFER_ERROR_ZERO_DATA_LEN				0x35
467 #define	PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED				0x36
468 #define	PMCOUT_STATUS_ERROR_INTERNAL_SMP_RESOURCE			0x37
469 #define	PMCOUT_STATUS_IO_PORT_IN_RESET					0x38
470 #define	PMCOUT_STATUS_IO_DS_NON_OPERATIONAL				0x39
471 #define	PMCOUT_STATUS_IO_DS_IN_RECOVERY					0x3A
472 #define	PMCOUT_STATUS_IO_TM_TAG_NOT_FOUND				0x3B
473 #define	PMCOUT_STATUS_IO_SSP_EXT_IU_ZERO_LEN_ERROR			0x3D
474 #define	PMCOUT_STATUS_IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY		0x3F
475 #define	PMCOUT_STATUS_IO_ABORT_IN_PROGRESS				0x40
476 
477 /*
478  * IOMB formats
479  *
480  * NOTE: All IOMBs are little-endian with exceptions to certain parts of
481  * some IOMBs.  For example, the SSP_RESPONSE_IU in the SSP_COMPLETION
482  * outbound IOMB is big-endian (SAS).
483  */
484 
485 /* Common IOMB header */
486 
487 typedef struct pmcs_iomb_header {
488 	uint8_t		opcode_lo;
489 	DECL_BITFIELD2(opcode_hi: 4,
490 	    cat			: 4);
491 	DECL_BITFIELD2(obid	: 6,
492 	    rsvd1		: 2);
493 	DECL_BITFIELD4(buf_count: 5,
494 	    rsvd2		: 1,
495 	    h_bit		: 1,
496 	    v_bit		: 1);
497 } pmcs_iomb_header_t;
498 
499 /* PMCOUT_SSP_COMPLETION */
500 
501 typedef struct pmcout_ssp_comp {
502 	pmcs_iomb_header_t	header;
503 	uint32_t		htag;
504 	uint32_t		status;
505 	uint32_t		param;
506 	uint16_t		ssp_tag;
507 	DECL_BITFIELD3(resc_v	: 1,
508 	    resc_pad	: 2,
509 	    rsvd1	: 5);
510 	uint8_t			rsvd2;
511 	/* SSP_RESPONSE_IU (if it exists) */
512 	/* Residual count (if resc_v is set) */
513 } pmcout_ssp_comp_t;
514 
515 
516 /*
517  * Device State definitions
518  */
519 #define	PMCS_DEVICE_STATE_NOT_AVAILABLE		0x0	/* Unconfigured tgt */
520 #define	PMCS_DEVICE_STATE_OPERATIONAL		0x1
521 #define	PMCS_DEVICE_STATE_PORT_IN_RESET		0x2
522 #define	PMCS_DEVICE_STATE_IN_RECOVERY		0x3
523 #define	PMCS_DEVICE_STATE_IN_ERROR		0x4
524 #define	PMCS_DEVICE_STATE_NON_OPERATIONAL	0x7
525 
526 /*
527  * Reset Types
528  */
529 #define	PMCS_SSP_LINK_RESET		0x1
530 #define	PMCS_SSP_HARD_RESET		0x2
531 #define	PMCS_SMP_HARD_RESET		0x3
532 
533 /*
534  * PHYOP for LOCAL_PHY_CONTROL Command
535  */
536 #define	PMCS_PHYOP_LINK_RESET		0x01
537 #define	PMCS_PHYOP_HARD_RESET		0x02
538 
539 /*
540  * Specialized status values
541  */
542 /* PHY Stop Status Results */
543 #define	IOP_PHY_STOP_OK		0x0
544 #define	IOP_PHY_STOP_INVALID	0x1
545 #define	IOP_PHY_STOP_ERROR	0x3
546 #define	IOP_PHY_STOP_ALREADY	0x4
547 
548 /* PHY Start Status Results */
549 #define	IOP_PHY_START_OK	0
550 #define	IOP_PHY_START_INVALID	1
551 #define	IOP_PHY_START_ALREADY	2
552 #define	IOP_PHY_START_ERROR	3
553 
554 /* SET/GET_NVMD status results */
555 #define	PMCS_NVMD_STAT_SUCCESS			0x0000
556 #define	PMCS_NVMD_STAT_PLD_NVMD_COMB_ERR	0x0001
557 #define	PMCS_NVMD_STAT_PLD_LEN_ERR		0x0002
558 #define	PMCS_NVMD_STAT_TWI_DEV_NACK		0x2001
559 #define	PMCS_NVMD_STAT_TWI_DEV_LOST_ARB		0x2002
560 #define	PMCS_NVMD_STAT_TWI_TIMEOUT		0x2021
561 #define	PMCS_NVMD_STAT_TWI_BUS_NACK		0x2081
562 #define	PMCS_NVMD_STAT_TWI_DEV_ARB_FAIL		0x2082
563 #define	PMCS_NVMD_STAT_TWI_BUS_SER_TIMEO	0x20FF
564 #define	PMCS_NVMD_STAT_PART_NOT_IN_FLASH	0x9001
565 #define	PMCS_NVMD_STAT_LEN_TOO_LARGE		0x9002
566 #define	PMCS_NVMD_STAT_FLASH_PRGRM_FAIL		0x9003
567 #define	PMCS_NVMD_STAT_DEVID_MATCH_FAIL		0x9004
568 #define	PMCS_NVMD_STAT_VENDID_MATCH_FAIL	0x9005
569 #define	PMCS_NVMD_STAT_SEC_ERASE_TIMEO		0x9006
570 #define	PMCS_NVMD_STAT_SEC_ERASE_CWE		0x9007
571 #define	PMCS_NVMD_STAT_FLASH_DEV_BUSY		0x9008
572 #define	PMCS_NVMD_STAT_FLASH_DEV_NOT_SUP	0x9009
573 #define	PMCS_NVMD_STAT_FLASH_NO_CFI		0x900A
574 #define	PMCS_NVMD_STAT_ERASE_BLOCKS		0x900B
575 #define	PMCS_NVMD_STAT_PART_READ_ONLY		0x900C
576 #define	PMCS_NVMD_STAT_PART_INV_MAP_TYPE	0x900D
577 #define	PMCS_NVMD_STAT_PART_INIT_STR_DIS	0x900E
578 
579 /*
580  * General Event Status Codes
581  */
582 #define	INBOUND_IOMB_V_BIT_NOT_SET		0x1
583 #define	INBOUND_IOMB_OPC_NOT_SUPPORTED		0x2
584 
585 /* Device Register Status Results */
586 #define	PMCS_DEVREG_OK				0x0
587 #define	PMCS_DEVREG_DEVICE_ALREADY_REGISTERED	0x2
588 #define	PMCS_DEVREG_PHY_ALREADY_REGISTERED	0x4
589 
590 /*
591  * Flash Update responses
592  */
593 #define	FLASH_UPDATE_COMPLETE_PENDING_REBOOT	0x0
594 #define	FLASH_UPDATE_IN_PROGRESS		0x1
595 #define	FLASH_UPDATE_HDR_ERR			0x2
596 #define	FLASH_UPDATE_OFFSET_ERR			0x3
597 #define	FLASH_UPDATE_UPDATE_CRC_ERR		0x4
598 #define	FLASH_UPDATE_LENGTH_ERR			0x5
599 #define	FLASH_UPDATE_HW_ERR			0x6
600 #define	FLASH_UPDATE_DNLD_NOT_SUPPORTED		0x10
601 #define	FLASH_UPDATE_DISABLED			0x11
602 
603 /*
604  * IOP SAS HW Event Related definitions
605  */
606 
607 #define	IOP_EVENT_LINK_RATE(x)		((x >> 28) & 0xf)
608 #define	IOP_EVENT_STATUS(x) 		((x >> 24) & 0xf)
609 #define	IOP_EVENT_EVENT(x)		((x >> 8) & 0xffff)
610 #define	IOP_EVENT_PHYNUM(x)		((x >> 4) & 0xf)
611 #define	IOP_EVENT_PORTID(x)		((x) & 0xf)
612 
613 
614 #define	IOP_EVENT_PHY_STOP_STATUS		0x03
615 #define	IOP_EVENT_SAS_PHY_UP			0x04
616 #define	IOP_EVENT_SATA_PHY_UP			0x05
617 #define	IOP_EVENT_SATA_SPINUP_HOLD		0x06
618 #define	IOP_EVENT_PHY_DOWN			0x07
619 #define	IOP_EVENT_PORT_INVALID			0x08	/* < fw 1.6 */
620 #define	IOP_EVENT_BROADCAST_CHANGE		0x09
621 #define	IOP_EVENT_BROADCAST_SES			0x0B
622 #define	IOP_EVENT_PHY_ERR_INBOUND_CRC		0x0C
623 #define	IOP_EVENT_HARD_RESET_RECEIVED		0x0D
624 #define	IOP_EVENT_EVENT_ID_FRAME_TIMO		0x0F
625 #define	IOP_EVENT_BROADCAST_EXP			0x10
626 #define	IOP_EVENT_PHY_START_STATUS		0x11
627 #define	IOP_EVENT_PHY_ERR_INVALID_DWORD		0x12
628 #define	IOP_EVENT_PHY_ERR_DISPARITY_ERROR	0x13
629 #define	IOP_EVENT_PHY_ERR_CODE_VIOLATION	0x14
630 #define	IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN	0x15
631 #define	IOP_EVENT_PHY_ERR_PHY_RESET_FAILD	0x16
632 #define	IOP_EVENT_PORT_RECOVERY_TIMER_TMO	0x17
633 #define	IOP_EVENT_PORT_RECOVER			0x18
634 #define	IOP_EVENT_PORT_RESET_TIMER_TMO		0x19
635 #define	IOP_EVENT_PORT_RESET_COMPLETE		0x20
636 #define	IOP_EVENT_BROADCAST_ASYNC_EVENT		0x21
637 #define	IOP_EVENT_IT_NEXUS_LOSS			0x22
638 
639 
640 #define	IOP_EVENT_PORT_STATE(x)		((x) & 0xf)
641 #define	IOP_EVENT_NPIP(x)		(((x) >> 4) & 0xf)
642 
643 #define	IOP_EVENT_PS_NIL		0x0	/* PORT_ID not valid yet */
644 #define	IOP_EVENT_PS_VALID		0x1	/* PORT_ID now valid */
645 #define	IOP_EVENT_PS_LOSTCOMM		0x2	/* Link temporarily down */
646 #define	IOP_EVENT_PS_IN_RESET		0x4	/* Port in reset */
647 #define	IOP_EVENT_PS_INVALID		0x8	/* PORT_ID now dead */
648 
649 /*
650  * HW Event Acknowledge Response Values
651  */
652 #define	SAS_HW_EVENT_ACK_OK		0x0
653 #define	SAS_HW_EVENT_ACK_INVALID_SEA	0x1
654 #define	SAS_HW_EVENT_ACK_INVALID_PHY	0x2
655 #define	SAS_HW_EVENT_ACK_INVALID_PORT	0x4
656 #define	SAS_HW_EVENT_ACK_INVALID_PARAM	0x8
657 
658 /*
659  * IOMB Queue definitions and Macros
660  */
661 
662 #define	ADDQI(ix, n, qd)	((ix + n) & (qd - 1))
663 #define	INCQI(ix, qd)		ix = ADDQI(ix, 1, qd)
664 #define	QI2O(ix, n, qd)		(ADDQI(ix, n, qd) * PMCS_QENTRY_SIZE)
665 
666 /*
667  * Inbound Queue Producer Indices live inside the PMC card.
668  *
669  * Inbound Queue Consumer indices live in host memory. We use the Consumer
670  * Index to return a pointer to an Inbound Queue entry. We then can fill
671  * it with an IOMB. We then update the the Producer index which kicks
672  * card to read the IOMB we just wrote.
673  *
674  * There is one mutex for each inbound queue that is held from the time
675  * we get an entry until we increment the producer index, or released
676  * manually if we don't actually send the message.
677  */
678 
679 /*
680  * NB: the appropriate iqp_lock must be held
681  */
682 #define	GET_IQ_ENTRY(hwp, qnum)	\
683 	((ADDQI(hwp->shadow_iqpi[qnum], 1, hwp->ioq_depth) == \
684 	pmcs_rd_iqci(hwp, qnum)) ? NULL : \
685 	&hwp->iqp[qnum][hwp->shadow_iqpi[qnum] * (PMCS_QENTRY_SIZE >> 2)])
686 
687 /*
688  * NB: This releases the lock on the Inbound Queue that GET_IO_IQ_ENTRY
689  * acquired below.
690  */
691 #ifdef	DEBUG
692 #define	INC_IQ_ENTRY(hwp, qnum)						\
693 {									\
694 	uint32_t htag;							\
695 	ASSERT(mutex_owned(&(hwp)->iqp_lock[qnum]));			\
696 	htag = hwp->iqp[qnum][(hwp->shadow_iqpi[qnum] *			\
697 	    (PMCS_QENTRY_SIZE >> 2)) + 1];				\
698 	mutex_enter(&(hwp)->dbglock);					\
699 	pmcs_iqp_trace(hwp, qnum);					\
700 	mutex_exit(&(hwp)->dbglock);					\
701 	INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth);			\
702 	if (ddi_dma_sync(hwp->cip_handles, 0, 0,			\
703 	    DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) {			\
704 		pmcs_prt(hwp, PMCS_PRT_DEBUG, NULL, NULL, "Condition "	\
705 		    "failed at %s():%d", __func__, __LINE__);		\
706 	}								\
707 	hwp->ftime[hwp->fti] = gethrtime();				\
708 	pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]);		\
709 	mutex_exit(&(hwp)->iqp_lock[qnum]);				\
710 	mutex_enter(&(hwp)->dbglock);					\
711 	hwp->ftag_lines[hwp->fti] = __LINE__;				\
712 	hwp->ftags[hwp->fti++] = htag;					\
713 	mutex_exit(&(hwp)->dbglock);					\
714 }
715 #else
716 #define	INC_IQ_ENTRY(hwp, qnum)						\
717 	INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth);			\
718 	if (ddi_dma_sync(hwp->cip_handles, 0, 0,			\
719 	    DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) {			\
720 		pmcs_prt(hwp, PMCS_PRT_DEBUG, NULL, NULL, "Condition "	\
721 		    "failed at %s():%d", __func__, __LINE__);		\
722 	}								\
723 	pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]);		\
724 	mutex_exit(&(hwp)->iqp_lock[qnum])
725 #endif
726 
727 
728 /*
729  * NB: sucessfull acquisition of an IO Inbound Queue
730  * entry leaves the lock on that Inbound Queue held.
731  */
732 #define	GET_IO_IQ_ENTRY(pwp, msg, did, iq)				\
733 	iq = did & PMCS_IO_IQ_MASK;					\
734 	mutex_enter(&(pwp)->iqp_lock[iq]);				\
735 	msg = GET_IQ_ENTRY(pwp, iq);					\
736 	if (msg == NULL) {						\
737 		mutex_exit(&(pwp)->iqp_lock[iq]);			\
738 		for (iq = 0; iq <= PMCS_NON_HIPRI_QUEUES; iq++) {	\
739 			mutex_enter(&(pwp)->iqp_lock[iq]);		\
740 			msg = GET_IQ_ENTRY(pwp, iq);			\
741 			if (msg) {					\
742 				break;					\
743 			}						\
744 			mutex_exit(&(pwp->iqp_lock[iq]));		\
745 		}							\
746 	}
747 
748 /*
749  * Outbound Queue Macros
750  *
751  * Outbound Queue Consumer indices live inside the card.
752  *
753  * Outbound Queue Producer indices live in host memory. When the card
754  * wants to send an IOMB, it uses the producer index to find the spot
755  * to write the IOMB. After it's done it updates the producer index
756  * and interrupts the host. The host reads the producer index (from
757  * host memory) and reads IOMBs up to but not including that index.
758  * It writes that index back to the consumer index on the card,
759  * signifying that it has read up to that which the card has sent.
760  */
761 #define	GET_OQ_ENTRY(hwp, qn, ix, o) \
762 	&hwp->oqp[qn][QI2O(ix, o, hwp->ioq_depth) >> 2]
763 
764 #define	STEP_OQ_ENTRY(hwp, qn, ix, n)	ix = ADDQI(ix, n, hwp->ioq_depth)
765 
766 #define	SYNC_OQ_ENTRY(hwp, qn, ci, pi) 		\
767 	pmcs_wr_oqci(hwp, qn, ci);		\
768 	(hwp)->oqci[qn] = ci;			\
769 	(hwp)->oqpi[qn] = pi
770 
771 #ifdef	__cplusplus
772 }
773 #endif
774 #endif	/* _PMCS_IOMB_H */
775