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