| 1 | /* $NetBSD: mpii.c,v 1.8 2016/05/02 19:18:29 christos Exp $ */ |
| 2 | /* OpenBSD: mpii.c,v 1.51 2012/04/11 13:29:14 naddy Exp */ |
| 3 | /* |
| 4 | * Copyright (c) 2010 Mike Belopuhov <mkb@crypt.org.ru> |
| 5 | * Copyright (c) 2009 James Giannoules |
| 6 | * Copyright (c) 2005 - 2010 David Gwynne <dlg@openbsd.org> |
| 7 | * Copyright (c) 2005 - 2010 Marco Peereboom <marco@openbsd.org> |
| 8 | * |
| 9 | * Permission to use, copy, modify, and distribute this software for any |
| 10 | * purpose with or without fee is hereby granted, provided that the above |
| 11 | * copyright notice and this permission notice appear in all copies. |
| 12 | * |
| 13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 20 | */ |
| 21 | |
| 22 | #include <sys/cdefs.h> |
| 23 | __KERNEL_RCSID(0, "$NetBSD: mpii.c,v 1.8 2016/05/02 19:18:29 christos Exp $" ); |
| 24 | |
| 25 | #include "bio.h" |
| 26 | |
| 27 | #include <sys/param.h> |
| 28 | #include <sys/systm.h> |
| 29 | #include <sys/buf.h> |
| 30 | #include <sys/device.h> |
| 31 | #include <sys/ioctl.h> |
| 32 | #include <sys/malloc.h> |
| 33 | #include <sys/kernel.h> |
| 34 | #include <sys/mutex.h> |
| 35 | #include <sys/condvar.h> |
| 36 | #include <sys/dkio.h> |
| 37 | #include <sys/tree.h> |
| 38 | |
| 39 | #include <dev/pci/pcireg.h> |
| 40 | #include <dev/pci/pcivar.h> |
| 41 | #include <dev/pci/pcidevs.h> |
| 42 | |
| 43 | #include <dev/scsipi/scsipi_all.h> |
| 44 | #include <dev/scsipi/scsi_all.h> |
| 45 | #include <dev/scsipi/scsiconf.h> |
| 46 | |
| 47 | #include <dev/biovar.h> |
| 48 | #include <dev/sysmon/sysmonvar.h> |
| 49 | #include <sys/envsys.h> |
| 50 | |
| 51 | #define MPII_DOORBELL (0x00) |
| 52 | /* doorbell read bits */ |
| 53 | #define MPII_DOORBELL_STATE (0xf<<28) /* ioc state */ |
| 54 | #define MPII_DOORBELL_STATE_RESET (0x0<<28) |
| 55 | #define MPII_DOORBELL_STATE_READY (0x1<<28) |
| 56 | #define MPII_DOORBELL_STATE_OPER (0x2<<28) |
| 57 | #define MPII_DOORBELL_STATE_FAULT (0x4<<28) |
| 58 | #define MPII_DOORBELL_INUSE (0x1<<27) /* doorbell used */ |
| 59 | #define MPII_DOORBELL_WHOINIT (0x7<<24) /* last to reset ioc */ |
| 60 | #define MPII_DOORBELL_WHOINIT_NOONE (0x0<<24) /* not initialized */ |
| 61 | #define MPII_DOORBELL_WHOINIT_SYSBIOS (0x1<<24) /* system bios */ |
| 62 | #define MPII_DOORBELL_WHOINIT_ROMBIOS (0x2<<24) /* rom bios */ |
| 63 | #define MPII_DOORBELL_WHOINIT_PCIPEER (0x3<<24) /* pci peer */ |
| 64 | #define MPII_DOORBELL_WHOINIT_DRIVER (0x4<<24) /* host driver */ |
| 65 | #define MPII_DOORBELL_WHOINIT_MANUFACT (0x5<<24) /* manufacturing */ |
| 66 | #define MPII_DOORBELL_FAULT (0xffff<<0) /* fault code */ |
| 67 | /* doorbell write bits */ |
| 68 | #define MPII_DOORBELL_FUNCTION_SHIFT (24) |
| 69 | #define MPII_DOORBELL_FUNCTION_MASK (0xff << MPII_DOORBELL_FUNCTION_SHIFT) |
| 70 | #define MPII_DOORBELL_FUNCTION(x) \ |
| 71 | (((x) << MPII_DOORBELL_FUNCTION_SHIFT) & MPII_DOORBELL_FUNCTION_MASK) |
| 72 | #define MPII_DOORBELL_DWORDS_SHIFT 16 |
| 73 | #define MPII_DOORBELL_DWORDS_MASK (0xff << MPII_DOORBELL_DWORDS_SHIFT) |
| 74 | #define MPII_DOORBELL_DWORDS(x) \ |
| 75 | (((x) << MPII_DOORBELL_DWORDS_SHIFT) & MPII_DOORBELL_DWORDS_MASK) |
| 76 | #define MPII_DOORBELL_DATA_MASK (0xffff) |
| 77 | |
| 78 | #define MPII_WRITESEQ (0x04) |
| 79 | #define MPII_WRITESEQ_KEY_VALUE_MASK (0x0000000f) /* key value */ |
| 80 | #define MPII_WRITESEQ_FLUSH (0x00) |
| 81 | #define MPII_WRITESEQ_1 (0x0f) |
| 82 | #define MPII_WRITESEQ_2 (0x04) |
| 83 | #define MPII_WRITESEQ_3 (0x0b) |
| 84 | #define MPII_WRITESEQ_4 (0x02) |
| 85 | #define MPII_WRITESEQ_5 (0x07) |
| 86 | #define MPII_WRITESEQ_6 (0x0d) |
| 87 | |
| 88 | #define MPII_HOSTDIAG (0x08) |
| 89 | #define MPII_HOSTDIAG_BDS_MASK (0x00001800) /* boot device select */ |
| 90 | #define MPII_HOSTDIAG_BDS_DEFAULT (0<<11) /* default address map, flash */ |
| 91 | #define MPII_HOSTDIAG_BDS_HCDW (1<<11) /* host code and data window */ |
| 92 | #define MPII_HOSTDIAG_CLEARFBS (1<<10) /* clear flash bad sig */ |
| 93 | #define MPII_HOSTDIAG_FORCE_HCB_ONBOOT (1<<9) /* force host controlled boot */ |
| 94 | #define MPII_HOSTDIAG_HCB_MODE (1<<8) /* host controlled boot mode */ |
| 95 | #define MPII_HOSTDIAG_DWRE (1<<7) /* diag reg write enabled */ |
| 96 | #define MPII_HOSTDIAG_FBS (1<<6) /* flash bad sig */ |
| 97 | #define MPII_HOSTDIAG_RESET_HIST (1<<5) /* reset history */ |
| 98 | #define MPII_HOSTDIAG_DIAGWR_EN (1<<4) /* diagnostic write enabled */ |
| 99 | #define MPII_HOSTDIAG_RESET_ADAPTER (1<<2) /* reset adapter */ |
| 100 | #define MPII_HOSTDIAG_HOLD_IOC_RESET (1<<1) /* hold ioc in reset */ |
| 101 | #define MPII_HOSTDIAG_DIAGMEM_EN (1<<0) /* diag mem enable */ |
| 102 | |
| 103 | #define MPII_DIAGRWDATA (0x10) |
| 104 | |
| 105 | #define MPII_DIAGRWADDRLOW (0x14) |
| 106 | |
| 107 | #define MPII_DIAGRWADDRHIGH (0x18) |
| 108 | |
| 109 | #define MPII_INTR_STATUS (0x30) |
| 110 | #define MPII_INTR_STATUS_SYS2IOCDB (1<<31) /* ioc written to by host */ |
| 111 | #define MPII_INTR_STATUS_RESET (1<<30) /* physical ioc reset */ |
| 112 | #define MPII_INTR_STATUS_REPLY (1<<3) /* reply message interrupt */ |
| 113 | #define MPII_INTR_STATUS_IOC2SYSDB (1<<0) /* ioc write to doorbell */ |
| 114 | |
| 115 | #define MPII_INTR_MASK (0x34) |
| 116 | #define MPII_INTR_MASK_RESET (1<<30) /* ioc reset intr mask */ |
| 117 | #define MPII_INTR_MASK_REPLY (1<<3) /* reply message intr mask */ |
| 118 | #define MPII_INTR_MASK_DOORBELL (1<<0) /* doorbell interrupt mask */ |
| 119 | |
| 120 | #define MPII_DCR_DATA (0x38) |
| 121 | |
| 122 | #define MPII_DCR_ADDRESS (0x3c) |
| 123 | |
| 124 | #define MPII_REPLY_FREE_HOST_INDEX (0x48) |
| 125 | |
| 126 | #define MPII_REPLY_POST_HOST_INDEX (0x6c) |
| 127 | |
| 128 | #define MPII_HCB_SIZE (0x74) |
| 129 | |
| 130 | #define MPII_HCB_ADDRESS_LOW (0x78) |
| 131 | #define MPII_HCB_ADDRESS_HIGH (0x7c) |
| 132 | |
| 133 | #define MPII_REQ_DESCR_POST_LOW (0xc0) |
| 134 | #define MPII_REQ_DESCR_POST_HIGH (0xc4) |
| 135 | |
| 136 | /* |
| 137 | * Scatter Gather Lists |
| 138 | */ |
| 139 | |
| 140 | #define MPII_SGE_FL_LAST (0x1<<31) /* last element in segment */ |
| 141 | #define MPII_SGE_FL_EOB (0x1<<30) /* last element of buffer */ |
| 142 | #define MPII_SGE_FL_TYPE (0x3<<28) /* element type */ |
| 143 | #define MPII_SGE_FL_TYPE_SIMPLE (0x1<<28) /* simple element */ |
| 144 | #define MPII_SGE_FL_TYPE_CHAIN (0x3<<28) /* chain element */ |
| 145 | #define MPII_SGE_FL_TYPE_XACTCTX (0x0<<28) /* transaction context */ |
| 146 | #define MPII_SGE_FL_LOCAL (0x1<<27) /* local address */ |
| 147 | #define MPII_SGE_FL_DIR (0x1<<26) /* direction */ |
| 148 | #define MPII_SGE_FL_DIR_OUT (0x1<<26) |
| 149 | #define MPII_SGE_FL_DIR_IN (0x0<<26) |
| 150 | #define MPII_SGE_FL_SIZE (0x1<<25) /* address size */ |
| 151 | #define MPII_SGE_FL_SIZE_32 (0x0<<25) |
| 152 | #define MPII_SGE_FL_SIZE_64 (0x1<<25) |
| 153 | #define MPII_SGE_FL_EOL (0x1<<24) /* end of list */ |
| 154 | |
| 155 | struct mpii_sge { |
| 156 | u_int32_t sg_hdr; |
| 157 | u_int32_t sg_lo_addr; |
| 158 | u_int32_t sg_hi_addr; |
| 159 | } __packed; |
| 160 | |
| 161 | struct mpii_fw_tce { |
| 162 | u_int8_t reserved1; |
| 163 | u_int8_t context_size; |
| 164 | u_int8_t details_length; |
| 165 | u_int8_t flags; |
| 166 | |
| 167 | u_int32_t reserved2; |
| 168 | |
| 169 | u_int32_t image_offset; |
| 170 | |
| 171 | u_int32_t image_size; |
| 172 | } __packed; |
| 173 | |
| 174 | /* |
| 175 | * Messages |
| 176 | */ |
| 177 | |
| 178 | /* functions */ |
| 179 | #define MPII_FUNCTION_SCSI_IO_REQUEST (0x00) |
| 180 | #define MPII_FUNCTION_SCSI_TASK_MGMT (0x01) |
| 181 | #define MPII_FUNCTION_IOC_INIT (0x02) |
| 182 | #define MPII_FUNCTION_IOC_FACTS (0x03) |
| 183 | #define MPII_FUNCTION_CONFIG (0x04) |
| 184 | #define MPII_FUNCTION_PORT_FACTS (0x05) |
| 185 | #define MPII_FUNCTION_PORT_ENABLE (0x06) |
| 186 | #define MPII_FUNCTION_EVENT_NOTIFICATION (0x07) |
| 187 | #define MPII_FUNCTION_EVENT_ACK (0x08) |
| 188 | #define MPII_FUNCTION_FW_DOWNLOAD (0x09) |
| 189 | #define MPII_FUNCTION_TARGET_CMD_BUFFER_POST (0x0a) |
| 190 | #define MPII_FUNCTION_TARGET_ASSIST (0x0b) |
| 191 | #define MPII_FUNCTION_TARGET_STATUS_SEND (0x0c) |
| 192 | #define MPII_FUNCTION_TARGET_MODE_ABORT (0x0d) |
| 193 | #define MPII_FUNCTION_FW_UPLOAD (0x12) |
| 194 | |
| 195 | #define MPII_FUNCTION_RAID_ACTION (0x15) |
| 196 | #define MPII_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) |
| 197 | |
| 198 | #define MPII_FUNCTION_TOOLBOX (0x17) |
| 199 | |
| 200 | #define MPII_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) |
| 201 | |
| 202 | #define MPII_FUNCTION_SMP_PASSTHROUGH (0x1a) |
| 203 | #define MPII_FUNCTION_SAS_IO_UNIT_CONTROL (0x1b) |
| 204 | #define MPII_FUNCTION_SATA_PASSTHROUGH (0x1c) |
| 205 | |
| 206 | #define MPII_FUNCTION_DIAG_BUFFER_POST (0x1d) |
| 207 | #define MPII_FUNCTION_DIAG_RELEASE (0x1e) |
| 208 | |
| 209 | #define MPII_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) |
| 210 | #define MPII_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) |
| 211 | |
| 212 | #define MPII_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) |
| 213 | #define MPII_FUNCTION_IO_UNIT_RESET (0x41) |
| 214 | #define MPII_FUNCTION_HANDSHAKE (0x42) |
| 215 | |
| 216 | /* Common IOCStatus values for all replies */ |
| 217 | #define MPII_IOCSTATUS_MASK (0x7fff) |
| 218 | #define MPII_IOCSTATUS_SUCCESS (0x0000) |
| 219 | #define MPII_IOCSTATUS_INVALID_FUNCTION (0x0001) |
| 220 | #define MPII_IOCSTATUS_BUSY (0x0002) |
| 221 | #define MPII_IOCSTATUS_INVALID_SGL (0x0003) |
| 222 | #define MPII_IOCSTATUS_INTERNAL_ERROR (0x0004) |
| 223 | #define MPII_IOCSTATUS_INVALID_VPID (0x0005) |
| 224 | #define MPII_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) |
| 225 | #define MPII_IOCSTATUS_INVALID_FIELD (0x0007) |
| 226 | #define MPII_IOCSTATUS_INVALID_STATE (0x0008) |
| 227 | #define MPII_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) |
| 228 | /* Config IOCStatus values */ |
| 229 | #define MPII_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) |
| 230 | #define MPII_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) |
| 231 | #define MPII_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) |
| 232 | #define MPII_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) |
| 233 | #define MPII_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) |
| 234 | #define MPII_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) |
| 235 | /* SCSIIO Reply initiator values */ |
| 236 | #define MPII_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) |
| 237 | #define MPII_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) |
| 238 | #define MPII_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) |
| 239 | #define MPII_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) |
| 240 | #define MPII_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) |
| 241 | #define MPII_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) |
| 242 | #define MPII_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) |
| 243 | #define MPII_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) |
| 244 | #define MPII_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) |
| 245 | #define MPII_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004a) |
| 246 | #define MPII_IOCSTATUS_SCSI_IOC_TERMINATED (0x004b) |
| 247 | #define MPII_IOCSTATUS_SCSI_EXT_TERMINATED (0x004c) |
| 248 | /* For use by SCSI Initiator and SCSI Target end-to-end data protection */ |
| 249 | #define MPII_IOCSTATUS_EEDP_GUARD_ERROR (0x004d) |
| 250 | #define MPII_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004e) |
| 251 | #define MPII_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004f) |
| 252 | /* SCSI (SPI & FCP) target values */ |
| 253 | #define MPII_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) |
| 254 | #define MPII_IOCSTATUS_TARGET_ABORTED (0x0063) |
| 255 | #define MPII_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) |
| 256 | #define MPII_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) |
| 257 | #define MPII_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006a) |
| 258 | #define MPII_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006d) |
| 259 | #define MPII_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006e) |
| 260 | #define MPII_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006f) |
| 261 | #define MPII_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) |
| 262 | #define MPII_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) |
| 263 | /* Serial Attached SCSI values */ |
| 264 | #define MPII_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) |
| 265 | #define MPII_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) |
| 266 | /* Diagnostic Tools values */ |
| 267 | #define MPII_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00a0) |
| 268 | |
| 269 | #define MPII_REP_IOCLOGINFO_TYPE (0xf<<28) |
| 270 | #define MPII_REP_IOCLOGINFO_TYPE_NONE (0x0<<28) |
| 271 | #define MPII_REP_IOCLOGINFO_TYPE_SCSI (0x1<<28) |
| 272 | #define MPII_REP_IOCLOGINFO_TYPE_FC (0x2<<28) |
| 273 | #define MPII_REP_IOCLOGINFO_TYPE_SAS (0x3<<28) |
| 274 | #define MPII_REP_IOCLOGINFO_TYPE_ISCSI (0x4<<28) |
| 275 | #define MPII_REP_IOCLOGINFO_DATA (0x0fffffff) |
| 276 | |
| 277 | /* event notification types */ |
| 278 | #define MPII_EVENT_NONE (0x00) |
| 279 | #define MPII_EVENT_LOG_DATA (0x01) |
| 280 | #define MPII_EVENT_STATE_CHANGE (0x02) |
| 281 | #define MPII_EVENT_HARD_RESET_RECEIVED (0x05) |
| 282 | #define MPII_EVENT_EVENT_CHANGE (0x0a) |
| 283 | #define MPII_EVENT_TASK_SET_FULL (0x0e) |
| 284 | #define MPII_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0f) |
| 285 | #define MPII_EVENT_IR_OPERATION_STATUS (0x14) |
| 286 | #define MPII_EVENT_SAS_DISCOVERY (0x16) |
| 287 | #define MPII_EVENT_SAS_BROADCAST_PRIMITIVE (0x17) |
| 288 | #define MPII_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x18) |
| 289 | #define MPII_EVENT_SAS_INIT_TABLE_OVERFLOW (0x19) |
| 290 | #define MPII_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x1c) |
| 291 | #define MPII_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x1d) |
| 292 | #define MPII_EVENT_IR_VOLUME (0x1e) |
| 293 | #define MPII_EVENT_IR_PHYSICAL_DISK (0x1f) |
| 294 | #define MPII_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x20) |
| 295 | #define MPII_EVENT_LOG_ENTRY_ADDED (0x21) |
| 296 | |
| 297 | /* messages */ |
| 298 | |
| 299 | #define MPII_WHOINIT_NOONE (0x00) |
| 300 | #define MPII_WHOINIT_SYSTEM_BIOS (0x01) |
| 301 | #define MPII_WHOINIT_ROM_BIOS (0x02) |
| 302 | #define MPII_WHOINIT_PCI_PEER (0x03) |
| 303 | #define MPII_WHOINIT_HOST_DRIVER (0x04) |
| 304 | #define MPII_WHOINIT_MANUFACTURER (0x05) |
| 305 | |
| 306 | /* default messages */ |
| 307 | |
| 308 | struct mpii_msg_request { |
| 309 | u_int8_t reserved1; |
| 310 | u_int8_t reserved2; |
| 311 | u_int8_t chain_offset; |
| 312 | u_int8_t function; |
| 313 | |
| 314 | u_int8_t reserved3; |
| 315 | u_int8_t reserved4; |
| 316 | u_int8_t reserved5; |
| 317 | u_int8_t msg_flags; |
| 318 | |
| 319 | u_int8_t vp_id; |
| 320 | u_int8_t vf_id; |
| 321 | u_int16_t reserved6; |
| 322 | } __packed; |
| 323 | |
| 324 | struct mpii_msg_reply { |
| 325 | u_int16_t reserved1; |
| 326 | u_int8_t msg_length; |
| 327 | u_int8_t function; |
| 328 | |
| 329 | u_int16_t reserved2; |
| 330 | u_int8_t reserved3; |
| 331 | u_int8_t msg_flags; |
| 332 | |
| 333 | u_int8_t vp_id; |
| 334 | u_int8_t vf_if; |
| 335 | u_int16_t reserved4; |
| 336 | |
| 337 | u_int16_t reserved5; |
| 338 | u_int16_t ioc_status; |
| 339 | |
| 340 | u_int32_t ioc_loginfo; |
| 341 | } __packed; |
| 342 | |
| 343 | /* ioc init */ |
| 344 | |
| 345 | struct mpii_msg_iocinit_request { |
| 346 | u_int8_t whoinit; |
| 347 | u_int8_t reserved1; |
| 348 | u_int8_t chain_offset; |
| 349 | u_int8_t function; |
| 350 | |
| 351 | u_int16_t reserved2; |
| 352 | u_int8_t reserved3; |
| 353 | u_int8_t msg_flags; |
| 354 | |
| 355 | u_int8_t vp_id; |
| 356 | u_int8_t vf_id; |
| 357 | u_int16_t reserved4; |
| 358 | |
| 359 | u_int8_t msg_version_min; |
| 360 | u_int8_t msg_version_maj; |
| 361 | u_int8_t hdr_version_unit; |
| 362 | u_int8_t hdr_version_dev; |
| 363 | |
| 364 | u_int32_t reserved5; |
| 365 | |
| 366 | u_int32_t reserved6; |
| 367 | |
| 368 | u_int16_t reserved7; |
| 369 | u_int16_t system_request_frame_size; |
| 370 | |
| 371 | u_int16_t reply_descriptor_post_queue_depth; |
| 372 | u_int16_t reply_free_queue_depth; |
| 373 | |
| 374 | u_int32_t sense_buffer_address_high; |
| 375 | |
| 376 | u_int32_t system_reply_address_high; |
| 377 | |
| 378 | u_int64_t system_request_frame_base_address; |
| 379 | |
| 380 | u_int64_t reply_descriptor_post_queue_address; |
| 381 | |
| 382 | u_int64_t reply_free_queue_address; |
| 383 | |
| 384 | u_int64_t timestamp; |
| 385 | } __packed; |
| 386 | |
| 387 | struct mpii_msg_iocinit_reply { |
| 388 | u_int8_t whoinit; |
| 389 | u_int8_t reserved1; |
| 390 | u_int8_t msg_length; |
| 391 | u_int8_t function; |
| 392 | |
| 393 | u_int16_t reserved2; |
| 394 | u_int8_t reserved3; |
| 395 | u_int8_t msg_flags; |
| 396 | |
| 397 | u_int8_t vp_id; |
| 398 | u_int8_t vf_id; |
| 399 | u_int16_t reserved4; |
| 400 | |
| 401 | u_int16_t reserved5; |
| 402 | u_int16_t ioc_status; |
| 403 | |
| 404 | u_int32_t ioc_loginfo; |
| 405 | } __packed; |
| 406 | |
| 407 | struct mpii_msg_iocfacts_request { |
| 408 | u_int16_t reserved1; |
| 409 | u_int8_t chain_offset; |
| 410 | u_int8_t function; |
| 411 | |
| 412 | u_int16_t reserved2; |
| 413 | u_int8_t reserved3; |
| 414 | u_int8_t msg_flags; |
| 415 | |
| 416 | u_int8_t vp_id; |
| 417 | u_int8_t vf_id; |
| 418 | u_int16_t reserved4; |
| 419 | } __packed; |
| 420 | |
| 421 | struct mpii_msg_iocfacts_reply { |
| 422 | u_int8_t msg_version_min; |
| 423 | u_int8_t msg_version_maj; |
| 424 | u_int8_t msg_length; |
| 425 | u_int8_t function; |
| 426 | |
| 427 | u_int8_t ; |
| 428 | u_int8_t ; |
| 429 | u_int8_t ioc_number; |
| 430 | u_int8_t msg_flags; |
| 431 | |
| 432 | u_int8_t vp_id; |
| 433 | u_int8_t vf_id; |
| 434 | u_int16_t reserved1; |
| 435 | |
| 436 | u_int16_t ioc_exceptions; |
| 437 | #define MPII_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (1<<0) |
| 438 | #define MPII_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (1<<1) |
| 439 | #define MPII_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (1<<2) |
| 440 | #define MPII_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (1<<3) |
| 441 | #define MPII_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (1<<4) |
| 442 | #define MPII_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAC (1<<8) |
| 443 | /* XXX JPG BOOT_STATUS in bits[7:5] */ |
| 444 | /* XXX JPG all these #defines need to be fixed up */ |
| 445 | u_int16_t ioc_status; |
| 446 | |
| 447 | u_int32_t ioc_loginfo; |
| 448 | |
| 449 | u_int8_t max_chain_depth; |
| 450 | u_int8_t whoinit; |
| 451 | u_int8_t number_of_ports; |
| 452 | u_int8_t reserved2; |
| 453 | |
| 454 | u_int16_t request_credit; |
| 455 | u_int16_t product_id; |
| 456 | |
| 457 | u_int32_t ioc_capabilities; |
| 458 | #define MPII_IOCFACTS_CAPABILITY_EVENT_REPLAY (1<<13) |
| 459 | #define MPII_IOCFACTS_CAPABILITY_INTEGRATED_RAID (1<<12) |
| 460 | #define MPII_IOCFACTS_CAPABILITY_TLR (1<<11) |
| 461 | #define MPII_IOCFACTS_CAPABILITY_MULTICAST (1<<8) |
| 462 | #define MPII_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (1<<7) |
| 463 | #define MPII_IOCFACTS_CAPABILITY_EEDP (1<<6) |
| 464 | #define MPII_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (1<<4) |
| 465 | #define MPII_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (1<<3) |
| 466 | #define MPII_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (1<<2) |
| 467 | |
| 468 | u_int8_t fw_version_dev; |
| 469 | u_int8_t fw_version_unit; |
| 470 | u_int8_t fw_version_min; |
| 471 | u_int8_t fw_version_maj; |
| 472 | |
| 473 | u_int16_t ioc_request_frame_size; |
| 474 | u_int16_t reserved3; |
| 475 | |
| 476 | u_int16_t max_initiators; |
| 477 | u_int16_t max_targets; |
| 478 | |
| 479 | u_int16_t max_sas_expanders; |
| 480 | u_int16_t max_enclosures; |
| 481 | |
| 482 | u_int16_t protocol_flags; |
| 483 | u_int16_t high_priority_credit; |
| 484 | |
| 485 | u_int16_t max_reply_descriptor_post_queue_depth; |
| 486 | u_int8_t reply_frame_size; |
| 487 | u_int8_t max_volumes; |
| 488 | |
| 489 | u_int16_t max_dev_handle; |
| 490 | u_int16_t max_persistent_entries; |
| 491 | |
| 492 | u_int32_t reserved4; |
| 493 | } __packed; |
| 494 | |
| 495 | struct mpii_msg_portfacts_request { |
| 496 | u_int16_t reserved1; |
| 497 | u_int8_t chain_offset; |
| 498 | u_int8_t function; |
| 499 | |
| 500 | u_int16_t reserved2; |
| 501 | u_int8_t port_number; |
| 502 | u_int8_t msg_flags; |
| 503 | |
| 504 | u_int8_t vp_id; |
| 505 | u_int8_t vf_id; |
| 506 | u_int16_t reserved3; |
| 507 | } __packed; |
| 508 | |
| 509 | struct mpii_msg_portfacts_reply { |
| 510 | u_int16_t reserved1; |
| 511 | u_int8_t msg_length; |
| 512 | u_int8_t function; |
| 513 | |
| 514 | u_int16_t reserved2; |
| 515 | u_int8_t port_number; |
| 516 | u_int8_t msg_flags; |
| 517 | |
| 518 | u_int8_t vp_id; |
| 519 | u_int8_t vf_id; |
| 520 | u_int16_t reserved3; |
| 521 | |
| 522 | u_int16_t reserved4; |
| 523 | u_int16_t ioc_status; |
| 524 | |
| 525 | u_int32_t ioc_loginfo; |
| 526 | |
| 527 | u_int8_t reserved5; |
| 528 | u_int8_t port_type; |
| 529 | #define MPII_PORTFACTS_PORTTYPE_INACTIVE (0x00) |
| 530 | #define MPII_PORTFACTS_PORTTYPE_FC (0x10) |
| 531 | #define MPII_PORTFACTS_PORTTYPE_ISCSI (0x20) |
| 532 | #define MPII_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) |
| 533 | #define MPII_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) |
| 534 | u_int16_t reserved6; |
| 535 | |
| 536 | u_int16_t max_posted_cmd_buffers; |
| 537 | u_int16_t reserved7; |
| 538 | } __packed; |
| 539 | |
| 540 | struct mpii_msg_portenable_request { |
| 541 | u_int16_t reserved1; |
| 542 | u_int8_t chain_offset; |
| 543 | u_int8_t function; |
| 544 | |
| 545 | u_int8_t reserved2; |
| 546 | u_int8_t port_flags; |
| 547 | u_int8_t reserved3; |
| 548 | u_int8_t msg_flags; |
| 549 | |
| 550 | u_int8_t vp_id; |
| 551 | u_int8_t vf_id; |
| 552 | u_int16_t reserved4; |
| 553 | } __packed; |
| 554 | |
| 555 | struct mpii_msg_portenable_reply { |
| 556 | u_int16_t reserved1; |
| 557 | u_int8_t msg_length; |
| 558 | u_int8_t function; |
| 559 | |
| 560 | u_int8_t reserved2; |
| 561 | u_int8_t port_flags; |
| 562 | u_int8_t reserved3; |
| 563 | u_int8_t msg_flags; |
| 564 | |
| 565 | u_int8_t vp_id; |
| 566 | u_int8_t vf_id; |
| 567 | u_int16_t reserved4; |
| 568 | |
| 569 | u_int16_t reserved5; |
| 570 | u_int16_t ioc_status; |
| 571 | |
| 572 | u_int32_t ioc_loginfo; |
| 573 | } __packed; |
| 574 | |
| 575 | struct mpii_msg_event_request { |
| 576 | u_int16_t reserved1; |
| 577 | u_int8_t chain_offset; |
| 578 | u_int8_t function; |
| 579 | |
| 580 | u_int16_t reserved2; |
| 581 | u_int8_t reserved3; |
| 582 | u_int8_t msg_flags; |
| 583 | |
| 584 | u_int8_t vp_id; |
| 585 | u_int8_t vf_id; |
| 586 | u_int16_t reserved4; |
| 587 | |
| 588 | u_int32_t reserved5; |
| 589 | |
| 590 | u_int32_t reserved6; |
| 591 | |
| 592 | u_int32_t event_masks[4]; |
| 593 | |
| 594 | u_int16_t sas_broadcase_primitive_masks; |
| 595 | u_int16_t reserved7; |
| 596 | |
| 597 | u_int32_t reserved8; |
| 598 | } __packed; |
| 599 | |
| 600 | struct mpii_msg_event_reply { |
| 601 | u_int16_t event_data_length; |
| 602 | u_int8_t msg_length; |
| 603 | u_int8_t function; |
| 604 | |
| 605 | u_int16_t reserved1; |
| 606 | u_int8_t ack_required; |
| 607 | #define MPII_EVENT_ACK_REQUIRED (0x01) |
| 608 | u_int8_t msg_flags; |
| 609 | #define MPII_EVENT_FLAGS_REPLY_KEPT (1<<7) |
| 610 | |
| 611 | u_int8_t vp_id; |
| 612 | u_int8_t vf_id; |
| 613 | u_int16_t reserved2; |
| 614 | |
| 615 | u_int16_t reserved3; |
| 616 | u_int16_t ioc_status; |
| 617 | |
| 618 | u_int32_t ioc_loginfo; |
| 619 | |
| 620 | u_int16_t event; |
| 621 | u_int16_t reserved4; |
| 622 | |
| 623 | u_int32_t event_context; |
| 624 | |
| 625 | /* event data follows */ |
| 626 | } __packed; |
| 627 | |
| 628 | struct mpii_msg_eventack_request { |
| 629 | u_int16_t reserved1; |
| 630 | u_int8_t chain_offset; |
| 631 | u_int8_t function; |
| 632 | |
| 633 | u_int8_t reserved2[3]; |
| 634 | u_int8_t msg_flags; |
| 635 | |
| 636 | u_int8_t vp_id; |
| 637 | u_int8_t vf_id; |
| 638 | u_int16_t reserved3; |
| 639 | |
| 640 | u_int16_t event; |
| 641 | u_int16_t reserved4; |
| 642 | |
| 643 | u_int32_t event_context; |
| 644 | } __packed; |
| 645 | |
| 646 | struct mpii_msg_eventack_reply { |
| 647 | u_int16_t reserved1; |
| 648 | u_int8_t msg_length; |
| 649 | u_int8_t function; |
| 650 | |
| 651 | u_int8_t reserved2[3]; |
| 652 | u_int8_t msg_flags; |
| 653 | |
| 654 | u_int8_t vp_id; |
| 655 | u_int8_t vf_id; |
| 656 | u_int16_t reserved3; |
| 657 | |
| 658 | u_int16_t reserved4; |
| 659 | u_int16_t ioc_status; |
| 660 | |
| 661 | u_int32_t ioc_loginfo; |
| 662 | } __packed; |
| 663 | |
| 664 | struct mpii_msg_fwupload_request { |
| 665 | u_int8_t image_type; |
| 666 | #define MPII_FWUPLOAD_IMAGETYPE_IOC_FW (0x00) |
| 667 | #define MPII_FWUPLOAD_IMAGETYPE_NV_FW (0x01) |
| 668 | #define MPII_FWUPLOAD_IMAGETYPE_NV_BACKUP (0x05) |
| 669 | #define MPII_FWUPLOAD_IMAGETYPE_NV_MANUFACTURING (0x06) |
| 670 | #define MPII_FWUPLOAD_IMAGETYPE_NV_CONFIG_1 (0x07) |
| 671 | #define MPII_FWUPLOAD_IMAGETYPE_NV_CONFIG_2 (0x08) |
| 672 | #define MPII_FWUPLOAD_IMAGETYPE_NV_MEGARAID (0x09) |
| 673 | #define MPII_FWUPLOAD_IMAGETYPE_NV_COMPLETE (0x0a) |
| 674 | #define MPII_FWUPLOAD_IMAGETYPE_COMMON_BOOT_BLOCK (0x0b) |
| 675 | u_int8_t reserved1; |
| 676 | u_int8_t chain_offset; |
| 677 | u_int8_t function; |
| 678 | |
| 679 | u_int8_t reserved2[3]; |
| 680 | u_int8_t msg_flags; |
| 681 | |
| 682 | u_int8_t vp_id; |
| 683 | u_int8_t vf_id; |
| 684 | u_int16_t reserved3; |
| 685 | |
| 686 | u_int32_t reserved4; |
| 687 | |
| 688 | u_int32_t reserved5; |
| 689 | |
| 690 | struct mpii_fw_tce tce; |
| 691 | |
| 692 | /* followed by an sgl */ |
| 693 | } __packed; |
| 694 | |
| 695 | struct mpii_msg_fwupload_reply { |
| 696 | u_int8_t image_type; |
| 697 | u_int8_t reserved1; |
| 698 | u_int8_t msg_length; |
| 699 | u_int8_t function; |
| 700 | |
| 701 | u_int8_t reserved2[3]; |
| 702 | u_int8_t msg_flags; |
| 703 | |
| 704 | u_int8_t vp_id; |
| 705 | u_int8_t vf_id; |
| 706 | u_int16_t reserved3; |
| 707 | |
| 708 | u_int16_t reserved4; |
| 709 | u_int16_t ioc_status; |
| 710 | |
| 711 | u_int32_t ioc_loginfo; |
| 712 | |
| 713 | u_int32_t actual_image_size; |
| 714 | } __packed; |
| 715 | |
| 716 | struct mpii_msg_scsi_io { |
| 717 | u_int16_t dev_handle; |
| 718 | u_int8_t chain_offset; |
| 719 | u_int8_t function; |
| 720 | |
| 721 | u_int16_t reserved1; |
| 722 | u_int8_t reserved2; |
| 723 | u_int8_t msg_flags; |
| 724 | |
| 725 | u_int8_t vp_id; |
| 726 | u_int8_t vf_id; |
| 727 | u_int16_t reserved3; |
| 728 | |
| 729 | u_int32_t sense_buffer_low_address; |
| 730 | |
| 731 | u_int16_t sgl_flags; |
| 732 | u_int8_t sense_buffer_length; |
| 733 | u_int8_t reserved4; |
| 734 | |
| 735 | u_int8_t sgl_offset0; |
| 736 | u_int8_t sgl_offset1; |
| 737 | u_int8_t sgl_offset2; |
| 738 | u_int8_t sgl_offset3; |
| 739 | |
| 740 | u_int32_t skip_count; |
| 741 | |
| 742 | u_int32_t data_length; |
| 743 | |
| 744 | u_int32_t bidirectional_data_length; |
| 745 | |
| 746 | u_int16_t io_flags; |
| 747 | u_int16_t eedp_flags; |
| 748 | |
| 749 | u_int32_t eedp_block_size; |
| 750 | |
| 751 | u_int32_t secondary_reference_tag; |
| 752 | |
| 753 | u_int16_t secondary_application_tag; |
| 754 | u_int16_t application_tag_translation_mask; |
| 755 | |
| 756 | u_int16_t lun[4]; |
| 757 | |
| 758 | /* the following 16 bits are defined in MPI2 as the control field */ |
| 759 | u_int8_t reserved5; |
| 760 | u_int8_t tagging; |
| 761 | #define MPII_SCSIIO_ATTR_SIMPLE_Q (0x0) |
| 762 | #define MPII_SCSIIO_ATTR_HEAD_OF_Q (0x1) |
| 763 | #define MPII_SCSIIO_ATTR_ORDERED_Q (0x2) |
| 764 | #define MPII_SCSIIO_ATTR_ACA_Q (0x4) |
| 765 | #define MPII_SCSIIO_ATTR_UNTAGGED (0x5) |
| 766 | #define MPII_SCSIIO_ATTR_NO_DISCONNECT (0x7) |
| 767 | u_int8_t reserved6; |
| 768 | u_int8_t direction; |
| 769 | #define MPII_SCSIIO_DIR_NONE (0x0) |
| 770 | #define MPII_SCSIIO_DIR_WRITE (0x1) |
| 771 | #define MPII_SCSIIO_DIR_READ (0x2) |
| 772 | |
| 773 | #define MPII_CDB_LEN (32) |
| 774 | u_int8_t cdb[MPII_CDB_LEN]; |
| 775 | |
| 776 | /* followed by an sgl */ |
| 777 | } __packed; |
| 778 | |
| 779 | struct mpii_msg_scsi_io_error { |
| 780 | u_int16_t dev_handle; |
| 781 | u_int8_t msg_length; |
| 782 | u_int8_t function; |
| 783 | |
| 784 | u_int16_t reserved1; |
| 785 | u_int8_t reserved2; |
| 786 | u_int8_t msg_flags; |
| 787 | |
| 788 | u_int8_t vp_id; |
| 789 | u_int8_t vf_id; |
| 790 | u_int16_t reserved3; |
| 791 | |
| 792 | u_int8_t scsi_status; |
| 793 | |
| 794 | #define MPII_SCSIIO_ERR_STATUS_SUCCESS (0x00) |
| 795 | #define MPII_SCSIIO_ERR_STATUS_CHECK_COND (0x02) |
| 796 | #define MPII_SCSIIO_ERR_STATUS_BUSY (0x04) |
| 797 | #define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE (0x08) |
| 798 | #define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE_CONDMET (0x10) |
| 799 | #define MPII_SCSIIO_ERR_STATUS_RESERVATION_CONFLICT (0x14) |
| 800 | #define MPII_SCSIIO_ERR_STATUS_CMD_TERM (0x22) |
| 801 | #define MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL (0x28) |
| 802 | #define MPII_SCSIIO_ERR_STATUS_ACA_ACTIVE (0x30) |
| 803 | #define MPII_SCSIIO_ERR_STATUS_TASK_ABORTED (0x40) |
| 804 | |
| 805 | u_int8_t scsi_state; |
| 806 | #define MPII_SCSIIO_ERR_STATE_AUTOSENSE_VALID (1<<0) |
| 807 | #define MPII_SCSIIO_ERR_STATE_AUTOSENSE_FAILED (1<<1) |
| 808 | #define MPII_SCSIIO_ERR_STATE_NO_SCSI_STATUS (1<<2) |
| 809 | #define MPII_SCSIIO_ERR_STATE_TERMINATED (1<<3) |
| 810 | #define MPII_SCSIIO_ERR_STATE_RESPONSE_INFO_VALID (1<<4) |
| 811 | #define MPII_SCSIIO_ERR_STATE_QUEUE_TAG_REJECTED (0xffff) |
| 812 | u_int16_t ioc_status; |
| 813 | |
| 814 | u_int32_t ioc_loginfo; |
| 815 | |
| 816 | u_int32_t transfer_count; |
| 817 | |
| 818 | u_int32_t sense_count; |
| 819 | |
| 820 | u_int32_t response_info; |
| 821 | |
| 822 | u_int16_t task_tag; |
| 823 | u_int16_t reserved4; |
| 824 | |
| 825 | u_int32_t bidirectional_transfer_count; |
| 826 | |
| 827 | u_int32_t reserved5; |
| 828 | |
| 829 | u_int32_t reserved6; |
| 830 | } __packed; |
| 831 | |
| 832 | struct mpii_request_descr { |
| 833 | u_int8_t request_flags; |
| 834 | #define MPII_REQ_DESCR_TYPE_MASK (0x0e) |
| 835 | #define MPII_REQ_DESCR_SCSI_IO (0x00) |
| 836 | #define MPII_REQ_DESCR_SCSI_TARGET (0x02) |
| 837 | #define MPII_REQ_DESCR_HIGH_PRIORITY (0x06) |
| 838 | #define MPII_REQ_DESCR_DEFAULT (0x08) |
| 839 | u_int8_t vf_id; |
| 840 | u_int16_t smid; |
| 841 | |
| 842 | u_int16_t lmid; |
| 843 | u_int16_t dev_handle; |
| 844 | } __packed; |
| 845 | |
| 846 | struct mpii_reply_descr { |
| 847 | u_int8_t reply_flags; |
| 848 | #define MPII_REPLY_DESCR_TYPE_MASK (0x0f) |
| 849 | #define MPII_REPLY_DESCR_SCSI_IO_SUCCESS (0x00) |
| 850 | #define MPII_REPLY_DESCR_ADDRESS_REPLY (0x01) |
| 851 | #define MPII_REPLY_DESCR_TARGET_ASSIST_SUCCESS (0x02) |
| 852 | #define MPII_REPLY_DESCR_TARGET_COMMAND_BUFFER (0x03) |
| 853 | #define MPII_REPLY_DESCR_UNUSED (0x0f) |
| 854 | u_int8_t vf_id; |
| 855 | u_int16_t smid; |
| 856 | |
| 857 | union { |
| 858 | u_int32_t data; |
| 859 | u_int32_t frame_addr; /* Address Reply */ |
| 860 | }; |
| 861 | } __packed; |
| 862 | |
| 863 | struct { |
| 864 | u_int16_t ; |
| 865 | u_int8_t ; |
| 866 | u_int8_t ; |
| 867 | |
| 868 | u_int16_t ; |
| 869 | u_int8_t ; |
| 870 | u_int8_t ; |
| 871 | |
| 872 | u_int8_t ; |
| 873 | u_int8_t ; |
| 874 | u_int16_t ; |
| 875 | } __packed; |
| 876 | |
| 877 | struct mpii_msg_scsi_task_request { |
| 878 | u_int16_t dev_handle; |
| 879 | u_int8_t chain_offset; |
| 880 | u_int8_t function; |
| 881 | |
| 882 | u_int8_t reserved1; |
| 883 | u_int8_t task_type; |
| 884 | #define MPII_SCSI_TASK_ABORT_TASK (0x01) |
| 885 | #define MPII_SCSI_TASK_ABRT_TASK_SET (0x02) |
| 886 | #define MPII_SCSI_TASK_TARGET_RESET (0x03) |
| 887 | #define MPII_SCSI_TASK_RESET_BUS (0x04) |
| 888 | #define MPII_SCSI_TASK_LOGICAL_UNIT_RESET (0x05) |
| 889 | u_int8_t reserved2; |
| 890 | u_int8_t msg_flags; |
| 891 | |
| 892 | u_int8_t vp_id; |
| 893 | u_int8_t vf_id; |
| 894 | u_int16_t reserved3; |
| 895 | |
| 896 | u_int16_t lun[4]; |
| 897 | |
| 898 | u_int32_t reserved4[7]; |
| 899 | |
| 900 | u_int16_t task_mid; |
| 901 | u_int16_t reserved5; |
| 902 | } __packed; |
| 903 | |
| 904 | struct mpii_msg_scsi_task_reply { |
| 905 | u_int16_t dev_handle; |
| 906 | u_int8_t msg_length; |
| 907 | u_int8_t function; |
| 908 | |
| 909 | u_int8_t response_code; |
| 910 | u_int8_t task_type; |
| 911 | u_int8_t reserved1; |
| 912 | u_int8_t msg_flags; |
| 913 | |
| 914 | u_int8_t vp_id; |
| 915 | u_int8_t vf_id; |
| 916 | u_int16_t reserved2; |
| 917 | |
| 918 | u_int16_t reserved3; |
| 919 | u_int16_t ioc_status; |
| 920 | |
| 921 | u_int32_t ioc_loginfo; |
| 922 | |
| 923 | u_int32_t termination_count; |
| 924 | } __packed; |
| 925 | |
| 926 | struct mpii_msg_sas_oper_request { |
| 927 | u_int8_t operation; |
| 928 | #define MPII_SAS_OP_CLEAR_PERSISTENT (0x02) |
| 929 | #define MPII_SAS_OP_PHY_LINK_RESET (0x06) |
| 930 | #define MPII_SAS_OP_PHY_HARD_RESET (0x07) |
| 931 | #define MPII_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) |
| 932 | #define MPII_SAS_OP_SEND_PRIMITIVE (0x0a) |
| 933 | #define MPII_SAS_OP_FORCE_FULL_DISCOVERY (0x0b) |
| 934 | #define MPII_SAS_OP_TRANSMIT_PORT_SELECT (0x0c) |
| 935 | #define MPII_SAS_OP_REMOVE_DEVICE (0x0d) |
| 936 | #define MPII_SAS_OP_LOOKUP_MAPPING (0x0e) |
| 937 | #define MPII_SAS_OP_SET_IOC_PARAM (0x0f) |
| 938 | u_int8_t reserved1; |
| 939 | u_int8_t chain_offset; |
| 940 | u_int8_t function; |
| 941 | |
| 942 | u_int16_t dev_handle; |
| 943 | u_int8_t ioc_param; |
| 944 | u_int8_t msg_flags; |
| 945 | |
| 946 | u_int8_t vp_id; |
| 947 | u_int8_t vf_id; |
| 948 | u_int16_t reserved2; |
| 949 | |
| 950 | u_int16_t reserved3; |
| 951 | u_int8_t phy_num; |
| 952 | u_int8_t prim_flags; |
| 953 | |
| 954 | u_int32_t primitive; |
| 955 | |
| 956 | u_int8_t lookup_method; |
| 957 | #define MPII_SAS_LOOKUP_METHOD_SAS_ADDR (0x01) |
| 958 | #define MPII_SAS_LOOKUP_METHOD_SAS_ENCL (0x02) |
| 959 | #define MPII_SAS_LOOKUP_METHOD_SAS_DEVNAME (0x03) |
| 960 | u_int8_t reserved4; |
| 961 | u_int16_t slot_num; |
| 962 | |
| 963 | u_int64_t lookup_addr; |
| 964 | |
| 965 | u_int32_t ioc_param_value; |
| 966 | |
| 967 | u_int64_t reserved5; |
| 968 | } __packed; |
| 969 | |
| 970 | struct mpii_msg_sas_oper_reply { |
| 971 | u_int8_t operation; |
| 972 | u_int8_t reserved1; |
| 973 | u_int8_t chain_offset; |
| 974 | u_int8_t function; |
| 975 | |
| 976 | u_int16_t dev_handle; |
| 977 | u_int8_t ioc_param; |
| 978 | u_int8_t msg_flags; |
| 979 | |
| 980 | u_int8_t vp_id; |
| 981 | u_int8_t vf_id; |
| 982 | u_int16_t reserved2; |
| 983 | |
| 984 | u_int16_t reserved3; |
| 985 | u_int16_t ioc_status; |
| 986 | |
| 987 | u_int32_t ioc_loginfo; |
| 988 | } __packed; |
| 989 | |
| 990 | struct mpii_msg_raid_action_request { |
| 991 | u_int8_t action; |
| 992 | #define MPII_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) |
| 993 | u_int8_t reserved1; |
| 994 | u_int8_t chain_offset; |
| 995 | u_int8_t function; |
| 996 | |
| 997 | u_int16_t vol_dev_handle; |
| 998 | u_int8_t phys_disk_num; |
| 999 | u_int8_t msg_flags; |
| 1000 | |
| 1001 | u_int8_t vp_id; |
| 1002 | u_int8_t vf_if; |
| 1003 | u_int16_t reserved2; |
| 1004 | |
| 1005 | u_int32_t reserved3; |
| 1006 | |
| 1007 | u_int32_t action_data; |
| 1008 | #define MPII_RAID_VOL_WRITE_CACHE_MASK (0x03) |
| 1009 | #define MPII_RAID_VOL_WRITE_CACHE_DISABLE (0x01) |
| 1010 | #define MPII_RAID_VOL_WRITE_CACHE_ENABLE (0x02) |
| 1011 | |
| 1012 | struct mpii_sge action_sge; |
| 1013 | } __packed; |
| 1014 | |
| 1015 | struct mpii_msg_raid_action_reply { |
| 1016 | u_int8_t action; |
| 1017 | u_int8_t reserved1; |
| 1018 | u_int8_t chain_offset; |
| 1019 | u_int8_t function; |
| 1020 | |
| 1021 | u_int16_t vol_dev_handle; |
| 1022 | u_int8_t phys_disk_num; |
| 1023 | u_int8_t msg_flags; |
| 1024 | |
| 1025 | u_int8_t vp_id; |
| 1026 | u_int8_t vf_if; |
| 1027 | u_int16_t reserved2; |
| 1028 | |
| 1029 | u_int16_t reserved3; |
| 1030 | u_int16_t ioc_status; |
| 1031 | |
| 1032 | u_int32_t action_data[5]; |
| 1033 | } __packed; |
| 1034 | |
| 1035 | struct mpii_cfg_hdr { |
| 1036 | u_int8_t page_version; |
| 1037 | u_int8_t page_length; |
| 1038 | u_int8_t page_number; |
| 1039 | u_int8_t page_type; |
| 1040 | #define MPII_CONFIG_REQ_PAGE_TYPE_ATTRIBUTE (0xf0) |
| 1041 | #define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) |
| 1042 | #define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) |
| 1043 | #define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) |
| 1044 | |
| 1045 | #define MPII_CONFIG_REQ_PAGE_TYPE_MASK (0x0f) |
| 1046 | #define MPII_CONFIG_REQ_PAGE_TYPE_IO_UNIT (0x00) |
| 1047 | #define MPII_CONFIG_REQ_PAGE_TYPE_IOC (0x01) |
| 1048 | #define MPII_CONFIG_REQ_PAGE_TYPE_BIOS (0x02) |
| 1049 | #define MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL (0x08) |
| 1050 | #define MPII_CONFIG_REQ_PAGE_TYPE_MANUFACTURING (0x09) |
| 1051 | #define MPII_CONFIG_REQ_PAGE_TYPE_RAID_PD (0x0a) |
| 1052 | #define MPII_CONFIG_REQ_PAGE_TYPE_EXTENDED (0x0f) |
| 1053 | } __packed; |
| 1054 | |
| 1055 | struct mpii_ecfg_hdr { |
| 1056 | u_int8_t page_version; |
| 1057 | u_int8_t reserved1; |
| 1058 | u_int8_t page_number; |
| 1059 | u_int8_t page_type; |
| 1060 | |
| 1061 | u_int16_t ext_page_length; |
| 1062 | u_int8_t ext_page_type; |
| 1063 | #define MPII_CONFIG_REQ_PAGE_TYPE_SAS_DEVICE (0x12) |
| 1064 | #define MPII_CONFIG_REQ_PAGE_TYPE_RAID_CONFIG (0x16) |
| 1065 | #define MPII_CONFIG_REQ_PAGE_TYPE_DRIVER_MAPPING (0x17) |
| 1066 | u_int8_t reserved2; |
| 1067 | } __packed; |
| 1068 | |
| 1069 | struct mpii_msg_config_request { |
| 1070 | u_int8_t action; |
| 1071 | #define (0x00) |
| 1072 | #define MPII_CONFIG_REQ_ACTION_PAGE_READ_CURRENT (0x01) |
| 1073 | #define MPII_CONFIG_REQ_ACTION_PAGE_WRITE_CURRENT (0x02) |
| 1074 | #define MPII_CONFIG_REQ_ACTION_PAGE_DEFAULT (0x03) |
| 1075 | #define MPII_CONFIG_REQ_ACTION_PAGE_WRITE_NVRAM (0x04) |
| 1076 | #define MPII_CONFIG_REQ_ACTION_PAGE_READ_DEFAULT (0x05) |
| 1077 | #define MPII_CONFIG_REQ_ACTION_PAGE_READ_NVRAM (0x06) |
| 1078 | u_int8_t sgl_flags; |
| 1079 | u_int8_t chain_offset; |
| 1080 | u_int8_t function; |
| 1081 | |
| 1082 | u_int16_t ext_page_len; |
| 1083 | u_int8_t ext_page_type; |
| 1084 | #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_IO_UNIT (0x10) |
| 1085 | #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_EXPANDER (0x11) |
| 1086 | #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_DEVICE (0x12) |
| 1087 | #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_PHY (0x13) |
| 1088 | #define MPII_CONFIG_REQ_EXTPAGE_TYPE_LOG (0x14) |
| 1089 | #define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) |
| 1090 | #define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) |
| 1091 | #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) |
| 1092 | #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) |
| 1093 | u_int8_t msg_flags; |
| 1094 | |
| 1095 | u_int8_t vp_id; |
| 1096 | u_int8_t vf_id; |
| 1097 | u_int16_t reserved1; |
| 1098 | |
| 1099 | u_int32_t reserved2[2]; |
| 1100 | |
| 1101 | struct mpii_cfg_hdr ; |
| 1102 | |
| 1103 | u_int32_t page_address; |
| 1104 | /* XXX lots of defns here */ |
| 1105 | |
| 1106 | struct mpii_sge page_buffer; |
| 1107 | } __packed; |
| 1108 | |
| 1109 | struct mpii_msg_config_reply { |
| 1110 | u_int8_t action; |
| 1111 | u_int8_t sgl_flags; |
| 1112 | u_int8_t msg_length; |
| 1113 | u_int8_t function; |
| 1114 | |
| 1115 | u_int16_t ext_page_length; |
| 1116 | u_int8_t ext_page_type; |
| 1117 | u_int8_t msg_flags; |
| 1118 | |
| 1119 | u_int8_t vp_id; |
| 1120 | u_int8_t vf_id; |
| 1121 | u_int16_t reserved1; |
| 1122 | |
| 1123 | u_int16_t reserved2; |
| 1124 | u_int16_t ioc_status; |
| 1125 | |
| 1126 | u_int32_t ioc_loginfo; |
| 1127 | |
| 1128 | struct mpii_cfg_hdr ; |
| 1129 | } __packed; |
| 1130 | |
| 1131 | struct mpii_cfg_manufacturing_pg0 { |
| 1132 | struct mpii_cfg_hdr ; |
| 1133 | |
| 1134 | char chip_name[16]; |
| 1135 | char chip_revision[8]; |
| 1136 | char board_name[16]; |
| 1137 | char board_assembly[16]; |
| 1138 | char board_tracer_number[16]; |
| 1139 | } __packed; |
| 1140 | |
| 1141 | struct mpii_cfg_ioc_pg1 { |
| 1142 | struct mpii_cfg_hdr ; |
| 1143 | |
| 1144 | u_int32_t flags; |
| 1145 | |
| 1146 | u_int32_t coalescing_timeout; |
| 1147 | #define MPII_CFG_IOC_1_REPLY_COALESCING (1<<0) |
| 1148 | |
| 1149 | u_int8_t coalescing_depth; |
| 1150 | u_int8_t pci_slot_num; |
| 1151 | u_int8_t pci_bus_num; |
| 1152 | u_int8_t pci_domain_segment; |
| 1153 | |
| 1154 | u_int32_t reserved1; |
| 1155 | |
| 1156 | u_int32_t reserved2; |
| 1157 | } __packed; |
| 1158 | |
| 1159 | struct mpii_cfg_ioc_pg3 { |
| 1160 | struct mpii_cfg_hdr ; |
| 1161 | |
| 1162 | u_int8_t no_phys_disks; |
| 1163 | u_int8_t reserved[3]; |
| 1164 | |
| 1165 | /* followed by a list of mpii_cfg_raid_physdisk structs */ |
| 1166 | } __packed; |
| 1167 | |
| 1168 | struct mpii_cfg_ioc_pg8 { |
| 1169 | struct mpii_cfg_hdr ; |
| 1170 | |
| 1171 | u_int8_t num_devs_per_enclosure; |
| 1172 | u_int8_t reserved1; |
| 1173 | u_int16_t reserved2; |
| 1174 | |
| 1175 | u_int16_t max_persistent_entries; |
| 1176 | u_int16_t max_num_physical_mapped_ids; |
| 1177 | |
| 1178 | u_int16_t flags; |
| 1179 | #define MPII_IOC_PG8_FLAGS_DA_START_SLOT_1 (1<<5) |
| 1180 | #define MPII_IOC_PG8_FLAGS_RESERVED_TARGETID_0 (1<<4) |
| 1181 | #define MPII_IOC_PG8_FLAGS_MAPPING_MODE_MASK (0x0000000e) |
| 1182 | #define MPII_IOC_PG8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0<<1) |
| 1183 | #define MPII_IOC_PG8_FLAGS_ENCLOSURE_SLOT_MAPPING (1<<1) |
| 1184 | #define MPII_IOC_PG8_FLAGS_DISABLE_PERSISTENT_MAPPING (1<<0) |
| 1185 | #define MPII_IOC_PG8_FLAGS_ENABLE_PERSISTENT_MAPPING (0<<0) |
| 1186 | u_int16_t reserved3; |
| 1187 | |
| 1188 | u_int16_t ir_volume_mapping_flags; |
| 1189 | #define MPII_IOC_PG8_IRFLAGS_VOLUME_MAPPING_MODE_MASK (0x00000003) |
| 1190 | #define MPII_IOC_PG8_IRFLAGS_LOW_VOLUME_MAPPING (0<<0) |
| 1191 | #define MPII_IOC_PG8_IRFLAGS_HIGH_VOLUME_MAPPING (1<<0) |
| 1192 | u_int16_t reserved4; |
| 1193 | |
| 1194 | u_int32_t reserved5; |
| 1195 | } __packed; |
| 1196 | |
| 1197 | struct mpii_cfg_raid_physdisk { |
| 1198 | u_int8_t phys_disk_id; |
| 1199 | u_int8_t phys_disk_bus; |
| 1200 | u_int8_t phys_disk_ioc; |
| 1201 | u_int8_t phys_disk_num; |
| 1202 | } __packed; |
| 1203 | |
| 1204 | struct mpii_cfg_fc_port_pg0 { |
| 1205 | struct mpii_cfg_hdr ; |
| 1206 | |
| 1207 | u_int32_t flags; |
| 1208 | |
| 1209 | u_int8_t mpii_port_nr; |
| 1210 | u_int8_t link_type; |
| 1211 | u_int8_t port_state; |
| 1212 | u_int8_t reserved1; |
| 1213 | |
| 1214 | u_int32_t port_id; |
| 1215 | |
| 1216 | u_int64_t wwnn; |
| 1217 | |
| 1218 | u_int64_t wwpn; |
| 1219 | |
| 1220 | u_int32_t supported_service_class; |
| 1221 | |
| 1222 | u_int32_t supported_speeds; |
| 1223 | |
| 1224 | u_int32_t current_speed; |
| 1225 | |
| 1226 | u_int32_t max_frame_size; |
| 1227 | |
| 1228 | u_int64_t fabric_wwnn; |
| 1229 | |
| 1230 | u_int64_t fabric_wwpn; |
| 1231 | |
| 1232 | u_int32_t discovered_port_count; |
| 1233 | |
| 1234 | u_int32_t max_initiators; |
| 1235 | |
| 1236 | u_int8_t max_aliases_supported; |
| 1237 | u_int8_t max_hard_aliases_supported; |
| 1238 | u_int8_t num_current_aliases; |
| 1239 | u_int8_t reserved2; |
| 1240 | } __packed; |
| 1241 | |
| 1242 | struct mpii_cfg_fc_port_pg1 { |
| 1243 | struct mpii_cfg_hdr ; |
| 1244 | |
| 1245 | u_int32_t flags; |
| 1246 | |
| 1247 | u_int64_t noseepromwwnn; |
| 1248 | |
| 1249 | u_int64_t noseepromwwpn; |
| 1250 | |
| 1251 | u_int8_t hard_alpa; |
| 1252 | u_int8_t link_config; |
| 1253 | u_int8_t topology_config; |
| 1254 | u_int8_t alt_connector; |
| 1255 | |
| 1256 | u_int8_t num_req_aliases; |
| 1257 | u_int8_t rr_tov; |
| 1258 | u_int8_t initiator_dev_to; |
| 1259 | u_int8_t initiator_lo_pend_to; |
| 1260 | } __packed; |
| 1261 | |
| 1262 | struct mpii_cfg_fc_device_pg0 { |
| 1263 | struct mpii_cfg_hdr ; |
| 1264 | |
| 1265 | u_int64_t wwnn; |
| 1266 | |
| 1267 | u_int64_t wwpn; |
| 1268 | |
| 1269 | u_int32_t port_id; |
| 1270 | |
| 1271 | u_int8_t protocol; |
| 1272 | u_int8_t flags; |
| 1273 | u_int16_t bb_credit; |
| 1274 | |
| 1275 | u_int16_t max_rx_frame_size; |
| 1276 | u_int8_t adisc_hard_alpa; |
| 1277 | u_int8_t port_nr; |
| 1278 | |
| 1279 | u_int8_t fc_ph_low_version; |
| 1280 | u_int8_t fc_ph_high_version; |
| 1281 | u_int8_t current_target_id; |
| 1282 | u_int8_t current_bus; |
| 1283 | } __packed; |
| 1284 | |
| 1285 | #define MPII_CFG_RAID_VOL_ADDR_HANDLE (1<<28) |
| 1286 | |
| 1287 | struct mpii_cfg_raid_vol_pg0 { |
| 1288 | struct mpii_cfg_hdr ; |
| 1289 | |
| 1290 | u_int16_t volume_handle; |
| 1291 | u_int8_t volume_state; |
| 1292 | #define MPII_CFG_RAID_VOL_0_STATE_MISSING (0x00) |
| 1293 | #define MPII_CFG_RAID_VOL_0_STATE_FAILED (0x01) |
| 1294 | #define MPII_CFG_RAID_VOL_0_STATE_INITIALIZING (0x02) |
| 1295 | #define MPII_CFG_RAID_VOL_0_STATE_ONLINE (0x03) |
| 1296 | #define MPII_CFG_RAID_VOL_0_STATE_DEGRADED (0x04) |
| 1297 | #define MPII_CFG_RAID_VOL_0_STATE_OPTIMAL (0x05) |
| 1298 | u_int8_t volume_type; |
| 1299 | #define MPII_CFG_RAID_VOL_0_TYPE_RAID0 (0x00) |
| 1300 | #define MPII_CFG_RAID_VOL_0_TYPE_RAID1E (0x01) |
| 1301 | #define MPII_CFG_RAID_VOL_0_TYPE_RAID1 (0x02) |
| 1302 | #define MPII_CFG_RAID_VOL_0_TYPE_RAID10 (0x05) |
| 1303 | #define MPII_CFG_RAID_VOL_0_TYPE_UNKNOWN (0xff) |
| 1304 | |
| 1305 | u_int32_t volume_status; |
| 1306 | #define MPII_CFG_RAID_VOL_0_STATUS_SCRUB (1<<20) |
| 1307 | #define MPII_CFG_RAID_VOL_0_STATUS_RESYNC (1<<16) |
| 1308 | |
| 1309 | u_int16_t volume_settings; |
| 1310 | #define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_MASK (0x3<<0) |
| 1311 | #define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_UNCHANGED (0x0<<0) |
| 1312 | #define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_DISABLED (0x1<<0) |
| 1313 | #define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_ENABLED (0x2<<0) |
| 1314 | |
| 1315 | u_int8_t hot_spare_pool; |
| 1316 | u_int8_t reserved1; |
| 1317 | |
| 1318 | u_int64_t max_lba; |
| 1319 | |
| 1320 | u_int32_t stripe_size; |
| 1321 | |
| 1322 | u_int16_t block_size; |
| 1323 | u_int16_t reserved2; |
| 1324 | |
| 1325 | u_int8_t phys_disk_types; |
| 1326 | u_int8_t resync_rate; |
| 1327 | u_int16_t data_scrub_rate; |
| 1328 | |
| 1329 | u_int8_t num_phys_disks; |
| 1330 | u_int16_t reserved3; |
| 1331 | u_int8_t inactive_status; |
| 1332 | #define MPII_CFG_RAID_VOL_0_INACTIVE_UNKNOWN (0x00) |
| 1333 | #define MPII_CFG_RAID_VOL_0_INACTIVE_STALE_META (0x01) |
| 1334 | #define MPII_CFG_RAID_VOL_0_INACTIVE_FOREIGN_VOL (0x02) |
| 1335 | #define MPII_CFG_RAID_VOL_0_INACTIVE_NO_RESOURCES (0x03) |
| 1336 | #define MPII_CFG_RAID_VOL_0_INACTIVE_CLONED_VOL (0x04) |
| 1337 | #define MPII_CFG_RAID_VOL_0_INACTIVE_INSUF_META (0x05) |
| 1338 | |
| 1339 | /* followed by a list of mpii_cfg_raid_vol_pg0_physdisk structs */ |
| 1340 | } __packed; |
| 1341 | |
| 1342 | struct mpii_cfg_raid_vol_pg0_physdisk { |
| 1343 | u_int8_t raid_set_num; |
| 1344 | u_int8_t phys_disk_map; |
| 1345 | u_int8_t phys_disk_num; |
| 1346 | u_int8_t reserved; |
| 1347 | } __packed; |
| 1348 | |
| 1349 | struct mpii_cfg_raid_vol_pg1 { |
| 1350 | struct mpii_cfg_hdr ; |
| 1351 | |
| 1352 | u_int8_t volume_id; |
| 1353 | u_int8_t volume_bus; |
| 1354 | u_int8_t volume_ioc; |
| 1355 | u_int8_t reserved1; |
| 1356 | |
| 1357 | u_int8_t guid[24]; |
| 1358 | |
| 1359 | u_int8_t name[32]; |
| 1360 | |
| 1361 | u_int64_t wwid; |
| 1362 | |
| 1363 | u_int32_t reserved2; |
| 1364 | |
| 1365 | u_int32_t reserved3; |
| 1366 | } __packed; |
| 1367 | |
| 1368 | #define MPII_CFG_RAID_PHYS_DISK_ADDR_NUMBER (1<<28) |
| 1369 | |
| 1370 | struct mpii_cfg_raid_physdisk_pg0 { |
| 1371 | struct mpii_cfg_hdr ; |
| 1372 | |
| 1373 | u_int16_t dev_handle; |
| 1374 | u_int8_t reserved1; |
| 1375 | u_int8_t phys_disk_num; |
| 1376 | |
| 1377 | u_int8_t enc_id; |
| 1378 | u_int8_t enc_bus; |
| 1379 | u_int8_t hot_spare_pool; |
| 1380 | u_int8_t enc_type; |
| 1381 | #define MPII_CFG_RAID_PHYDISK_0_ENCTYPE_NONE (0x0) |
| 1382 | #define MPII_CFG_RAID_PHYDISK_0_ENCTYPE_SAFTE (0x1) |
| 1383 | #define MPII_CFG_RAID_PHYDISK_0_ENCTYPE_SES (0x2) |
| 1384 | |
| 1385 | u_int32_t reserved2; |
| 1386 | |
| 1387 | u_int8_t vendor_id[8]; |
| 1388 | |
| 1389 | u_int8_t product_id[16]; |
| 1390 | |
| 1391 | u_int8_t product_rev[4]; |
| 1392 | |
| 1393 | u_int8_t serial[32]; |
| 1394 | |
| 1395 | u_int32_t reserved3; |
| 1396 | |
| 1397 | u_int8_t phys_disk_state; |
| 1398 | #define MPII_CFG_RAID_PHYDISK_0_STATE_NOTCONFIGURED (0x00) |
| 1399 | #define MPII_CFG_RAID_PHYDISK_0_STATE_NOTCOMPATIBLE (0x01) |
| 1400 | #define MPII_CFG_RAID_PHYDISK_0_STATE_OFFLINE (0x02) |
| 1401 | #define MPII_CFG_RAID_PHYDISK_0_STATE_ONLINE (0x03) |
| 1402 | #define MPII_CFG_RAID_PHYDISK_0_STATE_HOTSPARE (0x04) |
| 1403 | #define MPII_CFG_RAID_PHYDISK_0_STATE_DEGRADED (0x05) |
| 1404 | #define MPII_CFG_RAID_PHYDISK_0_STATE_REBUILDING (0x06) |
| 1405 | #define MPII_CFG_RAID_PHYDISK_0_STATE_OPTIMAL (0x07) |
| 1406 | u_int8_t offline_reason; |
| 1407 | #define MPII_CFG_RAID_PHYDISK_0_OFFLINE_MISSING (0x01) |
| 1408 | #define MPII_CFG_RAID_PHYDISK_0_OFFLINE_FAILED (0x03) |
| 1409 | #define MPII_CFG_RAID_PHYDISK_0_OFFLINE_INITIALIZING (0x04) |
| 1410 | #define MPII_CFG_RAID_PHYDISK_0_OFFLINE_REQUESTED (0x05) |
| 1411 | #define MPII_CFG_RAID_PHYDISK_0_OFFLINE_FAILEDREQ (0x06) |
| 1412 | #define MPII_CFG_RAID_PHYDISK_0_OFFLINE_OTHER (0xff) |
| 1413 | |
| 1414 | u_int8_t incompat_reason; |
| 1415 | u_int8_t phys_disk_attrs; |
| 1416 | |
| 1417 | u_int32_t phys_disk_status; |
| 1418 | #define MPII_CFG_RAID_PHYDISK_0_STATUS_OUTOFSYNC (1<<0) |
| 1419 | #define MPII_CFG_RAID_PHYDISK_0_STATUS_QUIESCED (1<<1) |
| 1420 | |
| 1421 | u_int64_t dev_max_lba; |
| 1422 | |
| 1423 | u_int64_t host_max_lba; |
| 1424 | |
| 1425 | u_int64_t coerced_max_lba; |
| 1426 | |
| 1427 | u_int16_t block_size; |
| 1428 | u_int16_t reserved4; |
| 1429 | |
| 1430 | u_int32_t reserved5; |
| 1431 | } __packed; |
| 1432 | |
| 1433 | struct mpii_cfg_raid_physdisk_pg1 { |
| 1434 | struct mpii_cfg_hdr ; |
| 1435 | |
| 1436 | u_int8_t num_phys_disk_paths; |
| 1437 | u_int8_t phys_disk_num; |
| 1438 | u_int16_t reserved1; |
| 1439 | |
| 1440 | u_int32_t reserved2; |
| 1441 | |
| 1442 | /* followed by mpii_cfg_raid_physdisk_path structs */ |
| 1443 | } __packed; |
| 1444 | |
| 1445 | struct mpii_cfg_raid_physdisk_path { |
| 1446 | u_int8_t phys_disk_id; |
| 1447 | u_int8_t phys_disk_bus; |
| 1448 | u_int16_t reserved1; |
| 1449 | |
| 1450 | u_int64_t wwwid; |
| 1451 | |
| 1452 | u_int64_t owner_wwid; |
| 1453 | |
| 1454 | u_int8_t ownder_id; |
| 1455 | u_int8_t reserved2; |
| 1456 | u_int16_t flags; |
| 1457 | #define MPII_CFG_RAID_PHYDISK_PATH_INVALID (1<<0) |
| 1458 | #define MPII_CFG_RAID_PHYDISK_PATH_BROKEN (1<<1) |
| 1459 | } __packed; |
| 1460 | |
| 1461 | #define MPII_CFG_SAS_DEV_ADDR_NEXT (0<<28) |
| 1462 | #define MPII_CFG_SAS_DEV_ADDR_BUS (1<<28) |
| 1463 | #define MPII_CFG_SAS_DEV_ADDR_HANDLE (2<<28) |
| 1464 | |
| 1465 | struct mpii_cfg_sas_dev_pg0 { |
| 1466 | struct mpii_ecfg_hdr ; |
| 1467 | |
| 1468 | u_int16_t slot; |
| 1469 | u_int16_t enc_handle; |
| 1470 | |
| 1471 | u_int64_t sas_addr; |
| 1472 | |
| 1473 | u_int16_t parent_dev_handle; |
| 1474 | u_int8_t phy_num; |
| 1475 | u_int8_t access_status; |
| 1476 | |
| 1477 | u_int16_t dev_handle; |
| 1478 | u_int8_t target; |
| 1479 | u_int8_t bus; |
| 1480 | |
| 1481 | u_int32_t device_info; |
| 1482 | #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE (0x7) |
| 1483 | #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_NONE (0x0) |
| 1484 | #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_END (0x1) |
| 1485 | #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_EDGE_EXPANDER (0x2) |
| 1486 | #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_FANOUT_EXPANDER (0x3) |
| 1487 | #define MPII_CFG_SAS_DEV_0_DEVINFO_SATA_HOST (1<<3) |
| 1488 | #define MPII_CFG_SAS_DEV_0_DEVINFO_SMP_INITIATOR (1<<4) |
| 1489 | #define MPII_CFG_SAS_DEV_0_DEVINFO_STP_INITIATOR (1<<5) |
| 1490 | #define MPII_CFG_SAS_DEV_0_DEVINFO_SSP_INITIATOR (1<<6) |
| 1491 | #define MPII_CFG_SAS_DEV_0_DEVINFO_SATA_DEVICE (1<<7) |
| 1492 | #define MPII_CFG_SAS_DEV_0_DEVINFO_SMP_TARGET (1<<8) |
| 1493 | #define MPII_CFG_SAS_DEV_0_DEVINFO_STP_TARGET (1<<9) |
| 1494 | #define MPII_CFG_SAS_DEV_0_DEVINFO_SSP_TARGET (1<<10) |
| 1495 | #define MPII_CFG_SAS_DEV_0_DEVINFO_DIRECT_ATTACHED (1<<11) |
| 1496 | #define MPII_CFG_SAS_DEV_0_DEVINFO_LSI_DEVICE (1<<12) |
| 1497 | #define MPII_CFG_SAS_DEV_0_DEVINFO_ATAPI_DEVICE (1<<13) |
| 1498 | #define MPII_CFG_SAS_DEV_0_DEVINFO_SEP_DEVICE (1<<14) |
| 1499 | |
| 1500 | u_int16_t flags; |
| 1501 | #define MPII_CFG_SAS_DEV_0_FLAGS_DEV_PRESENT (1<<0) |
| 1502 | #define MPII_CFG_SAS_DEV_0_FLAGS_DEV_MAPPED (1<<1) |
| 1503 | #define MPII_CFG_SAS_DEV_0_FLAGS_DEV_MAPPED_PERSISTENT (1<<2) |
| 1504 | #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_PORT_SELECTOR (1<<3) |
| 1505 | #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_FUA (1<<4) |
| 1506 | #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_NCQ (1<<5) |
| 1507 | #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_SMART (1<<6) |
| 1508 | #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_LBA48 (1<<7) |
| 1509 | #define MPII_CFG_SAS_DEV_0_FLAGS_UNSUPPORTED (1<<8) |
| 1510 | #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_SETTINGS (1<<9) |
| 1511 | u_int8_t physical_port; |
| 1512 | u_int8_t max_port_conn; |
| 1513 | |
| 1514 | u_int64_t device_name; |
| 1515 | |
| 1516 | u_int8_t port_groups; |
| 1517 | u_int8_t dma_group; |
| 1518 | u_int8_t ctrl_group; |
| 1519 | u_int8_t reserved1; |
| 1520 | |
| 1521 | u_int64_t reserved2; |
| 1522 | } __packed; |
| 1523 | |
| 1524 | #define MPII_CFG_RAID_CONFIG_ACTIVE_CONFIG (2<<28) |
| 1525 | |
| 1526 | struct mpii_cfg_raid_config_pg0 { |
| 1527 | struct mpii_ecfg_hdr ; |
| 1528 | |
| 1529 | u_int8_t num_hot_spares; |
| 1530 | u_int8_t num_phys_disks; |
| 1531 | u_int8_t num_volumes; |
| 1532 | u_int8_t config_num; |
| 1533 | |
| 1534 | u_int32_t flags; |
| 1535 | #define MPII_CFG_RAID_CONFIG_0_FLAGS_NATIVE (0<<0) |
| 1536 | #define MPII_CFG_RAID_CONFIG_0_FLAGS_FOREIGN (1<<0) |
| 1537 | |
| 1538 | u_int32_t config_guid[6]; |
| 1539 | |
| 1540 | u_int32_t reserved1; |
| 1541 | |
| 1542 | u_int8_t num_elements; |
| 1543 | u_int8_t reserved2[3]; |
| 1544 | |
| 1545 | /* followed by struct mpii_raid_config_element structs */ |
| 1546 | } __packed; |
| 1547 | |
| 1548 | struct mpii_raid_config_element { |
| 1549 | u_int16_t element_flags; |
| 1550 | #define MPII_RAID_CONFIG_ELEMENT_FLAG_VOLUME (0x0) |
| 1551 | #define MPII_RAID_CONFIG_ELEMENT_FLAG_VOLUME_PHYS_DISK (0x1) |
| 1552 | #define MPII_RAID_CONFIG_ELEMENT_FLAG_HSP_PHYS_DISK (0x2) |
| 1553 | #define MPII_RAID_CONFIG_ELEMENT_ONLINE_CE_PHYS_DISK (0x3) |
| 1554 | u_int16_t vol_dev_handle; |
| 1555 | |
| 1556 | u_int8_t hot_spare_pool; |
| 1557 | u_int8_t phys_disk_num; |
| 1558 | u_int16_t phys_disk_dev_handle; |
| 1559 | } __packed; |
| 1560 | |
| 1561 | struct mpii_cfg_dpm_pg0 { |
| 1562 | struct mpii_ecfg_hdr ; |
| 1563 | #define MPII_DPM_ADDRESS_FORM_MASK (0xf0000000) |
| 1564 | #define MPII_DPM_ADDRESS_FORM_ENTRY_RANGE (0x00000000) |
| 1565 | #define MPII_DPM_ADDRESS_ENTRY_COUNT_MASK (0x0fff0000) |
| 1566 | #define MPII_DPM_ADDRESS_ENTRY_COUNT_SHIFT (16) |
| 1567 | #define MPII_DPM_ADDRESS_START_ENTRY_MASK (0x0000ffff) |
| 1568 | |
| 1569 | /* followed by struct mpii_dpm_entry structs */ |
| 1570 | } __packed; |
| 1571 | |
| 1572 | struct mpii_dpm_entry { |
| 1573 | u_int64_t physical_identifier; |
| 1574 | |
| 1575 | u_int16_t mapping_information; |
| 1576 | u_int16_t device_index; |
| 1577 | |
| 1578 | u_int32_t physical_bits_mapping; |
| 1579 | |
| 1580 | u_int32_t reserved1; |
| 1581 | } __packed; |
| 1582 | |
| 1583 | struct mpii_evt_sas_discovery { |
| 1584 | u_int8_t flags; |
| 1585 | #define MPII_EVENT_SAS_DISC_FLAGS_DEV_CHANGE_MASK (1<<1) |
| 1586 | #define MPII_EVENT_SAS_DISC_FLAGS_DEV_CHANGE_NO_CHANGE (0<<1) |
| 1587 | #define MPII_EVENT_SAS_DISC_FLAGS_DEV_CHANGE_CHANGE (1<<1) |
| 1588 | #define MPII_EVENT_SAS_DISC_FLAGS_DISC_IN_PROG_MASK (1<<0) |
| 1589 | #define MPII_EVENT_SAS_DISC_FLAGS_DISC_NOT_IN_PROGRESS (1<<0) |
| 1590 | #define MPII_EVENT_SAS_DISC_FLAGS_DISC_IN_PROGRESS (0<<0) |
| 1591 | u_int8_t reason_code; |
| 1592 | #define MPII_EVENT_SAS_DISC_REASON_CODE_STARTED (0x01) |
| 1593 | #define MPII_EVENT_SAS_DISC_REASON_CODE_COMPLETED (0x02) |
| 1594 | u_int8_t physical_port; |
| 1595 | u_int8_t reserved1; |
| 1596 | |
| 1597 | u_int32_t discovery_status; |
| 1598 | } __packed; |
| 1599 | |
| 1600 | struct mpii_evt_ir_status { |
| 1601 | u_int16_t vol_dev_handle; |
| 1602 | u_int16_t reserved1; |
| 1603 | |
| 1604 | u_int8_t operation; |
| 1605 | #define MPII_EVENT_IR_RAIDOP_RESYNC (0x00) |
| 1606 | #define MPII_EVENT_IR_RAIDOP_OCE (0x01) |
| 1607 | #define MPII_EVENT_IR_RAIDOP_CONS_CHECK (0x02) |
| 1608 | #define MPII_EVENT_IR_RAIDOP_BG_INIT (0x03) |
| 1609 | #define MPII_EVENT_IR_RAIDOP_MAKE_CONS (0x04) |
| 1610 | u_int8_t percent; |
| 1611 | u_int16_t reserved2; |
| 1612 | |
| 1613 | u_int32_t reserved3; |
| 1614 | }; |
| 1615 | |
| 1616 | struct mpii_evt_ir_volume { |
| 1617 | u_int16_t vol_dev_handle; |
| 1618 | u_int8_t reason_code; |
| 1619 | #define MPII_EVENT_IR_VOL_RC_SETTINGS_CHANGED (0x01) |
| 1620 | #define MPII_EVENT_IR_VOL_RC_STATUS_CHANGED (0x02) |
| 1621 | #define MPII_EVENT_IR_VOL_RC_STATE_CHANGED (0x03) |
| 1622 | u_int8_t reserved1; |
| 1623 | |
| 1624 | u_int32_t new_value; |
| 1625 | u_int32_t prev_value; |
| 1626 | } __packed; |
| 1627 | |
| 1628 | struct mpii_evt_ir_physical_disk { |
| 1629 | u_int16_t reserved1; |
| 1630 | u_int8_t reason_code; |
| 1631 | #define MPII_EVENT_IR_PD_RC_SETTINGS_CHANGED (0x01) |
| 1632 | #define MPII_EVENT_IR_PD_RC_STATUS_FLAGS_CHANGED (0x02) |
| 1633 | #define MPII_EVENT_IR_PD_RC_STATUS_CHANGED (0x03) |
| 1634 | u_int8_t phys_disk_num; |
| 1635 | |
| 1636 | u_int16_t phys_disk_dev_handle; |
| 1637 | u_int16_t reserved2; |
| 1638 | |
| 1639 | u_int16_t slot; |
| 1640 | u_int16_t enclosure_handle; |
| 1641 | |
| 1642 | u_int32_t new_value; |
| 1643 | u_int32_t previous_value; |
| 1644 | } __packed; |
| 1645 | |
| 1646 | struct mpii_evt_sas_tcl { |
| 1647 | u_int16_t enclosure_handle; |
| 1648 | u_int16_t expander_handle; |
| 1649 | |
| 1650 | u_int8_t num_phys; |
| 1651 | u_int8_t reserved1[3]; |
| 1652 | |
| 1653 | u_int8_t num_entries; |
| 1654 | u_int8_t start_phy_num; |
| 1655 | u_int8_t expn_status; |
| 1656 | #define MPII_EVENT_SAS_TOPO_ES_ADDED (0x01) |
| 1657 | #define MPII_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) |
| 1658 | #define MPII_EVENT_SAS_TOPO_ES_RESPONDING (0x03) |
| 1659 | #define MPII_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) |
| 1660 | u_int8_t physical_port; |
| 1661 | |
| 1662 | /* followed by num_entries number of struct mpii_evt_phy_entry */ |
| 1663 | } __packed; |
| 1664 | |
| 1665 | struct mpii_evt_phy_entry { |
| 1666 | u_int16_t dev_handle; |
| 1667 | u_int8_t link_rate; |
| 1668 | u_int8_t phy_status; |
| 1669 | #define MPII_EVENT_SAS_TOPO_PS_RC_MASK (0x0f) |
| 1670 | #define MPII_EVENT_SAS_TOPO_PS_RC_ADDED (0x01) |
| 1671 | #define MPII_EVENT_SAS_TOPO_PS_RC_MISSING (0x02) |
| 1672 | } __packed; |
| 1673 | |
| 1674 | struct mpii_evt_ir_cfg_change_list { |
| 1675 | u_int8_t num_elements; |
| 1676 | u_int16_t reserved; |
| 1677 | u_int8_t config_num; |
| 1678 | |
| 1679 | u_int32_t flags; |
| 1680 | #define MPII_EVT_IR_CFG_CHANGE_LIST_FOREIGN (0x1) |
| 1681 | |
| 1682 | /* followed by num_elements struct mpii_evt_ir_cfg_elements */ |
| 1683 | } __packed; |
| 1684 | |
| 1685 | struct mpii_evt_ir_cfg_element { |
| 1686 | u_int16_t element_flags; |
| 1687 | #define MPII_EVT_IR_CFG_ELEMENT_TYPE_MASK (0xf) |
| 1688 | #define MPII_EVT_IR_CFG_ELEMENT_TYPE_VOLUME (0x0) |
| 1689 | #define MPII_EVT_IR_CFG_ELEMENT_TYPE_VOLUME_DISK (0x1) |
| 1690 | #define MPII_EVT_IR_CFG_ELEMENT_TYPE_HOT_SPARE (0x2) |
| 1691 | u_int16_t vol_dev_handle; |
| 1692 | |
| 1693 | u_int8_t reason_code; |
| 1694 | #define MPII_EVT_IR_CFG_ELEMENT_RC_ADDED (0x01) |
| 1695 | #define MPII_EVT_IR_CFG_ELEMENT_RC_REMOVED (0x02) |
| 1696 | #define MPII_EVT_IR_CFG_ELEMENT_RC_NO_CHANGE (0x03) |
| 1697 | #define MPII_EVT_IR_CFG_ELEMENT_RC_HIDE (0x04) |
| 1698 | #define MPII_EVT_IR_CFG_ELEMENT_RC_UNHIDE (0x05) |
| 1699 | #define MPII_EVT_IR_CFG_ELEMENT_RC_VOLUME_CREATED (0x06) |
| 1700 | #define MPII_EVT_IR_CFG_ELEMENT_RC_VOLUME_DELETED (0x07) |
| 1701 | #define MPII_EVT_IR_CFG_ELEMENT_RC_PD_CREATED (0x08) |
| 1702 | #define MPII_EVT_IR_CFG_ELEMENT_RC_PD_DELETED (0x09) |
| 1703 | u_int8_t phys_disk_num; |
| 1704 | u_int16_t phys_disk_dev_handle; |
| 1705 | } __packed; |
| 1706 | |
| 1707 | /* #define MPII_DEBUG */ |
| 1708 | #ifdef MPII_DEBUG |
| 1709 | #define DPRINTF(x...) do { if (mpii_debug) printf(x); } while(0) |
| 1710 | #define DNPRINTF(n,x...) do { if (mpii_debug & (n)) printf(x); } while(0) |
| 1711 | #define MPII_D_CMD (0x0001) |
| 1712 | #define MPII_D_INTR (0x0002) |
| 1713 | #define MPII_D_MISC (0x0004) |
| 1714 | #define MPII_D_DMA (0x0008) |
| 1715 | #define MPII_D_IOCTL (0x0010) |
| 1716 | #define MPII_D_RW (0x0020) |
| 1717 | #define MPII_D_MEM (0x0040) |
| 1718 | #define MPII_D_CCB (0x0080) |
| 1719 | #define MPII_D_PPR (0x0100) |
| 1720 | #define MPII_D_RAID (0x0200) |
| 1721 | #define MPII_D_EVT (0x0400) |
| 1722 | #define MPII_D_CFG (0x0800) |
| 1723 | #define MPII_D_MAP (0x1000) |
| 1724 | |
| 1725 | #if 0 |
| 1726 | u_int32_t mpii_debug = 0 |
| 1727 | | MPII_D_CMD |
| 1728 | | MPII_D_INTR |
| 1729 | | MPII_D_MISC |
| 1730 | | MPII_D_DMA |
| 1731 | | MPII_D_IOCTL |
| 1732 | | MPII_D_RW |
| 1733 | | MPII_D_MEM |
| 1734 | | MPII_D_CCB |
| 1735 | | MPII_D_PPR |
| 1736 | | MPII_D_RAID |
| 1737 | | MPII_D_EVT |
| 1738 | | MPII_D_CFG |
| 1739 | | MPII_D_MAP |
| 1740 | ; |
| 1741 | #endif |
| 1742 | u_int32_t mpii_debug = MPII_D_MISC; |
| 1743 | #else |
| 1744 | #define DPRINTF(x...) |
| 1745 | #define DNPRINTF(n,x...) |
| 1746 | #endif |
| 1747 | |
| 1748 | #define MPII_REQUEST_SIZE (512) |
| 1749 | #define MPII_REPLY_SIZE (128) |
| 1750 | #define MPII_REPLY_COUNT PAGE_SIZE / MPII_REPLY_SIZE |
| 1751 | |
| 1752 | /* |
| 1753 | * this is the max number of sge's we can stuff in a request frame: |
| 1754 | * sizeof(scsi_io) + sizeof(sense) + sizeof(sge) * 32 = MPII_REQUEST_SIZE |
| 1755 | */ |
| 1756 | #define MPII_MAX_SGL (32) |
| 1757 | |
| 1758 | #define MPII_MAX_REQUEST_CREDIT (128) |
| 1759 | |
| 1760 | #define MPII_MAXFER MAXPHYS /* XXX bogus */ |
| 1761 | |
| 1762 | struct mpii_dmamem { |
| 1763 | bus_dmamap_t mdm_map; |
| 1764 | bus_dma_segment_t mdm_seg; |
| 1765 | size_t mdm_size; |
| 1766 | void *mdm_kva; |
| 1767 | }; |
| 1768 | #define MPII_DMA_MAP(_mdm) (_mdm)->mdm_map |
| 1769 | #define MPII_DMA_DVA(_mdm) (_mdm)->mdm_map->dm_segs[0].ds_addr |
| 1770 | #define MPII_DMA_KVA(_mdm) (void *)(_mdm)->mdm_kva |
| 1771 | |
| 1772 | struct mpii_ccb_bundle { |
| 1773 | struct mpii_msg_scsi_io mcb_io; /* sgl must follow */ |
| 1774 | struct mpii_sge mcb_sgl[MPII_MAX_SGL]; |
| 1775 | struct scsi_sense_data mcb_sense; |
| 1776 | } __packed; |
| 1777 | |
| 1778 | struct mpii_softc; |
| 1779 | |
| 1780 | struct mpii_rcb { |
| 1781 | union { |
| 1782 | struct work rcb_wk; /* has to be first in struct */ |
| 1783 | SIMPLEQ_ENTRY(mpii_rcb) rcb_link; |
| 1784 | } u; |
| 1785 | void *rcb_reply; |
| 1786 | u_int32_t rcb_reply_dva; |
| 1787 | }; |
| 1788 | |
| 1789 | SIMPLEQ_HEAD(mpii_rcb_list, mpii_rcb); |
| 1790 | |
| 1791 | struct mpii_device { |
| 1792 | int flags; |
| 1793 | #define MPII_DF_ATTACH (0x0001) |
| 1794 | #define MPII_DF_DETACH (0x0002) |
| 1795 | #define MPII_DF_HIDDEN (0x0004) |
| 1796 | #define MPII_DF_UNUSED (0x0008) |
| 1797 | #define MPII_DF_VOLUME (0x0010) |
| 1798 | #define MPII_DF_VOLUME_DISK (0x0020) |
| 1799 | #define MPII_DF_HOT_SPARE (0x0040) |
| 1800 | short slot; |
| 1801 | short percent; |
| 1802 | u_int16_t dev_handle; |
| 1803 | u_int16_t enclosure; |
| 1804 | u_int16_t expander; |
| 1805 | u_int8_t phy_num; |
| 1806 | u_int8_t physical_port; |
| 1807 | }; |
| 1808 | |
| 1809 | struct mpii_ccb { |
| 1810 | union { |
| 1811 | struct work ccb_wk; /* has to be first in struct */ |
| 1812 | SIMPLEQ_ENTRY(mpii_ccb) ccb_link; |
| 1813 | } u; |
| 1814 | struct mpii_softc *ccb_sc; |
| 1815 | int ccb_smid; |
| 1816 | |
| 1817 | void * ccb_cookie; |
| 1818 | bus_dmamap_t ccb_dmamap; |
| 1819 | |
| 1820 | bus_addr_t ccb_offset; |
| 1821 | void *ccb_cmd; |
| 1822 | bus_addr_t ccb_cmd_dva; |
| 1823 | u_int16_t ccb_dev_handle; |
| 1824 | |
| 1825 | volatile enum { |
| 1826 | MPII_CCB_FREE, |
| 1827 | MPII_CCB_READY, |
| 1828 | MPII_CCB_QUEUED, |
| 1829 | MPII_CCB_TIMEOUT |
| 1830 | } ccb_state; |
| 1831 | |
| 1832 | void (*ccb_done)(struct mpii_ccb *); |
| 1833 | struct mpii_rcb *ccb_rcb; |
| 1834 | |
| 1835 | }; |
| 1836 | |
| 1837 | struct mpii_ccb_wait { |
| 1838 | kmutex_t mpii_ccbw_mtx; |
| 1839 | kcondvar_t mpii_ccbw_cv; |
| 1840 | }; |
| 1841 | |
| 1842 | SIMPLEQ_HEAD(mpii_ccb_list, mpii_ccb); |
| 1843 | |
| 1844 | struct mpii_softc { |
| 1845 | device_t sc_dev; |
| 1846 | |
| 1847 | pci_chipset_tag_t sc_pc; |
| 1848 | pcitag_t sc_tag; |
| 1849 | |
| 1850 | void *sc_ih; |
| 1851 | |
| 1852 | int sc_flags; |
| 1853 | #define MPII_F_RAID (1<<1) |
| 1854 | |
| 1855 | struct scsipi_adapter sc_adapt; |
| 1856 | struct scsipi_channel sc_chan; |
| 1857 | device_t sc_child; /* our scsibus */ |
| 1858 | |
| 1859 | struct mpii_device **sc_devs; |
| 1860 | |
| 1861 | bus_space_tag_t sc_iot; |
| 1862 | bus_space_handle_t sc_ioh; |
| 1863 | bus_size_t sc_ios; |
| 1864 | bus_dma_tag_t sc_dmat; |
| 1865 | |
| 1866 | kmutex_t sc_req_mtx; |
| 1867 | kmutex_t sc_rep_mtx; |
| 1868 | |
| 1869 | u_int8_t sc_porttype; |
| 1870 | int sc_request_depth; |
| 1871 | int sc_num_reply_frames; |
| 1872 | int sc_reply_free_qdepth; |
| 1873 | int sc_reply_post_qdepth; |
| 1874 | int sc_maxchdepth; |
| 1875 | int sc_first_sgl_len; |
| 1876 | int sc_chain_len; |
| 1877 | int sc_max_sgl_len; |
| 1878 | |
| 1879 | u_int8_t sc_ioc_event_replay; |
| 1880 | u_int16_t sc_max_enclosures; |
| 1881 | u_int16_t sc_max_expanders; |
| 1882 | u_int8_t sc_max_volumes; |
| 1883 | u_int16_t sc_max_devices; |
| 1884 | u_int16_t sc_max_dpm_entries; |
| 1885 | u_int16_t sc_vd_count; |
| 1886 | u_int16_t sc_vd_id_low; |
| 1887 | u_int16_t sc_pd_id_start; |
| 1888 | u_int8_t sc_num_channels; |
| 1889 | int sc_ioc_number; |
| 1890 | u_int8_t sc_vf_id; |
| 1891 | u_int8_t sc_num_ports; |
| 1892 | |
| 1893 | struct mpii_ccb *sc_ccbs; |
| 1894 | struct mpii_ccb_list sc_ccb_free; |
| 1895 | kmutex_t sc_ccb_free_mtx; |
| 1896 | kcondvar_t sc_ccb_free_cv; |
| 1897 | |
| 1898 | kmutex_t sc_ccb_mtx; |
| 1899 | /* |
| 1900 | * this protects the ccb state and list entry |
| 1901 | * between mpii_scsi_cmd and scsidone. |
| 1902 | */ |
| 1903 | |
| 1904 | struct workqueue *sc_ssb_tmowk; |
| 1905 | |
| 1906 | struct mpii_dmamem *sc_requests; |
| 1907 | |
| 1908 | struct mpii_dmamem *sc_replies; |
| 1909 | struct mpii_rcb *sc_rcbs; |
| 1910 | |
| 1911 | struct mpii_dmamem *sc_reply_postq; |
| 1912 | struct mpii_reply_descr *sc_reply_postq_kva; |
| 1913 | int sc_reply_post_host_index; |
| 1914 | |
| 1915 | struct mpii_dmamem *sc_reply_freeq; |
| 1916 | int sc_reply_free_host_index; |
| 1917 | |
| 1918 | struct workqueue *sc_ssb_evt_ackwk; |
| 1919 | |
| 1920 | struct sysmon_envsys *sc_sme; |
| 1921 | envsys_data_t *sc_sensors; |
| 1922 | }; |
| 1923 | |
| 1924 | static int mpii_match(device_t, cfdata_t, void *); |
| 1925 | static void mpii_attach(device_t, device_t, void *); |
| 1926 | static int mpii_detach(device_t, int); |
| 1927 | static void mpii_childdetached(device_t, device_t); |
| 1928 | static int mpii_rescan(device_t, const char *, const int *); |
| 1929 | |
| 1930 | static int mpii_intr(void *); |
| 1931 | |
| 1932 | CFATTACH_DECL3_NEW(mpii, sizeof(struct mpii_softc), |
| 1933 | mpii_match, mpii_attach, mpii_detach, NULL, mpii_rescan, |
| 1934 | mpii_childdetached, DVF_DETACH_SHUTDOWN); |
| 1935 | |
| 1936 | #define PREAD(s, r) pci_conf_read((s)->sc_pc, (s)->sc_tag, (r)) |
| 1937 | #define PWRITE(s, r, v) pci_conf_write((s)->sc_pc, (s)->sc_tag, (r), (v)) |
| 1938 | |
| 1939 | static void mpii_scsipi_request(struct scsipi_channel *, |
| 1940 | scsipi_adapter_req_t, void *); |
| 1941 | static void mpii_scsi_cmd_done(struct mpii_ccb *); |
| 1942 | static void mpii_minphys(struct buf *bp); |
| 1943 | |
| 1944 | static struct mpii_dmamem *mpii_dmamem_alloc(struct mpii_softc *, size_t); |
| 1945 | static void mpii_dmamem_free(struct mpii_softc *, struct mpii_dmamem *); |
| 1946 | static int mpii_alloc_ccbs(struct mpii_softc *); |
| 1947 | static struct mpii_ccb *mpii_get_ccb(struct mpii_softc *, int); |
| 1948 | #define MPII_NOSLEEP 0x0001 |
| 1949 | static void mpii_put_ccb(struct mpii_softc *, struct mpii_ccb *); |
| 1950 | static int mpii_alloc_replies(struct mpii_softc *); |
| 1951 | static int mpii_alloc_queues(struct mpii_softc *); |
| 1952 | static void mpii_push_reply(struct mpii_softc *, struct mpii_rcb *); |
| 1953 | static void mpii_push_replies(struct mpii_softc *); |
| 1954 | |
| 1955 | static void mpii_scsi_cmd_tmo(void *); |
| 1956 | static void mpii_scsi_cmd_tmo_handler(struct work *, void *); |
| 1957 | static void mpii_scsi_cmd_tmo_done(struct mpii_ccb *); |
| 1958 | |
| 1959 | static int mpii_alloc_dev(struct mpii_softc *); |
| 1960 | static int mpii_insert_dev(struct mpii_softc *, struct mpii_device *); |
| 1961 | static int mpii_remove_dev(struct mpii_softc *, struct mpii_device *); |
| 1962 | static struct mpii_device *mpii_find_dev(struct mpii_softc *, u_int16_t); |
| 1963 | |
| 1964 | static void mpii_start(struct mpii_softc *, struct mpii_ccb *); |
| 1965 | static int mpii_poll(struct mpii_softc *, struct mpii_ccb *); |
| 1966 | static void mpii_poll_done(struct mpii_ccb *); |
| 1967 | static struct mpii_rcb *mpii_reply(struct mpii_softc *, |
| 1968 | struct mpii_reply_descr *); |
| 1969 | |
| 1970 | static void mpii_wait(struct mpii_softc *, struct mpii_ccb *); |
| 1971 | static void mpii_wait_done(struct mpii_ccb *); |
| 1972 | |
| 1973 | static void mpii_init_queues(struct mpii_softc *); |
| 1974 | |
| 1975 | static int mpii_load_xs(struct mpii_ccb *); |
| 1976 | |
| 1977 | static u_int32_t mpii_read(struct mpii_softc *, bus_size_t); |
| 1978 | static void mpii_write(struct mpii_softc *, bus_size_t, u_int32_t); |
| 1979 | static int mpii_wait_eq(struct mpii_softc *, bus_size_t, u_int32_t, |
| 1980 | u_int32_t); |
| 1981 | static int mpii_wait_ne(struct mpii_softc *, bus_size_t, u_int32_t, |
| 1982 | u_int32_t); |
| 1983 | |
| 1984 | static int mpii_init(struct mpii_softc *); |
| 1985 | static int mpii_reset_soft(struct mpii_softc *); |
| 1986 | static int mpii_reset_hard(struct mpii_softc *); |
| 1987 | |
| 1988 | static int mpii_handshake_send(struct mpii_softc *, void *, size_t); |
| 1989 | static int mpii_handshake_recv_dword(struct mpii_softc *, |
| 1990 | u_int32_t *); |
| 1991 | static int mpii_handshake_recv(struct mpii_softc *, void *, size_t); |
| 1992 | |
| 1993 | static void mpii_empty_done(struct mpii_ccb *); |
| 1994 | |
| 1995 | static int mpii_iocinit(struct mpii_softc *); |
| 1996 | static int mpii_iocfacts(struct mpii_softc *); |
| 1997 | static int mpii_portfacts(struct mpii_softc *); |
| 1998 | static int mpii_portenable(struct mpii_softc *); |
| 1999 | static int mpii_cfg_coalescing(struct mpii_softc *); |
| 2000 | |
| 2001 | static int mpii_eventnotify(struct mpii_softc *); |
| 2002 | static void mpii_eventnotify_done(struct mpii_ccb *); |
| 2003 | static void mpii_eventack(struct work *, void *); |
| 2004 | static void mpii_eventack_done(struct mpii_ccb *); |
| 2005 | static void mpii_event_process(struct mpii_softc *, struct mpii_rcb *); |
| 2006 | static void mpii_event_sas(struct mpii_softc *, |
| 2007 | struct mpii_msg_event_reply *); |
| 2008 | static void mpii_event_raid(struct mpii_softc *, |
| 2009 | struct mpii_msg_event_reply *); |
| 2010 | static void mpii_event_defer(void *, void *); |
| 2011 | |
| 2012 | static void mpii_sas_remove_device(struct mpii_softc *, u_int16_t); |
| 2013 | |
| 2014 | static int mpii_req_cfg_header(struct mpii_softc *, u_int8_t, |
| 2015 | u_int8_t, u_int32_t, int, void *); |
| 2016 | static int mpii_req_cfg_page(struct mpii_softc *, u_int32_t, int, |
| 2017 | void *, int, void *, size_t); |
| 2018 | |
| 2019 | static int mpii_get_ioc_pg8(struct mpii_softc *); |
| 2020 | |
| 2021 | #if 0 |
| 2022 | static int mpii_ioctl_cache(struct scsi_link *, u_long, struct dk_cache *); |
| 2023 | #endif |
| 2024 | static int mpii_cache_enable(struct mpii_softc *, struct mpii_device *); |
| 2025 | |
| 2026 | #if NBIO > 0 |
| 2027 | static int mpii_ioctl(device_t, u_long, void *); |
| 2028 | static int mpii_ioctl_inq(struct mpii_softc *, struct bioc_inq *); |
| 2029 | static int mpii_ioctl_vol(struct mpii_softc *, struct bioc_vol *); |
| 2030 | static int mpii_ioctl_disk(struct mpii_softc *, struct bioc_disk *); |
| 2031 | static int mpii_bio_hs(struct mpii_softc *, struct bioc_disk *, int, |
| 2032 | int, int *); |
| 2033 | static int mpii_bio_disk(struct mpii_softc *, struct bioc_disk *, |
| 2034 | u_int8_t); |
| 2035 | static struct mpii_device *mpii_find_vol(struct mpii_softc *, int); |
| 2036 | static int mpii_bio_volstate(struct mpii_softc *, struct bioc_vol *); |
| 2037 | static int mpii_create_sensors(struct mpii_softc *); |
| 2038 | static int mpii_destroy_sensors(struct mpii_softc *); |
| 2039 | static void mpii_refresh_sensors(struct sysmon_envsys *, envsys_data_t *); |
| 2040 | #endif /* NBIO > 0 */ |
| 2041 | |
| 2042 | #define DEVNAME(_s) (device_xname((_s)->sc_dev)) |
| 2043 | |
| 2044 | #define dwordsof(s) (sizeof(s) / sizeof(u_int32_t)) |
| 2045 | #define dwordn(p, n) (((u_int32_t *)(p))[(n)]) |
| 2046 | |
| 2047 | #define mpii_read_db(s) mpii_read((s), MPII_DOORBELL) |
| 2048 | #define mpii_write_db(s, v) mpii_write((s), MPII_DOORBELL, (v)) |
| 2049 | #define mpii_read_intr(s) mpii_read((s), MPII_INTR_STATUS) |
| 2050 | #define mpii_write_intr(s, v) mpii_write((s), MPII_INTR_STATUS, (v)) |
| 2051 | #define mpii_reply_waiting(s) ((mpii_read_intr((s)) & MPII_INTR_STATUS_REPLY)\ |
| 2052 | == MPII_INTR_STATUS_REPLY) |
| 2053 | |
| 2054 | #define mpii_read_reply_free(s) mpii_read((s), \ |
| 2055 | MPII_REPLY_FREE_HOST_INDEX) |
| 2056 | #define mpii_write_reply_free(s, v) mpii_write((s), \ |
| 2057 | MPII_REPLY_FREE_HOST_INDEX, (v)) |
| 2058 | #define mpii_read_reply_post(s) mpii_read((s), \ |
| 2059 | MPII_REPLY_POST_HOST_INDEX) |
| 2060 | #define mpii_write_reply_post(s, v) mpii_write((s), \ |
| 2061 | MPII_REPLY_POST_HOST_INDEX, (v)) |
| 2062 | |
| 2063 | #define mpii_wait_db_int(s) mpii_wait_ne((s), MPII_INTR_STATUS, \ |
| 2064 | MPII_INTR_STATUS_IOC2SYSDB, 0) |
| 2065 | #define mpii_wait_db_ack(s) mpii_wait_eq((s), MPII_INTR_STATUS, \ |
| 2066 | MPII_INTR_STATUS_SYS2IOCDB, 0) |
| 2067 | |
| 2068 | #define MPII_PG_EXTENDED (1<<0) |
| 2069 | #define MPII_PG_POLL (1<<1) |
| 2070 | #define MPII_PG_FMT "\020" "\002POLL" "\001EXTENDED" |
| 2071 | |
| 2072 | #define (_s, _t, _n, _a, _h) \ |
| 2073 | mpii_req_cfg_header((_s), (_t), (_n), (_a), \ |
| 2074 | MPII_PG_POLL, (_h)) |
| 2075 | #define (_s, _t, _n, _a, _h) \ |
| 2076 | mpii_req_cfg_header((_s), (_t), (_n), (_a), \ |
| 2077 | MPII_PG_POLL|MPII_PG_EXTENDED, (_h)) |
| 2078 | |
| 2079 | #define mpii_cfg_page(_s, _a, _h, _r, _p, _l) \ |
| 2080 | mpii_req_cfg_page((_s), (_a), MPII_PG_POLL, \ |
| 2081 | (_h), (_r), (_p), (_l)) |
| 2082 | #define mpii_ecfg_page(_s, _a, _h, _r, _p, _l) \ |
| 2083 | mpii_req_cfg_page((_s), (_a), MPII_PG_POLL|MPII_PG_EXTENDED, \ |
| 2084 | (_h), (_r), (_p), (_l)) |
| 2085 | |
| 2086 | |
| 2087 | static const struct mpii_pci_product { |
| 2088 | pci_vendor_id_t mpii_vendor; |
| 2089 | pci_product_id_t mpii_product; |
| 2090 | } mpii_devices[] = { |
| 2091 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2004 }, |
| 2092 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2008 }, |
| 2093 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2108_3 }, |
| 2094 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2108_4 }, |
| 2095 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2108_5 }, |
| 2096 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2116_1 }, |
| 2097 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2116_2 }, |
| 2098 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2208_1 }, |
| 2099 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2208_2 }, |
| 2100 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2208_3 }, |
| 2101 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2208_4 }, |
| 2102 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2208_5 }, |
| 2103 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2208_6 }, |
| 2104 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2308_1 }, |
| 2105 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2308_2 }, |
| 2106 | { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2308_3 }, |
| 2107 | { 0, 0 } |
| 2108 | }; |
| 2109 | |
| 2110 | static int |
| 2111 | mpii_match(device_t parent, cfdata_t match, void *aux) |
| 2112 | { |
| 2113 | struct pci_attach_args *pa = aux; |
| 2114 | const struct mpii_pci_product *mpii; |
| 2115 | |
| 2116 | for (mpii = mpii_devices; mpii->mpii_vendor != 0; mpii++) { |
| 2117 | if (PCI_VENDOR(pa->pa_id) == mpii->mpii_vendor && |
| 2118 | PCI_PRODUCT(pa->pa_id) == mpii->mpii_product) |
| 2119 | return (1); |
| 2120 | } |
| 2121 | return (0); |
| 2122 | } |
| 2123 | |
| 2124 | static void |
| 2125 | mpii_attach(device_t parent, device_t self, void *aux) |
| 2126 | { |
| 2127 | struct mpii_softc *sc = device_private(self); |
| 2128 | struct pci_attach_args *pa = aux; |
| 2129 | pcireg_t memtype; |
| 2130 | int r; |
| 2131 | pci_intr_handle_t ih; |
| 2132 | const char *intrstr; |
| 2133 | struct mpii_ccb *ccb; |
| 2134 | struct scsipi_adapter *adapt = &sc->sc_adapt; |
| 2135 | struct scsipi_channel *chan = &sc->sc_chan; |
| 2136 | char wkname[15]; |
| 2137 | char intrbuf[PCI_INTRSTR_LEN]; |
| 2138 | |
| 2139 | pci_aprint_devinfo(pa, NULL); |
| 2140 | |
| 2141 | sc->sc_pc = pa->pa_pc; |
| 2142 | sc->sc_tag = pa->pa_tag; |
| 2143 | sc->sc_dmat = pa->pa_dmat; |
| 2144 | sc->sc_dev = self; |
| 2145 | |
| 2146 | mutex_init(&sc->sc_req_mtx, MUTEX_DEFAULT, IPL_BIO); |
| 2147 | mutex_init(&sc->sc_rep_mtx, MUTEX_DEFAULT, IPL_BIO); |
| 2148 | mutex_init(&sc->sc_ccb_free_mtx, MUTEX_DEFAULT, IPL_BIO); |
| 2149 | cv_init(&sc->sc_ccb_free_cv, "mpii_ccbs" ); |
| 2150 | mutex_init(&sc->sc_ccb_mtx, MUTEX_DEFAULT, IPL_BIO); |
| 2151 | |
| 2152 | snprintf(wkname, sizeof(wkname), "%s_tmo" , DEVNAME(sc)); |
| 2153 | if (workqueue_create(&sc->sc_ssb_tmowk, wkname, |
| 2154 | mpii_scsi_cmd_tmo_handler, sc, PRI_NONE, IPL_BIO, WQ_MPSAFE) != 0) { |
| 2155 | aprint_error_dev(self, "can't create %s workqueue\n" , wkname); |
| 2156 | return; |
| 2157 | } |
| 2158 | |
| 2159 | snprintf(wkname, sizeof(wkname), "%s_evt" , DEVNAME(sc)); |
| 2160 | if (workqueue_create(&sc->sc_ssb_evt_ackwk, wkname, |
| 2161 | mpii_eventack, sc, PRI_NONE, IPL_BIO, WQ_MPSAFE) != 0) { |
| 2162 | aprint_error_dev(self, "can't create %s workqueue\n" , wkname); |
| 2163 | return; |
| 2164 | } |
| 2165 | |
| 2166 | /* find the appropriate memory base */ |
| 2167 | for (r = PCI_MAPREG_START; r < PCI_MAPREG_END; r += sizeof(memtype)) { |
| 2168 | memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, r); |
| 2169 | if ((memtype & PCI_MAPREG_TYPE_MASK) == PCI_MAPREG_TYPE_MEM) |
| 2170 | break; |
| 2171 | } |
| 2172 | if (r >= PCI_MAPREG_END) { |
| 2173 | aprint_error_dev(self, |
| 2174 | "unable to locate system interface registers\n" ); |
| 2175 | return; |
| 2176 | } |
| 2177 | |
| 2178 | if (pci_mapreg_map(pa, r, memtype, 0, &sc->sc_iot, &sc->sc_ioh, |
| 2179 | NULL, &sc->sc_ios) != 0) { |
| 2180 | aprint_error_dev(self, |
| 2181 | "unable to map system interface registers\n" ); |
| 2182 | return; |
| 2183 | } |
| 2184 | |
| 2185 | /* disable the expansion rom */ |
| 2186 | PWRITE(sc, PCI_MAPREG_ROM, |
| 2187 | PREAD(sc, PCI_MAPREG_ROM) & ~PCI_MAPREG_ROM_ENABLE); |
| 2188 | |
| 2189 | /* disable interrupts */ |
| 2190 | mpii_write(sc, MPII_INTR_MASK, |
| 2191 | MPII_INTR_MASK_RESET | MPII_INTR_MASK_REPLY | |
| 2192 | MPII_INTR_MASK_DOORBELL); |
| 2193 | |
| 2194 | /* hook up the interrupt */ |
| 2195 | if (pci_intr_map(pa, &ih) != 0) { |
| 2196 | aprint_error_dev(self, "unable to map interrupt\n" ); |
| 2197 | goto unmap; |
| 2198 | } |
| 2199 | intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); |
| 2200 | |
| 2201 | if (mpii_init(sc) != 0) { |
| 2202 | aprint_error_dev(self, "unable to initialize ioc\n" ); |
| 2203 | goto unmap; |
| 2204 | } |
| 2205 | |
| 2206 | if (mpii_iocfacts(sc) != 0) { |
| 2207 | aprint_error_dev(self, "unable to get iocfacts\n" ); |
| 2208 | goto unmap; |
| 2209 | } |
| 2210 | |
| 2211 | if (mpii_alloc_ccbs(sc) != 0) { |
| 2212 | /* error already printed */ |
| 2213 | goto unmap; |
| 2214 | } |
| 2215 | |
| 2216 | if (mpii_alloc_replies(sc) != 0) { |
| 2217 | aprint_error_dev(self, "unable to allocated reply space\n" ); |
| 2218 | goto free_ccbs; |
| 2219 | } |
| 2220 | |
| 2221 | if (mpii_alloc_queues(sc) != 0) { |
| 2222 | aprint_error_dev(self, "unable to allocate reply queues\n" ); |
| 2223 | goto free_replies; |
| 2224 | } |
| 2225 | |
| 2226 | if (mpii_iocinit(sc) != 0) { |
| 2227 | aprint_error_dev(self, "unable to send iocinit\n" ); |
| 2228 | goto free_queues; |
| 2229 | } |
| 2230 | |
| 2231 | if (mpii_wait_eq(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, |
| 2232 | MPII_DOORBELL_STATE_OPER) != 0) { |
| 2233 | aprint_error_dev(self, "state: 0x%08x\n" , |
| 2234 | mpii_read_db(sc) & MPII_DOORBELL_STATE); |
| 2235 | aprint_error_dev(self, "operational state timeout\n" ); |
| 2236 | goto free_queues; |
| 2237 | } |
| 2238 | |
| 2239 | mpii_push_replies(sc); |
| 2240 | mpii_init_queues(sc); |
| 2241 | |
| 2242 | if (mpii_portfacts(sc) != 0) { |
| 2243 | aprint_error_dev(self, "unable to get portfacts\n" ); |
| 2244 | goto free_queues; |
| 2245 | } |
| 2246 | |
| 2247 | if (mpii_get_ioc_pg8(sc) != 0) { |
| 2248 | aprint_error_dev(self, "unable to get ioc page 8\n" ); |
| 2249 | goto free_queues; |
| 2250 | } |
| 2251 | |
| 2252 | if (mpii_cfg_coalescing(sc) != 0) { |
| 2253 | aprint_error_dev(self, "unable to configure coalescing\n" ); |
| 2254 | goto free_queues; |
| 2255 | } |
| 2256 | |
| 2257 | /* XXX bail on unsupported porttype? */ |
| 2258 | if ((sc->sc_porttype == MPII_PORTFACTS_PORTTYPE_SAS_PHYSICAL) || |
| 2259 | (sc->sc_porttype == MPII_PORTFACTS_PORTTYPE_SAS_VIRTUAL)) { |
| 2260 | if (mpii_eventnotify(sc) != 0) { |
| 2261 | aprint_error_dev(self, "unable to enable events\n" ); |
| 2262 | goto free_queues; |
| 2263 | } |
| 2264 | } |
| 2265 | |
| 2266 | if (mpii_alloc_dev(sc) != 0) { |
| 2267 | aprint_error_dev(self, |
| 2268 | "unable to allocate memory for mpii_device\n" ); |
| 2269 | goto free_queues; |
| 2270 | } |
| 2271 | |
| 2272 | if (mpii_portenable(sc) != 0) { |
| 2273 | aprint_error_dev(self, "unable to enable port\n" ); |
| 2274 | goto free_dev; |
| 2275 | } |
| 2276 | |
| 2277 | sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_BIO, |
| 2278 | mpii_intr, sc); |
| 2279 | if (sc->sc_ih == NULL) { |
| 2280 | aprint_error_dev(self, "can't establish interrupt" ); |
| 2281 | if (intrstr) |
| 2282 | aprint_error(" at %s" , intrstr); |
| 2283 | aprint_error("\n" ); |
| 2284 | goto free_dev; |
| 2285 | } |
| 2286 | |
| 2287 | memset(adapt, 0, sizeof(*adapt)); |
| 2288 | adapt->adapt_dev = sc->sc_dev; |
| 2289 | adapt->adapt_nchannels = 1; |
| 2290 | adapt->adapt_openings = sc->sc_request_depth - 1; |
| 2291 | adapt->adapt_max_periph = adapt->adapt_openings; |
| 2292 | adapt->adapt_request = mpii_scsipi_request; |
| 2293 | adapt->adapt_minphys = mpii_minphys; |
| 2294 | |
| 2295 | memset(chan, 0, sizeof(*chan)); |
| 2296 | chan->chan_adapter = adapt; |
| 2297 | chan->chan_bustype = &scsi_sas_bustype; |
| 2298 | chan->chan_channel = 0; |
| 2299 | chan->chan_flags = 0; |
| 2300 | chan->chan_nluns = 8; |
| 2301 | chan->chan_ntargets = sc->sc_max_devices; |
| 2302 | chan->chan_id = -1; |
| 2303 | |
| 2304 | mpii_rescan(self, "scsi" , NULL); |
| 2305 | |
| 2306 | /* enable interrupts */ |
| 2307 | mpii_write(sc, MPII_INTR_MASK, MPII_INTR_MASK_DOORBELL |
| 2308 | | MPII_INTR_MASK_RESET); |
| 2309 | |
| 2310 | #if NBIO > 0 |
| 2311 | if (ISSET(sc->sc_flags, MPII_F_RAID)) { |
| 2312 | if (bio_register(sc->sc_dev, mpii_ioctl) != 0) |
| 2313 | panic("%s: controller registration failed" , |
| 2314 | DEVNAME(sc)); |
| 2315 | |
| 2316 | if (mpii_create_sensors(sc) != 0) |
| 2317 | aprint_error_dev(self, "unable to create sensors\n" ); |
| 2318 | } |
| 2319 | #endif |
| 2320 | |
| 2321 | return; |
| 2322 | |
| 2323 | free_dev: |
| 2324 | if (sc->sc_devs) |
| 2325 | free(sc->sc_devs, M_DEVBUF); |
| 2326 | |
| 2327 | free_queues: |
| 2328 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_freeq), |
| 2329 | 0, sc->sc_reply_free_qdepth * 4, BUS_DMASYNC_POSTREAD); |
| 2330 | mpii_dmamem_free(sc, sc->sc_reply_freeq); |
| 2331 | |
| 2332 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), |
| 2333 | 0, sc->sc_reply_post_qdepth * 8, BUS_DMASYNC_POSTREAD); |
| 2334 | mpii_dmamem_free(sc, sc->sc_reply_postq); |
| 2335 | |
| 2336 | free_replies: |
| 2337 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_replies), |
| 2338 | 0, PAGE_SIZE, BUS_DMASYNC_POSTREAD); |
| 2339 | mpii_dmamem_free(sc, sc->sc_replies); |
| 2340 | |
| 2341 | free_ccbs: |
| 2342 | while ((ccb = mpii_get_ccb(sc, MPII_NOSLEEP)) != NULL) |
| 2343 | bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); |
| 2344 | mpii_dmamem_free(sc, sc->sc_requests); |
| 2345 | free(sc->sc_ccbs, M_DEVBUF); |
| 2346 | |
| 2347 | unmap: |
| 2348 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); |
| 2349 | sc->sc_ios = 0; |
| 2350 | } |
| 2351 | |
| 2352 | static int |
| 2353 | mpii_detach(device_t self, int flags) |
| 2354 | { |
| 2355 | struct mpii_softc *sc = device_private(self); |
| 2356 | int error; |
| 2357 | struct mpii_ccb *ccb; |
| 2358 | |
| 2359 | if ((error = config_detach_children(sc->sc_dev, flags)) != 0) |
| 2360 | return error; |
| 2361 | |
| 2362 | #if NBIO > 0 |
| 2363 | mpii_destroy_sensors(sc); |
| 2364 | bio_unregister(sc->sc_dev); |
| 2365 | #endif /* NBIO > 0 */ |
| 2366 | |
| 2367 | if (sc->sc_ih != NULL) { |
| 2368 | if (sc->sc_devs) |
| 2369 | free(sc->sc_devs, M_DEVBUF); |
| 2370 | |
| 2371 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_freeq), |
| 2372 | 0, sc->sc_reply_free_qdepth * 4, BUS_DMASYNC_POSTREAD); |
| 2373 | mpii_dmamem_free(sc, sc->sc_reply_freeq); |
| 2374 | |
| 2375 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), |
| 2376 | 0, sc->sc_reply_post_qdepth * 8, BUS_DMASYNC_POSTREAD); |
| 2377 | mpii_dmamem_free(sc, sc->sc_reply_postq); |
| 2378 | |
| 2379 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_replies), |
| 2380 | 0, PAGE_SIZE, BUS_DMASYNC_POSTREAD); |
| 2381 | mpii_dmamem_free(sc, sc->sc_replies); |
| 2382 | |
| 2383 | while ((ccb = mpii_get_ccb(sc, MPII_NOSLEEP)) != NULL) |
| 2384 | bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); |
| 2385 | mpii_dmamem_free(sc, sc->sc_requests); |
| 2386 | free(sc->sc_ccbs, M_DEVBUF); |
| 2387 | |
| 2388 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); |
| 2389 | sc->sc_ih = NULL; |
| 2390 | } |
| 2391 | if (sc->sc_ios != 0) { |
| 2392 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); |
| 2393 | sc->sc_ios = 0; |
| 2394 | } |
| 2395 | |
| 2396 | return (0); |
| 2397 | } |
| 2398 | |
| 2399 | static int |
| 2400 | mpii_rescan(device_t self, const char *ifattr, const int *locators) |
| 2401 | { |
| 2402 | struct mpii_softc *sc = device_private(self); |
| 2403 | |
| 2404 | if (sc->sc_child != NULL) |
| 2405 | return 0; |
| 2406 | |
| 2407 | sc->sc_child = config_found_sm_loc(self, ifattr, locators, &sc->sc_chan, |
| 2408 | scsiprint, NULL); |
| 2409 | |
| 2410 | return 0; |
| 2411 | } |
| 2412 | |
| 2413 | static void |
| 2414 | mpii_childdetached(device_t self, device_t child) |
| 2415 | { |
| 2416 | struct mpii_softc *sc = device_private(self); |
| 2417 | |
| 2418 | KASSERT(self == sc->sc_dev); |
| 2419 | KASSERT(child == sc->sc_child); |
| 2420 | |
| 2421 | if (child == sc->sc_child) |
| 2422 | sc->sc_child = NULL; |
| 2423 | } |
| 2424 | |
| 2425 | static int |
| 2426 | mpii_intr(void *arg) |
| 2427 | { |
| 2428 | struct mpii_rcb_list evts = SIMPLEQ_HEAD_INITIALIZER(evts); |
| 2429 | struct mpii_ccb_list ccbs = SIMPLEQ_HEAD_INITIALIZER(ccbs); |
| 2430 | struct mpii_softc *sc = arg; |
| 2431 | struct mpii_reply_descr *postq = sc->sc_reply_postq_kva, *rdp; |
| 2432 | struct mpii_ccb *ccb; |
| 2433 | struct mpii_rcb *rcb; |
| 2434 | int smid; |
| 2435 | int rv = 0; |
| 2436 | |
| 2437 | mutex_enter(&sc->sc_rep_mtx); |
| 2438 | bus_dmamap_sync(sc->sc_dmat, |
| 2439 | MPII_DMA_MAP(sc->sc_reply_postq), |
| 2440 | 0, 8 * sc->sc_reply_post_qdepth, |
| 2441 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); |
| 2442 | |
| 2443 | for (;;) { |
| 2444 | rdp = &postq[sc->sc_reply_post_host_index]; |
| 2445 | if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) == |
| 2446 | MPII_REPLY_DESCR_UNUSED) |
| 2447 | break; |
| 2448 | if (rdp->data == 0xffffffff) { |
| 2449 | /* |
| 2450 | * ioc is still writing to the reply post queue |
| 2451 | * race condition - bail! |
| 2452 | */ |
| 2453 | break; |
| 2454 | } |
| 2455 | |
| 2456 | smid = le16toh(rdp->smid); |
| 2457 | rcb = mpii_reply(sc, rdp); |
| 2458 | |
| 2459 | if (smid) { |
| 2460 | ccb = &sc->sc_ccbs[smid - 1]; |
| 2461 | ccb->ccb_state = MPII_CCB_READY; |
| 2462 | ccb->ccb_rcb = rcb; |
| 2463 | SIMPLEQ_INSERT_TAIL(&ccbs, ccb, u.ccb_link); |
| 2464 | } else |
| 2465 | SIMPLEQ_INSERT_TAIL(&evts, rcb, u.rcb_link); |
| 2466 | |
| 2467 | sc->sc_reply_post_host_index++; |
| 2468 | sc->sc_reply_post_host_index %= sc->sc_reply_post_qdepth; |
| 2469 | rv = 1; |
| 2470 | } |
| 2471 | |
| 2472 | bus_dmamap_sync(sc->sc_dmat, |
| 2473 | MPII_DMA_MAP(sc->sc_reply_postq), |
| 2474 | 0, 8 * sc->sc_reply_post_qdepth, |
| 2475 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
| 2476 | |
| 2477 | if (rv) |
| 2478 | mpii_write_reply_post(sc, sc->sc_reply_post_host_index); |
| 2479 | |
| 2480 | mutex_exit(&sc->sc_rep_mtx); |
| 2481 | |
| 2482 | if (rv == 0) |
| 2483 | return (0); |
| 2484 | |
| 2485 | while ((ccb = SIMPLEQ_FIRST(&ccbs)) != NULL) { |
| 2486 | SIMPLEQ_REMOVE_HEAD(&ccbs, u.ccb_link); |
| 2487 | ccb->ccb_done(ccb); |
| 2488 | } |
| 2489 | while ((rcb = SIMPLEQ_FIRST(&evts)) != NULL) { |
| 2490 | SIMPLEQ_REMOVE_HEAD(&evts, u.rcb_link); |
| 2491 | mpii_event_process(sc, rcb); |
| 2492 | } |
| 2493 | |
| 2494 | return (1); |
| 2495 | } |
| 2496 | |
| 2497 | static int |
| 2498 | mpii_load_xs(struct mpii_ccb *ccb) |
| 2499 | { |
| 2500 | struct mpii_softc *sc = ccb->ccb_sc; |
| 2501 | struct scsipi_xfer *xs = ccb->ccb_cookie; |
| 2502 | struct mpii_ccb_bundle *mcb = ccb->ccb_cmd; |
| 2503 | struct mpii_msg_scsi_io *io = &mcb->mcb_io; |
| 2504 | struct mpii_sge *sge = NULL, *nsge = &mcb->mcb_sgl[0]; |
| 2505 | struct mpii_sge *ce = NULL, *nce = NULL; |
| 2506 | u_int64_t ce_dva; |
| 2507 | bus_dmamap_t dmap = ccb->ccb_dmamap; |
| 2508 | u_int32_t addr, flags; |
| 2509 | int i, error; |
| 2510 | |
| 2511 | /* zero length transfer still requires an SGE */ |
| 2512 | if (xs->datalen == 0) { |
| 2513 | nsge->sg_hdr = htole32(MPII_SGE_FL_TYPE_SIMPLE | |
| 2514 | MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL); |
| 2515 | return (0); |
| 2516 | } |
| 2517 | |
| 2518 | error = bus_dmamap_load(sc->sc_dmat, dmap, |
| 2519 | xs->data, xs->datalen, NULL, (xs->xs_control & XS_CTL_NOSLEEP) ? |
| 2520 | BUS_DMA_NOWAIT : BUS_DMA_WAITOK); |
| 2521 | if (error) { |
| 2522 | aprint_error_dev(sc->sc_dev, "error %d loading dmamap\n" , |
| 2523 | error); |
| 2524 | return (1); |
| 2525 | } |
| 2526 | |
| 2527 | /* safe default staring flags */ |
| 2528 | flags = MPII_SGE_FL_TYPE_SIMPLE | MPII_SGE_FL_SIZE_64; |
| 2529 | /* if data out */ |
| 2530 | if (xs->xs_control & XS_CTL_DATA_OUT) |
| 2531 | flags |= MPII_SGE_FL_DIR_OUT; |
| 2532 | |
| 2533 | /* we will have to exceed the SGEs we can cram into the request frame */ |
| 2534 | if (dmap->dm_nsegs > sc->sc_first_sgl_len) { |
| 2535 | ce = &mcb->mcb_sgl[sc->sc_first_sgl_len - 1]; |
| 2536 | io->chain_offset = ((u_int8_t *)ce - (u_int8_t *)io) / 4; |
| 2537 | } |
| 2538 | |
| 2539 | for (i = 0; i < dmap->dm_nsegs; i++) { |
| 2540 | if (nsge == ce) { |
| 2541 | nsge++; |
| 2542 | sge->sg_hdr |= htole32(MPII_SGE_FL_LAST); |
| 2543 | |
| 2544 | DNPRINTF(MPII_D_DMA, "%s: - 0x%08x 0x%08x 0x%08x\n" , |
| 2545 | DEVNAME(sc), sge->sg_hdr, |
| 2546 | sge->sg_hi_addr, sge->sg_lo_addr); |
| 2547 | |
| 2548 | if ((dmap->dm_nsegs - i) > sc->sc_chain_len) { |
| 2549 | nce = &nsge[sc->sc_chain_len - 1]; |
| 2550 | addr = ((u_int8_t *)nce - (u_int8_t *)nsge) / 4; |
| 2551 | addr = addr << 16 | |
| 2552 | sizeof(struct mpii_sge) * sc->sc_chain_len; |
| 2553 | } else { |
| 2554 | nce = NULL; |
| 2555 | addr = sizeof(struct mpii_sge) * |
| 2556 | (dmap->dm_nsegs - i); |
| 2557 | } |
| 2558 | |
| 2559 | ce->sg_hdr = htole32(MPII_SGE_FL_TYPE_CHAIN | |
| 2560 | MPII_SGE_FL_SIZE_64 | addr); |
| 2561 | |
| 2562 | ce_dva = ccb->ccb_cmd_dva + |
| 2563 | ((u_int8_t *)nsge - (u_int8_t *)mcb); |
| 2564 | |
| 2565 | addr = (u_int32_t)(ce_dva >> 32); |
| 2566 | ce->sg_hi_addr = htole32(addr); |
| 2567 | addr = (u_int32_t)ce_dva; |
| 2568 | ce->sg_lo_addr = htole32(addr); |
| 2569 | |
| 2570 | DNPRINTF(MPII_D_DMA, "%s: ce: 0x%08x 0x%08x 0x%08x\n" , |
| 2571 | DEVNAME(sc), ce->sg_hdr, ce->sg_hi_addr, |
| 2572 | ce->sg_lo_addr); |
| 2573 | |
| 2574 | ce = nce; |
| 2575 | } |
| 2576 | |
| 2577 | DNPRINTF(MPII_D_DMA, "%s: %d: %" PRId64 " 0x%016" PRIx64 "\n" , |
| 2578 | DEVNAME(sc), i, (int64_t)dmap->dm_segs[i].ds_len, |
| 2579 | (u_int64_t)dmap->dm_segs[i].ds_addr); |
| 2580 | |
| 2581 | sge = nsge; |
| 2582 | |
| 2583 | sge->sg_hdr = htole32(flags | dmap->dm_segs[i].ds_len); |
| 2584 | addr = (u_int32_t)((u_int64_t)dmap->dm_segs[i].ds_addr >> 32); |
| 2585 | sge->sg_hi_addr = htole32(addr); |
| 2586 | addr = (u_int32_t)dmap->dm_segs[i].ds_addr; |
| 2587 | sge->sg_lo_addr = htole32(addr); |
| 2588 | |
| 2589 | DNPRINTF(MPII_D_DMA, "%s: %d: 0x%08x 0x%08x 0x%08x\n" , |
| 2590 | DEVNAME(sc), i, sge->sg_hdr, sge->sg_hi_addr, |
| 2591 | sge->sg_lo_addr); |
| 2592 | |
| 2593 | nsge = sge + 1; |
| 2594 | } |
| 2595 | |
| 2596 | /* terminate list */ |
| 2597 | sge->sg_hdr |= htole32(MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | |
| 2598 | MPII_SGE_FL_EOL); |
| 2599 | |
| 2600 | bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, |
| 2601 | (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD : |
| 2602 | BUS_DMASYNC_PREWRITE); |
| 2603 | |
| 2604 | return (0); |
| 2605 | } |
| 2606 | |
| 2607 | static u_int32_t |
| 2608 | mpii_read(struct mpii_softc *sc, bus_size_t r) |
| 2609 | { |
| 2610 | u_int32_t rv; |
| 2611 | |
| 2612 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, |
| 2613 | BUS_SPACE_BARRIER_READ); |
| 2614 | rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r); |
| 2615 | |
| 2616 | DNPRINTF(MPII_D_RW, "%s: mpii_read %#" PRIx64 " %#x\n" , DEVNAME(sc), |
| 2617 | (uint64_t)r, rv); |
| 2618 | |
| 2619 | return (rv); |
| 2620 | } |
| 2621 | |
| 2622 | static void |
| 2623 | mpii_write(struct mpii_softc *sc, bus_size_t r, u_int32_t v) |
| 2624 | { |
| 2625 | DNPRINTF(MPII_D_RW, "%s: mpii_write %#" PRIx64 " %#x\n" , DEVNAME(sc), |
| 2626 | (uint64_t)r, v); |
| 2627 | |
| 2628 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); |
| 2629 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, |
| 2630 | BUS_SPACE_BARRIER_WRITE); |
| 2631 | } |
| 2632 | |
| 2633 | |
| 2634 | static int |
| 2635 | mpii_wait_eq(struct mpii_softc *sc, bus_size_t r, u_int32_t mask, |
| 2636 | u_int32_t target) |
| 2637 | { |
| 2638 | int i; |
| 2639 | |
| 2640 | DNPRINTF(MPII_D_RW, "%s: mpii_wait_eq %#" PRIx64 " %#x %#x\n" , |
| 2641 | DEVNAME(sc), (uint64_t)r, mask, target); |
| 2642 | |
| 2643 | for (i = 0; i < 15000; i++) { |
| 2644 | if ((mpii_read(sc, r) & mask) == target) |
| 2645 | return (0); |
| 2646 | delay(1000); |
| 2647 | } |
| 2648 | |
| 2649 | return (1); |
| 2650 | } |
| 2651 | |
| 2652 | static int |
| 2653 | mpii_wait_ne(struct mpii_softc *sc, bus_size_t r, u_int32_t mask, |
| 2654 | u_int32_t target) |
| 2655 | { |
| 2656 | int i; |
| 2657 | |
| 2658 | DNPRINTF(MPII_D_RW, "%s: mpii_wait_ne %#" PRIx64 " %#x %#x\n" , |
| 2659 | DEVNAME(sc), (uint64_t)r, mask, target); |
| 2660 | |
| 2661 | for (i = 0; i < 15000; i++) { |
| 2662 | if ((mpii_read(sc, r) & mask) != target) |
| 2663 | return (0); |
| 2664 | delay(1000); |
| 2665 | } |
| 2666 | |
| 2667 | return (1); |
| 2668 | } |
| 2669 | |
| 2670 | |
| 2671 | static int |
| 2672 | mpii_init(struct mpii_softc *sc) |
| 2673 | { |
| 2674 | u_int32_t db; |
| 2675 | int i; |
| 2676 | |
| 2677 | /* spin until the ioc leaves the reset state */ |
| 2678 | if (mpii_wait_ne(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, |
| 2679 | MPII_DOORBELL_STATE_RESET) != 0) { |
| 2680 | DNPRINTF(MPII_D_MISC, "%s: mpii_init timeout waiting to leave " |
| 2681 | "reset state\n" , DEVNAME(sc)); |
| 2682 | return (1); |
| 2683 | } |
| 2684 | |
| 2685 | /* check current ownership */ |
| 2686 | db = mpii_read_db(sc); |
| 2687 | if ((db & MPII_DOORBELL_WHOINIT) == MPII_DOORBELL_WHOINIT_PCIPEER) { |
| 2688 | DNPRINTF(MPII_D_MISC, "%s: mpii_init initialised by pci peer\n" , |
| 2689 | DEVNAME(sc)); |
| 2690 | return (0); |
| 2691 | } |
| 2692 | |
| 2693 | for (i = 0; i < 5; i++) { |
| 2694 | switch (db & MPII_DOORBELL_STATE) { |
| 2695 | case MPII_DOORBELL_STATE_READY: |
| 2696 | DNPRINTF(MPII_D_MISC, "%s: mpii_init ioc is ready\n" , |
| 2697 | DEVNAME(sc)); |
| 2698 | return (0); |
| 2699 | |
| 2700 | case MPII_DOORBELL_STATE_OPER: |
| 2701 | DNPRINTF(MPII_D_MISC, "%s: mpii_init ioc is oper\n" , |
| 2702 | DEVNAME(sc)); |
| 2703 | if (sc->sc_ioc_event_replay) |
| 2704 | mpii_reset_soft(sc); |
| 2705 | else |
| 2706 | mpii_reset_hard(sc); |
| 2707 | break; |
| 2708 | |
| 2709 | case MPII_DOORBELL_STATE_FAULT: |
| 2710 | DNPRINTF(MPII_D_MISC, "%s: mpii_init ioc is being " |
| 2711 | "reset hard\n" , DEVNAME(sc)); |
| 2712 | mpii_reset_hard(sc); |
| 2713 | break; |
| 2714 | |
| 2715 | case MPII_DOORBELL_STATE_RESET: |
| 2716 | DNPRINTF(MPII_D_MISC, "%s: mpii_init waiting to come " |
| 2717 | "out of reset\n" , DEVNAME(sc)); |
| 2718 | if (mpii_wait_ne(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, |
| 2719 | MPII_DOORBELL_STATE_RESET) != 0) |
| 2720 | return (1); |
| 2721 | break; |
| 2722 | } |
| 2723 | db = mpii_read_db(sc); |
| 2724 | } |
| 2725 | |
| 2726 | return (1); |
| 2727 | } |
| 2728 | |
| 2729 | static int |
| 2730 | mpii_reset_soft(struct mpii_softc *sc) |
| 2731 | { |
| 2732 | DNPRINTF(MPII_D_MISC, "%s: mpii_reset_soft\n" , DEVNAME(sc)); |
| 2733 | |
| 2734 | if (mpii_read_db(sc) & MPII_DOORBELL_INUSE) { |
| 2735 | return (1); |
| 2736 | } |
| 2737 | |
| 2738 | mpii_write_db(sc, |
| 2739 | MPII_DOORBELL_FUNCTION(MPII_FUNCTION_IOC_MESSAGE_UNIT_RESET)); |
| 2740 | |
| 2741 | /* XXX LSI waits 15 sec */ |
| 2742 | if (mpii_wait_db_ack(sc) != 0) |
| 2743 | return (1); |
| 2744 | |
| 2745 | /* XXX LSI waits 15 sec */ |
| 2746 | if (mpii_wait_eq(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, |
| 2747 | MPII_DOORBELL_STATE_READY) != 0) |
| 2748 | return (1); |
| 2749 | |
| 2750 | /* XXX wait for Sys2IOCDB bit to clear in HIS?? */ |
| 2751 | |
| 2752 | return (0); |
| 2753 | } |
| 2754 | |
| 2755 | static int |
| 2756 | mpii_reset_hard(struct mpii_softc *sc) |
| 2757 | { |
| 2758 | u_int16_t i; |
| 2759 | |
| 2760 | DNPRINTF(MPII_D_MISC, "%s: mpii_reset_hard\n" , DEVNAME(sc)); |
| 2761 | |
| 2762 | mpii_write_intr(sc, 0); |
| 2763 | |
| 2764 | /* enable diagnostic register */ |
| 2765 | mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_FLUSH); |
| 2766 | mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_1); |
| 2767 | mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_2); |
| 2768 | mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_3); |
| 2769 | mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_4); |
| 2770 | mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_5); |
| 2771 | mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_6); |
| 2772 | |
| 2773 | delay(100); |
| 2774 | |
| 2775 | if ((mpii_read(sc, MPII_HOSTDIAG) & MPII_HOSTDIAG_DWRE) == 0) { |
| 2776 | DNPRINTF(MPII_D_MISC, "%s: mpii_reset_hard failure to enable " |
| 2777 | "diagnostic read/write\n" , DEVNAME(sc)); |
| 2778 | return(1); |
| 2779 | } |
| 2780 | |
| 2781 | /* reset ioc */ |
| 2782 | mpii_write(sc, MPII_HOSTDIAG, MPII_HOSTDIAG_RESET_ADAPTER); |
| 2783 | |
| 2784 | /* 240 milliseconds */ |
| 2785 | delay(240000); |
| 2786 | |
| 2787 | |
| 2788 | /* XXX this whole function should be more robust */ |
| 2789 | |
| 2790 | /* XXX read the host diagnostic reg until reset adapter bit clears ? */ |
| 2791 | for (i = 0; i < 30000; i++) { |
| 2792 | if ((mpii_read(sc, MPII_HOSTDIAG) & |
| 2793 | MPII_HOSTDIAG_RESET_ADAPTER) == 0) |
| 2794 | break; |
| 2795 | delay(10000); |
| 2796 | } |
| 2797 | |
| 2798 | /* disable diagnostic register */ |
| 2799 | mpii_write(sc, MPII_WRITESEQ, 0xff); |
| 2800 | |
| 2801 | /* XXX what else? */ |
| 2802 | |
| 2803 | DNPRINTF(MPII_D_MISC, "%s: done with mpii_reset_hard\n" , DEVNAME(sc)); |
| 2804 | |
| 2805 | return(0); |
| 2806 | } |
| 2807 | |
| 2808 | static int |
| 2809 | mpii_handshake_send(struct mpii_softc *sc, void *buf, size_t dwords) |
| 2810 | { |
| 2811 | u_int32_t *query = buf; |
| 2812 | int i; |
| 2813 | |
| 2814 | /* make sure the doorbell is not in use. */ |
| 2815 | if (mpii_read_db(sc) & MPII_DOORBELL_INUSE) |
| 2816 | return (1); |
| 2817 | |
| 2818 | /* clear pending doorbell interrupts */ |
| 2819 | if (mpii_read_intr(sc) & MPII_INTR_STATUS_IOC2SYSDB) |
| 2820 | mpii_write_intr(sc, 0); |
| 2821 | |
| 2822 | /* |
| 2823 | * first write the doorbell with the handshake function and the |
| 2824 | * dword count. |
| 2825 | */ |
| 2826 | mpii_write_db(sc, MPII_DOORBELL_FUNCTION(MPII_FUNCTION_HANDSHAKE) | |
| 2827 | MPII_DOORBELL_DWORDS(dwords)); |
| 2828 | |
| 2829 | /* |
| 2830 | * the doorbell used bit will be set because a doorbell function has |
| 2831 | * started. wait for the interrupt and then ack it. |
| 2832 | */ |
| 2833 | if (mpii_wait_db_int(sc) != 0) |
| 2834 | return (1); |
| 2835 | mpii_write_intr(sc, 0); |
| 2836 | |
| 2837 | /* poll for the acknowledgement. */ |
| 2838 | if (mpii_wait_db_ack(sc) != 0) |
| 2839 | return (1); |
| 2840 | |
| 2841 | /* write the query through the doorbell. */ |
| 2842 | for (i = 0; i < dwords; i++) { |
| 2843 | mpii_write_db(sc, htole32(query[i])); |
| 2844 | if (mpii_wait_db_ack(sc) != 0) |
| 2845 | return (1); |
| 2846 | } |
| 2847 | |
| 2848 | return (0); |
| 2849 | } |
| 2850 | |
| 2851 | static int |
| 2852 | mpii_handshake_recv_dword(struct mpii_softc *sc, u_int32_t *dword) |
| 2853 | { |
| 2854 | u_int16_t *words = (u_int16_t *)dword; |
| 2855 | int i; |
| 2856 | |
| 2857 | for (i = 0; i < 2; i++) { |
| 2858 | if (mpii_wait_db_int(sc) != 0) |
| 2859 | return (1); |
| 2860 | words[i] = le16toh(mpii_read_db(sc) & MPII_DOORBELL_DATA_MASK); |
| 2861 | mpii_write_intr(sc, 0); |
| 2862 | } |
| 2863 | |
| 2864 | return (0); |
| 2865 | } |
| 2866 | |
| 2867 | static int |
| 2868 | mpii_handshake_recv(struct mpii_softc *sc, void *buf, size_t dwords) |
| 2869 | { |
| 2870 | struct mpii_msg_reply *reply = buf; |
| 2871 | u_int32_t *dbuf = buf, dummy; |
| 2872 | int i; |
| 2873 | |
| 2874 | /* get the first dword so we can read the length out of the header. */ |
| 2875 | if (mpii_handshake_recv_dword(sc, &dbuf[0]) != 0) |
| 2876 | return (1); |
| 2877 | |
| 2878 | DNPRINTF(MPII_D_CMD, "%s: mpii_handshake_recv dwords: %zd reply: %d\n" , |
| 2879 | DEVNAME(sc), dwords, reply->msg_length); |
| 2880 | |
| 2881 | /* |
| 2882 | * the total length, in dwords, is in the message length field of the |
| 2883 | * reply header. |
| 2884 | */ |
| 2885 | for (i = 1; i < MIN(dwords, reply->msg_length); i++) { |
| 2886 | if (mpii_handshake_recv_dword(sc, &dbuf[i]) != 0) |
| 2887 | return (1); |
| 2888 | } |
| 2889 | |
| 2890 | /* if there's extra stuff to come off the ioc, discard it */ |
| 2891 | while (i++ < reply->msg_length) { |
| 2892 | if (mpii_handshake_recv_dword(sc, &dummy) != 0) |
| 2893 | return (1); |
| 2894 | DNPRINTF(MPII_D_CMD, "%s: mpii_handshake_recv dummy read: " |
| 2895 | "0x%08x\n" , DEVNAME(sc), dummy); |
| 2896 | } |
| 2897 | |
| 2898 | /* wait for the doorbell used bit to be reset and clear the intr */ |
| 2899 | if (mpii_wait_db_int(sc) != 0) |
| 2900 | return (1); |
| 2901 | |
| 2902 | if (mpii_wait_eq(sc, MPII_DOORBELL, MPII_DOORBELL_INUSE, 0) != 0) |
| 2903 | return (1); |
| 2904 | |
| 2905 | mpii_write_intr(sc, 0); |
| 2906 | |
| 2907 | return (0); |
| 2908 | } |
| 2909 | |
| 2910 | static void |
| 2911 | mpii_empty_done(struct mpii_ccb *ccb) |
| 2912 | { |
| 2913 | /* nothing to do */ |
| 2914 | } |
| 2915 | |
| 2916 | static int |
| 2917 | mpii_iocfacts(struct mpii_softc *sc) |
| 2918 | { |
| 2919 | struct mpii_msg_iocfacts_request ifq; |
| 2920 | struct mpii_msg_iocfacts_reply ifp; |
| 2921 | |
| 2922 | DNPRINTF(MPII_D_MISC, "%s: mpii_iocfacts\n" , DEVNAME(sc)); |
| 2923 | |
| 2924 | bzero(&ifq, sizeof(ifq)); |
| 2925 | bzero(&ifp, sizeof(ifp)); |
| 2926 | |
| 2927 | ifq.function = MPII_FUNCTION_IOC_FACTS; |
| 2928 | |
| 2929 | if (mpii_handshake_send(sc, &ifq, dwordsof(ifq)) != 0) { |
| 2930 | DNPRINTF(MPII_D_MISC, "%s: mpii_iocfacts send failed\n" , |
| 2931 | DEVNAME(sc)); |
| 2932 | return (1); |
| 2933 | } |
| 2934 | |
| 2935 | if (mpii_handshake_recv(sc, &ifp, dwordsof(ifp)) != 0) { |
| 2936 | DNPRINTF(MPII_D_MISC, "%s: mpii_iocfacts recv failed\n" , |
| 2937 | DEVNAME(sc)); |
| 2938 | return (1); |
| 2939 | } |
| 2940 | |
| 2941 | DNPRINTF(MPII_D_MISC, "%s: func: 0x%02x length: %d msgver: %d.%d\n" , |
| 2942 | DEVNAME(sc), ifp.function, ifp.msg_length, |
| 2943 | ifp.msg_version_maj, ifp.msg_version_min); |
| 2944 | DNPRINTF(MPII_D_MISC, "%s: msgflags: 0x%02x iocnumber: 0x%02x " |
| 2945 | "headerver: %d.%d\n" , DEVNAME(sc), ifp.msg_flags, |
| 2946 | ifp.ioc_number, ifp.header_version_unit, |
| 2947 | ifp.header_version_dev); |
| 2948 | DNPRINTF(MPII_D_MISC, "%s: vp_id: 0x%02x vf_id: 0x%02x\n" , DEVNAME(sc), |
| 2949 | ifp.vp_id, ifp.vf_id); |
| 2950 | DNPRINTF(MPII_D_MISC, "%s: iocstatus: 0x%04x ioexceptions: 0x%04x\n" , |
| 2951 | DEVNAME(sc), le16toh(ifp.ioc_status), |
| 2952 | le16toh(ifp.ioc_exceptions)); |
| 2953 | DNPRINTF(MPII_D_MISC, "%s: iocloginfo: 0x%08x\n" , DEVNAME(sc), |
| 2954 | le32toh(ifp.ioc_loginfo)); |
| 2955 | DNPRINTF(MPII_D_MISC, "%s: numberofports: 0x%02x whoinit: 0x%02x " |
| 2956 | "maxchaindepth: %d\n" , DEVNAME(sc), ifp.number_of_ports, |
| 2957 | ifp.whoinit, ifp.max_chain_depth); |
| 2958 | DNPRINTF(MPII_D_MISC, "%s: productid: 0x%04x requestcredit: 0x%04x\n" , |
| 2959 | DEVNAME(sc), le16toh(ifp.product_id), le16toh(ifp.request_credit)); |
| 2960 | DNPRINTF(MPII_D_MISC, "%s: ioc_capabilities: 0x%08x\n" , DEVNAME(sc), |
| 2961 | le32toh(ifp.ioc_capabilities)); |
| 2962 | DNPRINTF(MPII_D_MISC, "%s: fw_version: %d.%d fw_version_unit: 0x%02x " |
| 2963 | "fw_version_dev: 0x%02x\n" , DEVNAME(sc), |
| 2964 | ifp.fw_version_maj, ifp.fw_version_min, |
| 2965 | ifp.fw_version_unit, ifp.fw_version_dev); |
| 2966 | DNPRINTF(MPII_D_MISC, "%s: iocrequestframesize: 0x%04x\n" , |
| 2967 | DEVNAME(sc), le16toh(ifp.ioc_request_frame_size)); |
| 2968 | DNPRINTF(MPII_D_MISC, "%s: maxtargets: 0x%04x " |
| 2969 | "maxinitiators: 0x%04x\n" , DEVNAME(sc), |
| 2970 | le16toh(ifp.max_targets), le16toh(ifp.max_initiators)); |
| 2971 | DNPRINTF(MPII_D_MISC, "%s: maxenclosures: 0x%04x " |
| 2972 | "maxsasexpanders: 0x%04x\n" , DEVNAME(sc), |
| 2973 | le16toh(ifp.max_enclosures), le16toh(ifp.max_sas_expanders)); |
| 2974 | DNPRINTF(MPII_D_MISC, "%s: highprioritycredit: 0x%04x " |
| 2975 | "protocolflags: 0x%02x\n" , DEVNAME(sc), |
| 2976 | le16toh(ifp.high_priority_credit), le16toh(ifp.protocol_flags)); |
| 2977 | DNPRINTF(MPII_D_MISC, "%s: maxvolumes: 0x%02x replyframesize: 0x%02x " |
| 2978 | "mrdpqd: 0x%04x\n" , DEVNAME(sc), ifp.max_volumes, |
| 2979 | ifp.reply_frame_size, |
| 2980 | le16toh(ifp.max_reply_descriptor_post_queue_depth)); |
| 2981 | DNPRINTF(MPII_D_MISC, "%s: maxpersistententries: 0x%04x " |
| 2982 | "maxdevhandle: 0x%02x\n" , DEVNAME(sc), |
| 2983 | le16toh(ifp.max_persistent_entries), le16toh(ifp.max_dev_handle)); |
| 2984 | |
| 2985 | sc->sc_maxchdepth = ifp.max_chain_depth; |
| 2986 | sc->sc_ioc_number = ifp.ioc_number; |
| 2987 | sc->sc_vf_id = ifp.vf_id; |
| 2988 | |
| 2989 | sc->sc_num_ports = ifp.number_of_ports; |
| 2990 | sc->sc_ioc_event_replay = (le32toh(ifp.ioc_capabilities) & |
| 2991 | MPII_IOCFACTS_CAPABILITY_EVENT_REPLAY) ? 1 : 0; |
| 2992 | sc->sc_max_enclosures = le16toh(ifp.max_enclosures); |
| 2993 | sc->sc_max_expanders = le16toh(ifp.max_sas_expanders); |
| 2994 | sc->sc_max_volumes = ifp.max_volumes; |
| 2995 | sc->sc_max_devices = ifp.max_volumes + le16toh(ifp.max_targets); |
| 2996 | sc->sc_num_channels = 1; |
| 2997 | |
| 2998 | if (ISSET(le32toh(ifp.ioc_capabilities), |
| 2999 | MPII_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) |
| 3000 | SET(sc->sc_flags, MPII_F_RAID); |
| 3001 | |
| 3002 | sc->sc_request_depth = MIN(le16toh(ifp.request_credit), |
| 3003 | MPII_MAX_REQUEST_CREDIT); |
| 3004 | |
| 3005 | /* should not be multiple of 16 */ |
| 3006 | sc->sc_num_reply_frames = sc->sc_request_depth + 32; |
| 3007 | if (!(sc->sc_num_reply_frames % 16)) |
| 3008 | sc->sc_num_reply_frames--; |
| 3009 | |
| 3010 | /* must be multiple of 16 */ |
| 3011 | sc->sc_reply_free_qdepth = sc->sc_num_reply_frames + |
| 3012 | (16 - (sc->sc_num_reply_frames % 16)); |
| 3013 | sc->sc_reply_post_qdepth = ((sc->sc_request_depth + |
| 3014 | sc->sc_num_reply_frames + 1 + 15) / 16) * 16; |
| 3015 | |
| 3016 | if (sc->sc_reply_post_qdepth > |
| 3017 | ifp.max_reply_descriptor_post_queue_depth) |
| 3018 | sc->sc_reply_post_qdepth = |
| 3019 | ifp.max_reply_descriptor_post_queue_depth; |
| 3020 | |
| 3021 | DNPRINTF(MPII_D_MISC, "%s: sc_request_depth: %d " |
| 3022 | "sc_num_reply_frames: %d sc_reply_free_qdepth: %d " |
| 3023 | "sc_reply_post_qdepth: %d\n" , DEVNAME(sc), sc->sc_request_depth, |
| 3024 | sc->sc_num_reply_frames, sc->sc_reply_free_qdepth, |
| 3025 | sc->sc_reply_post_qdepth); |
| 3026 | |
| 3027 | /* |
| 3028 | * you can fit sg elements on the end of the io cmd if they fit in the |
| 3029 | * request frame size. |
| 3030 | */ |
| 3031 | |
| 3032 | sc->sc_first_sgl_len = ((le16toh(ifp.ioc_request_frame_size) * 4) - |
| 3033 | sizeof(struct mpii_msg_scsi_io)) / sizeof(struct mpii_sge); |
| 3034 | DNPRINTF(MPII_D_MISC, "%s: first sgl len: %d\n" , DEVNAME(sc), |
| 3035 | sc->sc_first_sgl_len); |
| 3036 | |
| 3037 | sc->sc_chain_len = (le16toh(ifp.ioc_request_frame_size) * 4) / |
| 3038 | sizeof(struct mpii_sge); |
| 3039 | DNPRINTF(MPII_D_MISC, "%s: chain len: %d\n" , DEVNAME(sc), |
| 3040 | sc->sc_chain_len); |
| 3041 | |
| 3042 | /* the sgl tailing the io cmd loses an entry to the chain element. */ |
| 3043 | sc->sc_max_sgl_len = MPII_MAX_SGL - 1; |
| 3044 | /* the sgl chains lose an entry for each chain element */ |
| 3045 | sc->sc_max_sgl_len -= (MPII_MAX_SGL - sc->sc_first_sgl_len) / |
| 3046 | sc->sc_chain_len; |
| 3047 | DNPRINTF(MPII_D_MISC, "%s: max sgl len: %d\n" , DEVNAME(sc), |
| 3048 | sc->sc_max_sgl_len); |
| 3049 | |
| 3050 | /* XXX we're ignoring the max chain depth */ |
| 3051 | |
| 3052 | return(0); |
| 3053 | |
| 3054 | } |
| 3055 | |
| 3056 | static int |
| 3057 | mpii_iocinit(struct mpii_softc *sc) |
| 3058 | { |
| 3059 | struct mpii_msg_iocinit_request iiq; |
| 3060 | struct mpii_msg_iocinit_reply iip; |
| 3061 | u_int32_t hi_addr; |
| 3062 | |
| 3063 | DNPRINTF(MPII_D_MISC, "%s: mpii_iocinit\n" , DEVNAME(sc)); |
| 3064 | |
| 3065 | bzero(&iiq, sizeof(iiq)); |
| 3066 | bzero(&iip, sizeof(iip)); |
| 3067 | |
| 3068 | iiq.function = MPII_FUNCTION_IOC_INIT; |
| 3069 | iiq.whoinit = MPII_WHOINIT_HOST_DRIVER; |
| 3070 | |
| 3071 | /* XXX JPG do something about vf_id */ |
| 3072 | iiq.vf_id = 0; |
| 3073 | |
| 3074 | iiq.msg_version_maj = 0x02; |
| 3075 | iiq.msg_version_min = 0x00; |
| 3076 | |
| 3077 | /* XXX JPG ensure compliance with some level and hard-code? */ |
| 3078 | iiq.hdr_version_unit = 0x00; |
| 3079 | iiq.hdr_version_dev = 0x00; |
| 3080 | |
| 3081 | iiq.system_request_frame_size = htole16(MPII_REQUEST_SIZE / 4); |
| 3082 | |
| 3083 | iiq.reply_descriptor_post_queue_depth = |
| 3084 | htole16(sc->sc_reply_post_qdepth); |
| 3085 | |
| 3086 | iiq.reply_free_queue_depth = htole16(sc->sc_reply_free_qdepth); |
| 3087 | |
| 3088 | hi_addr = (u_int32_t)((u_int64_t)MPII_DMA_DVA(sc->sc_requests) >> 32); |
| 3089 | iiq.sense_buffer_address_high = htole32(hi_addr); |
| 3090 | |
| 3091 | hi_addr = (u_int32_t) |
| 3092 | ((u_int64_t)MPII_DMA_DVA(sc->sc_replies) >> 32); |
| 3093 | iiq.system_reply_address_high = htole32(hi_addr); |
| 3094 | |
| 3095 | iiq.system_request_frame_base_address = |
| 3096 | (u_int64_t)MPII_DMA_DVA(sc->sc_requests); |
| 3097 | |
| 3098 | iiq.reply_descriptor_post_queue_address = |
| 3099 | (u_int64_t)MPII_DMA_DVA(sc->sc_reply_postq); |
| 3100 | |
| 3101 | iiq.reply_free_queue_address = |
| 3102 | (u_int64_t)MPII_DMA_DVA(sc->sc_reply_freeq); |
| 3103 | |
| 3104 | if (mpii_handshake_send(sc, &iiq, dwordsof(iiq)) != 0) { |
| 3105 | DNPRINTF(MPII_D_MISC, "%s: mpii_iocinit send failed\n" , |
| 3106 | DEVNAME(sc)); |
| 3107 | return (1); |
| 3108 | } |
| 3109 | |
| 3110 | if (mpii_handshake_recv(sc, &iip, dwordsof(iip)) != 0) { |
| 3111 | DNPRINTF(MPII_D_MISC, "%s: mpii_iocinit recv failed\n" , |
| 3112 | DEVNAME(sc)); |
| 3113 | return (1); |
| 3114 | } |
| 3115 | |
| 3116 | DNPRINTF(MPII_D_MISC, "%s: function: 0x%02x msg_length: %d " |
| 3117 | "whoinit: 0x%02x\n" , DEVNAME(sc), iip.function, |
| 3118 | iip.msg_length, iip.whoinit); |
| 3119 | DNPRINTF(MPII_D_MISC, "%s: msg_flags: 0x%02x\n" , DEVNAME(sc), |
| 3120 | iip.msg_flags); |
| 3121 | DNPRINTF(MPII_D_MISC, "%s: vf_id: 0x%02x vp_id: 0x%02x\n" , DEVNAME(sc), |
| 3122 | iip.vf_id, iip.vp_id); |
| 3123 | DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n" , DEVNAME(sc), |
| 3124 | le16toh(iip.ioc_status)); |
| 3125 | DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n" , DEVNAME(sc), |
| 3126 | le32toh(iip.ioc_loginfo)); |
| 3127 | |
| 3128 | if ((iip.ioc_status != MPII_IOCSTATUS_SUCCESS) || (iip.ioc_loginfo)) |
| 3129 | return (1); |
| 3130 | |
| 3131 | return (0); |
| 3132 | } |
| 3133 | |
| 3134 | static void |
| 3135 | mpii_push_reply(struct mpii_softc *sc, struct mpii_rcb *rcb) |
| 3136 | { |
| 3137 | u_int32_t *rfp; |
| 3138 | |
| 3139 | if (rcb == NULL) |
| 3140 | return; |
| 3141 | |
| 3142 | rfp = MPII_DMA_KVA(sc->sc_reply_freeq); |
| 3143 | rfp[sc->sc_reply_free_host_index] = rcb->rcb_reply_dva; |
| 3144 | |
| 3145 | sc->sc_reply_free_host_index = (sc->sc_reply_free_host_index + 1) % |
| 3146 | sc->sc_reply_free_qdepth; |
| 3147 | |
| 3148 | mpii_write_reply_free(sc, sc->sc_reply_free_host_index); |
| 3149 | } |
| 3150 | |
| 3151 | static int |
| 3152 | mpii_portfacts(struct mpii_softc *sc) |
| 3153 | { |
| 3154 | struct mpii_msg_portfacts_request *pfq; |
| 3155 | struct mpii_msg_portfacts_reply *pfp; |
| 3156 | struct mpii_ccb *ccb; |
| 3157 | int rv = 1; |
| 3158 | |
| 3159 | DNPRINTF(MPII_D_MISC, "%s: mpii_portfacts\n" , DEVNAME(sc)); |
| 3160 | |
| 3161 | ccb = mpii_get_ccb(sc, 0); |
| 3162 | if (ccb == NULL) { |
| 3163 | DNPRINTF(MPII_D_MISC, "%s: mpii_portfacts mpii_get_ccb fail\n" , |
| 3164 | DEVNAME(sc)); |
| 3165 | return (rv); |
| 3166 | } |
| 3167 | |
| 3168 | ccb->ccb_done = mpii_empty_done; |
| 3169 | pfq = ccb->ccb_cmd; |
| 3170 | |
| 3171 | bzero(pfq, sizeof(*pfq)); |
| 3172 | |
| 3173 | pfq->function = MPII_FUNCTION_PORT_FACTS; |
| 3174 | pfq->chain_offset = 0; |
| 3175 | pfq->msg_flags = 0; |
| 3176 | pfq->port_number = 0; |
| 3177 | pfq->vp_id = 0; |
| 3178 | pfq->vf_id = 0; |
| 3179 | |
| 3180 | if (mpii_poll(sc, ccb) != 0) { |
| 3181 | DNPRINTF(MPII_D_MISC, "%s: mpii_portfacts poll\n" , |
| 3182 | DEVNAME(sc)); |
| 3183 | goto err; |
| 3184 | } |
| 3185 | |
| 3186 | if (ccb->ccb_rcb == NULL) { |
| 3187 | DNPRINTF(MPII_D_MISC, "%s: empty portfacts reply\n" , |
| 3188 | DEVNAME(sc)); |
| 3189 | goto err; |
| 3190 | } |
| 3191 | |
| 3192 | pfp = ccb->ccb_rcb->rcb_reply; |
| 3193 | DNPRINTF(MPII_D_MISC, "%s pfp: %p\n" , DEVNAME(sc), pfp); |
| 3194 | |
| 3195 | DNPRINTF(MPII_D_MISC, "%s: function: 0x%02x msg_length: %d\n" , |
| 3196 | DEVNAME(sc), pfp->function, pfp->msg_length); |
| 3197 | DNPRINTF(MPII_D_MISC, "%s: msg_flags: 0x%02x port_number: %d\n" , |
| 3198 | DEVNAME(sc), pfp->msg_flags, pfp->port_number); |
| 3199 | DNPRINTF(MPII_D_MISC, "%s: vf_id: 0x%02x vp_id: 0x%02x\n" , |
| 3200 | DEVNAME(sc), pfp->vf_id, pfp->vp_id); |
| 3201 | DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n" , DEVNAME(sc), |
| 3202 | le16toh(pfp->ioc_status)); |
| 3203 | DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n" , DEVNAME(sc), |
| 3204 | le32toh(pfp->ioc_loginfo)); |
| 3205 | DNPRINTF(MPII_D_MISC, "%s: port_type: 0x%02x\n" , DEVNAME(sc), |
| 3206 | pfp->port_type); |
| 3207 | DNPRINTF(MPII_D_MISC, "%s: max_posted_cmd_buffers: %d\n" , DEVNAME(sc), |
| 3208 | le16toh(pfp->max_posted_cmd_buffers)); |
| 3209 | |
| 3210 | sc->sc_porttype = pfp->port_type; |
| 3211 | |
| 3212 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 3213 | rv = 0; |
| 3214 | err: |
| 3215 | mpii_put_ccb(sc, ccb); |
| 3216 | |
| 3217 | return (rv); |
| 3218 | } |
| 3219 | |
| 3220 | static void |
| 3221 | mpii_eventack(struct work *wk, void *cookie) |
| 3222 | { |
| 3223 | struct mpii_softc *sc = cookie; |
| 3224 | struct mpii_ccb *ccb; |
| 3225 | struct mpii_rcb *rcb = (void *)wk; |
| 3226 | struct mpii_msg_event_reply *enp; |
| 3227 | struct mpii_msg_eventack_request *eaq; |
| 3228 | |
| 3229 | ccb = mpii_get_ccb(sc, 0); |
| 3230 | |
| 3231 | enp = (struct mpii_msg_event_reply *)rcb->rcb_reply; |
| 3232 | |
| 3233 | ccb->ccb_done = mpii_eventack_done; |
| 3234 | eaq = ccb->ccb_cmd; |
| 3235 | |
| 3236 | eaq->function = MPII_FUNCTION_EVENT_ACK; |
| 3237 | |
| 3238 | eaq->event = enp->event; |
| 3239 | eaq->event_context = enp->event_context; |
| 3240 | |
| 3241 | mpii_push_reply(sc, rcb); |
| 3242 | |
| 3243 | mpii_start(sc, ccb); |
| 3244 | |
| 3245 | } |
| 3246 | |
| 3247 | static void |
| 3248 | mpii_eventack_done(struct mpii_ccb *ccb) |
| 3249 | { |
| 3250 | struct mpii_softc *sc = ccb->ccb_sc; |
| 3251 | |
| 3252 | DNPRINTF(MPII_D_EVT, "%s: event ack done\n" , DEVNAME(sc)); |
| 3253 | |
| 3254 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 3255 | mpii_put_ccb(sc, ccb); |
| 3256 | } |
| 3257 | |
| 3258 | static int |
| 3259 | mpii_portenable(struct mpii_softc *sc) |
| 3260 | { |
| 3261 | struct mpii_msg_portenable_request *peq; |
| 3262 | struct mpii_ccb *ccb; |
| 3263 | |
| 3264 | DNPRINTF(MPII_D_MISC, "%s: mpii_portenable\n" , DEVNAME(sc)); |
| 3265 | |
| 3266 | ccb = mpii_get_ccb(sc, 0); |
| 3267 | if (ccb == NULL) { |
| 3268 | DNPRINTF(MPII_D_MISC, "%s: mpii_portenable ccb_get\n" , |
| 3269 | DEVNAME(sc)); |
| 3270 | return (1); |
| 3271 | } |
| 3272 | |
| 3273 | ccb->ccb_done = mpii_empty_done; |
| 3274 | peq = ccb->ccb_cmd; |
| 3275 | |
| 3276 | peq->function = MPII_FUNCTION_PORT_ENABLE; |
| 3277 | peq->vf_id = sc->sc_vf_id; |
| 3278 | |
| 3279 | if (mpii_poll(sc, ccb) != 0) { |
| 3280 | DNPRINTF(MPII_D_MISC, "%s: mpii_portenable poll\n" , |
| 3281 | DEVNAME(sc)); |
| 3282 | return (1); |
| 3283 | } |
| 3284 | |
| 3285 | if (ccb->ccb_rcb == NULL) { |
| 3286 | DNPRINTF(MPII_D_MISC, "%s: empty portenable reply\n" , |
| 3287 | DEVNAME(sc)); |
| 3288 | return (1); |
| 3289 | } |
| 3290 | |
| 3291 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 3292 | mpii_put_ccb(sc, ccb); |
| 3293 | |
| 3294 | return (0); |
| 3295 | } |
| 3296 | |
| 3297 | static int |
| 3298 | mpii_cfg_coalescing(struct mpii_softc *sc) |
| 3299 | { |
| 3300 | struct mpii_cfg_hdr hdr; |
| 3301 | struct mpii_cfg_ioc_pg1 pg; |
| 3302 | |
| 3303 | if (mpii_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_IOC, 1, 0, |
| 3304 | &hdr) != 0) { |
| 3305 | DNPRINTF(MPII_D_MISC, "%s: unable to fetch IOC page 1 " |
| 3306 | "header\n" , DEVNAME(sc)); |
| 3307 | return (1); |
| 3308 | } |
| 3309 | |
| 3310 | if (mpii_cfg_page(sc, 0, &hdr, 1, &pg, sizeof(pg)) != 0) { |
| 3311 | DNPRINTF(MPII_D_MISC, "%s: unable to fetch IOC page 1\n" |
| 3312 | "page 1\n" , DEVNAME(sc)); |
| 3313 | return (1); |
| 3314 | } |
| 3315 | |
| 3316 | DNPRINTF(MPII_D_MISC, "%s: IOC page 1\n" , DEVNAME(sc)); |
| 3317 | DNPRINTF(MPII_D_MISC, "%s: flags: 0x08%x\n" , DEVNAME(sc), |
| 3318 | le32toh(pg.flags)); |
| 3319 | DNPRINTF(MPII_D_MISC, "%s: coalescing_timeout: %d\n" , DEVNAME(sc), |
| 3320 | le32toh(pg.coalescing_timeout)); |
| 3321 | DNPRINTF(MPII_D_MISC, "%s: coalescing_depth: %d pci_slot_num: %d\n" , |
| 3322 | DEVNAME(sc), pg.coalescing_timeout, pg.pci_slot_num); |
| 3323 | |
| 3324 | if (!ISSET(le32toh(pg.flags), MPII_CFG_IOC_1_REPLY_COALESCING)) |
| 3325 | return (0); |
| 3326 | |
| 3327 | CLR(pg.flags, htole32(MPII_CFG_IOC_1_REPLY_COALESCING)); |
| 3328 | if (mpii_cfg_page(sc, 0, &hdr, 0, &pg, sizeof(pg)) != 0) { |
| 3329 | DNPRINTF(MPII_D_MISC, "%s: unable to clear coalescing\n" , |
| 3330 | DEVNAME(sc)); |
| 3331 | return (1); |
| 3332 | } |
| 3333 | |
| 3334 | return (0); |
| 3335 | } |
| 3336 | |
| 3337 | #define MPII_EVENT_MASKALL(enq) do { \ |
| 3338 | enq->event_masks[0] = 0xffffffff; \ |
| 3339 | enq->event_masks[1] = 0xffffffff; \ |
| 3340 | enq->event_masks[2] = 0xffffffff; \ |
| 3341 | enq->event_masks[3] = 0xffffffff; \ |
| 3342 | } while (0) |
| 3343 | |
| 3344 | #define MPII_EVENT_UNMASK(enq, evt) do { \ |
| 3345 | enq->event_masks[evt / 32] &= \ |
| 3346 | htole32(~(1 << (evt % 32))); \ |
| 3347 | } while (0) |
| 3348 | |
| 3349 | static int |
| 3350 | mpii_eventnotify(struct mpii_softc *sc) |
| 3351 | { |
| 3352 | struct mpii_msg_event_request *enq; |
| 3353 | struct mpii_ccb *ccb; |
| 3354 | |
| 3355 | ccb = mpii_get_ccb(sc, 0); |
| 3356 | if (ccb == NULL) { |
| 3357 | DNPRINTF(MPII_D_MISC, "%s: mpii_eventnotify ccb_get\n" , |
| 3358 | DEVNAME(sc)); |
| 3359 | return (1); |
| 3360 | } |
| 3361 | |
| 3362 | ccb->ccb_done = mpii_eventnotify_done; |
| 3363 | enq = ccb->ccb_cmd; |
| 3364 | |
| 3365 | enq->function = MPII_FUNCTION_EVENT_NOTIFICATION; |
| 3366 | |
| 3367 | /* |
| 3368 | * Enable reporting of the following events: |
| 3369 | * |
| 3370 | * MPII_EVENT_SAS_DISCOVERY |
| 3371 | * MPII_EVENT_SAS_TOPOLOGY_CHANGE_LIST |
| 3372 | * MPII_EVENT_SAS_DEVICE_STATUS_CHANGE |
| 3373 | * MPII_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE |
| 3374 | * MPII_EVENT_IR_CONFIGURATION_CHANGE_LIST |
| 3375 | * MPII_EVENT_IR_VOLUME |
| 3376 | * MPII_EVENT_IR_PHYSICAL_DISK |
| 3377 | * MPII_EVENT_IR_OPERATION_STATUS |
| 3378 | */ |
| 3379 | |
| 3380 | MPII_EVENT_MASKALL(enq); |
| 3381 | MPII_EVENT_UNMASK(enq, MPII_EVENT_SAS_DISCOVERY); |
| 3382 | MPII_EVENT_UNMASK(enq, MPII_EVENT_SAS_TOPOLOGY_CHANGE_LIST); |
| 3383 | MPII_EVENT_UNMASK(enq, MPII_EVENT_SAS_DEVICE_STATUS_CHANGE); |
| 3384 | MPII_EVENT_UNMASK(enq, MPII_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); |
| 3385 | MPII_EVENT_UNMASK(enq, MPII_EVENT_IR_CONFIGURATION_CHANGE_LIST); |
| 3386 | MPII_EVENT_UNMASK(enq, MPII_EVENT_IR_VOLUME); |
| 3387 | MPII_EVENT_UNMASK(enq, MPII_EVENT_IR_PHYSICAL_DISK); |
| 3388 | MPII_EVENT_UNMASK(enq, MPII_EVENT_IR_OPERATION_STATUS); |
| 3389 | |
| 3390 | mpii_start(sc, ccb); |
| 3391 | |
| 3392 | return (0); |
| 3393 | } |
| 3394 | |
| 3395 | static void |
| 3396 | mpii_eventnotify_done(struct mpii_ccb *ccb) |
| 3397 | { |
| 3398 | struct mpii_softc *sc = ccb->ccb_sc; |
| 3399 | struct mpii_rcb *rcb = ccb->ccb_rcb; |
| 3400 | |
| 3401 | DNPRINTF(MPII_D_EVT, "%s: mpii_eventnotify_done\n" , DEVNAME(sc)); |
| 3402 | |
| 3403 | mpii_put_ccb(sc, ccb); |
| 3404 | mpii_event_process(sc, rcb); |
| 3405 | } |
| 3406 | |
| 3407 | static void |
| 3408 | mpii_event_raid(struct mpii_softc *sc, struct mpii_msg_event_reply *enp) |
| 3409 | { |
| 3410 | struct mpii_evt_ir_cfg_change_list *ccl; |
| 3411 | struct mpii_evt_ir_cfg_element *ce; |
| 3412 | struct mpii_device *dev; |
| 3413 | u_int16_t type; |
| 3414 | int i; |
| 3415 | |
| 3416 | ccl = (struct mpii_evt_ir_cfg_change_list *)(enp + 1); |
| 3417 | |
| 3418 | if (ccl->num_elements == 0) |
| 3419 | return; |
| 3420 | if (ISSET(le32toh(ccl->flags), MPII_EVT_IR_CFG_CHANGE_LIST_FOREIGN)) |
| 3421 | /* bail on foreign configurations */ |
| 3422 | return; |
| 3423 | |
| 3424 | ce = (struct mpii_evt_ir_cfg_element *)(ccl + 1); |
| 3425 | |
| 3426 | for (i = 0; i < ccl->num_elements; i++, ce++) { |
| 3427 | type = (le16toh(ce->element_flags) & |
| 3428 | MPII_EVT_IR_CFG_ELEMENT_TYPE_MASK); |
| 3429 | |
| 3430 | switch (type) { |
| 3431 | case MPII_EVT_IR_CFG_ELEMENT_TYPE_VOLUME: |
| 3432 | switch (ce->reason_code) { |
| 3433 | case MPII_EVT_IR_CFG_ELEMENT_RC_ADDED: |
| 3434 | case MPII_EVT_IR_CFG_ELEMENT_RC_VOLUME_CREATED: |
| 3435 | if (mpii_find_dev(sc, |
| 3436 | le16toh(ce->vol_dev_handle))) { |
| 3437 | printf("%s: device %#x is already " |
| 3438 | "configured\n" , DEVNAME(sc), |
| 3439 | le16toh(ce->vol_dev_handle)); |
| 3440 | break; |
| 3441 | } |
| 3442 | dev = malloc(sizeof(*dev), M_DEVBUF, |
| 3443 | M_NOWAIT | M_ZERO); |
| 3444 | if (!dev) { |
| 3445 | printf("%s: failed to allocate a " |
| 3446 | "device structure\n" , DEVNAME(sc)); |
| 3447 | break; |
| 3448 | } |
| 3449 | SET(dev->flags, MPII_DF_VOLUME); |
| 3450 | dev->slot = sc->sc_vd_id_low; |
| 3451 | dev->dev_handle = le16toh(ce->vol_dev_handle); |
| 3452 | if (mpii_insert_dev(sc, dev)) { |
| 3453 | free(dev, M_DEVBUF); |
| 3454 | break; |
| 3455 | } |
| 3456 | mpii_cache_enable(sc, dev); |
| 3457 | sc->sc_vd_count++; |
| 3458 | break; |
| 3459 | case MPII_EVT_IR_CFG_ELEMENT_RC_REMOVED: |
| 3460 | case MPII_EVT_IR_CFG_ELEMENT_RC_VOLUME_DELETED: |
| 3461 | if (!(dev = mpii_find_dev(sc, |
| 3462 | le16toh(ce->vol_dev_handle)))) |
| 3463 | break; |
| 3464 | mpii_remove_dev(sc, dev); |
| 3465 | sc->sc_vd_count--; |
| 3466 | break; |
| 3467 | } |
| 3468 | break; |
| 3469 | case MPII_EVT_IR_CFG_ELEMENT_TYPE_VOLUME_DISK: |
| 3470 | if (ce->reason_code == |
| 3471 | MPII_EVT_IR_CFG_ELEMENT_RC_PD_CREATED || |
| 3472 | ce->reason_code == |
| 3473 | MPII_EVT_IR_CFG_ELEMENT_RC_HIDE) { |
| 3474 | /* there should be an underlying sas drive */ |
| 3475 | if (!(dev = mpii_find_dev(sc, |
| 3476 | le16toh(ce->phys_disk_dev_handle)))) |
| 3477 | break; |
| 3478 | /* promoted from a hot spare? */ |
| 3479 | CLR(dev->flags, MPII_DF_HOT_SPARE); |
| 3480 | SET(dev->flags, MPII_DF_VOLUME_DISK | |
| 3481 | MPII_DF_HIDDEN); |
| 3482 | } |
| 3483 | break; |
| 3484 | case MPII_EVT_IR_CFG_ELEMENT_TYPE_HOT_SPARE: |
| 3485 | if (ce->reason_code == |
| 3486 | MPII_EVT_IR_CFG_ELEMENT_RC_HIDE) { |
| 3487 | /* there should be an underlying sas drive */ |
| 3488 | if (!(dev = mpii_find_dev(sc, |
| 3489 | le16toh(ce->phys_disk_dev_handle)))) |
| 3490 | break; |
| 3491 | SET(dev->flags, MPII_DF_HOT_SPARE | |
| 3492 | MPII_DF_HIDDEN); |
| 3493 | } |
| 3494 | break; |
| 3495 | } |
| 3496 | } |
| 3497 | } |
| 3498 | |
| 3499 | static void |
| 3500 | mpii_event_sas(struct mpii_softc *sc, struct mpii_msg_event_reply *enp) |
| 3501 | { |
| 3502 | struct mpii_evt_sas_tcl *tcl; |
| 3503 | struct mpii_evt_phy_entry *pe; |
| 3504 | struct mpii_device *dev; |
| 3505 | int i; |
| 3506 | |
| 3507 | tcl = (struct mpii_evt_sas_tcl *)(enp + 1); |
| 3508 | |
| 3509 | if (tcl->num_entries == 0) |
| 3510 | return; |
| 3511 | |
| 3512 | pe = (struct mpii_evt_phy_entry *)(tcl + 1); |
| 3513 | |
| 3514 | for (i = 0; i < tcl->num_entries; i++, pe++) { |
| 3515 | switch (pe->phy_status & MPII_EVENT_SAS_TOPO_PS_RC_MASK) { |
| 3516 | case MPII_EVENT_SAS_TOPO_PS_RC_ADDED: |
| 3517 | if (mpii_find_dev(sc, le16toh(pe->dev_handle))) { |
| 3518 | printf("%s: device %#x is already " |
| 3519 | "configured\n" , DEVNAME(sc), |
| 3520 | le16toh(pe->dev_handle)); |
| 3521 | break; |
| 3522 | } |
| 3523 | dev = malloc(sizeof(*dev), M_DEVBUF, M_NOWAIT | M_ZERO); |
| 3524 | if (!dev) { |
| 3525 | printf("%s: failed to allocate a " |
| 3526 | "device structure\n" , DEVNAME(sc)); |
| 3527 | break; |
| 3528 | } |
| 3529 | dev->slot = sc->sc_pd_id_start + tcl->start_phy_num + i; |
| 3530 | dev->dev_handle = le16toh(pe->dev_handle); |
| 3531 | dev->phy_num = tcl->start_phy_num + i; |
| 3532 | if (tcl->enclosure_handle) |
| 3533 | dev->physical_port = tcl->physical_port; |
| 3534 | dev->enclosure = le16toh(tcl->enclosure_handle); |
| 3535 | dev->expander = le16toh(tcl->expander_handle); |
| 3536 | if (mpii_insert_dev(sc, dev)) { |
| 3537 | free(dev, M_DEVBUF); |
| 3538 | break; |
| 3539 | } |
| 3540 | break; |
| 3541 | case MPII_EVENT_SAS_TOPO_PS_RC_MISSING: |
| 3542 | if (!(dev = mpii_find_dev(sc, |
| 3543 | le16toh(pe->dev_handle)))) |
| 3544 | break; |
| 3545 | mpii_remove_dev(sc, dev); |
| 3546 | #if 0 |
| 3547 | if (sc->sc_scsibus) { |
| 3548 | SET(dev->flags, MPII_DF_DETACH); |
| 3549 | scsi_activate(sc->sc_scsibus, dev->slot, -1, |
| 3550 | DVACT_DEACTIVATE); |
| 3551 | if (scsi_task(mpii_event_defer, sc, |
| 3552 | dev, 0) != 0) |
| 3553 | printf("%s: unable to run device " |
| 3554 | "detachment routine\n" , |
| 3555 | DEVNAME(sc)); |
| 3556 | } |
| 3557 | #else |
| 3558 | mpii_event_defer(sc, dev); |
| 3559 | #endif /* XXX */ |
| 3560 | break; |
| 3561 | } |
| 3562 | } |
| 3563 | } |
| 3564 | |
| 3565 | static void |
| 3566 | mpii_event_process(struct mpii_softc *sc, struct mpii_rcb *rcb) |
| 3567 | { |
| 3568 | struct mpii_msg_event_reply *enp; |
| 3569 | |
| 3570 | enp = (struct mpii_msg_event_reply *)rcb->rcb_reply; |
| 3571 | |
| 3572 | DNPRINTF(MPII_D_EVT, "%s: mpii_event_process: %#x\n" , DEVNAME(sc), |
| 3573 | le32toh(enp->event)); |
| 3574 | |
| 3575 | switch (le32toh(enp->event)) { |
| 3576 | case MPII_EVENT_EVENT_CHANGE: |
| 3577 | /* should be properly ignored */ |
| 3578 | break; |
| 3579 | case MPII_EVENT_SAS_DISCOVERY: { |
| 3580 | struct mpii_evt_sas_discovery *esd = |
| 3581 | (struct mpii_evt_sas_discovery *)(enp + 1); |
| 3582 | |
| 3583 | if (esd->reason_code == |
| 3584 | MPII_EVENT_SAS_DISC_REASON_CODE_COMPLETED && |
| 3585 | esd->discovery_status != 0) |
| 3586 | printf("%s: sas discovery completed with status %#x\n" , |
| 3587 | DEVNAME(sc), esd->discovery_status); |
| 3588 | } |
| 3589 | break; |
| 3590 | case MPII_EVENT_SAS_TOPOLOGY_CHANGE_LIST: |
| 3591 | mpii_event_sas(sc, enp); |
| 3592 | break; |
| 3593 | case MPII_EVENT_SAS_DEVICE_STATUS_CHANGE: |
| 3594 | break; |
| 3595 | case MPII_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: |
| 3596 | break; |
| 3597 | case MPII_EVENT_IR_VOLUME: { |
| 3598 | struct mpii_evt_ir_volume *evd = |
| 3599 | (struct mpii_evt_ir_volume *)(enp + 1); |
| 3600 | struct mpii_device *dev; |
| 3601 | #if NBIO > 0 |
| 3602 | const char *vol_states[] = { |
| 3603 | BIOC_SVINVALID_S, |
| 3604 | BIOC_SVOFFLINE_S, |
| 3605 | BIOC_SVBUILDING_S, |
| 3606 | BIOC_SVONLINE_S, |
| 3607 | BIOC_SVDEGRADED_S, |
| 3608 | BIOC_SVONLINE_S, |
| 3609 | }; |
| 3610 | #endif |
| 3611 | |
| 3612 | if (cold) |
| 3613 | break; |
| 3614 | if (!(dev = mpii_find_dev(sc, le16toh(evd->vol_dev_handle)))) |
| 3615 | break; |
| 3616 | #if NBIO > 0 |
| 3617 | if (evd->reason_code == MPII_EVENT_IR_VOL_RC_STATE_CHANGED) |
| 3618 | printf("%s: volume %d state changed from %s to %s\n" , |
| 3619 | DEVNAME(sc), dev->slot - sc->sc_vd_id_low, |
| 3620 | vol_states[evd->prev_value], |
| 3621 | vol_states[evd->new_value]); |
| 3622 | #endif |
| 3623 | if (evd->reason_code == MPII_EVENT_IR_VOL_RC_STATUS_CHANGED && |
| 3624 | ISSET(evd->new_value, MPII_CFG_RAID_VOL_0_STATUS_RESYNC) && |
| 3625 | !ISSET(evd->prev_value, MPII_CFG_RAID_VOL_0_STATUS_RESYNC)) |
| 3626 | printf("%s: started resync on a volume %d\n" , |
| 3627 | DEVNAME(sc), dev->slot - sc->sc_vd_id_low); |
| 3628 | } |
| 3629 | break; |
| 3630 | case MPII_EVENT_IR_PHYSICAL_DISK: |
| 3631 | break; |
| 3632 | case MPII_EVENT_IR_CONFIGURATION_CHANGE_LIST: |
| 3633 | mpii_event_raid(sc, enp); |
| 3634 | break; |
| 3635 | case MPII_EVENT_IR_OPERATION_STATUS: { |
| 3636 | struct mpii_evt_ir_status *evs = |
| 3637 | (struct mpii_evt_ir_status *)(enp + 1); |
| 3638 | struct mpii_device *dev; |
| 3639 | |
| 3640 | if (!(dev = mpii_find_dev(sc, le16toh(evs->vol_dev_handle)))) |
| 3641 | break; |
| 3642 | if (evs->operation == MPII_EVENT_IR_RAIDOP_RESYNC) |
| 3643 | dev->percent = evs->percent; |
| 3644 | break; |
| 3645 | } |
| 3646 | default: |
| 3647 | DNPRINTF(MPII_D_EVT, "%s: unhandled event 0x%02x\n" , |
| 3648 | DEVNAME(sc), le32toh(enp->event)); |
| 3649 | } |
| 3650 | |
| 3651 | if (enp->ack_required) |
| 3652 | workqueue_enqueue(sc->sc_ssb_evt_ackwk, &rcb->u.rcb_wk, NULL); |
| 3653 | else |
| 3654 | mpii_push_reply(sc, rcb); |
| 3655 | } |
| 3656 | |
| 3657 | static void |
| 3658 | mpii_event_defer(void *xsc, void *arg) |
| 3659 | { |
| 3660 | struct mpii_softc *sc = xsc; |
| 3661 | struct mpii_device *dev = arg; |
| 3662 | |
| 3663 | if (ISSET(dev->flags, MPII_DF_DETACH)) { |
| 3664 | mpii_sas_remove_device(sc, dev->dev_handle); |
| 3665 | #if 0 |
| 3666 | if (!ISSET(dev->flags, MPII_DF_HIDDEN)) { |
| 3667 | scsi_detach_target(sc->sc_scsibus, dev->slot, |
| 3668 | DETACH_FORCE); |
| 3669 | } |
| 3670 | #endif /* XXX */ |
| 3671 | free(dev, M_DEVBUF); |
| 3672 | |
| 3673 | } else if (ISSET(dev->flags, MPII_DF_ATTACH)) { |
| 3674 | CLR(dev->flags, MPII_DF_ATTACH); |
| 3675 | #if 0 |
| 3676 | if (!ISSET(dev->flags, MPII_DF_HIDDEN)) |
| 3677 | scsi_probe_target(sc->sc_scsibus, dev->slot); |
| 3678 | #endif /* XXX */ |
| 3679 | } |
| 3680 | } |
| 3681 | |
| 3682 | static void |
| 3683 | mpii_sas_remove_device(struct mpii_softc *sc, u_int16_t handle) |
| 3684 | { |
| 3685 | struct mpii_msg_scsi_task_request *stq; |
| 3686 | struct mpii_msg_sas_oper_request *soq; |
| 3687 | struct mpii_ccb *ccb; |
| 3688 | |
| 3689 | ccb = mpii_get_ccb(sc, 0); |
| 3690 | if (ccb == NULL) |
| 3691 | return; |
| 3692 | |
| 3693 | stq = ccb->ccb_cmd; |
| 3694 | stq->function = MPII_FUNCTION_SCSI_TASK_MGMT; |
| 3695 | stq->task_type = MPII_SCSI_TASK_TARGET_RESET; |
| 3696 | stq->dev_handle = htole16(handle); |
| 3697 | |
| 3698 | ccb->ccb_done = mpii_empty_done; |
| 3699 | mpii_wait(sc, ccb); |
| 3700 | |
| 3701 | if (ccb->ccb_rcb != NULL) |
| 3702 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 3703 | |
| 3704 | /* reuse a ccb */ |
| 3705 | ccb->ccb_state = MPII_CCB_READY; |
| 3706 | ccb->ccb_rcb = NULL; |
| 3707 | |
| 3708 | soq = ccb->ccb_cmd; |
| 3709 | bzero(soq, sizeof(*soq)); |
| 3710 | soq->function = MPII_FUNCTION_SAS_IO_UNIT_CONTROL; |
| 3711 | soq->operation = MPII_SAS_OP_REMOVE_DEVICE; |
| 3712 | soq->dev_handle = htole16(handle); |
| 3713 | |
| 3714 | ccb->ccb_done = mpii_empty_done; |
| 3715 | mpii_wait(sc, ccb); |
| 3716 | if (ccb->ccb_rcb != NULL) |
| 3717 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 3718 | } |
| 3719 | |
| 3720 | static int |
| 3721 | mpii_get_ioc_pg8(struct mpii_softc *sc) |
| 3722 | { |
| 3723 | struct mpii_cfg_hdr hdr; |
| 3724 | struct mpii_cfg_ioc_pg8 *page; |
| 3725 | size_t pagelen; |
| 3726 | u_int16_t flags; |
| 3727 | int pad = 0, rv = 0; |
| 3728 | |
| 3729 | DNPRINTF(MPII_D_RAID, "%s: mpii_get_ioc_pg8\n" , DEVNAME(sc)); |
| 3730 | |
| 3731 | if (mpii_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_IOC, 8, 0, |
| 3732 | &hdr) != 0) { |
| 3733 | DNPRINTF(MPII_D_CFG, "%s: mpii_get_ioc_pg8 unable to fetch " |
| 3734 | "header for IOC page 8\n" , DEVNAME(sc)); |
| 3735 | return (1); |
| 3736 | } |
| 3737 | |
| 3738 | pagelen = hdr.page_length * 4; /* dwords to bytes */ |
| 3739 | |
| 3740 | page = malloc(pagelen, M_TEMP, M_NOWAIT); |
| 3741 | if (page == NULL) { |
| 3742 | DNPRINTF(MPII_D_CFG, "%s: mpii_get_ioc_pg8 unable to allocate " |
| 3743 | "space for ioc config page 8\n" , DEVNAME(sc)); |
| 3744 | return (1); |
| 3745 | } |
| 3746 | |
| 3747 | if (mpii_cfg_page(sc, 0, &hdr, 1, page, pagelen) != 0) { |
| 3748 | DNPRINTF(MPII_D_CFG, "%s: mpii_get_raid unable to fetch IOC " |
| 3749 | "page 8\n" , DEVNAME(sc)); |
| 3750 | rv = 1; |
| 3751 | goto out; |
| 3752 | } |
| 3753 | |
| 3754 | DNPRINTF(MPII_D_CFG, "%s: numdevsperenclosure: 0x%02x\n" , DEVNAME(sc), |
| 3755 | page->num_devs_per_enclosure); |
| 3756 | DNPRINTF(MPII_D_CFG, "%s: maxpersistententries: 0x%04x " |
| 3757 | "maxnumphysicalmappedids: 0x%04x\n" , DEVNAME(sc), |
| 3758 | le16toh(page->max_persistent_entries), |
| 3759 | le16toh(page->max_num_physical_mapped_ids)); |
| 3760 | DNPRINTF(MPII_D_CFG, "%s: flags: 0x%04x\n" , DEVNAME(sc), |
| 3761 | le16toh(page->flags)); |
| 3762 | DNPRINTF(MPII_D_CFG, "%s: irvolumemappingflags: 0x%04x\n" , |
| 3763 | DEVNAME(sc), le16toh(page->ir_volume_mapping_flags)); |
| 3764 | |
| 3765 | if (page->flags & MPII_IOC_PG8_FLAGS_RESERVED_TARGETID_0) |
| 3766 | pad = 1; |
| 3767 | |
| 3768 | flags = page->ir_volume_mapping_flags & |
| 3769 | MPII_IOC_PG8_IRFLAGS_VOLUME_MAPPING_MODE_MASK; |
| 3770 | if (ISSET(sc->sc_flags, MPII_F_RAID)) { |
| 3771 | if (flags == MPII_IOC_PG8_IRFLAGS_LOW_VOLUME_MAPPING) { |
| 3772 | sc->sc_vd_id_low += pad; |
| 3773 | pad = sc->sc_max_volumes; /* for sc_pd_id_start */ |
| 3774 | } else |
| 3775 | sc->sc_vd_id_low = sc->sc_max_devices - |
| 3776 | sc->sc_max_volumes; |
| 3777 | } |
| 3778 | |
| 3779 | sc->sc_pd_id_start += pad; |
| 3780 | |
| 3781 | DNPRINTF(MPII_D_MAP, "%s: mpii_get_ioc_pg8 mapping: sc_pd_id_start: %d " |
| 3782 | "sc_vd_id_low: %d sc_max_volumes: %d\n" , DEVNAME(sc), |
| 3783 | sc->sc_pd_id_start, sc->sc_vd_id_low, sc->sc_max_volumes); |
| 3784 | |
| 3785 | out: |
| 3786 | free(page, M_TEMP); |
| 3787 | |
| 3788 | return(rv); |
| 3789 | } |
| 3790 | |
| 3791 | static int |
| 3792 | (struct mpii_softc *sc, u_int8_t type, u_int8_t number, |
| 3793 | u_int32_t address, int flags, void *p) |
| 3794 | { |
| 3795 | struct mpii_msg_config_request *cq; |
| 3796 | struct mpii_msg_config_reply *cp; |
| 3797 | struct mpii_cfg_hdr *hdr = p; |
| 3798 | struct mpii_ccb *ccb; |
| 3799 | struct mpii_ecfg_hdr *ehdr = p; |
| 3800 | int etype = 0; |
| 3801 | int rv = 0; |
| 3802 | |
| 3803 | DNPRINTF(MPII_D_MISC, "%s: mpii_req_cfg_header type: %#x number: %x " |
| 3804 | "address: 0x%08x flags: 0x%x\n" , DEVNAME(sc), type, number, |
| 3805 | address, flags); |
| 3806 | |
| 3807 | ccb = mpii_get_ccb(sc, ISSET(flags, MPII_PG_POLL) ? MPII_NOSLEEP : 0); |
| 3808 | if (ccb == NULL) { |
| 3809 | DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_header ccb_get\n" , |
| 3810 | DEVNAME(sc)); |
| 3811 | return (1); |
| 3812 | } |
| 3813 | |
| 3814 | if (ISSET(flags, MPII_PG_EXTENDED)) { |
| 3815 | etype = type; |
| 3816 | type = MPII_CONFIG_REQ_PAGE_TYPE_EXTENDED; |
| 3817 | } |
| 3818 | |
| 3819 | cq = ccb->ccb_cmd; |
| 3820 | |
| 3821 | cq->function = MPII_FUNCTION_CONFIG; |
| 3822 | |
| 3823 | cq->action = MPII_CONFIG_REQ_ACTION_PAGE_HEADER; |
| 3824 | |
| 3825 | cq->config_header.page_number = number; |
| 3826 | cq->config_header.page_type = type; |
| 3827 | cq->ext_page_type = etype; |
| 3828 | cq->page_address = htole32(address); |
| 3829 | cq->page_buffer.sg_hdr = htole32(MPII_SGE_FL_TYPE_SIMPLE | |
| 3830 | MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL); |
| 3831 | |
| 3832 | ccb->ccb_done = mpii_empty_done; |
| 3833 | if (ISSET(flags, MPII_PG_POLL)) { |
| 3834 | if (mpii_poll(sc, ccb) != 0) { |
| 3835 | DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_header poll\n" , |
| 3836 | DEVNAME(sc)); |
| 3837 | return (1); |
| 3838 | } |
| 3839 | } else |
| 3840 | mpii_wait(sc, ccb); |
| 3841 | |
| 3842 | if (ccb->ccb_rcb == NULL) { |
| 3843 | mpii_put_ccb(sc, ccb); |
| 3844 | return (1); |
| 3845 | } |
| 3846 | cp = ccb->ccb_rcb->rcb_reply; |
| 3847 | |
| 3848 | DNPRINTF(MPII_D_MISC, "%s: action: 0x%02x sgl_flags: 0x%02x " |
| 3849 | "msg_length: %d function: 0x%02x\n" , DEVNAME(sc), cp->action, |
| 3850 | cp->sgl_flags, cp->msg_length, cp->function); |
| 3851 | DNPRINTF(MPII_D_MISC, "%s: ext_page_length: %d ext_page_type: 0x%02x " |
| 3852 | "msg_flags: 0x%02x\n" , DEVNAME(sc), |
| 3853 | le16toh(cp->ext_page_length), cp->ext_page_type, |
| 3854 | cp->msg_flags); |
| 3855 | DNPRINTF(MPII_D_MISC, "%s: vp_id: 0x%02x vf_id: 0x%02x\n" , DEVNAME(sc), |
| 3856 | cp->vp_id, cp->vf_id); |
| 3857 | DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n" , DEVNAME(sc), |
| 3858 | le16toh(cp->ioc_status)); |
| 3859 | DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n" , DEVNAME(sc), |
| 3860 | le32toh(cp->ioc_loginfo)); |
| 3861 | DNPRINTF(MPII_D_MISC, "%s: page_version: 0x%02x page_length: %d " |
| 3862 | "page_number: 0x%02x page_type: 0x%02x\n" , DEVNAME(sc), |
| 3863 | cp->config_header.page_version, |
| 3864 | cp->config_header.page_length, |
| 3865 | cp->config_header.page_number, |
| 3866 | cp->config_header.page_type); |
| 3867 | |
| 3868 | if (le16toh(cp->ioc_status) != MPII_IOCSTATUS_SUCCESS) |
| 3869 | rv = 1; |
| 3870 | else if (ISSET(flags, MPII_PG_EXTENDED)) { |
| 3871 | bzero(ehdr, sizeof(*ehdr)); |
| 3872 | ehdr->page_version = cp->config_header.page_version; |
| 3873 | ehdr->page_number = cp->config_header.page_number; |
| 3874 | ehdr->page_type = cp->config_header.page_type; |
| 3875 | ehdr->ext_page_length = cp->ext_page_length; |
| 3876 | ehdr->ext_page_type = cp->ext_page_type; |
| 3877 | } else |
| 3878 | *hdr = cp->config_header; |
| 3879 | |
| 3880 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 3881 | mpii_put_ccb(sc, ccb); |
| 3882 | |
| 3883 | return (rv); |
| 3884 | } |
| 3885 | |
| 3886 | static int |
| 3887 | mpii_req_cfg_page(struct mpii_softc *sc, u_int32_t address, int flags, |
| 3888 | void *p, int read, void *page, size_t len) |
| 3889 | { |
| 3890 | struct mpii_msg_config_request *cq; |
| 3891 | struct mpii_msg_config_reply *cp; |
| 3892 | struct mpii_cfg_hdr *hdr = p; |
| 3893 | struct mpii_ccb *ccb; |
| 3894 | struct mpii_ecfg_hdr *ehdr = p; |
| 3895 | u_int64_t dva; |
| 3896 | char *kva; |
| 3897 | int page_length; |
| 3898 | int rv = 0; |
| 3899 | |
| 3900 | DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_page address: %d read: %d " |
| 3901 | "type: %x\n" , DEVNAME(sc), address, read, hdr->page_type); |
| 3902 | |
| 3903 | page_length = ISSET(flags, MPII_PG_EXTENDED) ? |
| 3904 | le16toh(ehdr->ext_page_length) : hdr->page_length; |
| 3905 | |
| 3906 | if (len > MPII_REQUEST_SIZE - sizeof(struct mpii_msg_config_request) || |
| 3907 | len < page_length * 4) |
| 3908 | return (1); |
| 3909 | |
| 3910 | ccb = mpii_get_ccb(sc, |
| 3911 | ISSET(flags, MPII_PG_POLL) ? MPII_NOSLEEP : 0); |
| 3912 | if (ccb == NULL) { |
| 3913 | DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_page ccb_get\n" , |
| 3914 | DEVNAME(sc)); |
| 3915 | return (1); |
| 3916 | } |
| 3917 | |
| 3918 | cq = ccb->ccb_cmd; |
| 3919 | |
| 3920 | cq->function = MPII_FUNCTION_CONFIG; |
| 3921 | |
| 3922 | cq->action = (read ? MPII_CONFIG_REQ_ACTION_PAGE_READ_CURRENT : |
| 3923 | MPII_CONFIG_REQ_ACTION_PAGE_WRITE_CURRENT); |
| 3924 | |
| 3925 | if (ISSET(flags, MPII_PG_EXTENDED)) { |
| 3926 | cq->config_header.page_version = ehdr->page_version; |
| 3927 | cq->config_header.page_number = ehdr->page_number; |
| 3928 | cq->config_header.page_type = ehdr->page_type; |
| 3929 | cq->ext_page_len = ehdr->ext_page_length; |
| 3930 | cq->ext_page_type = ehdr->ext_page_type; |
| 3931 | } else |
| 3932 | cq->config_header = *hdr; |
| 3933 | cq->config_header.page_type &= MPII_CONFIG_REQ_PAGE_TYPE_MASK; |
| 3934 | cq->page_address = htole32(address); |
| 3935 | cq->page_buffer.sg_hdr = htole32(MPII_SGE_FL_TYPE_SIMPLE | |
| 3936 | MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL | |
| 3937 | MPII_SGE_FL_SIZE_64 | (page_length * 4) | |
| 3938 | (read ? MPII_SGE_FL_DIR_IN : MPII_SGE_FL_DIR_OUT)); |
| 3939 | |
| 3940 | /* bounce the page via the request space to avoid more bus_dma games */ |
| 3941 | dva = ccb->ccb_cmd_dva + sizeof(struct mpii_msg_config_request); |
| 3942 | |
| 3943 | cq->page_buffer.sg_hi_addr = htole32((u_int32_t)(dva >> 32)); |
| 3944 | cq->page_buffer.sg_lo_addr = htole32((u_int32_t)dva); |
| 3945 | |
| 3946 | kva = ccb->ccb_cmd; |
| 3947 | kva += sizeof(struct mpii_msg_config_request); |
| 3948 | |
| 3949 | if (!read) |
| 3950 | bcopy(page, kva, len); |
| 3951 | |
| 3952 | ccb->ccb_done = mpii_empty_done; |
| 3953 | if (ISSET(flags, MPII_PG_POLL)) { |
| 3954 | if (mpii_poll(sc, ccb) != 0) { |
| 3955 | DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_header poll\n" , |
| 3956 | DEVNAME(sc)); |
| 3957 | return (1); |
| 3958 | } |
| 3959 | } else |
| 3960 | mpii_wait(sc, ccb); |
| 3961 | |
| 3962 | if (ccb->ccb_rcb == NULL) { |
| 3963 | mpii_put_ccb(sc, ccb); |
| 3964 | return (1); |
| 3965 | } |
| 3966 | cp = ccb->ccb_rcb->rcb_reply; |
| 3967 | |
| 3968 | DNPRINTF(MPII_D_MISC, "%s: action: 0x%02x " |
| 3969 | "msg_length: %d function: 0x%02x\n" , DEVNAME(sc), cp->action, |
| 3970 | cp->msg_length, cp->function); |
| 3971 | DNPRINTF(MPII_D_MISC, "%s: ext_page_length: %d ext_page_type: 0x%02x " |
| 3972 | "msg_flags: 0x%02x\n" , DEVNAME(sc), |
| 3973 | le16toh(cp->ext_page_length), cp->ext_page_type, |
| 3974 | cp->msg_flags); |
| 3975 | DNPRINTF(MPII_D_MISC, "%s: vp_id: 0x%02x vf_id: 0x%02x\n" , DEVNAME(sc), |
| 3976 | cp->vp_id, cp->vf_id); |
| 3977 | DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n" , DEVNAME(sc), |
| 3978 | le16toh(cp->ioc_status)); |
| 3979 | DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n" , DEVNAME(sc), |
| 3980 | le32toh(cp->ioc_loginfo)); |
| 3981 | DNPRINTF(MPII_D_MISC, "%s: page_version: 0x%02x page_length: %d " |
| 3982 | "page_number: 0x%02x page_type: 0x%02x\n" , DEVNAME(sc), |
| 3983 | cp->config_header.page_version, |
| 3984 | cp->config_header.page_length, |
| 3985 | cp->config_header.page_number, |
| 3986 | cp->config_header.page_type); |
| 3987 | |
| 3988 | if (le16toh(cp->ioc_status) != MPII_IOCSTATUS_SUCCESS) |
| 3989 | rv = 1; |
| 3990 | else if (read) |
| 3991 | bcopy(kva, page, len); |
| 3992 | |
| 3993 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 3994 | mpii_put_ccb(sc, ccb); |
| 3995 | |
| 3996 | return (rv); |
| 3997 | } |
| 3998 | |
| 3999 | static struct mpii_rcb * |
| 4000 | mpii_reply(struct mpii_softc *sc, struct mpii_reply_descr *rdp) |
| 4001 | { |
| 4002 | struct mpii_rcb *rcb = NULL; |
| 4003 | u_int32_t rfid; |
| 4004 | |
| 4005 | DNPRINTF(MPII_D_INTR, "%s: mpii_reply\n" , DEVNAME(sc)); |
| 4006 | |
| 4007 | if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) == |
| 4008 | MPII_REPLY_DESCR_ADDRESS_REPLY) { |
| 4009 | rfid = (le32toh(rdp->frame_addr) - |
| 4010 | (u_int32_t)MPII_DMA_DVA(sc->sc_replies)) / MPII_REPLY_SIZE; |
| 4011 | |
| 4012 | bus_dmamap_sync(sc->sc_dmat, |
| 4013 | MPII_DMA_MAP(sc->sc_replies), MPII_REPLY_SIZE * rfid, |
| 4014 | MPII_REPLY_SIZE, BUS_DMASYNC_POSTREAD); |
| 4015 | |
| 4016 | rcb = &sc->sc_rcbs[rfid]; |
| 4017 | } |
| 4018 | |
| 4019 | memset(rdp, 0xff, sizeof(*rdp)); |
| 4020 | |
| 4021 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), |
| 4022 | 8 * sc->sc_reply_post_host_index, 8, |
| 4023 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); |
| 4024 | |
| 4025 | return (rcb); |
| 4026 | } |
| 4027 | |
| 4028 | static struct mpii_dmamem * |
| 4029 | mpii_dmamem_alloc(struct mpii_softc *sc, size_t size) |
| 4030 | { |
| 4031 | struct mpii_dmamem *mdm; |
| 4032 | int nsegs; |
| 4033 | |
| 4034 | mdm = malloc(sizeof(*mdm), M_DEVBUF, M_NOWAIT | M_ZERO); |
| 4035 | if (mdm == NULL) |
| 4036 | return (NULL); |
| 4037 | |
| 4038 | mdm->mdm_size = size; |
| 4039 | |
| 4040 | if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, |
| 4041 | BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mdm->mdm_map) != 0) |
| 4042 | goto mdmfree; |
| 4043 | |
| 4044 | if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mdm->mdm_seg, |
| 4045 | 1, &nsegs, BUS_DMA_NOWAIT) != 0) goto destroy; |
| 4046 | |
| 4047 | if (bus_dmamem_map(sc->sc_dmat, &mdm->mdm_seg, nsegs, size, |
| 4048 | &mdm->mdm_kva, BUS_DMA_NOWAIT) != 0) |
| 4049 | goto free; |
| 4050 | |
| 4051 | if (bus_dmamap_load(sc->sc_dmat, mdm->mdm_map, mdm->mdm_kva, size, |
| 4052 | NULL, BUS_DMA_NOWAIT) != 0) |
| 4053 | goto unmap; |
| 4054 | |
| 4055 | DNPRINTF(MPII_D_MEM, |
| 4056 | " kva: %p dva: 0x%" PRIx64 " map: %p size: %" PRId64 "\n" , |
| 4057 | mdm->mdm_kva, (uint64_t)mdm->mdm_map->dm_segs[0].ds_addr, |
| 4058 | mdm->mdm_map, (uint64_t)size); |
| 4059 | |
| 4060 | bzero(mdm->mdm_kva, size); |
| 4061 | |
| 4062 | return (mdm); |
| 4063 | |
| 4064 | unmap: |
| 4065 | bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, size); |
| 4066 | free: |
| 4067 | bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1); |
| 4068 | destroy: |
| 4069 | bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map); |
| 4070 | mdmfree: |
| 4071 | free(mdm, M_DEVBUF); |
| 4072 | |
| 4073 | return (NULL); |
| 4074 | } |
| 4075 | |
| 4076 | static void |
| 4077 | mpii_dmamem_free(struct mpii_softc *sc, struct mpii_dmamem *mdm) |
| 4078 | { |
| 4079 | DNPRINTF(MPII_D_MEM, "%s: mpii_dmamem_free %p\n" , DEVNAME(sc), mdm); |
| 4080 | |
| 4081 | bus_dmamap_unload(sc->sc_dmat, mdm->mdm_map); |
| 4082 | bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, mdm->mdm_size); |
| 4083 | bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1); |
| 4084 | bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map); |
| 4085 | free(mdm, M_DEVBUF); |
| 4086 | } |
| 4087 | |
| 4088 | static int |
| 4089 | mpii_alloc_dev(struct mpii_softc *sc) |
| 4090 | { |
| 4091 | sc->sc_devs = malloc(sc->sc_max_devices * |
| 4092 | sizeof(struct mpii_device *), M_DEVBUF, M_NOWAIT | M_ZERO); |
| 4093 | if (sc->sc_devs == NULL) |
| 4094 | return (1); |
| 4095 | return (0); |
| 4096 | } |
| 4097 | |
| 4098 | static int |
| 4099 | mpii_insert_dev(struct mpii_softc *sc, struct mpii_device *dev) |
| 4100 | { |
| 4101 | int slot = dev->slot; /* initial hint */ |
| 4102 | |
| 4103 | if (!dev || slot < 0) |
| 4104 | return (1); |
| 4105 | while (slot < sc->sc_max_devices && sc->sc_devs[slot] != NULL) |
| 4106 | slot++; |
| 4107 | if (slot >= sc->sc_max_devices) |
| 4108 | return (1); |
| 4109 | dev->slot = slot; |
| 4110 | sc->sc_devs[slot] = dev; |
| 4111 | return (0); |
| 4112 | } |
| 4113 | |
| 4114 | static int |
| 4115 | mpii_remove_dev(struct mpii_softc *sc, struct mpii_device *dev) |
| 4116 | { |
| 4117 | int i; |
| 4118 | |
| 4119 | if (!dev) |
| 4120 | return (1); |
| 4121 | for (i = 0; i < sc->sc_max_devices; i++) |
| 4122 | if (sc->sc_devs[i] && |
| 4123 | sc->sc_devs[i]->dev_handle == dev->dev_handle) { |
| 4124 | sc->sc_devs[i] = NULL; |
| 4125 | return (0); |
| 4126 | } |
| 4127 | return (1); |
| 4128 | } |
| 4129 | |
| 4130 | static struct mpii_device * |
| 4131 | mpii_find_dev(struct mpii_softc *sc, u_int16_t handle) |
| 4132 | { |
| 4133 | int i; |
| 4134 | |
| 4135 | for (i = 0; i < sc->sc_max_devices; i++) |
| 4136 | if (sc->sc_devs[i] && sc->sc_devs[i]->dev_handle == handle) |
| 4137 | return (sc->sc_devs[i]); |
| 4138 | return (NULL); |
| 4139 | } |
| 4140 | |
| 4141 | static int |
| 4142 | mpii_alloc_ccbs(struct mpii_softc *sc) |
| 4143 | { |
| 4144 | struct mpii_ccb *ccb; |
| 4145 | u_int8_t *cmd; |
| 4146 | int i; |
| 4147 | |
| 4148 | SIMPLEQ_INIT(&sc->sc_ccb_free); |
| 4149 | |
| 4150 | sc->sc_ccbs = malloc(sizeof(*ccb) * (sc->sc_request_depth-1), |
| 4151 | M_DEVBUF, M_NOWAIT | M_ZERO); |
| 4152 | if (sc->sc_ccbs == NULL) { |
| 4153 | printf("%s: unable to allocate ccbs\n" , DEVNAME(sc)); |
| 4154 | return (1); |
| 4155 | } |
| 4156 | |
| 4157 | sc->sc_requests = mpii_dmamem_alloc(sc, |
| 4158 | MPII_REQUEST_SIZE * sc->sc_request_depth); |
| 4159 | if (sc->sc_requests == NULL) { |
| 4160 | printf("%s: unable to allocate ccb dmamem\n" , DEVNAME(sc)); |
| 4161 | goto free_ccbs; |
| 4162 | } |
| 4163 | cmd = MPII_DMA_KVA(sc->sc_requests); |
| 4164 | bzero(cmd, MPII_REQUEST_SIZE * sc->sc_request_depth); |
| 4165 | |
| 4166 | /* |
| 4167 | * we have sc->sc_request_depth system request message |
| 4168 | * frames, but smid zero cannot be used. so we then |
| 4169 | * have (sc->sc_request_depth - 1) number of ccbs |
| 4170 | */ |
| 4171 | for (i = 1; i < sc->sc_request_depth; i++) { |
| 4172 | ccb = &sc->sc_ccbs[i - 1]; |
| 4173 | |
| 4174 | if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, |
| 4175 | sc->sc_max_sgl_len, MAXPHYS, 0, |
| 4176 | BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, |
| 4177 | &ccb->ccb_dmamap) != 0) { |
| 4178 | printf("%s: unable to create dma map\n" , DEVNAME(sc)); |
| 4179 | goto free_maps; |
| 4180 | } |
| 4181 | |
| 4182 | ccb->ccb_sc = sc; |
| 4183 | ccb->ccb_smid = i; |
| 4184 | ccb->ccb_offset = MPII_REQUEST_SIZE * i; |
| 4185 | |
| 4186 | ccb->ccb_cmd = &cmd[ccb->ccb_offset]; |
| 4187 | ccb->ccb_cmd_dva = (u_int32_t)MPII_DMA_DVA(sc->sc_requests) + |
| 4188 | ccb->ccb_offset; |
| 4189 | |
| 4190 | DNPRINTF(MPII_D_CCB, "%s: mpii_alloc_ccbs(%d) ccb: %p map: %p " |
| 4191 | "sc: %p smid: %#x offs: %#" PRIx64 " cmd: %#" PRIx64 " dva: %#" PRIx64 "\n" , |
| 4192 | DEVNAME(sc), i, ccb, ccb->ccb_dmamap, ccb->ccb_sc, |
| 4193 | ccb->ccb_smid, (uint64_t)ccb->ccb_offset, |
| 4194 | (uint64_t)ccb->ccb_cmd, (uint64_t)ccb->ccb_cmd_dva); |
| 4195 | |
| 4196 | mpii_put_ccb(sc, ccb); |
| 4197 | } |
| 4198 | |
| 4199 | return (0); |
| 4200 | |
| 4201 | free_maps: |
| 4202 | while ((ccb = mpii_get_ccb(sc, MPII_NOSLEEP)) != NULL) |
| 4203 | bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); |
| 4204 | |
| 4205 | mpii_dmamem_free(sc, sc->sc_requests); |
| 4206 | free_ccbs: |
| 4207 | free(sc->sc_ccbs, M_DEVBUF); |
| 4208 | |
| 4209 | return (1); |
| 4210 | } |
| 4211 | |
| 4212 | static void |
| 4213 | mpii_put_ccb(struct mpii_softc *sc, struct mpii_ccb *ccb) |
| 4214 | { |
| 4215 | KASSERT(ccb->ccb_sc == sc); |
| 4216 | DNPRINTF(MPII_D_CCB, "%s: mpii_put_ccb %p\n" , DEVNAME(sc), ccb); |
| 4217 | |
| 4218 | ccb->ccb_state = MPII_CCB_FREE; |
| 4219 | ccb->ccb_cookie = NULL; |
| 4220 | ccb->ccb_done = NULL; |
| 4221 | ccb->ccb_rcb = NULL; |
| 4222 | bzero(ccb->ccb_cmd, MPII_REQUEST_SIZE); |
| 4223 | |
| 4224 | mutex_enter(&sc->sc_ccb_free_mtx); |
| 4225 | SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, u.ccb_link); |
| 4226 | cv_signal(&sc->sc_ccb_free_cv); |
| 4227 | mutex_exit(&sc->sc_ccb_free_mtx); |
| 4228 | } |
| 4229 | |
| 4230 | static struct mpii_ccb * |
| 4231 | mpii_get_ccb(struct mpii_softc *sc, int flags) |
| 4232 | { |
| 4233 | struct mpii_ccb *ccb; |
| 4234 | |
| 4235 | mutex_enter(&sc->sc_ccb_free_mtx); |
| 4236 | while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) == NULL) { |
| 4237 | if (flags & MPII_NOSLEEP) |
| 4238 | break; |
| 4239 | cv_wait(&sc->sc_ccb_free_cv, &sc->sc_ccb_free_mtx); |
| 4240 | } |
| 4241 | |
| 4242 | if (ccb != NULL) { |
| 4243 | SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, u.ccb_link); |
| 4244 | ccb->ccb_state = MPII_CCB_READY; |
| 4245 | KASSERT(ccb->ccb_sc == sc); |
| 4246 | } |
| 4247 | mutex_exit(&sc->sc_ccb_free_mtx); |
| 4248 | |
| 4249 | DNPRINTF(MPII_D_CCB, "%s: mpii_get_ccb %p\n" , DEVNAME(sc), ccb); |
| 4250 | |
| 4251 | return (ccb); |
| 4252 | } |
| 4253 | |
| 4254 | static int |
| 4255 | mpii_alloc_replies(struct mpii_softc *sc) |
| 4256 | { |
| 4257 | DNPRINTF(MPII_D_MISC, "%s: mpii_alloc_replies\n" , DEVNAME(sc)); |
| 4258 | |
| 4259 | sc->sc_rcbs = malloc(sc->sc_num_reply_frames * sizeof(struct mpii_rcb), |
| 4260 | M_DEVBUF, M_NOWAIT); |
| 4261 | if (sc->sc_rcbs == NULL) |
| 4262 | return (1); |
| 4263 | |
| 4264 | sc->sc_replies = mpii_dmamem_alloc(sc, MPII_REPLY_SIZE * |
| 4265 | sc->sc_num_reply_frames); |
| 4266 | if (sc->sc_replies == NULL) { |
| 4267 | free(sc->sc_rcbs, M_DEVBUF); |
| 4268 | return (1); |
| 4269 | } |
| 4270 | |
| 4271 | return (0); |
| 4272 | } |
| 4273 | |
| 4274 | static void |
| 4275 | mpii_push_replies(struct mpii_softc *sc) |
| 4276 | { |
| 4277 | struct mpii_rcb *rcb; |
| 4278 | char *kva = MPII_DMA_KVA(sc->sc_replies); |
| 4279 | int i; |
| 4280 | |
| 4281 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_replies), |
| 4282 | 0, MPII_REPLY_SIZE * sc->sc_num_reply_frames, BUS_DMASYNC_PREREAD); |
| 4283 | |
| 4284 | for (i = 0; i < sc->sc_num_reply_frames; i++) { |
| 4285 | rcb = &sc->sc_rcbs[i]; |
| 4286 | |
| 4287 | rcb->rcb_reply = kva + MPII_REPLY_SIZE * i; |
| 4288 | rcb->rcb_reply_dva = (u_int32_t)MPII_DMA_DVA(sc->sc_replies) + |
| 4289 | MPII_REPLY_SIZE * i; |
| 4290 | mpii_push_reply(sc, rcb); |
| 4291 | } |
| 4292 | } |
| 4293 | |
| 4294 | static void |
| 4295 | mpii_start(struct mpii_softc *sc, struct mpii_ccb *ccb) |
| 4296 | { |
| 4297 | struct mpii_request_header *rhp; |
| 4298 | struct mpii_request_descr descr; |
| 4299 | u_int32_t *rdp = (u_int32_t *)&descr; |
| 4300 | |
| 4301 | DNPRINTF(MPII_D_RW, "%s: mpii_start %#" PRIx64 "\n" , DEVNAME(sc), |
| 4302 | (uint64_t)ccb->ccb_cmd_dva); |
| 4303 | |
| 4304 | rhp = ccb->ccb_cmd; |
| 4305 | |
| 4306 | bzero(&descr, sizeof(descr)); |
| 4307 | |
| 4308 | switch (rhp->function) { |
| 4309 | case MPII_FUNCTION_SCSI_IO_REQUEST: |
| 4310 | descr.request_flags = MPII_REQ_DESCR_SCSI_IO; |
| 4311 | descr.dev_handle = htole16(ccb->ccb_dev_handle); |
| 4312 | break; |
| 4313 | case MPII_FUNCTION_SCSI_TASK_MGMT: |
| 4314 | descr.request_flags = MPII_REQ_DESCR_HIGH_PRIORITY; |
| 4315 | break; |
| 4316 | default: |
| 4317 | descr.request_flags = MPII_REQ_DESCR_DEFAULT; |
| 4318 | } |
| 4319 | |
| 4320 | descr.vf_id = sc->sc_vf_id; |
| 4321 | descr.smid = htole16(ccb->ccb_smid); |
| 4322 | |
| 4323 | bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_requests), |
| 4324 | ccb->ccb_offset, MPII_REQUEST_SIZE, |
| 4325 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
| 4326 | |
| 4327 | ccb->ccb_state = MPII_CCB_QUEUED; |
| 4328 | |
| 4329 | DNPRINTF(MPII_D_RW, "%s: MPII_REQ_DESCR_POST_LOW (0x%08x) write " |
| 4330 | "0x%08x\n" , DEVNAME(sc), MPII_REQ_DESCR_POST_LOW, *rdp); |
| 4331 | |
| 4332 | DNPRINTF(MPII_D_RW, "%s: MPII_REQ_DESCR_POST_HIGH (0x%08x) write " |
| 4333 | "0x%08x\n" , DEVNAME(sc), MPII_REQ_DESCR_POST_HIGH, *(rdp+1)); |
| 4334 | |
| 4335 | mutex_enter(&sc->sc_req_mtx); |
| 4336 | mpii_write(sc, MPII_REQ_DESCR_POST_LOW, htole32(*rdp)); |
| 4337 | mpii_write(sc, MPII_REQ_DESCR_POST_HIGH, htole32(*(rdp+1))); |
| 4338 | mutex_exit(&sc->sc_req_mtx); |
| 4339 | } |
| 4340 | |
| 4341 | static int |
| 4342 | mpii_poll(struct mpii_softc *sc, struct mpii_ccb *ccb) |
| 4343 | { |
| 4344 | void (*done)(struct mpii_ccb *); |
| 4345 | void *cookie; |
| 4346 | int rv = 1; |
| 4347 | |
| 4348 | DNPRINTF(MPII_D_INTR, "%s: mpii_complete\n" , DEVNAME(sc)); |
| 4349 | |
| 4350 | done = ccb->ccb_done; |
| 4351 | cookie = ccb->ccb_cookie; |
| 4352 | |
| 4353 | ccb->ccb_done = mpii_poll_done; |
| 4354 | ccb->ccb_cookie = &rv; |
| 4355 | |
| 4356 | mpii_start(sc, ccb); |
| 4357 | |
| 4358 | while (rv == 1) { |
| 4359 | /* avoid excessive polling */ |
| 4360 | if (mpii_reply_waiting(sc)) |
| 4361 | mpii_intr(sc); |
| 4362 | else |
| 4363 | delay(10); |
| 4364 | } |
| 4365 | |
| 4366 | ccb->ccb_cookie = cookie; |
| 4367 | done(ccb); |
| 4368 | |
| 4369 | return (0); |
| 4370 | } |
| 4371 | |
| 4372 | static void |
| 4373 | mpii_poll_done(struct mpii_ccb *ccb) |
| 4374 | { |
| 4375 | int *rv = ccb->ccb_cookie; |
| 4376 | |
| 4377 | *rv = 0; |
| 4378 | } |
| 4379 | |
| 4380 | static int |
| 4381 | mpii_alloc_queues(struct mpii_softc *sc) |
| 4382 | { |
| 4383 | u_int32_t *kva; |
| 4384 | u_int64_t *kva64; |
| 4385 | int i; |
| 4386 | |
| 4387 | DNPRINTF(MPII_D_MISC, "%s: mpii_alloc_queues\n" , DEVNAME(sc)); |
| 4388 | |
| 4389 | sc->sc_reply_freeq = mpii_dmamem_alloc(sc, |
| 4390 | sc->sc_reply_free_qdepth * 4); |
| 4391 | if (sc->sc_reply_freeq == NULL) |
| 4392 | return (1); |
| 4393 | |
| 4394 | kva = MPII_DMA_KVA(sc->sc_reply_freeq); |
| 4395 | for (i = 0; i < sc->sc_num_reply_frames; i++) { |
| 4396 | kva[i] = (u_int32_t)MPII_DMA_DVA(sc->sc_replies) + |
| 4397 | MPII_REPLY_SIZE * i; |
| 4398 | |
| 4399 | DNPRINTF(MPII_D_MISC, "%s: %d: %p = 0x%08x\n" , |
| 4400 | DEVNAME(sc), i, |
| 4401 | &kva[i], (u_int)MPII_DMA_DVA(sc->sc_replies) + |
| 4402 | MPII_REPLY_SIZE * i); |
| 4403 | } |
| 4404 | |
| 4405 | sc->sc_reply_postq = |
| 4406 | mpii_dmamem_alloc(sc, sc->sc_reply_post_qdepth * 8); |
| 4407 | if (sc->sc_reply_postq == NULL) |
| 4408 | goto free_reply_freeq; |
| 4409 | sc->sc_reply_postq_kva = MPII_DMA_KVA(sc->sc_reply_postq); |
| 4410 | |
| 4411 | DNPRINTF(MPII_D_MISC, "%s: populating reply post descriptor queue\n" , |
| 4412 | DEVNAME(sc)); |
| 4413 | kva64 = (u_int64_t *)MPII_DMA_KVA(sc->sc_reply_postq); |
| 4414 | for (i = 0; i < sc->sc_reply_post_qdepth; i++) { |
| 4415 | kva64[i] = 0xffffffffffffffffllu; |
| 4416 | DNPRINTF(MPII_D_MISC, "%s: %d: %p = 0x%" PRIx64 "\n" , |
| 4417 | DEVNAME(sc), i, &kva64[i], kva64[i]); |
| 4418 | } |
| 4419 | |
| 4420 | return (0); |
| 4421 | |
| 4422 | free_reply_freeq: |
| 4423 | |
| 4424 | mpii_dmamem_free(sc, sc->sc_reply_freeq); |
| 4425 | return (1); |
| 4426 | } |
| 4427 | |
| 4428 | static void |
| 4429 | mpii_init_queues(struct mpii_softc *sc) |
| 4430 | { |
| 4431 | DNPRINTF(MPII_D_MISC, "%s: mpii_init_queues\n" , DEVNAME(sc)); |
| 4432 | |
| 4433 | sc->sc_reply_free_host_index = sc->sc_reply_free_qdepth - 1; |
| 4434 | sc->sc_reply_post_host_index = 0; |
| 4435 | mpii_write_reply_free(sc, sc->sc_reply_free_host_index); |
| 4436 | mpii_write_reply_post(sc, sc->sc_reply_post_host_index); |
| 4437 | } |
| 4438 | |
| 4439 | static void |
| 4440 | mpii_wait(struct mpii_softc *sc, struct mpii_ccb *ccb) |
| 4441 | { |
| 4442 | struct mpii_ccb_wait mpii_ccb_wait; |
| 4443 | void (*done)(struct mpii_ccb *); |
| 4444 | void *cookie; |
| 4445 | |
| 4446 | done = ccb->ccb_done; |
| 4447 | cookie = ccb->ccb_cookie; |
| 4448 | |
| 4449 | ccb->ccb_done = mpii_wait_done; |
| 4450 | ccb->ccb_cookie = &mpii_ccb_wait; |
| 4451 | |
| 4452 | mutex_init(&mpii_ccb_wait.mpii_ccbw_mtx, MUTEX_DEFAULT, IPL_BIO); |
| 4453 | cv_init(&mpii_ccb_wait.mpii_ccbw_cv, "mpii_wait" ); |
| 4454 | |
| 4455 | /* XXX this will wait forever for the ccb to complete */ |
| 4456 | |
| 4457 | mpii_start(sc, ccb); |
| 4458 | |
| 4459 | mutex_enter(&mpii_ccb_wait.mpii_ccbw_mtx); |
| 4460 | while (ccb->ccb_cookie != NULL) { |
| 4461 | cv_wait(&mpii_ccb_wait.mpii_ccbw_cv, |
| 4462 | &mpii_ccb_wait.mpii_ccbw_mtx); |
| 4463 | } |
| 4464 | mutex_exit(&mpii_ccb_wait.mpii_ccbw_mtx); |
| 4465 | mutex_destroy(&mpii_ccb_wait.mpii_ccbw_mtx); |
| 4466 | cv_destroy(&mpii_ccb_wait.mpii_ccbw_cv); |
| 4467 | |
| 4468 | ccb->ccb_cookie = cookie; |
| 4469 | done(ccb); |
| 4470 | } |
| 4471 | |
| 4472 | static void |
| 4473 | mpii_wait_done(struct mpii_ccb *ccb) |
| 4474 | { |
| 4475 | struct mpii_ccb_wait *mpii_ccb_waitp = ccb->ccb_cookie; |
| 4476 | |
| 4477 | mutex_enter(&mpii_ccb_waitp->mpii_ccbw_mtx); |
| 4478 | ccb->ccb_cookie = NULL; |
| 4479 | cv_signal(&mpii_ccb_waitp->mpii_ccbw_cv); |
| 4480 | mutex_exit(&mpii_ccb_waitp->mpii_ccbw_mtx); |
| 4481 | } |
| 4482 | |
| 4483 | static void |
| 4484 | mpii_minphys(struct buf *bp) |
| 4485 | { |
| 4486 | DNPRINTF(MPII_D_MISC, "mpii_minphys: %d\n" , bp->b_bcount); |
| 4487 | |
| 4488 | /* XXX currently using MPII_MAXFER = MAXPHYS */ |
| 4489 | if (bp->b_bcount > MPII_MAXFER) { |
| 4490 | bp->b_bcount = MPII_MAXFER; |
| 4491 | minphys(bp); |
| 4492 | } |
| 4493 | } |
| 4494 | |
| 4495 | static void |
| 4496 | mpii_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, |
| 4497 | void *arg) |
| 4498 | { |
| 4499 | struct scsipi_periph *periph; |
| 4500 | struct scsipi_xfer *xs; |
| 4501 | struct scsipi_adapter *adapt = chan->chan_adapter; |
| 4502 | struct mpii_softc *sc = device_private(adapt->adapt_dev); |
| 4503 | struct mpii_ccb *ccb; |
| 4504 | struct mpii_ccb_bundle *mcb; |
| 4505 | struct mpii_msg_scsi_io *io; |
| 4506 | struct mpii_device *dev; |
| 4507 | int target; |
| 4508 | int timeout; |
| 4509 | |
| 4510 | DNPRINTF(MPII_D_CMD, "%s: mpii_scsipi_request\n" , DEVNAME(sc)); |
| 4511 | switch (req) { |
| 4512 | case ADAPTER_REQ_GROW_RESOURCES: |
| 4513 | /* Not supported. */ |
| 4514 | return; |
| 4515 | case ADAPTER_REQ_SET_XFER_MODE: |
| 4516 | { |
| 4517 | struct scsipi_xfer_mode *xm = arg; |
| 4518 | xm->xm_mode = PERIPH_CAP_TQING; |
| 4519 | xm->xm_period = 0; |
| 4520 | xm->xm_offset = 0; |
| 4521 | scsipi_async_event(&sc->sc_chan, ASYNC_EVENT_XFER_MODE, xm); |
| 4522 | return; |
| 4523 | } |
| 4524 | case ADAPTER_REQ_RUN_XFER: |
| 4525 | break; |
| 4526 | } |
| 4527 | |
| 4528 | xs = arg; |
| 4529 | periph = xs->xs_periph; |
| 4530 | target = periph->periph_target; |
| 4531 | |
| 4532 | if (xs->cmdlen > MPII_CDB_LEN) { |
| 4533 | DNPRINTF(MPII_D_CMD, "%s: CBD too big %d\n" , |
| 4534 | DEVNAME(sc), xs->cmdlen); |
| 4535 | bzero(&xs->sense, sizeof(xs->sense)); |
| 4536 | xs->sense.scsi_sense.response_code = |
| 4537 | SSD_RCODE_VALID | SSD_RCODE_CURRENT; |
| 4538 | xs->sense.scsi_sense.flags = SKEY_ILLEGAL_REQUEST; |
| 4539 | xs->sense.scsi_sense.asc = 0x20; |
| 4540 | xs->error = XS_SENSE; |
| 4541 | scsipi_done(xs); |
| 4542 | return; |
| 4543 | } |
| 4544 | |
| 4545 | if ((dev = sc->sc_devs[target]) == NULL) { |
| 4546 | /* device no longer exists */ |
| 4547 | xs->error = XS_SELTIMEOUT; |
| 4548 | scsipi_done(xs); |
| 4549 | return; |
| 4550 | } |
| 4551 | |
| 4552 | ccb = mpii_get_ccb(sc, MPII_NOSLEEP); |
| 4553 | if (ccb == NULL) { |
| 4554 | xs->error = XS_RESOURCE_SHORTAGE; |
| 4555 | scsipi_done(xs); |
| 4556 | return; |
| 4557 | } |
| 4558 | |
| 4559 | DNPRINTF(MPII_D_CMD, "%s: ccb_smid: %d xs->xs_control: 0x%x\n" , |
| 4560 | DEVNAME(sc), ccb->ccb_smid, xs->xs_control); |
| 4561 | |
| 4562 | ccb->ccb_cookie = xs; |
| 4563 | ccb->ccb_done = mpii_scsi_cmd_done; |
| 4564 | ccb->ccb_dev_handle = dev->dev_handle; |
| 4565 | |
| 4566 | mcb = ccb->ccb_cmd; |
| 4567 | io = &mcb->mcb_io; |
| 4568 | |
| 4569 | io->function = MPII_FUNCTION_SCSI_IO_REQUEST; |
| 4570 | io->sense_buffer_length = sizeof(xs->sense); |
| 4571 | io->sgl_offset0 = 24; /* XXX fix this */ |
| 4572 | io->io_flags = htole16(xs->cmdlen); |
| 4573 | io->dev_handle = htole16(ccb->ccb_dev_handle); |
| 4574 | io->lun[0] = htobe16(periph->periph_lun); |
| 4575 | |
| 4576 | switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { |
| 4577 | case XS_CTL_DATA_IN: |
| 4578 | io->direction = MPII_SCSIIO_DIR_READ; |
| 4579 | break; |
| 4580 | case XS_CTL_DATA_OUT: |
| 4581 | io->direction = MPII_SCSIIO_DIR_WRITE; |
| 4582 | break; |
| 4583 | default: |
| 4584 | io->direction = MPII_SCSIIO_DIR_NONE; |
| 4585 | } |
| 4586 | |
| 4587 | io->tagging = MPII_SCSIIO_ATTR_SIMPLE_Q; |
| 4588 | |
| 4589 | memcpy(io->cdb, xs->cmd, xs->cmdlen); |
| 4590 | |
| 4591 | io->data_length = htole32(xs->datalen); |
| 4592 | |
| 4593 | io->sense_buffer_low_address = htole32(ccb->ccb_cmd_dva + |
| 4594 | ((u_int8_t *)&mcb->mcb_sense - (u_int8_t *)mcb)); |
| 4595 | |
| 4596 | if (mpii_load_xs(ccb) != 0) { |
| 4597 | xs->error = XS_DRIVER_STUFFUP; |
| 4598 | mpii_put_ccb(sc, ccb); |
| 4599 | scsipi_done(xs); |
| 4600 | return; |
| 4601 | } |
| 4602 | |
| 4603 | DNPRINTF(MPII_D_CMD, "%s: sizeof(mpii_msg_scsi_io): %ld " |
| 4604 | "sizeof(mpii_ccb_bundle): %ld sge offset: 0x%02lx\n" , |
| 4605 | DEVNAME(sc), sizeof(struct mpii_msg_scsi_io), |
| 4606 | sizeof(struct mpii_ccb_bundle), |
| 4607 | (u_int8_t *)&mcb->mcb_sgl[0] - (u_int8_t *)mcb); |
| 4608 | |
| 4609 | DNPRINTF(MPII_D_CMD, "%s sgl[0]: 0x%04x 0%04x 0x%04x\n" , |
| 4610 | DEVNAME(sc), mcb->mcb_sgl[0].sg_hdr, mcb->mcb_sgl[0].sg_lo_addr, |
| 4611 | mcb->mcb_sgl[0].sg_hi_addr); |
| 4612 | |
| 4613 | DNPRINTF(MPII_D_CMD, "%s: Offset0: 0x%02x\n" , DEVNAME(sc), |
| 4614 | io->sgl_offset0); |
| 4615 | |
| 4616 | if (xs->xs_control & XS_CTL_POLL) { |
| 4617 | if (mpii_poll(sc, ccb) != 0) { |
| 4618 | xs->error = XS_DRIVER_STUFFUP; |
| 4619 | mpii_put_ccb(sc, ccb); |
| 4620 | scsipi_done(xs); |
| 4621 | } |
| 4622 | return; |
| 4623 | } |
| 4624 | timeout = mstohz(xs->timeout); |
| 4625 | if (timeout == 0) |
| 4626 | timeout = 1; |
| 4627 | callout_reset(&xs->xs_callout, timeout, mpii_scsi_cmd_tmo, ccb); |
| 4628 | |
| 4629 | DNPRINTF(MPII_D_CMD, "%s: mpii_scsipi_request(): opcode: %02x " |
| 4630 | "datalen: %d\n" , DEVNAME(sc), xs->cmd->opcode, xs->datalen); |
| 4631 | |
| 4632 | mpii_start(sc, ccb); |
| 4633 | } |
| 4634 | |
| 4635 | static void |
| 4636 | mpii_scsi_cmd_tmo(void *xccb) |
| 4637 | { |
| 4638 | struct mpii_ccb *ccb = xccb; |
| 4639 | struct mpii_softc *sc = ccb->ccb_sc; |
| 4640 | |
| 4641 | printf("%s: mpii_scsi_cmd_tmo\n" , DEVNAME(sc)); |
| 4642 | |
| 4643 | mutex_enter(&sc->sc_ccb_mtx); |
| 4644 | if (ccb->ccb_state == MPII_CCB_QUEUED) { |
| 4645 | ccb->ccb_state = MPII_CCB_TIMEOUT; |
| 4646 | workqueue_enqueue(sc->sc_ssb_tmowk, &ccb->u.ccb_wk, NULL); |
| 4647 | } |
| 4648 | mutex_exit(&sc->sc_ccb_mtx); |
| 4649 | } |
| 4650 | |
| 4651 | static void |
| 4652 | mpii_scsi_cmd_tmo_handler(struct work *wk, void *cookie) |
| 4653 | { |
| 4654 | struct mpii_softc *sc = cookie; |
| 4655 | struct mpii_ccb *tccb; |
| 4656 | struct mpii_ccb *ccb; |
| 4657 | struct mpii_msg_scsi_task_request *stq; |
| 4658 | |
| 4659 | ccb = (void *)wk; |
| 4660 | tccb = mpii_get_ccb(sc, 0); |
| 4661 | |
| 4662 | mutex_enter(&sc->sc_ccb_mtx); |
| 4663 | if (ccb->ccb_state != MPII_CCB_TIMEOUT) { |
| 4664 | mpii_put_ccb(sc, tccb); |
| 4665 | } |
| 4666 | /* should remove any other ccbs for the same dev handle */ |
| 4667 | mutex_exit(&sc->sc_ccb_mtx); |
| 4668 | |
| 4669 | stq = tccb->ccb_cmd; |
| 4670 | stq->function = MPII_FUNCTION_SCSI_TASK_MGMT; |
| 4671 | stq->task_type = MPII_SCSI_TASK_TARGET_RESET; |
| 4672 | stq->dev_handle = htole16(ccb->ccb_dev_handle); |
| 4673 | |
| 4674 | tccb->ccb_done = mpii_scsi_cmd_tmo_done; |
| 4675 | mpii_start(sc, tccb); |
| 4676 | } |
| 4677 | |
| 4678 | static void |
| 4679 | mpii_scsi_cmd_tmo_done(struct mpii_ccb *tccb) |
| 4680 | { |
| 4681 | mpii_put_ccb(tccb->ccb_sc, tccb); |
| 4682 | } |
| 4683 | |
| 4684 | static u_int8_t |
| 4685 | map_scsi_status(u_int8_t mpii_scsi_status) |
| 4686 | { |
| 4687 | u_int8_t scsi_status; |
| 4688 | |
| 4689 | switch (mpii_scsi_status) |
| 4690 | { |
| 4691 | case MPII_SCSIIO_ERR_STATUS_SUCCESS: |
| 4692 | scsi_status = SCSI_OK; |
| 4693 | break; |
| 4694 | |
| 4695 | case MPII_SCSIIO_ERR_STATUS_CHECK_COND: |
| 4696 | scsi_status = SCSI_CHECK; |
| 4697 | break; |
| 4698 | |
| 4699 | case MPII_SCSIIO_ERR_STATUS_BUSY: |
| 4700 | scsi_status = SCSI_BUSY; |
| 4701 | break; |
| 4702 | |
| 4703 | case MPII_SCSIIO_ERR_STATUS_INTERMEDIATE: |
| 4704 | scsi_status = SCSI_INTERM; |
| 4705 | break; |
| 4706 | |
| 4707 | case MPII_SCSIIO_ERR_STATUS_INTERMEDIATE_CONDMET: |
| 4708 | scsi_status = SCSI_INTERM; |
| 4709 | break; |
| 4710 | |
| 4711 | case MPII_SCSIIO_ERR_STATUS_RESERVATION_CONFLICT: |
| 4712 | scsi_status = SCSI_RESV_CONFLICT; |
| 4713 | break; |
| 4714 | |
| 4715 | case MPII_SCSIIO_ERR_STATUS_CMD_TERM: |
| 4716 | case MPII_SCSIIO_ERR_STATUS_TASK_ABORTED: |
| 4717 | scsi_status = SCSI_TERMINATED; |
| 4718 | break; |
| 4719 | |
| 4720 | case MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL: |
| 4721 | scsi_status = SCSI_QUEUE_FULL; |
| 4722 | break; |
| 4723 | |
| 4724 | case MPII_SCSIIO_ERR_STATUS_ACA_ACTIVE: |
| 4725 | scsi_status = SCSI_ACA_ACTIVE; |
| 4726 | break; |
| 4727 | |
| 4728 | default: |
| 4729 | /* XXX: for the lack of anything better and other than OK */ |
| 4730 | scsi_status = 0xFF; |
| 4731 | break; |
| 4732 | } |
| 4733 | |
| 4734 | return scsi_status; |
| 4735 | } |
| 4736 | |
| 4737 | static void |
| 4738 | mpii_scsi_cmd_done(struct mpii_ccb *ccb) |
| 4739 | { |
| 4740 | struct mpii_msg_scsi_io_error *sie; |
| 4741 | struct mpii_softc *sc = ccb->ccb_sc; |
| 4742 | struct scsipi_xfer *xs = ccb->ccb_cookie; |
| 4743 | struct mpii_ccb_bundle *mcb = ccb->ccb_cmd; |
| 4744 | bus_dmamap_t dmap = ccb->ccb_dmamap; |
| 4745 | bool timeout = 0; |
| 4746 | |
| 4747 | callout_stop(&xs->xs_callout); |
| 4748 | mutex_enter(&sc->sc_ccb_mtx); |
| 4749 | if (ccb->ccb_state == MPII_CCB_TIMEOUT) |
| 4750 | timeout = 1; |
| 4751 | ccb->ccb_state = MPII_CCB_READY; |
| 4752 | mutex_exit(&sc->sc_ccb_mtx); |
| 4753 | |
| 4754 | if (xs->datalen != 0) { |
| 4755 | bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, |
| 4756 | (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_POSTREAD : |
| 4757 | BUS_DMASYNC_POSTWRITE); |
| 4758 | |
| 4759 | bus_dmamap_unload(sc->sc_dmat, dmap); |
| 4760 | } |
| 4761 | |
| 4762 | xs->error = XS_NOERROR; |
| 4763 | xs->resid = 0; |
| 4764 | |
| 4765 | if (ccb->ccb_rcb == NULL) { |
| 4766 | /* no scsi error, we're ok so drop out early */ |
| 4767 | xs->status = SCSI_OK; |
| 4768 | mpii_put_ccb(sc, ccb); |
| 4769 | scsipi_done(xs); |
| 4770 | return; |
| 4771 | } |
| 4772 | |
| 4773 | sie = ccb->ccb_rcb->rcb_reply; |
| 4774 | |
| 4775 | DNPRINTF(MPII_D_CMD, "%s: mpii_scsi_cmd_done xs cmd: 0x%02x len: %d " |
| 4776 | "xs_control 0x%x\n" , DEVNAME(sc), xs->cmd->opcode, xs->datalen, |
| 4777 | xs->xs_control); |
| 4778 | DNPRINTF(MPII_D_CMD, "%s: dev_handle: %d msg_length: %d " |
| 4779 | "function: 0x%02x\n" , DEVNAME(sc), le16toh(sie->dev_handle), |
| 4780 | sie->msg_length, sie->function); |
| 4781 | DNPRINTF(MPII_D_CMD, "%s: vp_id: 0x%02x vf_id: 0x%02x\n" , DEVNAME(sc), |
| 4782 | sie->vp_id, sie->vf_id); |
| 4783 | DNPRINTF(MPII_D_CMD, "%s: scsi_status: 0x%02x scsi_state: 0x%02x " |
| 4784 | "ioc_status: 0x%04x\n" , DEVNAME(sc), sie->scsi_status, |
| 4785 | sie->scsi_state, le16toh(sie->ioc_status)); |
| 4786 | DNPRINTF(MPII_D_CMD, "%s: ioc_loginfo: 0x%08x\n" , DEVNAME(sc), |
| 4787 | le32toh(sie->ioc_loginfo)); |
| 4788 | DNPRINTF(MPII_D_CMD, "%s: transfer_count: %d\n" , DEVNAME(sc), |
| 4789 | le32toh(sie->transfer_count)); |
| 4790 | DNPRINTF(MPII_D_CMD, "%s: sense_count: %d\n" , DEVNAME(sc), |
| 4791 | le32toh(sie->sense_count)); |
| 4792 | DNPRINTF(MPII_D_CMD, "%s: response_info: 0x%08x\n" , DEVNAME(sc), |
| 4793 | le32toh(sie->response_info)); |
| 4794 | DNPRINTF(MPII_D_CMD, "%s: task_tag: 0x%04x\n" , DEVNAME(sc), |
| 4795 | le16toh(sie->task_tag)); |
| 4796 | DNPRINTF(MPII_D_CMD, "%s: bidirectional_transfer_count: 0x%08x\n" , |
| 4797 | DEVNAME(sc), le32toh(sie->bidirectional_transfer_count)); |
| 4798 | |
| 4799 | xs->status = map_scsi_status(sie->scsi_status); |
| 4800 | |
| 4801 | switch (le16toh(sie->ioc_status) & MPII_IOCSTATUS_MASK) { |
| 4802 | case MPII_IOCSTATUS_SCSI_DATA_UNDERRUN: |
| 4803 | switch (sie->scsi_status) { |
| 4804 | case MPII_SCSIIO_ERR_STATUS_CHECK_COND: |
| 4805 | xs->error = XS_SENSE; |
| 4806 | /*FALLTHROUGH*/ |
| 4807 | case MPII_SCSIIO_ERR_STATUS_SUCCESS: |
| 4808 | xs->resid = xs->datalen - le32toh(sie->transfer_count); |
| 4809 | break; |
| 4810 | |
| 4811 | default: |
| 4812 | xs->error = XS_DRIVER_STUFFUP; |
| 4813 | break; |
| 4814 | } |
| 4815 | break; |
| 4816 | |
| 4817 | case MPII_IOCSTATUS_SUCCESS: |
| 4818 | case MPII_IOCSTATUS_SCSI_RECOVERED_ERROR: |
| 4819 | switch (sie->scsi_status) { |
| 4820 | case MPII_SCSIIO_ERR_STATUS_SUCCESS: |
| 4821 | /* |
| 4822 | * xs->resid = 0; - already set above |
| 4823 | * |
| 4824 | * XXX: check whether UNDERUN strategy |
| 4825 | * would be appropriate here too. |
| 4826 | * that would allow joining these cases. |
| 4827 | */ |
| 4828 | break; |
| 4829 | |
| 4830 | case MPII_SCSIIO_ERR_STATUS_CHECK_COND: |
| 4831 | xs->error = XS_SENSE; |
| 4832 | break; |
| 4833 | |
| 4834 | case MPII_SCSIIO_ERR_STATUS_BUSY: |
| 4835 | case MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL: |
| 4836 | xs->error = XS_BUSY; |
| 4837 | break; |
| 4838 | |
| 4839 | default: |
| 4840 | xs->error = XS_DRIVER_STUFFUP; |
| 4841 | } |
| 4842 | break; |
| 4843 | |
| 4844 | case MPII_IOCSTATUS_BUSY: |
| 4845 | case MPII_IOCSTATUS_INSUFFICIENT_RESOURCES: |
| 4846 | xs->error = XS_BUSY; |
| 4847 | break; |
| 4848 | |
| 4849 | case MPII_IOCSTATUS_SCSI_IOC_TERMINATED: |
| 4850 | case MPII_IOCSTATUS_SCSI_TASK_TERMINATED: |
| 4851 | xs->error = timeout ? XS_TIMEOUT : XS_RESET; |
| 4852 | break; |
| 4853 | |
| 4854 | case MPII_IOCSTATUS_SCSI_INVALID_DEVHANDLE: |
| 4855 | case MPII_IOCSTATUS_SCSI_DEVICE_NOT_THERE: |
| 4856 | xs->error = XS_SELTIMEOUT; |
| 4857 | break; |
| 4858 | |
| 4859 | default: |
| 4860 | xs->error = XS_DRIVER_STUFFUP; |
| 4861 | break; |
| 4862 | } |
| 4863 | |
| 4864 | if (sie->scsi_state & MPII_SCSIIO_ERR_STATE_AUTOSENSE_VALID) |
| 4865 | memcpy(&xs->sense, &mcb->mcb_sense, sizeof(xs->sense)); |
| 4866 | |
| 4867 | DNPRINTF(MPII_D_CMD, "%s: xs err: %d status: %#x\n" , DEVNAME(sc), |
| 4868 | xs->error, xs->status); |
| 4869 | |
| 4870 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 4871 | mpii_put_ccb(sc, ccb); |
| 4872 | scsipi_done(xs); |
| 4873 | } |
| 4874 | |
| 4875 | #if 0 |
| 4876 | static int |
| 4877 | mpii_ioctl_cache(struct scsi_link *link, u_long cmd, struct dk_cache *dc) |
| 4878 | { |
| 4879 | struct mpii_softc *sc = (struct mpii_softc *)link->adapter_softc; |
| 4880 | struct mpii_device *dev = sc->sc_devs[link->target]; |
| 4881 | struct mpii_cfg_raid_vol_pg0 *vpg; |
| 4882 | struct mpii_msg_raid_action_request *req; |
| 4883 | struct mpii_msg_raid_action_reply *rep; |
| 4884 | struct mpii_cfg_hdr hdr; |
| 4885 | struct mpii_ccb *ccb; |
| 4886 | u_int32_t addr = MPII_CFG_RAID_VOL_ADDR_HANDLE | dev->dev_handle; |
| 4887 | size_t pagelen; |
| 4888 | int rv = 0; |
| 4889 | int enabled; |
| 4890 | |
| 4891 | if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, |
| 4892 | addr, MPII_PG_POLL, &hdr) != 0) |
| 4893 | return (EINVAL); |
| 4894 | |
| 4895 | pagelen = hdr.page_length * 4; |
| 4896 | vpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); |
| 4897 | if (vpg == NULL) |
| 4898 | return (ENOMEM); |
| 4899 | |
| 4900 | if (mpii_req_cfg_page(sc, addr, MPII_PG_POLL, &hdr, 1, |
| 4901 | vpg, pagelen) != 0) { |
| 4902 | rv = EINVAL; |
| 4903 | goto done; |
| 4904 | } |
| 4905 | |
| 4906 | enabled = ((le16toh(vpg->volume_settings) & |
| 4907 | MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_MASK) == |
| 4908 | MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_ENABLED) ? 1 : 0; |
| 4909 | |
| 4910 | if (cmd == DIOCGCACHE) { |
| 4911 | dc->wrcache = enabled; |
| 4912 | dc->rdcache = 0; |
| 4913 | goto done; |
| 4914 | } /* else DIOCSCACHE */ |
| 4915 | |
| 4916 | if (dc->rdcache) { |
| 4917 | rv = EOPNOTSUPP; |
| 4918 | goto done; |
| 4919 | } |
| 4920 | |
| 4921 | if (((dc->wrcache) ? 1 : 0) == enabled) |
| 4922 | goto done; |
| 4923 | |
| 4924 | ccb = mpii_get_ccb(sc, MPII_NOSLEEP); |
| 4925 | if (ccb == NULL) { |
| 4926 | rv = ENOMEM; |
| 4927 | goto done; |
| 4928 | } |
| 4929 | |
| 4930 | ccb->ccb_done = mpii_empty_done; |
| 4931 | |
| 4932 | req = ccb->ccb_cmd; |
| 4933 | bzero(req, sizeof(*req)); |
| 4934 | req->function = MPII_FUNCTION_RAID_ACTION; |
| 4935 | req->action = MPII_RAID_ACTION_CHANGE_VOL_WRITE_CACHE; |
| 4936 | req->vol_dev_handle = htole16(dev->dev_handle); |
| 4937 | req->action_data = htole32(dc->wrcache ? |
| 4938 | MPII_RAID_VOL_WRITE_CACHE_ENABLE : |
| 4939 | MPII_RAID_VOL_WRITE_CACHE_DISABLE); |
| 4940 | |
| 4941 | if (mpii_poll(sc, ccb) != 0) { |
| 4942 | rv = EIO; |
| 4943 | goto done; |
| 4944 | } |
| 4945 | |
| 4946 | if (ccb->ccb_rcb != NULL) { |
| 4947 | rep = ccb->ccb_rcb->rcb_reply; |
| 4948 | if ((rep->ioc_status != MPII_IOCSTATUS_SUCCESS) || |
| 4949 | ((rep->action_data[0] & |
| 4950 | MPII_RAID_VOL_WRITE_CACHE_MASK) != |
| 4951 | (dc->wrcache ? MPII_RAID_VOL_WRITE_CACHE_ENABLE : |
| 4952 | MPII_RAID_VOL_WRITE_CACHE_DISABLE))) |
| 4953 | rv = EINVAL; |
| 4954 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 4955 | } |
| 4956 | |
| 4957 | mpii_put_ccb(sc, ccb); |
| 4958 | |
| 4959 | done: |
| 4960 | free(vpg, M_TEMP); |
| 4961 | return (rv); |
| 4962 | } |
| 4963 | #endif |
| 4964 | static int |
| 4965 | mpii_cache_enable(struct mpii_softc *sc, struct mpii_device *dev) |
| 4966 | { |
| 4967 | struct mpii_cfg_raid_vol_pg0 *vpg; |
| 4968 | struct mpii_msg_raid_action_request *req; |
| 4969 | struct mpii_msg_raid_action_reply *rep; |
| 4970 | struct mpii_cfg_hdr hdr; |
| 4971 | struct mpii_ccb *ccb; |
| 4972 | u_int32_t addr = MPII_CFG_RAID_VOL_ADDR_HANDLE | dev->dev_handle; |
| 4973 | size_t pagelen; |
| 4974 | int rv = 0; |
| 4975 | int enabled; |
| 4976 | |
| 4977 | if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, |
| 4978 | addr, MPII_PG_POLL, &hdr) != 0) |
| 4979 | return (EINVAL); |
| 4980 | |
| 4981 | pagelen = hdr.page_length * 4; |
| 4982 | vpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); |
| 4983 | if (vpg == NULL) |
| 4984 | return (ENOMEM); |
| 4985 | |
| 4986 | if (mpii_req_cfg_page(sc, addr, MPII_PG_POLL, &hdr, 1, |
| 4987 | vpg, pagelen) != 0) { |
| 4988 | rv = EINVAL; |
| 4989 | goto done; |
| 4990 | free(vpg, M_TEMP); |
| 4991 | return (EINVAL); |
| 4992 | } |
| 4993 | |
| 4994 | enabled = ((le16toh(vpg->volume_settings) & |
| 4995 | MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_MASK) == |
| 4996 | MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_ENABLED) ? 1 : 0; |
| 4997 | aprint_normal_dev(sc->sc_dev, "target %d cache %s" , dev->slot, |
| 4998 | enabled ? "enabled" : "disabled, enabling" ); |
| 4999 | aprint_normal("\n" ); |
| 5000 | |
| 5001 | if (enabled == 0) |
| 5002 | goto done; |
| 5003 | |
| 5004 | ccb = mpii_get_ccb(sc, MPII_NOSLEEP); |
| 5005 | if (ccb == NULL) { |
| 5006 | rv = ENOMEM; |
| 5007 | goto done; |
| 5008 | } |
| 5009 | |
| 5010 | ccb->ccb_done = mpii_empty_done; |
| 5011 | |
| 5012 | req = ccb->ccb_cmd; |
| 5013 | bzero(req, sizeof(*req)); |
| 5014 | req->function = MPII_FUNCTION_RAID_ACTION; |
| 5015 | req->action = MPII_RAID_ACTION_CHANGE_VOL_WRITE_CACHE; |
| 5016 | req->vol_dev_handle = htole16(dev->dev_handle); |
| 5017 | req->action_data = htole32( |
| 5018 | MPII_RAID_VOL_WRITE_CACHE_ENABLE); |
| 5019 | |
| 5020 | if (mpii_poll(sc, ccb) != 0) { |
| 5021 | rv = EIO; |
| 5022 | goto done; |
| 5023 | } |
| 5024 | |
| 5025 | if (ccb->ccb_rcb != NULL) { |
| 5026 | rep = ccb->ccb_rcb->rcb_reply; |
| 5027 | if ((rep->ioc_status != MPII_IOCSTATUS_SUCCESS) || |
| 5028 | ((rep->action_data[0] & |
| 5029 | MPII_RAID_VOL_WRITE_CACHE_MASK) != |
| 5030 | MPII_RAID_VOL_WRITE_CACHE_ENABLE)) |
| 5031 | rv = EINVAL; |
| 5032 | mpii_push_reply(sc, ccb->ccb_rcb); |
| 5033 | } |
| 5034 | |
| 5035 | mpii_put_ccb(sc, ccb); |
| 5036 | |
| 5037 | done: |
| 5038 | free(vpg, M_TEMP); |
| 5039 | if (rv) { |
| 5040 | aprint_error_dev(sc->sc_dev, |
| 5041 | "enabling cache on target %d failed (%d)\n" , |
| 5042 | dev->slot, rv); |
| 5043 | } |
| 5044 | return (rv); |
| 5045 | } |
| 5046 | |
| 5047 | #if NBIO > 0 |
| 5048 | static int |
| 5049 | mpii_ioctl(device_t dev, u_long cmd, void *addr) |
| 5050 | { |
| 5051 | struct mpii_softc *sc = device_private(dev); |
| 5052 | int s, error = 0; |
| 5053 | |
| 5054 | DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl " , DEVNAME(sc)); |
| 5055 | KERNEL_LOCK(1, curlwp); |
| 5056 | s = splbio(); |
| 5057 | |
| 5058 | switch (cmd) { |
| 5059 | case BIOCINQ: |
| 5060 | DNPRINTF(MPII_D_IOCTL, "inq\n" ); |
| 5061 | error = mpii_ioctl_inq(sc, (struct bioc_inq *)addr); |
| 5062 | break; |
| 5063 | case BIOCVOL: |
| 5064 | DNPRINTF(MPII_D_IOCTL, "vol\n" ); |
| 5065 | error = mpii_ioctl_vol(sc, (struct bioc_vol *)addr); |
| 5066 | break; |
| 5067 | case BIOCDISK: |
| 5068 | DNPRINTF(MPII_D_IOCTL, "disk\n" ); |
| 5069 | error = mpii_ioctl_disk(sc, (struct bioc_disk *)addr); |
| 5070 | break; |
| 5071 | default: |
| 5072 | DNPRINTF(MPII_D_IOCTL, " invalid ioctl\n" ); |
| 5073 | error = EINVAL; |
| 5074 | } |
| 5075 | |
| 5076 | splx(s); |
| 5077 | KERNEL_UNLOCK_ONE(curlwp); |
| 5078 | return (error); |
| 5079 | } |
| 5080 | |
| 5081 | static int |
| 5082 | mpii_ioctl_inq(struct mpii_softc *sc, struct bioc_inq *bi) |
| 5083 | { |
| 5084 | int i; |
| 5085 | |
| 5086 | DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl_inq\n" , DEVNAME(sc)); |
| 5087 | |
| 5088 | strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); |
| 5089 | for (i = 0; i < sc->sc_max_devices; i++) |
| 5090 | if (sc->sc_devs[i] && |
| 5091 | ISSET(sc->sc_devs[i]->flags, MPII_DF_VOLUME)) |
| 5092 | bi->bi_novol++; |
| 5093 | return (0); |
| 5094 | } |
| 5095 | |
| 5096 | static int |
| 5097 | mpii_ioctl_vol(struct mpii_softc *sc, struct bioc_vol *bv) |
| 5098 | { |
| 5099 | struct mpii_cfg_raid_vol_pg0 *vpg; |
| 5100 | struct mpii_cfg_hdr hdr; |
| 5101 | struct mpii_device *dev; |
| 5102 | struct scsipi_periph *periph; |
| 5103 | size_t pagelen; |
| 5104 | u_int16_t volh; |
| 5105 | int rv, hcnt = 0; |
| 5106 | |
| 5107 | DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl_vol %d\n" , |
| 5108 | DEVNAME(sc), bv->bv_volid); |
| 5109 | |
| 5110 | if ((dev = mpii_find_vol(sc, bv->bv_volid)) == NULL) |
| 5111 | return (ENODEV); |
| 5112 | volh = dev->dev_handle; |
| 5113 | |
| 5114 | if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, |
| 5115 | MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, &hdr) != 0) { |
| 5116 | printf("%s: unable to fetch header for raid volume page 0\n" , |
| 5117 | DEVNAME(sc)); |
| 5118 | return (EINVAL); |
| 5119 | } |
| 5120 | |
| 5121 | pagelen = hdr.page_length * 4; |
| 5122 | vpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); |
| 5123 | if (vpg == NULL) { |
| 5124 | printf("%s: unable to allocate space for raid " |
| 5125 | "volume page 0\n" , DEVNAME(sc)); |
| 5126 | return (ENOMEM); |
| 5127 | } |
| 5128 | |
| 5129 | if (mpii_req_cfg_page(sc, MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, |
| 5130 | &hdr, 1, vpg, pagelen) != 0) { |
| 5131 | printf("%s: unable to fetch raid volume page 0\n" , |
| 5132 | DEVNAME(sc)); |
| 5133 | free(vpg, M_TEMP); |
| 5134 | return (EINVAL); |
| 5135 | } |
| 5136 | |
| 5137 | switch (vpg->volume_state) { |
| 5138 | case MPII_CFG_RAID_VOL_0_STATE_ONLINE: |
| 5139 | case MPII_CFG_RAID_VOL_0_STATE_OPTIMAL: |
| 5140 | bv->bv_status = BIOC_SVONLINE; |
| 5141 | break; |
| 5142 | case MPII_CFG_RAID_VOL_0_STATE_DEGRADED: |
| 5143 | if (ISSET(le32toh(vpg->volume_status), |
| 5144 | MPII_CFG_RAID_VOL_0_STATUS_RESYNC)) { |
| 5145 | bv->bv_status = BIOC_SVREBUILD; |
| 5146 | bv->bv_percent = dev->percent; |
| 5147 | } else |
| 5148 | bv->bv_status = BIOC_SVDEGRADED; |
| 5149 | break; |
| 5150 | case MPII_CFG_RAID_VOL_0_STATE_FAILED: |
| 5151 | bv->bv_status = BIOC_SVOFFLINE; |
| 5152 | break; |
| 5153 | case MPII_CFG_RAID_VOL_0_STATE_INITIALIZING: |
| 5154 | bv->bv_status = BIOC_SVBUILDING; |
| 5155 | break; |
| 5156 | case MPII_CFG_RAID_VOL_0_STATE_MISSING: |
| 5157 | default: |
| 5158 | bv->bv_status = BIOC_SVINVALID; |
| 5159 | break; |
| 5160 | } |
| 5161 | |
| 5162 | switch (vpg->volume_type) { |
| 5163 | case MPII_CFG_RAID_VOL_0_TYPE_RAID0: |
| 5164 | bv->bv_level = 0; |
| 5165 | break; |
| 5166 | case MPII_CFG_RAID_VOL_0_TYPE_RAID1: |
| 5167 | bv->bv_level = 1; |
| 5168 | break; |
| 5169 | case MPII_CFG_RAID_VOL_0_TYPE_RAID1E: |
| 5170 | case MPII_CFG_RAID_VOL_0_TYPE_RAID10: |
| 5171 | bv->bv_level = 10; |
| 5172 | break; |
| 5173 | default: |
| 5174 | bv->bv_level = -1; |
| 5175 | } |
| 5176 | |
| 5177 | if ((rv = mpii_bio_hs(sc, NULL, 0, vpg->hot_spare_pool, &hcnt)) != 0) { |
| 5178 | free(vpg, M_TEMP); |
| 5179 | return (rv); |
| 5180 | } |
| 5181 | |
| 5182 | bv->bv_nodisk = vpg->num_phys_disks + hcnt; |
| 5183 | |
| 5184 | bv->bv_size = le64toh(vpg->max_lba) * le16toh(vpg->block_size); |
| 5185 | |
| 5186 | periph = scsipi_lookup_periph(&sc->sc_chan, dev->slot, 0); |
| 5187 | if (periph != NULL) { |
| 5188 | if (periph->periph_dev == NULL) { |
| 5189 | snprintf(bv->bv_dev, sizeof(bv->bv_dev), "%s:%d" , |
| 5190 | DEVNAME(sc), dev->slot); |
| 5191 | } else { |
| 5192 | strlcpy(bv->bv_dev, device_xname(periph->periph_dev), |
| 5193 | sizeof(bv->bv_dev)); |
| 5194 | } |
| 5195 | } |
| 5196 | |
| 5197 | free(vpg, M_TEMP); |
| 5198 | return (0); |
| 5199 | } |
| 5200 | |
| 5201 | static int |
| 5202 | mpii_ioctl_disk(struct mpii_softc *sc, struct bioc_disk *bd) |
| 5203 | { |
| 5204 | struct mpii_cfg_raid_vol_pg0 *vpg; |
| 5205 | struct mpii_cfg_raid_vol_pg0_physdisk *pd; |
| 5206 | struct mpii_cfg_hdr hdr; |
| 5207 | struct mpii_device *dev; |
| 5208 | size_t pagelen; |
| 5209 | u_int16_t volh; |
| 5210 | u_int8_t dn; |
| 5211 | |
| 5212 | DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl_disk %d/%d\n" , |
| 5213 | DEVNAME(sc), bd->bd_volid, bd->bd_diskid); |
| 5214 | |
| 5215 | if ((dev = mpii_find_vol(sc, bd->bd_volid)) == NULL) |
| 5216 | return (ENODEV); |
| 5217 | volh = dev->dev_handle; |
| 5218 | |
| 5219 | if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, |
| 5220 | MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, &hdr) != 0) { |
| 5221 | printf("%s: unable to fetch header for raid volume page 0\n" , |
| 5222 | DEVNAME(sc)); |
| 5223 | return (EINVAL); |
| 5224 | } |
| 5225 | |
| 5226 | pagelen = hdr.page_length * 4; |
| 5227 | vpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); |
| 5228 | if (vpg == NULL) { |
| 5229 | printf("%s: unable to allocate space for raid " |
| 5230 | "volume page 0\n" , DEVNAME(sc)); |
| 5231 | return (ENOMEM); |
| 5232 | } |
| 5233 | |
| 5234 | if (mpii_req_cfg_page(sc, MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, |
| 5235 | &hdr, 1, vpg, pagelen) != 0) { |
| 5236 | printf("%s: unable to fetch raid volume page 0\n" , |
| 5237 | DEVNAME(sc)); |
| 5238 | free(vpg, M_TEMP); |
| 5239 | return (EINVAL); |
| 5240 | } |
| 5241 | |
| 5242 | if (bd->bd_diskid >= vpg->num_phys_disks) { |
| 5243 | int nvdsk = vpg->num_phys_disks; |
| 5244 | int hsmap = vpg->hot_spare_pool; |
| 5245 | |
| 5246 | free(vpg, M_TEMP); |
| 5247 | return (mpii_bio_hs(sc, bd, nvdsk, hsmap, NULL)); |
| 5248 | } |
| 5249 | |
| 5250 | pd = (struct mpii_cfg_raid_vol_pg0_physdisk *)(vpg + 1) + |
| 5251 | bd->bd_diskid; |
| 5252 | dn = pd->phys_disk_num; |
| 5253 | |
| 5254 | free(vpg, M_TEMP); |
| 5255 | return (mpii_bio_disk(sc, bd, dn)); |
| 5256 | } |
| 5257 | |
| 5258 | static int |
| 5259 | mpii_bio_hs(struct mpii_softc *sc, struct bioc_disk *bd, int nvdsk, |
| 5260 | int hsmap, int *hscnt) |
| 5261 | { |
| 5262 | struct mpii_cfg_raid_config_pg0 *cpg; |
| 5263 | struct mpii_raid_config_element *el; |
| 5264 | struct mpii_ecfg_hdr ehdr; |
| 5265 | size_t pagelen; |
| 5266 | int i, nhs = 0; |
| 5267 | |
| 5268 | if (bd) { |
| 5269 | DNPRINTF(MPII_D_IOCTL, "%s: mpii_bio_hs %d\n" , DEVNAME(sc), |
| 5270 | bd->bd_diskid - nvdsk); |
| 5271 | } else { |
| 5272 | DNPRINTF(MPII_D_IOCTL, "%s: mpii_bio_hs\n" , DEVNAME(sc)); |
| 5273 | } |
| 5274 | |
| 5275 | if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_CONFIG, |
| 5276 | 0, MPII_CFG_RAID_CONFIG_ACTIVE_CONFIG, MPII_PG_EXTENDED, |
| 5277 | &ehdr) != 0) { |
| 5278 | printf("%s: unable to fetch header for raid config page 0\n" , |
| 5279 | DEVNAME(sc)); |
| 5280 | return (EINVAL); |
| 5281 | } |
| 5282 | |
| 5283 | pagelen = le16toh(ehdr.ext_page_length) * 4; |
| 5284 | cpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); |
| 5285 | if (cpg == NULL) { |
| 5286 | printf("%s: unable to allocate space for raid config page 0\n" , |
| 5287 | DEVNAME(sc)); |
| 5288 | return (ENOMEM); |
| 5289 | } |
| 5290 | |
| 5291 | if (mpii_req_cfg_page(sc, MPII_CFG_RAID_CONFIG_ACTIVE_CONFIG, |
| 5292 | MPII_PG_EXTENDED, &ehdr, 1, cpg, pagelen) != 0) { |
| 5293 | printf("%s: unable to fetch raid config page 0\n" , |
| 5294 | DEVNAME(sc)); |
| 5295 | free(cpg, M_TEMP); |
| 5296 | return (EINVAL); |
| 5297 | } |
| 5298 | |
| 5299 | el = (struct mpii_raid_config_element *)(cpg + 1); |
| 5300 | for (i = 0; i < cpg->num_elements; i++, el++) { |
| 5301 | if (ISSET(le16toh(el->element_flags), |
| 5302 | MPII_RAID_CONFIG_ELEMENT_FLAG_HSP_PHYS_DISK) && |
| 5303 | el->hot_spare_pool == hsmap) { |
| 5304 | /* |
| 5305 | * diskid comparison is based on the idea that all |
| 5306 | * disks are counted by the bio(4) in sequence, thus |
| 5307 | * substracting the number of disks in the volume |
| 5308 | * from the diskid yields us a "relative" hotspare |
| 5309 | * number, which is good enough for us. |
| 5310 | */ |
| 5311 | if (bd != NULL && bd->bd_diskid == nhs + nvdsk) { |
| 5312 | u_int8_t dn = el->phys_disk_num; |
| 5313 | |
| 5314 | free(cpg, M_TEMP); |
| 5315 | return (mpii_bio_disk(sc, bd, dn)); |
| 5316 | } |
| 5317 | nhs++; |
| 5318 | } |
| 5319 | } |
| 5320 | |
| 5321 | if (hscnt) |
| 5322 | *hscnt = nhs; |
| 5323 | |
| 5324 | free(cpg, M_TEMP); |
| 5325 | return (0); |
| 5326 | } |
| 5327 | |
| 5328 | static int |
| 5329 | mpii_bio_disk(struct mpii_softc *sc, struct bioc_disk *bd, u_int8_t dn) |
| 5330 | { |
| 5331 | struct mpii_cfg_raid_physdisk_pg0 *ppg; |
| 5332 | struct mpii_cfg_hdr hdr; |
| 5333 | struct mpii_device *dev; |
| 5334 | int len; |
| 5335 | |
| 5336 | DNPRINTF(MPII_D_IOCTL, "%s: mpii_bio_disk %d\n" , DEVNAME(sc), |
| 5337 | bd->bd_diskid); |
| 5338 | |
| 5339 | ppg = malloc(sizeof(*ppg), M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); |
| 5340 | if (ppg == NULL) { |
| 5341 | printf("%s: unable to allocate space for raid physical disk " |
| 5342 | "page 0\n" , DEVNAME(sc)); |
| 5343 | return (ENOMEM); |
| 5344 | } |
| 5345 | |
| 5346 | hdr.page_version = 0; |
| 5347 | hdr.page_length = sizeof(*ppg) / 4; |
| 5348 | hdr.page_number = 0; |
| 5349 | hdr.page_type = MPII_CONFIG_REQ_PAGE_TYPE_RAID_PD; |
| 5350 | |
| 5351 | if (mpii_req_cfg_page(sc, MPII_CFG_RAID_PHYS_DISK_ADDR_NUMBER | dn, 0, |
| 5352 | &hdr, 1, ppg, sizeof(*ppg)) != 0) { |
| 5353 | printf("%s: unable to fetch raid drive page 0\n" , |
| 5354 | DEVNAME(sc)); |
| 5355 | free(ppg, M_TEMP); |
| 5356 | return (EINVAL); |
| 5357 | } |
| 5358 | |
| 5359 | bd->bd_target = ppg->phys_disk_num; |
| 5360 | |
| 5361 | if ((dev = mpii_find_dev(sc, le16toh(ppg->dev_handle))) == NULL) { |
| 5362 | bd->bd_status = BIOC_SDINVALID; |
| 5363 | free(ppg, M_TEMP); |
| 5364 | return (0); |
| 5365 | } |
| 5366 | |
| 5367 | switch (ppg->phys_disk_state) { |
| 5368 | case MPII_CFG_RAID_PHYDISK_0_STATE_ONLINE: |
| 5369 | case MPII_CFG_RAID_PHYDISK_0_STATE_OPTIMAL: |
| 5370 | bd->bd_status = BIOC_SDONLINE; |
| 5371 | break; |
| 5372 | case MPII_CFG_RAID_PHYDISK_0_STATE_OFFLINE: |
| 5373 | if (ppg->offline_reason == |
| 5374 | MPII_CFG_RAID_PHYDISK_0_OFFLINE_FAILED || |
| 5375 | ppg->offline_reason == |
| 5376 | MPII_CFG_RAID_PHYDISK_0_OFFLINE_FAILEDREQ) |
| 5377 | bd->bd_status = BIOC_SDFAILED; |
| 5378 | else |
| 5379 | bd->bd_status = BIOC_SDOFFLINE; |
| 5380 | break; |
| 5381 | case MPII_CFG_RAID_PHYDISK_0_STATE_DEGRADED: |
| 5382 | bd->bd_status = BIOC_SDFAILED; |
| 5383 | break; |
| 5384 | case MPII_CFG_RAID_PHYDISK_0_STATE_REBUILDING: |
| 5385 | bd->bd_status = BIOC_SDREBUILD; |
| 5386 | break; |
| 5387 | case MPII_CFG_RAID_PHYDISK_0_STATE_HOTSPARE: |
| 5388 | bd->bd_status = BIOC_SDHOTSPARE; |
| 5389 | break; |
| 5390 | case MPII_CFG_RAID_PHYDISK_0_STATE_NOTCONFIGURED: |
| 5391 | bd->bd_status = BIOC_SDUNUSED; |
| 5392 | break; |
| 5393 | case MPII_CFG_RAID_PHYDISK_0_STATE_NOTCOMPATIBLE: |
| 5394 | default: |
| 5395 | bd->bd_status = BIOC_SDINVALID; |
| 5396 | break; |
| 5397 | } |
| 5398 | |
| 5399 | bd->bd_size = le64toh(ppg->dev_max_lba) * le16toh(ppg->block_size); |
| 5400 | |
| 5401 | strnvisx(bd->bd_vendor, sizeof(bd->bd_vendor), |
| 5402 | ppg->vendor_id, sizeof(ppg->vendor_id), |
| 5403 | VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
| 5404 | len = strlen(bd->bd_vendor); |
| 5405 | bd->bd_vendor[len] = ' '; |
| 5406 | strnvisx(&bd->bd_vendor[len + 1], sizeof(ppg->vendor_id) - len - 1, |
| 5407 | ppg->product_id, sizeof(ppg->product_id), |
| 5408 | VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
| 5409 | strnvisx(bd->bd_serial, sizeof(bd->bd_serial), |
| 5410 | ppg->serial, sizeof(ppg->serial), VIS_TRIM|VIS_SAFE|VIS_OCTAL); |
| 5411 | |
| 5412 | free(ppg, M_TEMP); |
| 5413 | return (0); |
| 5414 | } |
| 5415 | |
| 5416 | static struct mpii_device * |
| 5417 | mpii_find_vol(struct mpii_softc *sc, int volid) |
| 5418 | { |
| 5419 | struct mpii_device *dev = NULL; |
| 5420 | |
| 5421 | if (sc->sc_vd_id_low + volid >= sc->sc_max_devices) |
| 5422 | return (NULL); |
| 5423 | dev = sc->sc_devs[sc->sc_vd_id_low + volid]; |
| 5424 | if (dev && ISSET(dev->flags, MPII_DF_VOLUME)) |
| 5425 | return (dev); |
| 5426 | return (NULL); |
| 5427 | } |
| 5428 | |
| 5429 | /* |
| 5430 | * Non-sleeping lightweight version of the mpii_ioctl_vol |
| 5431 | */ |
| 5432 | static int |
| 5433 | mpii_bio_volstate(struct mpii_softc *sc, struct bioc_vol *bv) |
| 5434 | { |
| 5435 | struct mpii_cfg_raid_vol_pg0 *vpg; |
| 5436 | struct mpii_cfg_hdr hdr; |
| 5437 | struct mpii_device *dev = NULL; |
| 5438 | size_t pagelen; |
| 5439 | u_int16_t volh; |
| 5440 | |
| 5441 | if ((dev = mpii_find_vol(sc, bv->bv_volid)) == NULL) |
| 5442 | return (ENODEV); |
| 5443 | volh = dev->dev_handle; |
| 5444 | |
| 5445 | if (mpii_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, |
| 5446 | MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, &hdr) != 0) { |
| 5447 | DNPRINTF(MPII_D_MISC, "%s: unable to fetch header for raid " |
| 5448 | "volume page 0\n" , DEVNAME(sc)); |
| 5449 | return (EINVAL); |
| 5450 | } |
| 5451 | |
| 5452 | pagelen = hdr.page_length * 4; |
| 5453 | vpg = malloc(pagelen, M_TEMP, M_NOWAIT | M_ZERO); |
| 5454 | if (vpg == NULL) { |
| 5455 | DNPRINTF(MPII_D_MISC, "%s: unable to allocate space for raid " |
| 5456 | "volume page 0\n" , DEVNAME(sc)); |
| 5457 | return (ENOMEM); |
| 5458 | } |
| 5459 | |
| 5460 | if (mpii_cfg_page(sc, MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, |
| 5461 | &hdr, 1, vpg, pagelen) != 0) { |
| 5462 | DNPRINTF(MPII_D_MISC, "%s: unable to fetch raid volume " |
| 5463 | "page 0\n" , DEVNAME(sc)); |
| 5464 | free(vpg, M_TEMP); |
| 5465 | return (EINVAL); |
| 5466 | } |
| 5467 | |
| 5468 | switch (vpg->volume_state) { |
| 5469 | case MPII_CFG_RAID_VOL_0_STATE_ONLINE: |
| 5470 | case MPII_CFG_RAID_VOL_0_STATE_OPTIMAL: |
| 5471 | bv->bv_status = BIOC_SVONLINE; |
| 5472 | break; |
| 5473 | case MPII_CFG_RAID_VOL_0_STATE_DEGRADED: |
| 5474 | if (ISSET(le32toh(vpg->volume_status), |
| 5475 | MPII_CFG_RAID_VOL_0_STATUS_RESYNC)) |
| 5476 | bv->bv_status = BIOC_SVREBUILD; |
| 5477 | else |
| 5478 | bv->bv_status = BIOC_SVDEGRADED; |
| 5479 | break; |
| 5480 | case MPII_CFG_RAID_VOL_0_STATE_FAILED: |
| 5481 | bv->bv_status = BIOC_SVOFFLINE; |
| 5482 | break; |
| 5483 | case MPII_CFG_RAID_VOL_0_STATE_INITIALIZING: |
| 5484 | bv->bv_status = BIOC_SVBUILDING; |
| 5485 | break; |
| 5486 | case MPII_CFG_RAID_VOL_0_STATE_MISSING: |
| 5487 | default: |
| 5488 | bv->bv_status = BIOC_SVINVALID; |
| 5489 | break; |
| 5490 | } |
| 5491 | |
| 5492 | free(vpg, M_TEMP); |
| 5493 | return (0); |
| 5494 | } |
| 5495 | |
| 5496 | static int |
| 5497 | mpii_create_sensors(struct mpii_softc *sc) |
| 5498 | { |
| 5499 | int i, rv; |
| 5500 | |
| 5501 | sc->sc_sme = sysmon_envsys_create(); |
| 5502 | sc->sc_sensors = malloc(sizeof(envsys_data_t) * sc->sc_vd_count, |
| 5503 | M_DEVBUF, M_NOWAIT | M_ZERO); |
| 5504 | if (sc->sc_sensors == NULL) { |
| 5505 | aprint_error_dev(sc->sc_dev, |
| 5506 | "can't allocate envsys_data_t\n" ); |
| 5507 | return (1); |
| 5508 | } |
| 5509 | |
| 5510 | for (i = 0; i < sc->sc_vd_count; i++) { |
| 5511 | sc->sc_sensors[i].units = ENVSYS_DRIVE; |
| 5512 | sc->sc_sensors[i].state = ENVSYS_SINVALID; |
| 5513 | sc->sc_sensors[i].value_cur = ENVSYS_DRIVE_EMPTY; |
| 5514 | /* Enable monitoring for drive state changes */ |
| 5515 | sc->sc_sensors[i].flags |= ENVSYS_FMONSTCHANGED; |
| 5516 | |
| 5517 | /* logical drives */ |
| 5518 | snprintf(sc->sc_sensors[i].desc, |
| 5519 | sizeof(sc->sc_sensors[i].desc), "%s:%d" , |
| 5520 | DEVNAME(sc), i); |
| 5521 | if ((rv = sysmon_envsys_sensor_attach(sc->sc_sme, |
| 5522 | &sc->sc_sensors[i])) != 0) { |
| 5523 | aprint_error_dev(sc->sc_dev, |
| 5524 | "unable to attach sensor (rv = %d)\n" , rv); |
| 5525 | goto out; |
| 5526 | } |
| 5527 | } |
| 5528 | sc->sc_sme->sme_name = DEVNAME(sc); |
| 5529 | sc->sc_sme->sme_cookie = sc; |
| 5530 | sc->sc_sme->sme_refresh = mpii_refresh_sensors; |
| 5531 | |
| 5532 | rv = sysmon_envsys_register(sc->sc_sme); |
| 5533 | |
| 5534 | if (rv != 0) { |
| 5535 | aprint_error_dev(sc->sc_dev, |
| 5536 | "unable to register with sysmon (rv = %d)\n" , rv); |
| 5537 | goto out; |
| 5538 | } |
| 5539 | return 0; |
| 5540 | |
| 5541 | out: |
| 5542 | free(sc->sc_sensors, M_DEVBUF); |
| 5543 | sysmon_envsys_destroy(sc->sc_sme); |
| 5544 | sc->sc_sme = NULL; |
| 5545 | return EINVAL; |
| 5546 | } |
| 5547 | |
| 5548 | static int |
| 5549 | mpii_destroy_sensors(struct mpii_softc *sc) |
| 5550 | { |
| 5551 | if (sc->sc_sme == NULL) |
| 5552 | return 0; |
| 5553 | sysmon_envsys_unregister(sc->sc_sme); |
| 5554 | sc->sc_sme = NULL; |
| 5555 | free(sc->sc_sensors, M_DEVBUF); |
| 5556 | return 0; |
| 5557 | } |
| 5558 | |
| 5559 | static void |
| 5560 | mpii_refresh_sensors(struct sysmon_envsys *sme, envsys_data_t *edata) |
| 5561 | { |
| 5562 | struct mpii_softc *sc = sc = sme->sme_cookie; |
| 5563 | struct bioc_vol bv; |
| 5564 | int s, error; |
| 5565 | |
| 5566 | bzero(&bv, sizeof(bv)); |
| 5567 | bv.bv_volid = edata->sensor; |
| 5568 | KERNEL_LOCK(1, curlwp); |
| 5569 | s = splbio(); |
| 5570 | error = mpii_bio_volstate(sc, &bv); |
| 5571 | splx(s); |
| 5572 | KERNEL_UNLOCK_ONE(curlwp); |
| 5573 | if (error) |
| 5574 | bv.bv_status = BIOC_SVINVALID; |
| 5575 | bio_vol_to_envsys(edata, &bv); |
| 5576 | } |
| 5577 | #endif /* NBIO > 0 */ |
| 5578 | |