/* $OpenBSD: mpii.c,v 1.3 2009/11/05 03:43:18 marco Exp $ */ /* * Copyright (c) James Giannoules * Copyright (c) 2005 David Gwynne * Copyright (c) 2005 Marco Peereboom * * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "bio.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __sparc64__ #include #endif #include #include #include #define MPII_DOORBELL 0x00 /* doorbell read bits */ #define MPII_DOORBELL_STATE (0xf<<28) /* ioc state */ #define MPII_DOORBELL_STATE_RESET (0x0<<28) #define MPII_DOORBELL_STATE_READY (0x1<<28) #define MPII_DOORBELL_STATE_OPER (0x2<<28) #define MPII_DOORBELL_STATE_FAULT (0x4<<28) #define MPII_DOORBELL_INUSE (0x1<<27) /* doorbell used */ #define MPII_DOORBELL_WHOINIT (0x7<<24) /* last to reset ioc */ #define MPII_DOORBELL_WHOINIT_NOONE (0x0<<24) /* not initialized */ #define MPII_DOORBELL_WHOINIT_SYSBIOS (0x1<<24) /* system bios */ #define MPII_DOORBELL_WHOINIT_ROMBIOS (0x2<<24) /* rom bios */ #define MPII_DOORBELL_WHOINIT_PCIPEER (0x3<<24) /* pci peer */ #define MPII_DOORBELL_WHOINIT_DRIVER (0x4<<24) /* host driver */ #define MPII_DOORBELL_WHOINIT_MANUFACT (0x5<<24) /* manufacturing */ #define MPII_DOORBELL_FAULT (0xffff<<0) /* fault code */ /* doorbell write bits */ #define MPII_DOORBELL_FUNCTION_SHIFT 24 #define MPII_DOORBELL_FUNCTION_MASK (0xff << MPII_DOORBELL_FUNCTION_SHIFT) #define MPII_DOORBELL_FUNCTION(x) \ (((x) << MPII_DOORBELL_FUNCTION_SHIFT) & MPII_DOORBELL_FUNCTION_MASK) #define MPII_DOORBELL_DWORDS_SHIFT 16 #define MPII_DOORBELL_DWORDS_MASK (0xff << MPII_DOORBELL_DWORDS_SHIFT) #define MPII_DOORBELL_DWORDS(x) \ (((x) << MPII_DOORBELL_DWORDS_SHIFT) & MPII_DOORBELL_DWORDS_MASK) #define MPII_DOORBELL_DATA_MASK 0xffff #define MPII_WRITESEQ 0x04 #define MPII_WRITESEQ_KEY_VALUE_MASK 0x0000000f /* key value */ #define MPII_WRITESEQ_FLUSH 0x00 #define MPII_WRITESEQ_1 0x0f #define MPII_WRITESEQ_2 0x04 #define MPII_WRITESEQ_3 0x0b #define MPII_WRITESEQ_4 0x03 #define MPII_WRITESEQ_5 0x07 #define MPII_WRITESEQ_6 0x0d #define MPII_HOSTDIAG 0x08 #define MPII_HOSTDIAG_BDS_MASK 0x00001800 /* boot device select */ #define MPII_HOSTDIAG_BDS_DEFAULT (0<<11) /* default address map, flash */ #define MPII_HOSTDIAG_BDS_HCDW (1<<11) /* host code and data window */ #define MPII_HOSTDIAG_CLEARFBS (1<<10) /* clear flash bad sig */ #define MPII_HOSTDIAG_FORCE_HCB_ONBOOT (1<<9) /* force host controlled boot */ #define MPII_HOSTDIAG_HCB_MODE (1<<8) /* host controlled boot mode */ #define MPII_HOSTDIAG_DWRE (1<<7) /* diag reg write enabled */ #define MPII_HOSTDIAG_FBS (1<<6) /* flash bad sig */ #define MPII_HOSTDIAG_RESET_HIST (1<<5) /* reset history */ #define MPII_HOSTDIAG_DIAGWR_EN (1<<4) /* diagnostic write enabled */ #define MPII_HOSTDIAG_RESET_ADAPTER (1<<2) /* reset adapter */ #define MPII_HOSTDIAG_HOLD_IOC_RESET (1<<1) /* hold ioc in reset */ #define MPII_HOSTDIAG_DIAGMEM_EN (1<<0) /* diag mem enable */ #define MPII_DIAGRWDATA 0x10 #define MPII_DIAGRWADDRLOW 0x14 #define MPII_DIAGRWADDRHIGH 0x18 #define MPII_INTR_STATUS 0x30 #define MPII_INTR_STATUS_SYS2IOCDB (1<<31) /* ioc written to by host */ #define MPII_INTR_STATUS_RESET (1<<30) /* physical ioc reset */ #define MPII_INTR_STATUS_REPLY (1<<3) /* reply message interrupt */ #define MPII_INTR_STATUS_IOC2SYSDB (1<<0) /* ioc write to doorbell */ #define MPII_INTR_MASK 0x34 #define MPII_INTR_MASK_RESET (1<<30) /* ioc reset intr mask */ #define MPII_INTR_MASK_REPLY (1<<3) /* reply message intr mask */ #define MPII_INTR_MASK_DOORBELL (1<<0) /* doorbell interrupt mask */ #define MPII_DCR_DATA 0x38 #define MPII_DCR_ADDRESS 0x3C #define MPII_REPLY_FREE_HOST_INDEX 0x48 #define MPII_REPLY_POST_HOST_INDEX 0x6C #define MPII_HCB_SIZE 0x74 #define MPII_HCB_ADDRESS_LOW 0x78 #define MPII_HCB_ADDRESS_HIGH 0x7C #define MPII_REQ_DESC_POST_LOW 0xC0 #define MPII_REQ_DESC_POST_HIGH 0xC4 /* * Scatter Gather Lists */ #define MPII_SGE_FL_LAST (0x1<<31) /* last element in segment */ #define MPII_SGE_FL_EOB (0x1<<30) /* last element of buffer */ #define MPII_SGE_FL_TYPE (0x3<<28) /* element type */ #define MPII_SGE_FL_TYPE_SIMPLE (0x1<<28) /* simple element */ #define MPII_SGE_FL_TYPE_CHAIN (0x3<<28) /* chain element */ #define MPII_SGE_FL_TYPE_XACTCTX (0x0<<28) /* transaction context */ #define MPII_SGE_FL_LOCAL (0x1<<27) /* local address */ #define MPII_SGE_FL_DIR (0x1<<26) /* direction */ #define MPII_SGE_FL_DIR_OUT (0x1<<26) #define MPII_SGE_FL_DIR_IN (0x0<<26) #define MPII_SGE_FL_SIZE (0x1<<25) /* address size */ #define MPII_SGE_FL_SIZE_32 (0x0<<25) #define MPII_SGE_FL_SIZE_64 (0x1<<25) #define MPII_SGE_FL_EOL (0x1<<24) /* end of list */ struct mpii_sge { u_int32_t sg_hdr; u_int32_t sg_lo_addr; u_int32_t sg_hi_addr; } __packed; struct mpii_fw_tce { u_int8_t reserved1; u_int8_t context_size; u_int8_t details_length; u_int8_t flags; u_int32_t reserved2; u_int32_t image_offset; u_int32_t image_size; } __packed; /* * Messages */ /* functions */ #define MPII_FUNCTION_SCSI_IO_REQUEST (0x00) #define MPII_FUNCTION_SCSI_TASK_MGMT (0x01) #define MPII_FUNCTION_IOC_INIT (0x02) #define MPII_FUNCTION_IOC_FACTS (0x03) #define MPII_FUNCTION_CONFIG (0x04) #define MPII_FUNCTION_PORT_FACTS (0x05) #define MPII_FUNCTION_PORT_ENABLE (0x06) #define MPII_FUNCTION_EVENT_NOTIFICATION (0x07) #define MPII_FUNCTION_EVENT_ACK (0x08) #define MPII_FUNCTION_FW_DOWNLOAD (0x09) #define MPII_FUNCTION_TARGET_CMD_BUFFER_POST (0x0A) #define MPII_FUNCTION_TARGET_ASSIST (0x0B) #define MPII_FUNCTION_TARGET_STATUS_SEND (0x0C) #define MPII_FUNCTION_TARGET_MODE_ABORT (0x0D) #define MPII_FUNCTION_FW_UPLOAD (0x12) #define MPII_FUNCTION_RAID_ACTION (0x15) #define MPII_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) #define MPII_FUNCTION_TOOLBOX (0x17) #define MPII_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) #define MPII_FUNCTION_SMP_PASSTHROUGH (0x1A) #define MPII_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) #define MPII_FUNCTION_SATA_PASSTHROUGH (0x1C) #define MPII_FUNCTION_DIAG_BUFFER_POST (0x1D) #define MPII_FUNCTION_DIAG_RELEASE (0x1E) #define MPII_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) #define MPII_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) #define MPII_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) #define MPII_FUNCTION_IO_UNIT_RESET (0x41) #define MPII_FUNCTION_HANDSHAKE (0x42) /* request flags fields for request descriptors */ #define MPII_REQ_DESCRIPTOR_FLAGS_TYPE_SHIFT (0x01) #define MPII_REQ_DESCRIPTOR_FLAGS_TYPE_MASK (0x07 << \ MPII_REQ_DESCRIPTOR_FLAGS_TYPE_SHIFT) #define MPII_REQ_DESCRIPTOR_FLAGS_SCSI_IO (0x00) #define MPII_REQ_DESCRIPTOR_FLAGS_SCSI_TARGET (0x02) #define MPII_REQ_DESCRIPTOR_FLAGS_HIGH_PRIORITY (0x06) #define MPII_REQ_DESCRIPTOR_FLAGS_DEFAULT (0x08) #define MPII_REQ_DESCRIPTOR_FLAGS_IOC_FIFO_MARKER (0x01) /* reply flags */ #define MPII_REP_FLAGS_CONT (1<<7) /* continuation reply */ #define MPII_REP_IOCSTATUS_AVAIL (1<<15) /* logging info available */ #define MPII_REP_IOCSTATUS (0x7fff) /* status */ /* Common IOCStatus values for all replies */ #define MPII_IOCSTATUS_SUCCESS (0x0000) #define MPII_IOCSTATUS_INVALID_FUNCTION (0x0001) #define MPII_IOCSTATUS_BUSY (0x0002) #define MPII_IOCSTATUS_INVALID_SGL (0x0003) #define MPII_IOCSTATUS_INTERNAL_ERROR (0x0004) #define MPII_IOCSTATUS_INVALID_VPID (0x0005) #define MPII_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) #define MPII_IOCSTATUS_INVALID_FIELD (0x0007) #define MPII_IOCSTATUS_INVALID_STATE (0x0008) #define MPII_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) /* Config IOCStatus values */ #define MPII_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) #define MPII_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) #define MPII_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) #define MPII_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) #define MPII_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) #define MPII_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) /* SCSIIO Reply initiator values */ #define MPII_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) #define MPII_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) #define MPII_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) #define MPII_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) #define MPII_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) #define MPII_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) #define MPII_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) #define MPII_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) #define MPII_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) #define MPII_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) #define MPII_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) #define MPII_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) /* For use by SCSI Initiator and SCSI Target end-to-end data protection */ #define MPII_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) #define MPII_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) #define MPII_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) /* SCSI (SPI & FCP) target values */ #define MPII_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) #define MPII_IOCSTATUS_TARGET_ABORTED (0x0063) #define MPII_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) #define MPII_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) #define MPII_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) #define MPII_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) #define MPII_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) #define MPII_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) #define MPII_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) #define MPII_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) /* Serial Attached SCSI values */ #define MPII_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) #define MPII_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) /* Diagnostic Tools values */ #define MPII_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) #define MPII_REP_IOCLOGINFO_TYPE (0xf<<28) /* logging info type */ #define MPII_REP_IOCLOGINFO_TYPE_NONE (0x0<<28) #define MPII_REP_IOCLOGINFO_TYPE_SCSI (0x1<<28) #define MPII_REP_IOCLOGINFO_TYPE_FC (0x2<<28) #define MPII_REP_IOCLOGINFO_TYPE_SAS (0x3<<28) #define MPII_REP_IOCLOGINFO_TYPE_ISCSI (0x4<<28) #define MPII_REP_IOCLOGINFO_DATA (0x0fffffff) /* logging info data */ /* event notification types */ #define MPII_EVENT_NONE 0x00 #define MPII_EVENT_LOG_DATA 0x01 #define MPII_EVENT_STATE_CHANGE 0x02 #define MPII_EVENT_UNIT_ATTENTION 0x03 #define MPII_EVENT_IOC_BUS_RESET 0x04 #define MPII_EVENT_EXT_BUS_RESET 0x05 #define MPII_EVENT_RESCAN 0x06 #define MPII_EVENT_LINK_STATUS_CHANGE 0x07 #define MPII_EVENT_LOOP_STATE_CHANGE 0x08 #define MPII_EVENT_LOGOUT 0x09 #define MPII_EVENT_EVENT_CHANGE 0x0a #define MPII_EVENT_INTEGRATED_RAID 0x0b #define MPII_EVENT_SCSI_DEVICE_STATUS_CHANGE 0x0c #define MPII_EVENT_ON_BUS_TIMER_EXPIRED 0x0d #define MPII_EVENT_QUEUE_FULL 0x0e #define MPII_EVENT_SAS_DEVICE_STATUS_CHANGE 0x0f #define MPII_EVENT_SAS_SES 0x10 #define MPII_EVENT_PERSISTENT_TABLE_FULL 0x11 #define MPII_EVENT_SAS_PHY_LINK_STATUS 0x12 #define MPII_EVENT_SAS_DISCOVERY_ERROR 0x13 #define MPII_EVENT_IR_RESYNC_UPDATE 0x14 #define MPII_EVENT_IR2 0x15 #define MPII_EVENT_SAS_DISCOVERY 0x16 #define MPII_EVENT_LOG_ENTRY_ADDED 0x21 /* messages */ #define MPII_WHOINIT_NOONE 0x00 #define MPII_WHOINIT_SYSTEM_BIOS 0x01 #define MPII_WHOINIT_ROM_BIOS 0x02 #define MPII_WHOINIT_PCI_PEER 0x03 #define MPII_WHOINIT_HOST_DRIVER 0x04 #define MPII_WHOINIT_MANUFACTURER 0x05 /* page address fields */ #define MPII_PAGE_ADDRESS_FC_BTID (1<<24) /* Bus Target ID */ /* default messages */ struct mpii_msg_request { u_int8_t reserved1; u_int8_t reserved2; u_int8_t chain_offset; u_int8_t function; u_int8_t reserved3; u_int8_t reserved4; u_int8_t reserved5; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved6; } __packed; struct mpii_msg_reply { u_int16_t reserved1; u_int8_t msg_length; u_int8_t function; u_int16_t reserved2; u_int8_t reserved3; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_if; u_int16_t reserved4; u_int16_t reserved5; u_int16_t ioc_status; u_int32_t ioc_loginfo; } __packed; /* ioc init */ struct mpii_msg_iocinit_request { u_int8_t whoinit; u_int8_t reserved1; u_int8_t chain_offset; u_int8_t function; u_int16_t reserved2; u_int8_t reserved3; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved4; u_int8_t msg_version_min; u_int8_t msg_version_maj; u_int8_t hdr_version_unit; u_int8_t hdr_version_dev; u_int32_t reserved5; u_int32_t reserved6; u_int16_t reserved7; u_int16_t system_request_frame_size; u_int16_t reply_descriptor_post_queue_depth; u_int16_t reply_free_queue_depth; u_int32_t sense_buffer_address_high; u_int32_t system_reply_address_high; u_int64_t system_request_frame_base_address; u_int64_t reply_descriptor_post_queue_address; u_int64_t reply_free_queue_address; u_int64_t timestamp; } __packed; struct mpii_msg_iocinit_reply { u_int8_t whoinit; u_int8_t reserved1; u_int8_t msg_length; u_int8_t function; u_int16_t reserved2; u_int8_t reserved3; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved4; u_int16_t reserved5; u_int16_t ioc_status; u_int32_t ioc_loginfo; } __packed; struct mpii_msg_iocfacts_request { u_int16_t reserved1; u_int8_t chain_offset; u_int8_t function; u_int16_t reserved2; u_int8_t reserved3; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved4; } __packed; struct mpii_msg_iocfacts_reply { u_int8_t msg_version_min; u_int8_t msg_version_maj; u_int8_t msg_length; u_int8_t function; u_int8_t header_version_dev; u_int8_t header_version_unit; u_int8_t ioc_number; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved1; u_int16_t ioc_exceptions; #define MPII_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (1<<0) #define MPII_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (1<<1) #define MPII_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (1<<2) #define MPII_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (1<<3) #define MPII_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (1<<4) #define MPII_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAC (1<<8) /* XXX JPG BOOT_STATUS in bits[7:5] */ /* XXX JPG all these #defines need to be fixed up */ u_int16_t ioc_status; u_int32_t ioc_loginfo; u_int8_t max_chain_depth; u_int8_t whoinit; u_int8_t number_of_ports; u_int8_t reserved2; u_int16_t request_credit; u_int16_t product_id; u_int32_t ioc_capabilities; #define MPII_IOCFACTS_CAPABILITY_EVENT_REPLAY (1<<13) #define MPII_IOCFACTS_CAPABILITY_INTEGRATED_RAID (1<<12) #define MPII_IOCFACTS_CAPABILITY_TLR (1<<11) #define MPII_IOCFACTS_CAPABILITY_MULTICAST (1<<8) #define MPII_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (1<<7) #define MPII_IOCFACTS_CAPABILITY_EEDP (1<<6) #define MPII_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (1<<4) #define MPII_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (1<<3) #define MPII_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (1<<2) u_int8_t fw_version_dev; u_int8_t fw_version_unit; u_int8_t fw_version_min; u_int8_t fw_version_maj; u_int16_t ioc_request_frame_size; u_int16_t reserved3; u_int16_t max_initiators; u_int16_t max_targets; u_int16_t max_sas_expanders; u_int16_t max_enclosures; u_int16_t protocol_flags; u_int16_t high_priority_credit; u_int16_t max_reply_descriptor_post_queue_depth; u_int8_t reply_frame_size; u_int8_t max_volumes; u_int16_t max_dev_handle; u_int16_t max_persistent_entries; u_int32_t reserved4; } __packed; struct mpii_msg_portfacts_request { u_int16_t reserved1; u_int8_t chain_offset; u_int8_t function; u_int16_t reserved2; u_int8_t port_number; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; } __packed; struct mpii_msg_portfacts_reply { u_int16_t reserved1; u_int8_t msg_length; u_int8_t function; u_int16_t reserved2; u_int8_t port_number; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; u_int16_t reserved4; u_int16_t ioc_status; u_int32_t ioc_loginfo; u_int8_t reserved5; u_int8_t port_type; #define MPII_PORTFACTS_PORTTYPE_INACTIVE 0x00 #define MPII_PORTFACTS_PORTTYPE_FC 0x10 #define MPII_PORTFACTS_PORTTYPE_ISCSI 0x20 #define MPII_PORTFACTS_PORTTYPE_SAS_PHYSICAL 0x30 #define MPII_PORTFACTS_PORTTYPE_SAS_VIRTUAL 0x31 u_int16_t reserved6; u_int16_t max_posted_cmd_buffers; u_int16_t reserved7; } __packed; struct mpii_msg_portenable_request { u_int16_t reserved1; u_int8_t chain_offset; u_int8_t function; u_int8_t reserved2; u_int8_t port_flags; u_int8_t reserved3; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved4; } __packed; struct mpii_msg_portenable_reply { u_int16_t reserved1; u_int8_t msg_length; u_int8_t function; u_int8_t reserved2; u_int8_t port_flags; u_int8_t reserved3; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved4; u_int16_t reserved5; u_int16_t ioc_status; u_int32_t ioc_loginfo; } __packed; struct mpii_msg_event_request { u_int16_t reserved1; u_int8_t chain_offset; u_int8_t function; u_int16_t reserved2; u_int8_t reserved3; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved4; u_int32_t reserved5; u_int32_t reserved6; u_int32_t event_masks[4]; u_int16_t sas_broadcase_primitive_masks; u_int16_t reserved7; u_int32_t reserved8; } __packed; struct mpii_msg_event_reply { u_int16_t event_data_length; u_int8_t msg_length; u_int8_t function; u_int16_t reserved1; u_int8_t ack_required; #define MPII_EVENT_ACK_REQUIRED (0x01) u_int8_t msg_flags; #define MPII_EVENT_FLAGS_REPLY_KEPT (1<<7) u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved2; u_int16_t reserved3; u_int16_t ioc_status; u_int32_t ioc_loginfo; u_int16_t event; u_int16_t reserved4; u_int32_t event_context; /* event data follows */ } __packed; /* XXX JPG */ struct mpii_evt_change { u_int8_t event_state; u_int8_t reserved[3]; } __packed; /* XXX JPG */ struct mpii_evt_sas_phy { u_int8_t phy_num; u_int8_t link_rates; #define MPII_EVT_SASPHY_LINK_CUR(x) (((x) & 0xf0) >> 4) #define MPII_EVT_SASPHY_LINK_PREV(x) ((x) & 0x0f) #define MPII_EVT_SASPHY_LINK_ENABLED 0x0 #define MPII_EVT_SASPHY_LINK_DISABLED 0x1 #define MPII_EVT_SASPHY_LINK_NEGFAIL 0x2 #define MPII_EVT_SASPHY_LINK_SATAOOB 0x3 #define MPII_EVT_SASPHY_LINK_1_5GBPS 0x8 #define MPII_EVT_SASPHY_LINK_3_0GBPS 0x9 u_int16_t dev_handle; u_int64_t sas_addr; } __packed; struct mpii_evt_sas_change { u_int16_t task_tag; u_int8_t reason; #define MPII_EVT_SASCH_REASON_SMART_DATA 0x05 #define MPII_EVT_SASCH_REASON_UNSUPPORTED 0x07 #define MPII_EVT_SASCH_REASON_INTERNAL_RESET 0x08 #define MPII_EVT_SASCH_REASON_TASK_ABORT_INTERVAL 0x09 #define MPII_EVT_SASCH_REASON_ABORT_TASK_SET_INTERVAL 0x0A #define MPII_EVT_SASCH_REASON_CLEAR_TASK_SET_INTERVAL 0x0B #define MPII_EVT_SASCH_REASON_QUERY_TASK_INTERVAL 0x0C #define MPII_EVT_SASCH_REASON_ASYNC_NOTIFICATION 0x0D #define MPII_EVT_SASCH_REASON_CMP_INTERNAL_DEV_RESET 0x0E #define MPII_EVT_SASCH_REASON_CMP_TASK_ABORT_INTERNAL 0x0F #define MPII_EVT_SASCH_REASON_SATA_INIT_FAILURE 0x10 u_int8_t reserved1; u_int8_t asc; u_int8_t ascq; u_int16_t dev_handle; u_int32_t reserved2; u_int64_t sas_addr; u_int16_t lun[4]; } __packed; struct mpii_msg_eventack_request { u_int16_t reserved1; u_int8_t chain_offset; u_int8_t function; u_int8_t reserved2[3]; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; u_int16_t event; u_int16_t reserved4; u_int32_t event_context; } __packed; struct mpii_msg_eventack_reply { u_int16_t reserved1; u_int8_t msg_length; u_int8_t function; u_int8_t reserved2[3]; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; u_int16_t reserved4; u_int16_t ioc_status; u_int32_t ioc_loginfo; } __packed; struct mpii_msg_fwupload_request { u_int8_t image_type; #define MPII_FWUPLOAD_IMAGETYPE_IOC_FW (0x00) #define MPII_FWUPLOAD_IMAGETYPE_NV_FW (0x01) #define MPII_FWUPLOAD_IMAGETYPE_NV_BACKUP (0x05) #define MPII_FWUPLOAD_IMAGETYPE_NV_MANUFACTURING (0x06) #define MPII_FWUPLOAD_IMAGETYPE_NV_CONFIG_1 (0x07) #define MPII_FWUPLOAD_IMAGETYPE_NV_CONFIG_2 (0x08) #define MPII_FWUPLOAD_IMAGETYPE_NV_MEGARAID (0x09) #define MPII_FWUPLOAD_IMAGETYPE_NV_COMPLETE (0x0A) #define MPII_FWUPLOAD_IMAGETYPE_COMMON_BOOT_BLOCK (0x0B) u_int8_t reserved1; u_int8_t chain_offset; u_int8_t function; u_int8_t reserved2[3]; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; u_int32_t reserved4; u_int32_t reserved5; struct mpii_fw_tce tce; /* followed by an sgl */ } __packed; struct mpii_msg_fwupload_reply { u_int8_t image_type; u_int8_t reserved1; u_int8_t msg_length; u_int8_t function; u_int8_t reserved2[3]; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; u_int16_t reserved4; u_int16_t ioc_status; u_int32_t ioc_loginfo; u_int32_t actual_image_size; } __packed; struct mpii_msg_scsi_io { u_int16_t dev_handle; u_int8_t chain_offset; u_int8_t function; u_int16_t reserved1; u_int8_t reserved2; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; u_int32_t sense_buffer_low_address; u_int16_t sgl_flags; u_int8_t sense_buffer_length; u_int8_t reserved4; u_int8_t sgl_offset0; u_int8_t sgl_offset1; u_int8_t sgl_offset2; u_int8_t sgl_offset3; u_int32_t skip_count; u_int32_t data_length; u_int32_t bidirectional_data_length; u_int16_t io_flags; u_int16_t eedp_flags; u_int32_t eedp_block_size; u_int32_t secondary_reference_tag; u_int16_t secondary_application_tag; u_int16_t application_tag_translation_mask; u_int16_t lun[4]; /* the following 16 bits are defined in MPI2 as the control field */ u_int8_t reserved5; u_int8_t tagging; #define MPII_SCSIIO_ATTR_SIMPLE_Q (0x0) #define MPII_SCSIIO_ATTR_HEAD_OF_Q (0x1) #define MPII_SCSIIO_ATTR_ORDERED_Q (0x2) #define MPII_SCSIIO_ATTR_ACA_Q (0x4) #define MPII_SCSIIO_ATTR_UNTAGGED (0x5) #define MPII_SCSIIO_ATTR_NO_DISCONNECT (0x7) u_int8_t reserved6; u_int8_t direction; #define MPII_SCSIIO_DIR_NONE (0x0) #define MPII_SCSIIO_DIR_WRITE (0x1) #define MPII_SCSIIO_DIR_READ (0x2) #define MPII_CDB_LEN 32 u_int8_t cdb[MPII_CDB_LEN]; /* followed by an sgl */ } __packed; struct mpii_msg_scsi_io_error { u_int16_t dev_handle; u_int8_t msg_length; u_int8_t function; u_int16_t reserved1; u_int8_t reserved2; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved3; u_int8_t scsi_status; /* XXX JPG validate this */ #if notyet #define MPII_SCSIIO_ERR_STATUS_SUCCESS #define MPII_SCSIIO_ERR_STATUS_CHECK_COND #define MPII_SCSIIO_ERR_STATUS_BUSY #define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE #define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE_CONDMET #define MPII_SCSIIO_ERR_STATUS_RESERVATION_CONFLICT #define MPII_SCSIIO_ERR_STATUS_CMD_TERM #define MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL #define MPII_SCSIIO_ERR_STATUS_ACA_ACTIVE #endif u_int8_t scsi_state; #define MPII_SCSIIO_ERR_STATE_AUTOSENSE_VALID (1<<0) #define MPII_SCSIIO_ERR_STATE_AUTOSENSE_FAILED (1<<1) #define MPII_SCSIIO_ERR_STATE_NO_SCSI_STATUS (1<<2) #define MPII_SCSIIO_ERR_STATE_TERMINATED (1<<3) #define MPII_SCSIIO_ERR_STATE_RESPONSE_INFO_VALID (1<<4) #define MPII_SCSIIO_ERR_STATE_QUEUE_TAG_REJECTED (0xffff) u_int16_t ioc_status; u_int32_t ioc_loginfo; u_int32_t transfer_count; u_int32_t sense_count; u_int32_t response_info; u_int16_t task_tag; u_int16_t reserved4; u_int32_t bidirectional_transfer_count; u_int32_t reserved5; u_int32_t reserved6; } __packed; struct mpii_request_descriptor { u_int8_t request_flags; u_int8_t vf_id; u_int16_t smid; u_int16_t lmid; /* * the following field is descriptor type dependent * default - undefined * scsi io - device handle * high priority - reserved */ u_int16_t type_dependent; } __packed; struct mpii_reply_descriptor { u_int8_t reply_flags; #define MPII_REPLY_DESCR_FLAGS_TYPE_MASK (0x0F) #define MPII_REPLY_DESCR_FLAGS_SCSI_IO_SUCCESS (0x00) #define MPII_REPLY_DESCR_FLAGS_ADDRESS_REPLY (0x01) #define MPII_REPLY_DESCR_FLAGS_TARGETASSIST_SUCCESS (0x02) #define MPII_REPLY_DESCR_FLAGS_TARGET_COMMAND_BUFFER (0x03) #define MPII_REPLY_DESCR_FLAGS_UNUSED (0x0F) u_int8_t vf_id; /* * the following field is reply descriptor type dependent * default - undefined * scsi io success - smid * address reply - smid */ u_int16_t type_dependent1; /* * the following field is reply descriptor type dependent * default - undefined * scsi io success - bottom 16 bits is task tag * address reply - reply frame address */ u_int32_t type_dependent2; } __packed; struct mpii_request_header { u_int16_t function_dependent1; u_int8_t chain_offset; u_int8_t function; u_int16_t function_dependent2; u_int8_t function_dependent3; u_int8_t message_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved; } __packed; /* XXX JPG delete this? */ struct mpii_msg_scsi_task_request { u_int8_t target_id; u_int8_t bus; u_int8_t chain_offset; u_int8_t function; u_int8_t reserved1; u_int8_t task_type; #define MPII_MSG_SCSI_TASK_TYPE_ABORT_TASK (0x01) #define MPII_MSG_SCSI_TASK_TYPE_ABRT_TASK_SET (0x02) #define MPII_MSG_SCSI_TASK_TYPE_TARGET_RESET (0x03) #define MPII_MSG_SCSI_TASK_TYPE_RESET_BUS (0x04) #define MPII_MSG_SCSI_TASK_TYPE_LOGICAL_UNIT_RESET (0x05) u_int8_t reserved2; u_int8_t msg_flags; u_int32_t msg_context; u_int16_t lun[4]; u_int32_t reserved3[7]; u_int32_t target_msg_context; } __packed; /* XXX JPG delete this? */ struct mpii_msg_scsi_task_reply { u_int8_t target_id; u_int8_t bus; u_int8_t msg_length; u_int8_t function; u_int8_t response_code; u_int8_t task_type; u_int8_t reserved1; u_int8_t msg_flags; u_int32_t msg_context; u_int16_t reserved2; u_int16_t ioc_status; u_int32_t ioc_loginfo; u_int32_t termination_count; } __packed; struct mpii_cfg_hdr { u_int8_t page_version; u_int8_t page_length; u_int8_t page_number; u_int8_t page_type; #define MPII_CONFIG_REQ_PAGE_TYPE_ATTRIBUTE (0xf0) #define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) #define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) #define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) #define MPII_CONFIG_REQ_PAGE_TYPE_MASK (0x0f) #define MPII_CONFIG_REQ_PAGE_TYPE_IO_UNIT (0x00) #define MPII_CONFIG_REQ_PAGE_TYPE_IOC (0x01) #define MPII_CONFIG_REQ_PAGE_TYPE_BIOS (0x02) #define MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL (0x08) #define MPII_CONFIG_REQ_PAGE_TYPE_MANUFACTURING (0x09) #define MPII_CONFIG_REQ_PAGE_TYPE_RAID_PD (0x0A) #define MPII_CONFIG_REQ_PAGE_TYPE_EXTENDED (0x0F) } __packed; struct mpii_ecfg_hdr { u_int8_t page_version; u_int8_t reserved1; u_int8_t page_number; u_int8_t page_type; u_int16_t ext_page_length; u_int8_t ext_page_type; u_int8_t reserved2; } __packed; struct mpii_msg_config_request { u_int8_t action; #define MPII_CONFIG_REQ_ACTION_PAGE_HEADER (0x00) #define MPII_CONFIG_REQ_ACTION_PAGE_READ_CURRENT (0x01) #define MPII_CONFIG_REQ_ACTION_PAGE_WRITE_CURRENT (0x02) #define MPII_CONFIG_REQ_ACTION_PAGE_DEFAULT (0x03) #define MPII_CONFIG_REQ_ACTION_PAGE_WRITE_NVRAM (0x04) #define MPII_CONFIG_REQ_ACTION_PAGE_READ_DEFAULT (0x05) #define MPII_CONFIG_REQ_ACTION_PAGE_READ_NVRAM (0x06) u_int8_t sgl_flags; u_int8_t chain_offset; u_int8_t function; u_int16_t ext_page_len; u_int8_t ext_page_type; #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_IO_UNIT (0x10) #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_EXPANDER (0x11) #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_DEVICE (0x12) #define MPII_CONFIG_REQ_EXTPAGE_TYPE_SAS_PHY (0x13) #define MPII_CONFIG_REQ_EXTPAGE_TYPE_LOG (0x14) #define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) #define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved1; u_int32_t reserved2[2]; struct mpii_cfg_hdr config_header; u_int32_t page_address; /* XXX lots of defns here */ struct mpii_sge page_buffer; } __packed; struct mpii_msg_config_reply { u_int8_t action; u_int8_t sgl_flags; u_int8_t msg_length; u_int8_t function; u_int16_t ext_page_length; u_int8_t ext_page_type; u_int8_t msg_flags; u_int8_t vp_id; u_int8_t vf_id; u_int16_t reserved1; u_int16_t reserved2; u_int16_t ioc_status; u_int32_t ioc_loginfo; struct mpii_cfg_hdr config_header; } __packed; struct mpii_cfg_manufacturing_pg0 { struct mpii_cfg_hdr config_header; char chip_name[16]; char chip_revision[8]; char board_name[16]; char board_assembly[16]; char board_tracer_number[16]; } __packed; struct mpii_cfg_ioc_pg1 { struct mpii_cfg_hdr config_header; u_int32_t flags; u_int32_t coalescing_timeout; #define MPII_CFG_IOC_1_REPLY_COALESCING (1<<0) u_int8_t coalescing_depth; u_int8_t pci_slot_num; u_int8_t pci_bus_num; u_int8_t pci_domain_segment; u_int32_t reserved1; u_int32_t reserved2; } __packed; /* struct mpii_cfg_raid_vol_pg0 { u_int8_t vol_id; u_int8_t vol_bus; u_int8_t vol_ioc; u_int8_t vol_page; u_int8_t vol_type; #define MPII_CFG_RAID_TYPE_RAID_IS (0x00) #define MPII_CFG_RAID_TYPE_RAID_IME (0x01) #define MPII_CFG_RAID_TYPE_RAID_IM (0x02) #define MPII_CFG_RAID_TYPE_RAID_5 (0x03) #define MPII_CFG_RAID_TYPE_RAID_6 (0x04) #define MPII_CFG_RAID_TYPE_RAID_10 (0x05) #define MPII_CFG_RAID_TYPE_RAID_50 (0x06) u_int8_t flags; #define MPII_CFG_RAID_VOL_INACTIVE (1<<3) u_int16_t reserved; } __packed; */ struct mpii_cfg_ioc_pg3 { struct mpii_cfg_hdr config_header; u_int8_t no_phys_disks; u_int8_t reserved[3]; /* followed by a list of mpii_cfg_raid_physdisk structs */ } __packed; struct mpii_cfg_ioc_pg8 { struct mpii_cfg_hdr config_header; u_int8_t num_devs_per_enclosure; u_int8_t reserved1; u_int16_t reserved2; u_int16_t max_persistent_entries; u_int16_t max_num_physical_mapped_ids; u_int16_t flags; u_int16_t reserved3; u_int16_t ir_volume_mapping_flags; u_int16_t reserved4; u_int32_t reserved5; } __packed; struct mpii_cfg_raid_physdisk { u_int8_t phys_disk_id; u_int8_t phys_disk_bus; u_int8_t phys_disk_ioc; u_int8_t phys_disk_num; } __packed; struct mpii_cfg_fc_port_pg0 { struct mpii_cfg_hdr config_header; u_int32_t flags; u_int8_t mpii_port_nr; u_int8_t link_type; u_int8_t port_state; u_int8_t reserved1; u_int32_t port_id; u_int64_t wwnn; u_int64_t wwpn; u_int32_t supported_service_class; u_int32_t supported_speeds; u_int32_t current_speed; u_int32_t max_frame_size; u_int64_t fabric_wwnn; u_int64_t fabric_wwpn; u_int32_t discovered_port_count; u_int32_t max_initiators; u_int8_t max_aliases_supported; u_int8_t max_hard_aliases_supported; u_int8_t num_current_aliases; u_int8_t reserved2; } __packed; struct mpii_cfg_fc_port_pg1 { struct mpii_cfg_hdr config_header; u_int32_t flags; u_int64_t noseepromwwnn; u_int64_t noseepromwwpn; u_int8_t hard_alpa; u_int8_t link_config; u_int8_t topology_config; u_int8_t alt_connector; u_int8_t num_req_aliases; u_int8_t rr_tov; u_int8_t initiator_dev_to; u_int8_t initiator_lo_pend_to; } __packed; struct mpii_cfg_fc_device_pg0 { struct mpii_cfg_hdr config_header; u_int64_t wwnn; u_int64_t wwpn; u_int32_t port_id; u_int8_t protocol; u_int8_t flags; u_int16_t bb_credit; u_int16_t max_rx_frame_size; u_int8_t adisc_hard_alpa; u_int8_t port_nr; u_int8_t fc_ph_low_version; u_int8_t fc_ph_high_version; u_int8_t current_target_id; u_int8_t current_bus; } __packed; struct mpii_cfg_raid_vol_pg0 { struct mpii_cfg_hdr config_header; u_int8_t volume_id; u_int8_t volume_bus; u_int8_t volume_ioc; u_int8_t volume_type; u_int8_t volume_status; #define MPII_CFG_RAID_VOL_0_STATUS_ENABLED (1<<0) #define MPII_CFG_RAID_VOL_0_STATUS_QUIESCED (1<<1) #define MPII_CFG_RAID_VOL_0_STATUS_RESYNCING (1<<2) #define MPII_CFG_RAID_VOL_0_STATUS_ACTIVE (1<<3) #define MPII_CFG_RAID_VOL_0_STATUS_BADBLOCK_FULL (1<<4) u_int8_t volume_state; #define MPII_CFG_RAID_VOL_0_STATE_OPTIMAL (0x00) #define MPII_CFG_RAID_VOL_0_STATE_DEGRADED (0x01) #define MPII_CFG_RAID_VOL_0_STATE_FAILED (0x02) #define MPII_CFG_RAID_VOL_0_STATE_MISSING (0x03) u_int16_t reserved1; u_int16_t volume_settings; #define MPII_CFG_RAID_VOL_0_SETTINGS_WRITE_CACHE_EN (1<<0) #define MPII_CFG_RAID_VOL_0_SETTINGS_OFFLINE_SMART_ERR (1<<1) #define MPII_CFG_RAID_VOL_0_SETTINGS_OFFLINE_SMART (1<<2) #define MPII_CFG_RAID_VOL_0_SETTINGS_AUTO_SWAP (1<<3) #define MPII_CFG_RAID_VOL_0_SETTINGS_HI_PRI_RESYNC (1<<4) #define MPII_CFG_RAID_VOL_0_SETTINGS_PROD_SUFFIX (1<<5) #define MPII_CFG_RAID_VOL_0_SETTINGS_FAST_SCRUB (1<<6) /* obsolete */ #define MPII_CFG_RAID_VOL_0_SETTINGS_DEFAULTS (1<<15) u_int8_t hot_spare_pool; u_int8_t reserved2; u_int32_t max_lba; u_int32_t reserved3; u_int32_t stripe_size; u_int32_t reserved4; u_int32_t reserved5; u_int8_t num_phys_disks; u_int8_t data_scrub_rate; u_int8_t resync_rate; u_int8_t inactive_status; #define MPII_CFG_RAID_VOL_0_INACTIVE_UNKNOWN (0x00) #define MPII_CFG_RAID_VOL_0_INACTIVE_STALE_META (0x01) #define MPII_CFG_RAID_VOL_0_INACTIVE_FOREIGN_VOL (0x02) #define MPII_CFG_RAID_VOL_0_INACTIVE_NO_RESOURCES (0x03) #define MPII_CFG_RAID_VOL_0_INACTIVE_CLONED_VOL (0x04) #define MPII_CFG_RAID_VOL_0_INACTIVE_INSUF_META (0x05) /* followed by a list of mpii_cfg_raid_vol_pg0_physdisk structs */ } __packed; struct mpii_cfg_raid_vol_pg0_physdisk { u_int16_t reserved; u_int8_t phys_disk_map; u_int8_t phys_disk_num; } __packed; struct mpii_cfg_raid_vol_pg1 { struct mpii_cfg_hdr config_header; u_int8_t volume_id; u_int8_t volume_bus; u_int8_t volume_ioc; u_int8_t reserved1; u_int8_t guid[24]; u_int8_t name[32]; u_int64_t wwid; u_int32_t reserved2; u_int32_t reserved3; } __packed; struct mpii_cfg_raid_physdisk_pg0 { struct mpii_cfg_hdr config_header; u_int8_t phys_disk_id; u_int8_t phys_disk_bus; u_int8_t phys_disk_ioc; u_int8_t phys_disk_num; u_int8_t enc_id; u_int8_t enc_bus; u_int8_t hot_spare_pool; u_int8_t enc_type; #define MPII_CFG_RAID_PHYDISK_0_ENCTYPE_NONE (0x0) #define MPII_CFG_RAID_PHYDISK_0_ENCTYPE_SAFTE (0x1) #define MPII_CFG_RAID_PHYDISK_0_ENCTYPE_SES (0x2) u_int32_t reserved1; u_int8_t ext_disk_id[8]; u_int8_t disk_id[16]; u_int8_t vendor_id[8]; u_int8_t product_id[16]; u_int8_t product_rev[4]; u_int8_t info[32]; u_int8_t phys_disk_status; #define MPII_CFG_RAID_PHYDISK_0_STATUS_OUTOFSYNC (1<<0) #define MPII_CFG_RAID_PHYDISK_0_STATUS_QUIESCED (1<<1) u_int8_t phys_disk_state; #define MPII_CFG_RAID_PHYDISK_0_STATE_ONLINE (0x00) #define MPII_CFG_RAID_PHYDISK_0_STATE_MISSING (0x01) #define MPII_CFG_RAID_PHYDISK_0_STATE_INCOMPAT (0x02) #define MPII_CFG_RAID_PHYDISK_0_STATE_FAILED (0x03) #define MPII_CFG_RAID_PHYDISK_0_STATE_INIT (0x04) #define MPII_CFG_RAID_PHYDISK_0_STATE_OFFLINE (0x05) #define MPII_CFG_RAID_PHYDISK_0_STATE_HOSTFAIL (0x06) #define MPII_CFG_RAID_PHYDISK_0_STATE_OTHER (0xff) u_int16_t reserved2; u_int32_t max_lba; u_int8_t error_cdb_byte; u_int8_t error_sense_key; u_int16_t reserved3; u_int16_t error_count; u_int8_t error_asc; u_int8_t error_ascq; u_int16_t smart_count; u_int8_t smart_asc; u_int8_t smart_ascq; } __packed; struct mpii_cfg_raid_physdisk_pg1 { struct mpii_cfg_hdr config_header; u_int8_t num_phys_disk_paths; u_int8_t phys_disk_num; u_int16_t reserved1; u_int32_t reserved2; /* followed by mpii_cfg_raid_physdisk_path structs */ } __packed; struct mpii_cfg_raid_physdisk_path { u_int8_t phys_disk_id; u_int8_t phys_disk_bus; u_int16_t reserved1; u_int64_t wwwid; u_int64_t owner_wwid; u_int8_t ownder_id; u_int8_t reserved2; u_int16_t flags; #define MPII_CFG_RAID_PHYDISK_PATH_INVALID (1<<0) #define MPII_CFG_RAID_PHYDISK_PATH_BROKEN (1<<1) } __packed; #define MPII_CFG_SAS_DEV_ADDR_NEXT (0<<28) #define MPII_CFG_SAS_DEV_ADDR_BUS (1<<28) #define MPII_CFG_SAS_DEV_ADDR_HANDLE (2<<28) struct mpii_cfg_sas_dev_pg0 { struct mpii_ecfg_hdr config_header; u_int16_t slot; u_int16_t enc_handle; u_int64_t sas_addr; u_int16_t parent_dev_handle; u_int8_t phy_num; u_int8_t access_status; u_int16_t dev_handle; u_int8_t target; u_int8_t bus; u_int32_t device_info; #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE (0x7) #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_NONE (0x0) #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_END (0x1) #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_EDGE_EXPANDER (0x2) #define MPII_CFG_SAS_DEV_0_DEVINFO_TYPE_FANOUT_EXPANDER (0x3) #define MPII_CFG_SAS_DEV_0_DEVINFO_SATA_HOST (1<<3) #define MPII_CFG_SAS_DEV_0_DEVINFO_SMP_INITIATOR (1<<4) #define MPII_CFG_SAS_DEV_0_DEVINFO_STP_INITIATOR (1<<5) #define MPII_CFG_SAS_DEV_0_DEVINFO_SSP_INITIATOR (1<<6) #define MPII_CFG_SAS_DEV_0_DEVINFO_SATA_DEVICE (1<<7) #define MPII_CFG_SAS_DEV_0_DEVINFO_SMP_TARGET (1<<8) #define MPII_CFG_SAS_DEV_0_DEVINFO_STP_TARGET (1<<9) #define MPII_CFG_SAS_DEV_0_DEVINFO_SSP_TARGET (1<<10) #define MPII_CFG_SAS_DEV_0_DEVINFO_DIRECT_ATTACHED (1<<11) #define MPII_CFG_SAS_DEV_0_DEVINFO_LSI_DEVICE (1<<12) #define MPII_CFG_SAS_DEV_0_DEVINFO_ATAPI_DEVICE (1<<13) #define MPII_CFG_SAS_DEV_0_DEVINFO_SEP_DEVICE (1<<14) u_int16_t flags; #define MPII_CFG_SAS_DEV_0_FLAGS_DEV_PRESENT (1<<0) #define MPII_CFG_SAS_DEV_0_FLAGS_DEV_MAPPED (1<<1) #define MPII_CFG_SAS_DEV_0_FLAGS_DEV_MAPPED_PERSISTENT (1<<2) #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_PORT_SELECTOR (1<<3) #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_FUA (1<<4) #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_NCQ (1<<5) #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_SMART (1<<6) #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_LBA48 (1<<7) #define MPII_CFG_SAS_DEV_0_FLAGS_UNSUPPORTED (1<<8) #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_SETTINGS (1<<9) u_int8_t physical_port; u_int8_t reserved; } __packed; struct mpii_cfg_raid_config_pg0 { struct mpii_ecfg_hdr config_header; u_int8_t num_hot_spares; u_int8_t num_phys_disks; u_int8_t num_volumes; u_int8_t config_num; u_int32_t flags; #define MPII_CFG_RAID_CONFIG_0_FLAGS_NATIVE (0<<0) #define MPII_CFG_RAID_CONFIG_0_FLAGS_FOREIGN (1<<0) u_int32_t config_guid[6]; u_int32_t reserved1; u_int8_t num_elements; u_int8_t reserved2[3]; /* followed by struct mpii_raid_config_element structs */ } __packed; struct mpii_raid_config_element { u_int16_t element_flags; #define MPII_RAID_CONFIG_ELEMENT_FLAG_VOLUME (0x0) #define MPII_RAID_CONFIG_ELEMENT_FLAG_VOLUME_PHYS_DISK (0x1) #define MPII_RAID_CONFIG_ELEMENT_FLAG_HSP_PHYS_DISK (0x2) #define MPII_RAID_CONFIG_ELEMENT_ONLINE_CE_PHYS_DISK (0x3) u_int16_t vol_dev_handle; u_int8_t hot_spare_pool; u_int8_t phys_disk_num; u_int16_t phys_disk_dev_handle; } __packed; /*#define MPII_DEBUG*/ #ifdef MPII_DEBUG #define DPRINTF(x...) do { if (mpii_debug) printf(x); } while(0) #define DNPRINTF(n,x...) do { if (mpii_debug & (n)) printf(x); } while(0) #define MPII_D_CMD 0x0001 #define MPII_D_INTR 0x0002 #define MPII_D_MISC 0x0004 #define MPII_D_DMA 0x0008 #define MPII_D_IOCTL 0x0010 #define MPII_D_RW 0x0020 #define MPII_D_MEM 0x0040 #define MPII_D_CCB 0x0080 #define MPII_D_PPR 0x0100 #define MPII_D_RAID 0x0200 #define MPII_D_EVT 0x0400 #define MPII_D_CFG 0x0800 uint32_t mpii_debug = 0 | MPII_D_CMD | MPII_D_INTR | MPII_D_MISC | MPII_D_DMA | MPII_D_IOCTL | MPII_D_RW | MPII_D_MEM | MPII_D_CCB | MPII_D_PPR | MPII_D_RAID | MPII_D_EVT | MPII_D_CFG ; #else #define DPRINTF(x...) #define DNPRINTF(n,x...) #endif #define MPII_REQUEST_SIZE 512 #define MPII_REPLY_SIZE 128 #define MPII_REPLY_COUNT (PAGE_SIZE / MPII_REPLY_SIZE) /* * this is the max number of sge's we can stuff in a request frame: * sizeof(scsi_io) + sizeof(sense) + sizeof(sge) * 32 = MPII_REQUEST_SIZE */ #define MPII_MAX_SGL 32 #define MPII_MAX_REQUEST_CREDIT 500 #define MPII_MAX_REPLY_POST_QDEPTH 128 struct mpii_dmamem { bus_dmamap_t mdm_map; bus_dma_segment_t mdm_seg; size_t mdm_size; caddr_t mdm_kva; }; #define MPII_DMA_MAP(_mdm) ((_mdm)->mdm_map) #define MPII_DMA_DVA(_mdm) ((_mdm)->mdm_map->dm_segs[0].ds_addr) #define MPII_DMA_KVA(_mdm) ((void *)(_mdm)->mdm_kva) struct mpii_ccb_bundle { struct mpii_msg_scsi_io mcb_io; /* sgl must follow */ struct mpii_sge mcb_sgl[MPII_MAX_SGL]; struct scsi_sense_data mcb_sense; } __packed; struct mpii_softc; struct mpii_rcb { void *rcb_reply; u_int32_t rcb_reply_dva; }; struct mpii_ccb { struct mpii_softc *ccb_sc; int ccb_smid; struct scsi_xfer *ccb_xs; bus_dmamap_t ccb_dmamap; bus_addr_t ccb_offset; void *ccb_cmd; bus_addr_t ccb_cmd_dva; u_int16_t ccb_dev_handle; volatile enum { MPII_CCB_FREE, MPII_CCB_READY, MPII_CCB_QUEUED } ccb_state; void (*ccb_done)(struct mpii_ccb *); struct mpii_rcb *ccb_rcb; TAILQ_ENTRY(mpii_ccb) ccb_link; }; TAILQ_HEAD(mpii_ccb_list, mpii_ccb); struct mpii_softc { struct device sc_dev; struct scsi_link sc_link; int sc_flags; #define MPII_F_RAID (1<<1) struct scsibus_softc *sc_scsibus; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; bus_size_t sc_ios; bus_dma_tag_t sc_dmat; u_int8_t sc_porttype; int sc_request_depth; int sc_num_reply_frames; int sc_reply_free_qdepth; int sc_reply_post_qdepth; int sc_maxchdepth; int sc_first_sgl_len; int sc_chain_len; int sc_max_sgl_len; u_int8_t sc_ir_firmware; int sc_buswidth; int sc_target; int sc_ioc_number; u_int8_t sc_vf_id; u_int8_t sc_num_ports; struct mpii_ccb *sc_ccbs; struct mpii_ccb_list sc_ccb_free; struct mpii_dmamem *sc_requests; struct mpii_dmamem *sc_replies; struct mpii_rcb *sc_rcbs; struct mpii_dmamem *sc_reply_postq; struct mpii_reply_descriptor *sc_reply_postq_kva; int sc_reply_post_host_index; struct mpii_dmamem *sc_reply_freeq; int sc_reply_free_host_index; size_t sc_fw_len; struct mpii_dmamem *sc_fw; /* scsi ioctl from sd device */ int (*sc_ioctl)(struct device *, u_long, caddr_t); struct rwlock sc_lock; struct mpii_cfg_hdr sc_cfg_hdr; struct mpii_cfg_ioc_pg2 *sc_vol_page; struct mpii_cfg_raid_vol *sc_vol_list; struct mpii_cfg_raid_vol_pg0 *sc_rpg0; struct ksensor *sc_sensors; struct ksensordev sc_sensordev; }; int mpii_attach(struct mpii_softc *); void mpii_detach(struct mpii_softc *); int mpii_intr(void *); int mpii_pci_match(struct device *, void *, void *); void mpii_pci_attach(struct device *, struct device *, void *); int mpii_pci_detach(struct device *, int); struct mpii_pci_softc { struct mpii_softc psc_mpii; pci_chipset_tag_t psc_pc; pcitag_t psc_tag; void *psc_ih; }; struct cfattach mpii_pci_ca = { sizeof(struct mpii_pci_softc), mpii_pci_match, mpii_pci_attach, mpii_pci_detach }; #define PREAD(s, r) pci_conf_read((s)->psc_pc, (s)->psc_tag, (r)) #define PWRITE(s, r, v) pci_conf_write((s)->psc_pc, (s)->psc_tag, (r), (v)) static const struct pci_matchid mpii_devices[] = { { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_SAS2008 } }; int mpii_pci_match(struct device *parent, void *match, void *aux) { return (pci_matchbyid(aux, mpii_devices, nitems(mpii_devices))); } void mpii_pci_attach(struct device *parent, struct device *self, void *aux) { struct mpii_pci_softc *psc = (void *)self; struct mpii_softc *sc = &psc->psc_mpii; struct pci_attach_args *pa = aux; pcireg_t memtype; int r; pci_intr_handle_t ih; const char *intrstr; #ifdef __sparc64__ int node; #endif psc->psc_pc = pa->pa_pc; psc->psc_tag = pa->pa_tag; psc->psc_ih = NULL; sc->sc_dmat = pa->pa_dmat; sc->sc_ios = 0; sc->sc_target = -1; /* find the appropriate memory base */ for (r = PCI_MAPREG_START; r < PCI_MAPREG_END; r += sizeof(memtype)) { memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag, r); if ((memtype & PCI_MAPREG_TYPE_MASK) == PCI_MAPREG_TYPE_MEM) break; } if (r >= PCI_MAPREG_END) { printf(": unable to locate system interface registers\n"); return; } if (pci_mapreg_map(pa, r, memtype, 0, &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, 0xFF) != 0) { printf(": unable to map system interface registers\n"); return; } /* disable the expansion rom */ PWRITE(psc, PCI_ROM_REG, PREAD(psc, PCI_ROM_REG) & ~PCI_ROM_ENABLE); /* hook up the interrupt */ if (pci_intr_map(pa, &ih)) { printf(": unable to map interrupt\n"); goto unmap; } intrstr = pci_intr_string(psc->psc_pc, ih); psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO, mpii_intr, sc, sc->sc_dev.dv_xname); if (psc->psc_ih == NULL) { printf(": unable to map interrupt%s%s\n", intrstr == NULL ? "" : " at ", intrstr == NULL ? "" : intrstr); goto unmap; } printf(": %s", intrstr); #ifdef __sparc64__ /* * Walk up the Open Firmware device tree until we find a * "scsi-initiator-id" property. */ node = PCITAG_NODE(pa->pa_tag); while (node) { if (OF_getprop(node, "scsi-initiator-id", &sc->sc_target, sizeof(sc->sc_target)) == sizeof(sc->sc_target)) break; node = OF_parent(node); #endif if (mpii_attach(sc) != 0) { /* error printed by mpii_attach */ goto deintr; } return; deintr: pci_intr_disestablish(psc->psc_pc, psc->psc_ih); psc->psc_ih = NULL; unmap: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); sc->sc_ios = 0; } int mpii_pci_detach(struct device *self, int flags) { struct mpii_pci_softc *psc = (struct mpii_pci_softc *)self; struct mpii_softc *sc = &psc->psc_mpii; mpii_detach(sc); if (psc->psc_ih != NULL) { pci_intr_disestablish(psc->psc_pc, psc->psc_ih); psc->psc_ih = NULL; } if (sc->sc_ios != 0) { bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); sc->sc_ios = 0; } return (0); } struct cfdriver mpii_cd = { NULL, "mpii", DV_DULL }; int mpii_scsi_cmd(struct scsi_xfer *); void mpii_scsi_cmd_done(struct mpii_ccb *); void mpii_minphys(struct buf *bp, struct scsi_link *sl); int mpii_scsi_probe(struct scsi_link *); int mpii_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int, struct proc *); struct scsi_adapter mpii_switch = { mpii_scsi_cmd, mpii_minphys, NULL, NULL, NULL }; struct scsi_device mpii_dev = { NULL, NULL, NULL, NULL }; struct mpii_dmamem *mpii_dmamem_alloc(struct mpii_softc *, size_t); void mpii_dmamem_free(struct mpii_softc *, struct mpii_dmamem *); int mpii_alloc_ccbs(struct mpii_softc *); struct mpii_ccb *mpii_get_ccb(struct mpii_softc *); void mpii_put_ccb(struct mpii_softc *, struct mpii_ccb *); int mpii_alloc_replies(struct mpii_softc *); int mpii_alloc_queues(struct mpii_softc *); void mpii_push_reply(struct mpii_softc *, u_int32_t); void mpii_push_replies(struct mpii_softc *); void mpii_start(struct mpii_softc *, struct mpii_ccb *); int mpii_complete(struct mpii_softc *, struct mpii_ccb *, int); int mpii_poll(struct mpii_softc *, struct mpii_ccb *, int); int mpii_reply(struct mpii_softc *); void mpii_init_queues(struct mpii_softc *); void mpii_timeout_xs(void *); int mpii_load_xs(struct mpii_ccb *); u_int32_t mpii_read(struct mpii_softc *, bus_size_t); void mpii_write(struct mpii_softc *, bus_size_t, u_int32_t); int mpii_wait_eq(struct mpii_softc *, bus_size_t, u_int32_t, u_int32_t); int mpii_wait_ne(struct mpii_softc *, bus_size_t, u_int32_t, u_int32_t); int mpii_init(struct mpii_softc *); int mpii_reset_soft(struct mpii_softc *); int mpii_reset_hard(struct mpii_softc *); int mpii_handshake_send(struct mpii_softc *, void *, size_t); int mpii_handshake_recv_dword(struct mpii_softc *, u_int32_t *); int mpii_handshake_recv(struct mpii_softc *, void *, size_t); void mpii_empty_done(struct mpii_ccb *); int mpii_iocinit(struct mpii_softc *); int mpii_iocfacts(struct mpii_softc *); int mpii_portfacts(struct mpii_softc *); int mpii_portenable(struct mpii_softc *); int mpii_cfg_coalescing(struct mpii_softc *); /* void mpii_get_raid(struct mpii_softc *); int mpii_fwupload(struct mpii_softc *); int mpii_eventnotify(struct mpii_softc *); void mpii_eventnotify_done(struct mpii_ccb *); void mpii_eventack(struct mpii_softc *, struct mpii_msg_event_reply *); void mpii_eventack_done(struct mpii_ccb *); void mpii_evt_sas(void *, void *); */ int mpii_req_cfg_header(struct mpii_softc *, u_int8_t, u_int8_t, u_int32_t, int, void *); int mpii_req_cfg_page(struct mpii_softc *, u_int32_t, int, void *, int, void *, size_t); void mpii_get_ioc_pg8(struct mpii_softc *); void mpii_get_raid_config_pg0(struct mpii_softc *); #if NBIO > 0 int mpii_bio_get_pg0_raid(struct mpii_softc *, int); int mpii_ioctl(struct device *, u_long, caddr_t); int mpii_ioctl_inq(struct mpii_softc *, struct bioc_inq *); int mpii_ioctl_vol(struct mpii_softc *, struct bioc_vol *); int mpii_ioctl_disk(struct mpii_softc *, struct bioc_disk *); int mpii_ioctl_setstate(struct mpii_softc *, struct bioc_setstate *); #ifndef SMALL_KERNEL int mpii_create_sensors(struct mpii_softc *); void mpii_refresh_sensors(void *); #endif /* SMALL_KERNEL */ #endif /* NBIO > 0 */ #define DEVNAME(s) ((s)->sc_dev.dv_xname) #define dwordsof(s) (sizeof(s) / sizeof(u_int32_t)) #define dwordn(p, n) (((u_int32_t *)(p))[(n)]) #define mpii_read_db(s) mpii_read((s), MPII_DOORBELL) #define mpii_write_db(s, v) mpii_write((s), MPII_DOORBELL, (v)) #define mpii_read_intr(s) mpii_read((s), MPII_INTR_STATUS) #define mpii_write_intr(s, v) mpii_write((s), MPII_INTR_STATUS, (v)) #define mpii_reply_waiting(s) ((mpii_read_intr((s)) & MPII_INTR_STATUS_REPLY)\ == MPII_INTR_STATUS_REPLY) #define mpii_read_reply_free(s, v) mpii_read((s), \ MPII_REPLY_FREE_HOST_INDEX) #define mpii_write_reply_free(s, v) mpii_write((s), \ MPII_REPLY_FREE_HOST_INDEX, (v)) #define mpii_read_reply_post(s, v) mpii_read((s), \ MPII_REPLY_POST_HOST_INDEX) #define mpii_write_reply_post(s, v) mpii_write((s), \ MPII_REPLY_POST_HOST_INDEX, (v)) #define mpii_wait_db_int(s) mpii_wait_ne((s), MPII_INTR_STATUS, \ MPII_INTR_STATUS_IOC2SYSDB, 0) #define mpii_wait_db_ack(s) mpii_wait_eq((s), MPII_INTR_STATUS, \ MPII_INTR_STATUS_SYS2IOCDB, 0) #define mpii_cfg_header(_s, _t, _n, _a, _h) \ mpii_req_cfg_header((_s), (_t), (_n), (_a), 0, (_h)) #define mpii_ecfg_header(_s, _t, _n, _a, _h) \ mpii_req_cfg_header((_s), (_t), (_n), (_a), 1, (_h)) #define mpii_cfg_page(_s, _a, _h, _r, _p, _l) \ mpii_req_cfg_page((_s), (_a), 0, (_h), (_r), (_p), (_l)) #define mpii_ecfg_page(_s, _a, _h, _r, _p, _l) \ mpii_req_cfg_page((_s), (_a), 1, (_h), (_r), (_p), (_l)) int mpii_attach(struct mpii_softc *sc) { struct scsibus_attach_args saa; struct mpii_ccb *ccb; printf("\n"); /* disable interrupts */ mpii_write(sc, MPII_INTR_MASK, MPII_INTR_MASK_RESET | MPII_INTR_MASK_REPLY | MPII_INTR_MASK_DOORBELL); if (mpii_init(sc) != 0) { printf("%s: unable to initialize ioc\n", DEVNAME(sc)); return (1); } if (mpii_iocfacts(sc) != 0) { printf("%s: unable to get iocfacts\n", DEVNAME(sc)); return (1); } if (mpii_alloc_ccbs(sc) != 0) { /* error already printed */ return(1); } if (mpii_alloc_replies(sc) != 0) { printf("%s: unable to allocated reply space\n", DEVNAME(sc)); goto free_ccbs; } if (mpii_alloc_queues(sc) != 0) { printf("%s: unable to allocate reply queues\n", DEVNAME(sc)); goto free_replies; } if (mpii_iocinit(sc) != 0) { printf("%s: unable to send iocinit\n", DEVNAME(sc)); goto free_ccbs; } if (mpii_wait_eq(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, MPII_DOORBELL_STATE_OPER) != 0) { printf("%s: state: 0x%08x\n", DEVNAME(sc), mpii_read_db(sc) & MPII_DOORBELL_STATE); printf("%s: operational state timeout\n", DEVNAME(sc)); goto free_ccbs; } mpii_push_replies(sc); mpii_init_queues(sc); if (mpii_portfacts(sc) != 0) { printf("%s: unable to get portfacts\n", DEVNAME(sc)); goto free_replies; } if (mpii_portenable(sc) != 0) { printf("%s: unable to enable port\n", DEVNAME(sc)); goto free_replies; } mpii_get_ioc_pg8(sc); mpii_get_raid_config_pg0(sc); if (mpii_cfg_coalescing(sc) != 0) /* this is fatal in mpi */ printf("%s: unable to configure coalescing\n", DEVNAME(sc)); /* XXX JPG not yet implemented if (mpii_fwupload(sc) != 0) { printf("%s: unabel to upload firmware\n", DEVNAME(sc)); goto free_replies; }*/ rw_init(&sc->sc_lock, "mpii_lock"); /* we should be good to go now, attach scsibus */ sc->sc_link.device = &mpii_dev; sc->sc_link.adapter = &mpii_switch; sc->sc_link.adapter_softc = sc; sc->sc_link.adapter_target = sc->sc_target; sc->sc_link.adapter_buswidth = sc->sc_buswidth; sc->sc_link.openings = sc->sc_request_depth / sc->sc_buswidth; bzero(&saa, sizeof(saa)); saa.saa_sc_link = &sc->sc_link; /* config_found() returns the scsibus attached to us */ sc->sc_scsibus = (struct scsibus_softc *) config_found(&sc->sc_dev, &saa, scsiprint); /* XXX JPG here we need to: * * get raid pages * do whatever is necessary for MPI2 host mapping * update our array/RB tree for target -> dev_handle mapping */ /* enable interrupts */ mpii_write(sc, MPII_INTR_MASK, MPII_INTR_MASK_DOORBELL | MPII_INTR_MASK_RESET); return (0); free_replies: bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_replies), 0, PAGE_SIZE, BUS_DMASYNC_POSTREAD); mpii_dmamem_free(sc, sc->sc_replies); free_ccbs: while ((ccb = mpii_get_ccb(sc)) != NULL) bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); mpii_dmamem_free(sc, sc->sc_requests); free(sc->sc_ccbs, M_DEVBUF); return(1); } void mpii_detach(struct mpii_softc *sc) { } int mpii_intr(void *arg) { struct mpii_softc *sc = arg; if (mpii_reply(sc) < 0) return (0); while (mpii_reply(sc) >= 0) ; mpii_write_reply_post(sc, sc->sc_reply_post_host_index); return (1); } void mpii_timeout_xs(void *arg) { /* XXX */ } int mpii_load_xs(struct mpii_ccb *ccb) { struct mpii_softc *sc = ccb->ccb_sc; struct scsi_xfer *xs = ccb->ccb_xs; struct mpii_ccb_bundle *mcb = ccb->ccb_cmd; struct mpii_msg_scsi_io *io = &mcb->mcb_io; struct mpii_sge *sge, *nsge = &mcb->mcb_sgl[0]; struct mpii_sge *ce = NULL, *nce; u_int64_t ce_dva; bus_dmamap_t dmap = ccb->ccb_dmamap; u_int32_t addr, flags; int i, error; /* zero length transfer still requires an SGE */ if (xs->datalen == 0) { nsge->sg_hdr = htole32(MPII_SGE_FL_TYPE_SIMPLE | MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL); return (0); } error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL, (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); if (error) { printf("%s: error %d loading dmamap\n", DEVNAME(sc), error); return (1); } /* safe default staring flags */ flags = MPII_SGE_FL_TYPE_SIMPLE | MPII_SGE_FL_SIZE_64; /* if data out */ if (xs->flags & SCSI_DATA_OUT) flags |= MPII_SGE_FL_DIR_OUT; /* we will have to exceed the SGEs we can cram into the request frame */ if (dmap->dm_nsegs > sc->sc_first_sgl_len) { ce = &mcb->mcb_sgl[sc->sc_first_sgl_len - 1]; io->chain_offset = ((u_int8_t *)ce - (u_int8_t *)io) / 4; } for (i = 0; i < dmap->dm_nsegs; i++) { if (nsge == ce) { nsge++; sge->sg_hdr |= htole32(MPII_SGE_FL_LAST); DNPRINTF(MPII_D_DMA, "%s: - 0x%08x 0x%08x 0x%08x\n", DEVNAME(sc), sge->sg_hdr, sge->sg_hi_addr, sge->sg_lo_addr); if ((dmap->dm_nsegs - i) > sc->sc_chain_len) { nce = &nsge[sc->sc_chain_len - 1]; addr = ((u_int8_t *)nce - (u_int8_t *)nsge) / 4; addr = addr << 16 | sizeof(struct mpii_sge) * sc->sc_chain_len; } else { nce = NULL; addr = sizeof(struct mpii_sge) * (dmap->dm_nsegs - i); } ce->sg_hdr = htole32(MPII_SGE_FL_TYPE_CHAIN | MPII_SGE_FL_SIZE_64 | addr); ce_dva = ccb->ccb_cmd_dva + ((u_int8_t *)nsge - (u_int8_t *)mcb); addr = (u_int32_t)(ce_dva >> 32); ce->sg_hi_addr = htole32(addr); addr = (u_int32_t)ce_dva; ce->sg_lo_addr = htole32(addr); DNPRINTF(MPII_D_DMA, "%s: ce: 0x%08x 0x%08x 0x%08x\n", DEVNAME(sc), ce->sg_hdr, ce->sg_hi_addr, ce->sg_lo_addr); ce = nce; } DNPRINTF(MPII_D_DMA, "%s: %d: %d 0x%016llx\n", DEVNAME(sc), i, dmap->dm_segs[i].ds_len, (u_int64_t)dmap->dm_segs[i].ds_addr); sge = nsge; sge->sg_hdr = htole32(flags | dmap->dm_segs[i].ds_len); addr = (u_int32_t)((u_int64_t)dmap->dm_segs[i].ds_addr >> 32); sge->sg_hi_addr = htole32(addr); addr = (u_int32_t)dmap->dm_segs[i].ds_addr; sge->sg_lo_addr = htole32(addr); DNPRINTF(MPII_D_DMA, "%s: %d: 0x%08x 0x%08x 0x%08x\n", DEVNAME(sc), i, sge->sg_hdr, sge->sg_hi_addr, sge->sg_lo_addr); nsge = sge + 1; } /* terminate list */ sge->sg_hdr |= htole32(MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL); bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); return (0); } void mpii_minphys(struct buf *bp, struct scsi_link *sl) { /* XXX */ minphys(bp); } u_int32_t mpii_read(struct mpii_softc *sc, bus_size_t r) { u_int32_t rv; bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, BUS_SPACE_BARRIER_READ); rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r); DNPRINTF(MPII_D_RW, "%s: mpii_read %#x %#x\n", DEVNAME(sc), r, rv); return (rv); } void mpii_write(struct mpii_softc *sc, bus_size_t r, u_int32_t v) { DNPRINTF(MPII_D_RW, "%s: mpii_write %#x %#x\n", DEVNAME(sc), r, v); bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, BUS_SPACE_BARRIER_WRITE); } int mpii_wait_eq(struct mpii_softc *sc, bus_size_t r, u_int32_t mask, u_int32_t target) { int i; DNPRINTF(MPII_D_RW, "%s: mpii_wait_eq %#x %#x %#x\n", DEVNAME(sc), r, mask, target); for (i = 0; i < 10000; i++) { if ((mpii_read(sc, r) & mask) == target) return (0); delay(1000); } return (1); } int mpii_wait_ne(struct mpii_softc *sc, bus_size_t r, u_int32_t mask, u_int32_t target) { int i; DNPRINTF(MPII_D_RW, "%s: mpii_wait_ne %#x %#x %#x\n", DEVNAME(sc), r, mask, target); for (i = 0; i < 10000; i++) { if ((mpii_read(sc, r) & mask) != target) return (0); delay(1000); } return (1); } int mpii_init(struct mpii_softc *sc) { u_int32_t db; int i; /* spin until the ioc leaves the reset state */ if (mpii_wait_ne(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, MPII_DOORBELL_STATE_RESET) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_init timeout waiting to leave " "reset state\n", DEVNAME(sc)); return (1); } /* check current ownership */ db = mpii_read_db(sc); if ((db & MPII_DOORBELL_WHOINIT) == MPII_DOORBELL_WHOINIT_PCIPEER) { DNPRINTF(MPII_D_MISC, "%s: mpii_init initialised by pci peer\n", DEVNAME(sc)); return (0); } for (i = 0; i < 5; i++) { switch (db & MPII_DOORBELL_STATE) { case MPII_DOORBELL_STATE_READY: DNPRINTF(MPII_D_MISC, "%s: mpii_init ioc is ready\n", DEVNAME(sc)); return (0); case MPII_DOORBELL_STATE_OPER: case MPII_DOORBELL_STATE_FAULT: DNPRINTF(MPII_D_MISC, "%s: mpii_init ioc is being " "reset\n" , DEVNAME(sc)); if (mpii_reset_soft(sc) != 0) mpii_reset_hard(sc); break; case MPII_DOORBELL_STATE_RESET: DNPRINTF(MPII_D_MISC, "%s: mpii_init waiting to come " "out of reset\n", DEVNAME(sc)); if (mpii_wait_ne(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, MPII_DOORBELL_STATE_RESET) != 0) return (1); break; } db = mpii_read_db(sc); } return (1); } int mpii_reset_soft(struct mpii_softc *sc) { DNPRINTF(MPII_D_MISC, "%s: mpii_reset_soft\n", DEVNAME(sc)); if (mpii_read_db(sc) & MPII_DOORBELL_INUSE) { printf("db in use\n"); return (1); } mpii_write_db(sc, MPII_DOORBELL_FUNCTION(MPII_FUNCTION_IOC_MESSAGE_UNIT_RESET)); /* XXX LSI waits 15 sec */ if (mpii_wait_db_ack(sc) != 0) return (1); /* XXX LSI waits 15 sec */ if (mpii_wait_eq(sc, MPII_DOORBELL, MPII_DOORBELL_STATE, MPII_DOORBELL_STATE_READY) != 0) return (1); /* XXX wait for Sys2IOCDB bit to clear in HIS?? */ return (0); } int mpii_reset_hard(struct mpii_softc *sc) { u_int16_t i; DNPRINTF(MPII_D_MISC, "%s: mpii_reset_hard\n", DEVNAME(sc)); mpii_write_intr(sc, 0); /* enable diagnostic register */ mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_FLUSH); mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_1); mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_2); mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_3); mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_4); mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_5); mpii_write(sc, MPII_WRITESEQ, MPII_WRITESEQ_6); delay(100); if ((mpii_read(sc, MPII_HOSTDIAG) & MPII_HOSTDIAG_DWRE) == 0) return(1); /* reset ioc */ mpii_write(sc, MPII_HOSTDIAG, MPII_HOSTDIAG_RESET_ADAPTER); /* 200 milliseconds */ delay(200000); /* XXX this whole function should be more robust */ /* XXX read the host diagnostic reg until reset adapter bit clears ? */ for (i = 0; i < 30000; i++) { if ((mpii_read(sc, MPII_HOSTDIAG) & MPII_HOSTDIAG_RESET_ADAPTER) == 0) break; delay(10000); } /* disable diagnostic register */ mpii_write(sc, MPII_WRITESEQ, 0xff); /* XXX what else? */ DNPRINTF(MPII_D_MISC, "%s: done with mpii_reset_hard\n", DEVNAME(sc)); return(0); } int mpii_handshake_send(struct mpii_softc *sc, void *buf, size_t dwords) { u_int32_t *query = buf; int i; /* make sure the doorbell is not in use. */ if (mpii_read_db(sc) & MPII_DOORBELL_INUSE) return (1); /* clear pending doorbell interrupts */ if (mpii_read_intr(sc) & MPII_INTR_STATUS_IOC2SYSDB) mpii_write_intr(sc, 0); /* * first write the doorbell with the handshake function and the * dword count. */ mpii_write_db(sc, MPII_DOORBELL_FUNCTION(MPII_FUNCTION_HANDSHAKE) | MPII_DOORBELL_DWORDS(dwords)); /* * the doorbell used bit will be set because a doorbell function has * started. wait for the interrupt and then ack it. */ if (mpii_wait_db_int(sc) != 0) return (1); mpii_write_intr(sc, 0); /* poll for the acknowledgement. */ if (mpii_wait_db_ack(sc) != 0) return (1); /* write the query through the doorbell. */ for (i = 0; i < dwords; i++) { mpii_write_db(sc, htole32(query[i])); if (mpii_wait_db_ack(sc) != 0) return (1); } return (0); } int mpii_handshake_recv_dword(struct mpii_softc *sc, u_int32_t *dword) { u_int16_t *words = (u_int16_t *)dword; int i; for (i = 0; i < 2; i++) { if (mpii_wait_db_int(sc) != 0) return (1); words[i] = letoh16(mpii_read_db(sc) & MPII_DOORBELL_DATA_MASK); mpii_write_intr(sc, 0); } return (0); } int mpii_handshake_recv(struct mpii_softc *sc, void *buf, size_t dwords) { struct mpii_msg_reply *reply = buf; u_int32_t *dbuf = buf, dummy; int i; /* get the first dword so we can read the length out of the header. */ if (mpii_handshake_recv_dword(sc, &dbuf[0]) != 0) return (1); DNPRINTF(MPII_D_CMD, "%s: mpii_handshake_recv dwords: %d reply: %d\n", DEVNAME(sc), dwords, reply->msg_length); /* * the total length, in dwords, is in the message length field of the * reply header. */ for (i = 1; i < MIN(dwords, reply->msg_length); i++) { if (mpii_handshake_recv_dword(sc, &dbuf[i]) != 0) return (1); } /* if there's extra stuff to come off the ioc, discard it */ while (i++ < reply->msg_length) { if (mpii_handshake_recv_dword(sc, &dummy) != 0) return (1); DNPRINTF(MPII_D_CMD, "%s: mpii_handshake_recv dummy read: " "0x%08x\n", DEVNAME(sc), dummy); } /* wait for the doorbell used bit to be reset and clear the intr */ if (mpii_wait_db_int(sc) != 0) return (1); if (mpii_wait_eq(sc, MPII_DOORBELL, MPII_DOORBELL_INUSE, 0) != 0) return (1); mpii_write_intr(sc, 0); return (0); } void mpii_empty_done(struct mpii_ccb *ccb) { /* nothing to do */ } int mpii_iocfacts(struct mpii_softc *sc) { struct mpii_msg_iocfacts_request ifq; struct mpii_msg_iocfacts_reply ifp; DNPRINTF(MPII_D_MISC, "%s: mpii_iocfacts\n", DEVNAME(sc)); bzero(&ifq, sizeof(ifq)); bzero(&ifp, sizeof(ifp)); ifq.function = MPII_FUNCTION_IOC_FACTS; if (mpii_handshake_send(sc, &ifq, dwordsof(ifq)) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_iocfacts send failed\n", DEVNAME(sc)); return (1); } if (mpii_handshake_recv(sc, &ifp, dwordsof(ifp)) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_iocfacts recv failed\n", DEVNAME(sc)); return (1); } DNPRINTF(MPII_D_MISC, "%s: func: 0x%02x length: %d msgver: %d.%d\n", DEVNAME(sc), ifp.function, ifp.msg_length, ifp.msg_version_maj, ifp.msg_version_min); DNPRINTF(MPII_D_MISC, "%s: msgflags: 0x%02x iocnumber: 0x%02x " "headerver: %d.%d\n", DEVNAME(sc), ifp.msg_flags, ifp.ioc_number, ifp.header_version_unit, ifp.header_version_dev); DNPRINTF(MPII_D_MISC, "%s: vp_id: 0x%02x vf_id: 0x%02x\n", DEVNAME(sc), ifp.vp_id, ifp.vf_id); DNPRINTF(MPII_D_MISC, "%s: iocstatus: 0x%04x ioexceptions: 0x%04x\n", DEVNAME(sc), letoh16(ifp.ioc_status), letoh16(ifp.ioc_exceptions)); DNPRINTF(MPII_D_MISC, "%s: iocloginfo: 0x%08x\n", DEVNAME(sc), letoh32(ifp.ioc_loginfo)); DNPRINTF(MPII_D_MISC, "%s: numberofports: 0x%02x whoinit: 0x%02x " "maxchaindepth: %d\n", DEVNAME(sc), ifp.number_of_ports, ifp.whoinit, ifp.max_chain_depth); DNPRINTF(MPII_D_MISC, "%s: productid: 0x%04x requestcredit: 0x%04x\n", DEVNAME(sc), letoh16(ifp.product_id), letoh16(ifp.request_credit)); DNPRINTF(MPII_D_MISC, "%s: ioc_capabilities: 0x%08x\n", DEVNAME(sc), letoh32(ifp.ioc_capabilities)); DNPRINTF(MPII_D_MISC, "%s: fw_version: %d.%d fw_version_unit: 0x%02x " "fw_version_dev: 0x%02x\n", DEVNAME(sc), ifp.fw_version_maj, ifp.fw_version_min, ifp.fw_version_unit, ifp.fw_version_dev); DNPRINTF(MPII_D_MISC, "%s: iocrequestframesize: 0x%04x\n", DEVNAME(sc), letoh16(ifp.ioc_request_frame_size)); DNPRINTF(MPII_D_MISC, "%s: maxtargets: 0x%04x " "maxinitiators: 0x%04x\n", DEVNAME(sc), letoh16(ifp.max_targets), letoh16(ifp.max_initiators)); DNPRINTF(MPII_D_MISC, "%s: maxenclosures: 0x%04x " "maxsasexpanders: 0x%04x\n", DEVNAME(sc), letoh16(ifp.max_enclosures), letoh16(ifp.max_sas_expanders)); DNPRINTF(MPII_D_MISC, "%s: highprioritycredit: 0x%04x " "protocolflags: 0x%02x\n", DEVNAME(sc), letoh16(ifp.high_priority_credit), letoh16(ifp.protocol_flags)); DNPRINTF(MPII_D_MISC, "%s: maxvolumes: 0x%02x replyframesize: 0x%02x " "mrdpqd: 0x%04x\n", DEVNAME(sc), ifp.max_volumes, ifp.reply_frame_size, letoh16(ifp.max_reply_descriptor_post_queue_depth)); DNPRINTF(MPII_D_MISC, "%s: maxpersistententries: 0x%04x " "maxdevhandle: 0x%02x\n", DEVNAME(sc), letoh16(ifp.max_persistent_entries), letoh16(ifp.max_dev_handle)); sc->sc_maxchdepth = ifp.max_chain_depth; sc->sc_ioc_number = ifp.ioc_number; sc->sc_vf_id = ifp.vf_id; /* XXX JPG should this be max targets + max vol from cfg page ?? */ sc->sc_buswidth = (ifp.max_targets == 0) ? 256 : letoh16(ifp.max_targets); sc->sc_num_ports = ifp.number_of_ports; sc->sc_ir_firmware = (letoh32(ifp.ioc_capabilities) & MPII_IOCFACTS_CAPABILITY_INTEGRATED_RAID) ? 1 : 0; sc->sc_request_depth = MIN(letoh16(ifp.request_credit), MPII_MAX_REQUEST_CREDIT); /* should not be multiple of 16 */ sc->sc_num_reply_frames = sc->sc_request_depth + 32; if (!(sc->sc_num_reply_frames % 16)) sc->sc_num_reply_frames--; /* must be multiple of 16 */ sc->sc_reply_free_qdepth = sc->sc_num_reply_frames + (16 - (sc->sc_num_reply_frames % 16)); sc->sc_reply_post_qdepth = sc->sc_request_depth + sc->sc_num_reply_frames + 1; if (sc->sc_reply_post_qdepth > MPII_MAX_REPLY_POST_QDEPTH) sc->sc_reply_post_qdepth = MPII_MAX_REPLY_POST_QDEPTH; if (sc->sc_reply_post_qdepth > ifp.max_reply_descriptor_post_queue_depth) sc->sc_reply_post_qdepth = ifp.max_reply_descriptor_post_queue_depth; /* XXX JPG temporary override of calculated values. * need to think this through as the specs * and other existing drivers contradict */ sc->sc_reply_post_qdepth = 128; sc->sc_request_depth = 128; sc->sc_num_reply_frames = 63; sc->sc_reply_free_qdepth = 64; DNPRINTF(MPII_D_MISC, "%s: sc_request_depth: %d " "sc_num_reply_frames: %d sc_reply_free_qdepth: %d " "sc_reply_post_qdepth: %d\n", DEVNAME(sc), sc->sc_request_depth, sc->sc_num_reply_frames, sc->sc_reply_free_qdepth, sc->sc_reply_post_qdepth); /* * you can fit sg elements on the end of the io cmd if they fit in the * request frame size. */ sc->sc_first_sgl_len = ((letoh16(ifp.ioc_request_frame_size) * 4) - sizeof(struct mpii_msg_scsi_io)) / sizeof(struct mpii_sge); DNPRINTF(MPII_D_MISC, "%s: first sgl len: %d\n", DEVNAME(sc), sc->sc_first_sgl_len); sc->sc_chain_len = (letoh16(ifp.ioc_request_frame_size) * 4) / sizeof(struct mpii_sge); DNPRINTF(MPII_D_MISC, "%s: chain len: %d\n", DEVNAME(sc), sc->sc_chain_len); /* the sgl tailing the io cmd loses an entry to the chain element. */ sc->sc_max_sgl_len = MPII_MAX_SGL - 1; /* the sgl chains lose an entry for each chain element */ sc->sc_max_sgl_len -= (MPII_MAX_SGL - sc->sc_first_sgl_len) / sc->sc_chain_len; DNPRINTF(MPII_D_MISC, "%s: max sgl len: %d\n", DEVNAME(sc), sc->sc_max_sgl_len); /* XXX we're ignoring the max chain depth */ return(0); } int mpii_iocinit(struct mpii_softc *sc) { struct mpii_msg_iocinit_request iiq; struct mpii_msg_iocinit_reply iip; u_int32_t hi_addr; DNPRINTF(MPII_D_MISC, "%s: mpii_iocinit\n", DEVNAME(sc)); bzero(&iiq, sizeof(iiq)); bzero(&iip, sizeof(iip)); iiq.function = MPII_FUNCTION_IOC_INIT; iiq.whoinit = MPII_WHOINIT_HOST_DRIVER; /* XXX JPG do something about vf_id */ iiq.vf_id = 0; iiq.msg_version_maj = 0x02; iiq.msg_version_min = 0x00; /* XXX JPG ensure compliance with some level and hard-code? */ iiq.hdr_version_unit = 0x00; iiq.hdr_version_dev = 0x00; iiq.system_request_frame_size = htole16(MPII_REQUEST_SIZE / 4); iiq.reply_descriptor_post_queue_depth = htole16(sc->sc_reply_post_qdepth); iiq.reply_free_queue_depth = htole16(sc->sc_reply_free_qdepth); hi_addr = (u_int32_t)((u_int64_t)MPII_DMA_DVA(sc->sc_requests) >> 32); iiq.sense_buffer_address_high = htole32(hi_addr); hi_addr = (u_int32_t) ((u_int64_t)MPII_DMA_DVA(sc->sc_replies) >> 32); iiq.system_reply_address_high = hi_addr; iiq.system_request_frame_base_address = (u_int64_t)MPII_DMA_DVA(sc->sc_requests); iiq.reply_descriptor_post_queue_address = (u_int64_t)MPII_DMA_DVA(sc->sc_reply_postq); iiq.reply_free_queue_address = (u_int64_t)MPII_DMA_DVA(sc->sc_reply_freeq); if (mpii_handshake_send(sc, &iiq, dwordsof(iiq)) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_iocinit send failed\n", DEVNAME(sc)); return (1); } if (mpii_handshake_recv(sc, &iip, dwordsof(iip)) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_iocinit recv failed\n", DEVNAME(sc)); return (1); } DNPRINTF(MPII_D_MISC, "%s: function: 0x%02x msg_length: %d " "whoinit: 0x%02x\n", DEVNAME(sc), iip.function, iip.msg_length, iip.whoinit); DNPRINTF(MPII_D_MISC, "%s: msg_flags: 0x%02x\n", DEVNAME(sc), iip.msg_flags); DNPRINTF(MPII_D_MISC, "%s: vf_id: 0x%02x vp_id: 0x%02x\n", DEVNAME(sc), iip.vf_id, iip.vp_id); DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n", DEVNAME(sc), letoh16(iip.ioc_status)); DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc), letoh32(iip.ioc_loginfo)); if ((iip.ioc_status != MPII_IOCSTATUS_SUCCESS) || (iip.ioc_loginfo)) return (1); return (0); } void mpii_push_reply(struct mpii_softc *sc, u_int32_t rdva) { u_int32_t *rfp; rfp = MPII_DMA_KVA(sc->sc_reply_freeq); rfp[sc->sc_reply_free_host_index] = rdva; sc->sc_reply_free_host_index = (sc->sc_reply_free_host_index + 1) % sc->sc_reply_free_qdepth; mpii_write_reply_free(sc, sc->sc_reply_free_host_index); } int mpii_portfacts(struct mpii_softc *sc) { struct mpii_msg_portfacts_request *pfq; struct mpii_msg_portfacts_reply *pfp; int rv = 1, s; struct mpii_ccb *ccb; DNPRINTF(MPII_D_MISC, "%s: mpii_portfacts\n", DEVNAME(sc)); s = splbio(); ccb = mpii_get_ccb(sc); splx(s); if (ccb == NULL) { DNPRINTF(MPII_D_MISC, "%s: mpii_portfacts mpii_get_ccb fail\n", DEVNAME(sc)); return (rv); } ccb->ccb_done = mpii_empty_done; pfq = ccb->ccb_cmd; bzero(pfq, sizeof(struct mpii_msg_portfacts_request)); pfq->function = MPII_FUNCTION_PORT_FACTS; pfq->chain_offset = 0; pfq->msg_flags = 0; pfq->port_number = 0; pfq->vp_id = 0; pfq->vf_id = 0; if (mpii_poll(sc, ccb, 50000) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_portfacts poll\n", DEVNAME(sc)); goto err; } if (ccb->ccb_rcb == NULL) { DNPRINTF(MPII_D_MISC, "%s: empty portfacts reply\n", DEVNAME(sc)); goto err; } pfp = ccb->ccb_rcb->rcb_reply; DNPRINTF(MPII_D_MISC, "%s pfp: 0x%04x\n", DEVNAME(sc), pfp); DNPRINTF(MPII_D_MISC, "%s: function: 0x%02x msg_length: %d\n", DEVNAME(sc), pfp->function, pfp->msg_length); DNPRINTF(MPII_D_MISC, "%s: msg_flags: 0x%02x port_number: %d\n", DEVNAME(sc), pfp->msg_flags, pfp->port_number); DNPRINTF(MPII_D_MISC, "%s: vf_id: 0x%02x vp_id: 0x%02x\n", DEVNAME(sc), pfp->vf_id, pfp->vp_id); DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n", DEVNAME(sc), letoh16(pfp->ioc_status)); DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc), letoh32(pfp->ioc_loginfo)); DNPRINTF(MPII_D_MISC, "%s: port_type: 0x%02x\n", DEVNAME(sc), pfp->port_type); DNPRINTF(MPII_D_MISC, "%s: max_posted_cmd_buffers: %d\n", DEVNAME(sc), letoh16(pfp->max_posted_cmd_buffers)); sc->sc_porttype = pfp->port_type; /* no such field in MPI2 .... but the dilemma is what * to return to sc_link.adapter_target ... is -1 acceptable? fake 255? if (sc->sc_target == -1) sc->sc_target = letoh16(pfp->port_scsi_id); */ mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); rv = 0; err: mpii_put_ccb(sc, ccb); return (rv); } int mpii_portenable(struct mpii_softc *sc) { struct mpii_msg_portenable_request *peq; struct mpii_msg_portenable_repy *pep; struct mpii_ccb *ccb; int s; DNPRINTF(MPII_D_MISC, "%s: mpii_portenable\n", DEVNAME(sc)); s = splbio(); ccb = mpii_get_ccb(sc); splx(s); if (ccb == NULL) { DNPRINTF(MPII_D_MISC, "%s: mpii_portenable ccb_get\n", DEVNAME(sc)); return (1); } ccb->ccb_done = mpii_empty_done; peq = ccb->ccb_cmd; peq->function = MPII_FUNCTION_PORT_ENABLE; peq->vf_id = sc->sc_vf_id; if (mpii_poll(sc, ccb, 50000) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_portenable poll\n", DEVNAME(sc)); return (1); } if (ccb->ccb_rcb == NULL) { DNPRINTF(MPII_D_MISC, "%s: empty portenable reply\n", DEVNAME(sc)); return (1); } pep = ccb->ccb_rcb->rcb_reply; mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); mpii_put_ccb(sc, ccb); return (0); } int mpii_cfg_coalescing(struct mpii_softc *sc) { struct mpii_cfg_hdr hdr; struct mpii_cfg_ioc_pg1 pg; u_int32_t flags; if (mpii_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_IOC, 1, 0, &hdr) != 0) { DNPRINTF(MPII_D_MISC, "%s: unable to fetch IOC page 1 header\n", DEVNAME(sc)); return (1); } if (mpii_cfg_page(sc, 0, &hdr, 1, &pg, sizeof(pg)) != 0) { DNPRINTF(MPII_D_MISC, "%s: unable to fetch IOC page 1\n" "page 1\n", DEVNAME(sc)); return (1); } DNPRINTF(MPII_D_MISC, "%s: IOC page 1\n", DEVNAME(sc)); DNPRINTF(MPII_D_MISC, "%s: flags: 0x08%x\n", DEVNAME(sc), letoh32(pg.flags)); DNPRINTF(MPII_D_MISC, "%s: coalescing_timeout: %d\n", DEVNAME(sc), letoh32(pg.coalescing_timeout)); DNPRINTF(MPII_D_MISC, "%s: coalescing_depth: %d pci_slot_num: %d\n", DEVNAME(sc), pg.coalescing_timeout, pg.pci_slot_num); flags = letoh32(pg.flags); if (!ISSET(flags, MPII_CFG_IOC_1_REPLY_COALESCING)) return (0); CLR(pg.flags, htole32(MPII_CFG_IOC_1_REPLY_COALESCING)); if (mpii_cfg_page(sc, 0, &hdr, 0, &pg, sizeof(pg)) != 0) { DNPRINTF(MPII_D_MISC, "%s: unable to clear coalescing\n", DEVNAME(sc)); return (1); } return (0); } void mpii_get_raid_config_pg0(struct mpii_softc *sc) { struct mpii_cfg_raid_config_pg0 *config_page; struct mpii_raid_config_element *element_list, *element; struct mpii_ecfg_hdr hdr; size_t pagelen; struct scsi_link *link; int i; DNPRINTF(MPII_D_RAID, "%s: mpii_get_raid_config_pg0\n", DEVNAME(sc)); if (mpii_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, 0, &hdr) != 0) { DNPRINTF(MPII_D_RAID, "%s: mpii_get_raid_config_pg0 unable to " "fetch header for IOC page 2\n", DEVNAME(sc)); return; } pagelen = hdr.ext_page_length * 4; /* dwords to bytes */ config_page = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL); if (config_page == NULL) { DNPRINTF(MPII_D_RAID, "%s: mpii_get_raid_config_pg0 unable to " "allocate space for raid config page 0\n", DEVNAME(sc)); return; } element_list = (struct mpii_raid_config_element *)(config_page + 1); if (mpii_cfg_page(sc, 0, &hdr, 1, config_page, pagelen) != 0) { DNPRINTF(MPII_D_RAID, "%s: mpii_get_raid_config_pg0 unable to " "fetch raid config page 0\n", DEVNAME(sc)); goto out; } DNPRINTF(MPII_D_RAID, "%s: numhotspares: 0x%2x numphysdisks: 0x%02x " "numvolumes: 0x%02x confignum: 0x%02x\n", DEVNAME(sc), config_page->num_hot_spares, config_page->num_phys_disks, config_page->num_volumes, config_page->config_num); DNPRINTF(MPII_D_RAID, "%s: flags: 0x%08x\n", DEVNAME(sc), config_page->flags); DNPRINTF(MPII_D_RAID, "%s: configguid: 0x%08x\n", DEVNAME(sc), config_page->config_guid[0]); DNPRINTF(MPII_D_RAID, "%s: 0x%08x\n", DEVNAME(sc), config_page->config_guid[1]); DNPRINTF(MPII_D_RAID, "%s: 0x%08x\n", DEVNAME(sc), config_page->config_guid[2]); DNPRINTF(MPII_D_RAID, "%s: 0x%08x\n", DEVNAME(sc), config_page->config_guid[3]); DNPRINTF(MPII_D_RAID, "%s numelements: 0x%02x\n", DEVNAME(sc), config_page->num_elements); /* don't walk list if there are no RAID capability */ /* XXX anything like this for MPI2? if (capabilities == 0xdeadbeef) { printf("%s: deadbeef in raid configuration\n", DEVNAME(sc)); goto out; } */ if (config_page->num_volumes == 0) goto out; sc->sc_flags |= MPII_F_RAID; for (i = 0; i < config_page->num_volumes; i++) { element = &element_list[i]; DNPRINTF(MPII_D_RAID, "%s: elementflags: 0x%04x voldevhandle: " "0x%04x\n", DEVNAME(sc), letoh16(element->element_flags), letoh16(element->vol_dev_handle)); DNPRINTF(MPII_D_RAID, "%s: hotsparepool: 0x%02x physdisknum: " "0x%02x physdiskdevhandle: 0x%04x\n", DEVNAME(sc), element->hot_spare_pool, element->phys_disk_num, letoh16(element->phys_disk_dev_handle)); link = sc->sc_scsibus->sc_link[element->vol_dev_handle][0]; if (link == NULL) continue; link->flags |= SDEV_VIRTUAL; } out: free(config_page, M_TEMP); } void mpii_get_ioc_pg8(struct mpii_softc *sc) { struct mpii_cfg_raid_vol *vol_list; struct mpii_cfg_hdr hdr; struct mpii_cfg_ioc_pg8 *vol_page; size_t pagelen; DNPRINTF(MPII_D_RAID, "%s: mpii_get_ioc_pg8\n", DEVNAME(sc)); if (mpii_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_IOC, 8, 0, &hdr) != 0) { DNPRINTF(MPII_D_RAID, "%s: mpii_get_ioc_pg8 unable to fetch header" "for IOC page 8\n", DEVNAME(sc)); return; } pagelen = hdr.page_length * 4; /* dwords to bytes */ vol_page = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL); if (vol_page == NULL) { DNPRINTF(MPII_D_RAID, "%s: mpii_get_ioc_pg8 unable to allocate " "space for ioc config page 8\n", DEVNAME(sc)); return; } vol_list = (struct mpii_cfg_raid_vol *)(vol_page + 1); if (mpii_cfg_page(sc, 0, &hdr, 1, vol_page, pagelen) != 0) { DNPRINTF(MPII_D_RAID, "%s: mpii_get_raid unable to fetch IOC " "page 8\n", DEVNAME(sc)); goto out; } DNPRINTF(MPII_D_RAID, "%s: numdevsperenclosure: 0x%02x\n", DEVNAME(sc), vol_page->num_devs_per_enclosure); DNPRINTF(MPII_D_RAID, "%s: maxpersistententries: 0x%04x " "maxnumphysicalmappedids: 0x%04x\n", DEVNAME(sc), letoh16(vol_page->max_persistent_entries), letoh16(vol_page->max_num_physical_mapped_ids)); DNPRINTF(MPII_D_RAID, "%s: flags: 0x%04x\n", DEVNAME(sc), letoh16(vol_page->flags)); DNPRINTF(MPII_D_RAID, "%s: irvolumemappingflags: 0x%04x\n", DEVNAME(sc), letoh16(vol_page->ir_volume_mapping_flags)); out: free(vol_page, M_TEMP); } int mpii_req_cfg_header(struct mpii_softc *sc, u_int8_t type, u_int8_t number, u_int32_t address, int extended, void *p) { struct mpii_msg_config_request *cq; struct mpii_msg_config_reply *cp; struct mpii_ccb *ccb; struct mpii_cfg_hdr *hdr = p; struct mpii_ecfg_hdr *ehdr = p; int etype = 0; int rv = 0; int s; DNPRINTF(MPII_D_MISC, "%s: mpii_req_cfg_header type: %#x number: %x " "address: 0x%08x extended: %d\n", DEVNAME(sc), type, number, address, extended); s = splbio(); ccb = mpii_get_ccb(sc); splx(s); if (ccb == NULL) { DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_header ccb_get\n", DEVNAME(sc)); return (1); } if (extended) { etype = type; type = MPII_CONFIG_REQ_PAGE_TYPE_EXTENDED; } ccb->ccb_done = mpii_empty_done; cq = ccb->ccb_cmd; cq->function = MPII_FUNCTION_CONFIG; cq->action = MPII_CONFIG_REQ_ACTION_PAGE_HEADER; cq->config_header.page_number = number; cq->config_header.page_type = type; cq->ext_page_type = etype; cq->page_address = htole32(address); cq->page_buffer.sg_hdr = htole32(MPII_SGE_FL_TYPE_SIMPLE | MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL); if (mpii_poll(sc, ccb, 50000) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_header poll\n", DEVNAME(sc)); return (1); } if (ccb->ccb_rcb == NULL) panic("%s: unable to fetch config header\n", DEVNAME(sc)); cp = ccb->ccb_rcb->rcb_reply; DNPRINTF(MPII_D_MISC, "%s: action: 0x%02x sgl_flags: 0x%02x " "msg_length: %d function: 0x%02x\n", DEVNAME(sc), cp->action, cp->sgl_flags, cp->msg_length, cp->function); DNPRINTF(MPII_D_MISC, "%s: ext_page_length: %d ext_page_type: 0x%02x " "msg_flags: 0x%02x\n", DEVNAME(sc), letoh16(cp->ext_page_length), cp->ext_page_type, cp->msg_flags); DNPRINTF(MPII_D_MISC, "%s: vp_id: 0x%02x vf_id: 0x%02x\n", DEVNAME(sc), cp->vp_id, cp->vf_id); DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n", DEVNAME(sc), letoh16(cp->ioc_status)); DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc), letoh32(cp->ioc_loginfo)); DNPRINTF(MPII_D_MISC, "%s: page_version: 0x%02x page_length: %d " "page_number: 0x%02x page_type: 0x%02x\n", DEVNAME(sc), cp->config_header.page_version, cp->config_header.page_length, cp->config_header.page_number, cp->config_header.page_type); if (letoh16(cp->ioc_status) != MPII_IOCSTATUS_SUCCESS) rv = 1; else if (extended) { bzero(ehdr, sizeof(*ehdr)); ehdr->page_version = cp->config_header.page_version; ehdr->page_number = cp->config_header.page_number; ehdr->page_type = cp->config_header.page_type; ehdr->ext_page_length = cp->ext_page_length; ehdr->ext_page_type = cp->ext_page_type; } else *hdr = cp->config_header; mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); mpii_put_ccb(sc, ccb); return (rv); } int mpii_req_cfg_page(struct mpii_softc *sc, u_int32_t address, int extended, void *p, int read, void *page, size_t len) { struct mpii_msg_config_request *cq; struct mpii_msg_config_reply *cp; struct mpii_ccb *ccb; struct mpii_cfg_hdr *hdr = p; struct mpii_ecfg_hdr *ehdr = p; u_int64_t dva; char *kva; int page_length; int rv = 0; int s; DNPRINTF(MPII_D_MISC, "%s: mpii_req_cfg_page address: %d read: %d type: %x\n", DEVNAME(sc), address, read, hdr->page_type); page_length = extended ? letoh16(ehdr->ext_page_length) : hdr->page_length; if (len > MPII_REQUEST_SIZE - sizeof(struct mpii_msg_config_request) || len < page_length * 4) return (1); s = splbio(); ccb = mpii_get_ccb(sc); splx(s); if (ccb == NULL) { DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_page ccb_get\n", DEVNAME(sc)); return (1); } ccb->ccb_done = mpii_empty_done; cq = ccb->ccb_cmd; cq->function = MPII_FUNCTION_CONFIG; cq->action = (read ? MPII_CONFIG_REQ_ACTION_PAGE_READ_CURRENT : MPII_CONFIG_REQ_ACTION_PAGE_WRITE_CURRENT); if (extended) { cq->config_header.page_version = ehdr->page_version; cq->config_header.page_number = ehdr->page_number; cq->config_header.page_type = ehdr->page_type; cq->ext_page_len = ehdr->ext_page_length; cq->ext_page_type = ehdr->ext_page_type; } else cq->config_header = *hdr; cq->config_header.page_type &= MPII_CONFIG_REQ_PAGE_TYPE_MASK; cq->page_address = htole32(address); cq->page_buffer.sg_hdr = htole32(MPII_SGE_FL_TYPE_SIMPLE | MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL | (page_length * 4) | (read ? MPII_SGE_FL_DIR_IN : MPII_SGE_FL_DIR_OUT)); /* bounce the page via the request space to avoid more bus_dma games */ dva = ccb->ccb_cmd_dva + sizeof(struct mpii_msg_config_request); cq->page_buffer.sg_hi_addr = htole32((u_int32_t)(dva >> 32)); cq->page_buffer.sg_lo_addr = htole32((u_int32_t)dva); kva = ccb->ccb_cmd; kva += sizeof(struct mpii_msg_config_request); if (!read) bcopy(page, kva, len); if (mpii_poll(sc, ccb, 50000) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_page poll\n", DEVNAME(sc)); return (1); } if (ccb->ccb_rcb == NULL) { mpii_put_ccb(sc, ccb); return (1); } cp = ccb->ccb_rcb->rcb_reply; DNPRINTF(MPII_D_MISC, "%s: action: 0x%02x sglflags: 0x%02x " "msg_length: %d function: 0x%02x\n", DEVNAME(sc), cp->action, cp->msg_length, cp->function); DNPRINTF(MPII_D_MISC, "%s: ext_page_length: %d ext_page_type: 0x%02x " "msg_flags: 0x%02x\n", DEVNAME(sc), letoh16(cp->ext_page_length), cp->ext_page_type, cp->msg_flags); DNPRINTF(MPII_D_MISC, "%s: vp_id: 0x%02x vf_id: 0x%02x\n", DEVNAME(sc), cp->vp_id, cp->vf_id); DNPRINTF(MPII_D_MISC, "%s: ioc_status: 0x%04x\n", DEVNAME(sc), letoh16(cp->ioc_status)); DNPRINTF(MPII_D_MISC, "%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc), letoh32(cp->ioc_loginfo)); DNPRINTF(MPII_D_MISC, "%s: page_version: 0x%02x page_length: %d " "page_number: 0x%02x page_type: 0x%02x\n", DEVNAME(sc), cp->config_header.page_version, cp->config_header.page_length, cp->config_header.page_number, cp->config_header.page_type); if (letoh16(cp->ioc_status) != MPII_IOCSTATUS_SUCCESS) rv = 1; else if (read) bcopy(kva, page, len); mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); mpii_put_ccb(sc, ccb); return (rv); } int mpii_reply(struct mpii_softc *sc) { struct mpii_reply_descriptor *rdp; struct mpii_ccb *ccb; struct mpii_rcb *rcb = NULL; struct mpii_msg_reply *reply = NULL; u_int8_t reply_flags; u_int32_t reply_dva, i; int smid; DNPRINTF(MPII_D_INTR, "%s: mpii_reply\n", DEVNAME(sc)); /* XXX need to change to to be just the reply we expect to read */ bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), 0, 8 * sc->sc_reply_post_qdepth, BUS_DMASYNC_POSTWRITE); rdp = &sc->sc_reply_postq_kva[sc->sc_reply_post_host_index]; reply_flags = (u_int8_t)(rdp->reply_flags) & MPII_REPLY_DESCR_FLAGS_TYPE_MASK; if ((reply_flags == MPII_REPLY_DESCR_FLAGS_UNUSED)) return (-1); if (dwordn(rdp, 1) == 0xffffffff) /* * ioc is still writing to the reply post queue * race condition - bail! */ return (0); DNPRINTF(MPII_D_INTR, "%s: dword[0]: 0x%08x\n", DEVNAME(sc), letoh32(dwordn(rdp, 0))); DNPRINTF(MPII_D_INTR, "%s: dword[1]: 0x%08x\n", DEVNAME(sc), letoh32(dwordn(rdp, 1))); switch (reply_flags) { case MPII_REPLY_DESCR_FLAGS_ADDRESS_REPLY: /* reply frame address */ reply_dva = letoh32(rdp->type_dependent2); i = (reply_dva - (u_int32_t)MPII_DMA_DVA(sc->sc_replies)) / MPII_REPLY_SIZE; bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_replies), MPII_REPLY_SIZE * i, MPII_REPLY_SIZE, BUS_DMASYNC_POSTREAD); rcb = &sc->sc_rcbs[i]; reply = rcb->rcb_reply; /* fall through */ default: /* smid */ smid = letoh16(rdp->type_dependent1); } DNPRINTF(MPII_D_INTR, "%s: mpii_reply reply_flags: %d smid: %d reply: %p\n", DEVNAME(sc), reply_flags, smid, reply); if (smid == 0) { printf("smid == 0 !!\n"); goto end; } ccb = &sc->sc_ccbs[smid - 1]; /* XXX why is this necessary ? */ bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_requests), ccb->ccb_offset, MPII_REQUEST_SIZE, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ccb->ccb_state = MPII_CCB_READY; ccb->ccb_rcb = rcb; DNPRINTF(MPII_D_INTR, " rcb: 0x%04x\n", rcb); dwordn(rdp, 0) = 0xffffffff; dwordn(rdp, 1) = 0xffffffff; bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), 8 * sc->sc_reply_post_host_index, 8, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); sc->sc_reply_post_host_index = (sc->sc_reply_post_host_index + 1) % sc->sc_reply_post_qdepth; ccb->ccb_done(ccb); end: return (smid); } struct mpii_dmamem * mpii_dmamem_alloc(struct mpii_softc *sc, size_t size) { struct mpii_dmamem *mdm; int nsegs; mdm = malloc(sizeof(struct mpii_dmamem), M_DEVBUF, M_NOWAIT | M_ZERO); if (mdm == NULL) return (NULL); mdm->mdm_size = size; if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mdm->mdm_map) != 0) goto mdmfree; if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mdm->mdm_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) goto destroy; if (bus_dmamem_map(sc->sc_dmat, &mdm->mdm_seg, nsegs, size, &mdm->mdm_kva, BUS_DMA_NOWAIT) != 0) goto free; if (bus_dmamap_load(sc->sc_dmat, mdm->mdm_map, mdm->mdm_kva, size, NULL, BUS_DMA_NOWAIT) != 0) goto unmap; bzero(mdm->mdm_kva, size); DNPRINTF(MPII_D_MEM, "%s: mpii_dmamem_alloc size: %d mdm: %#x " "map: %#x nsegs: %d segs: %#x kva: %x\n", DEVNAME(sc), size, mdm->mdm_map, nsegs, mdm->mdm_seg, mdm->mdm_kva); return (mdm); unmap: bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, size); free: bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1); destroy: bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map); mdmfree: free(mdm, M_DEVBUF); return (NULL); } void mpii_dmamem_free(struct mpii_softc *sc, struct mpii_dmamem *mdm) { DNPRINTF(MPII_D_MEM, "%s: mpii_dmamem_free %#x\n", DEVNAME(sc), mdm); bus_dmamap_unload(sc->sc_dmat, mdm->mdm_map); bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, mdm->mdm_size); bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1); bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map); free(mdm, M_DEVBUF); } int mpii_alloc_ccbs(struct mpii_softc *sc) { struct mpii_ccb *ccb; u_int8_t *cmd; int i; TAILQ_INIT(&sc->sc_ccb_free); sc->sc_ccbs = malloc(sizeof(struct mpii_ccb) * (sc->sc_request_depth-1), M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO); if (sc->sc_ccbs == NULL) { printf("%s: unable to allocate ccbs\n", DEVNAME(sc)); return (1); } sc->sc_requests = mpii_dmamem_alloc(sc, MPII_REQUEST_SIZE * sc->sc_request_depth); if (sc->sc_requests == NULL) { printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc)); goto free_ccbs; } cmd = MPII_DMA_KVA(sc->sc_requests); bzero(cmd, MPII_REQUEST_SIZE * sc->sc_request_depth); /* * we have sc->sc_request_depth system request message frames, but * smid zero cannot be used. * * we then have (sc->sc_request_depth - 1) number of ccbs */ for (i = 1; i < sc->sc_request_depth; i++) { ccb = &sc->sc_ccbs[i - 1]; if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, sc->sc_max_sgl_len, MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap) != 0) { printf("%s: unable to create dma map\n", DEVNAME(sc)); goto free_maps; } ccb->ccb_sc = sc; ccb->ccb_smid = i; ccb->ccb_offset = MPII_REQUEST_SIZE * i; ccb->ccb_cmd = &cmd[ccb->ccb_offset]; ccb->ccb_cmd_dva = (u_int32_t)MPII_DMA_DVA(sc->sc_requests) + ccb->ccb_offset; DNPRINTF(MPII_D_CCB, "%s: mpii_alloc_ccbs(%d) ccb: %#x map: %#x " "sc: %#x smid: %#x offs: %#x cmd: %#x dva: %#x\n", DEVNAME(sc), i, ccb, ccb->ccb_dmamap, ccb->ccb_sc, ccb->ccb_smid, ccb->ccb_offset, ccb->ccb_cmd, ccb->ccb_cmd_dva); mpii_put_ccb(sc, ccb); } return (0); free_maps: while ((ccb = mpii_get_ccb(sc)) != NULL) bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); mpii_dmamem_free(sc, sc->sc_requests); free_ccbs: free(sc->sc_ccbs, M_DEVBUF); return (1); } void mpii_put_ccb(struct mpii_softc *sc, struct mpii_ccb *ccb) { DNPRINTF(MPII_D_CCB, "%s: mpii_put_ccb %#x\n", DEVNAME(sc), ccb); ccb->ccb_state = MPII_CCB_FREE; ccb->ccb_xs = NULL; ccb->ccb_done = NULL; bzero(ccb->ccb_cmd, MPII_REQUEST_SIZE); TAILQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_link); } struct mpii_ccb * mpii_get_ccb(struct mpii_softc *sc) { struct mpii_ccb *ccb; ccb = TAILQ_FIRST(&sc->sc_ccb_free); if (ccb == NULL) { DNPRINTF(MPII_D_CCB, "%s: mpii_get_ccb == NULL\n", DEVNAME(sc)); return (NULL); } TAILQ_REMOVE(&sc->sc_ccb_free, ccb, ccb_link); ccb->ccb_state = MPII_CCB_READY; DNPRINTF(MPII_D_CCB, "%s: mpii_get_ccb %#x\n", DEVNAME(sc), ccb); return (ccb); } int mpii_alloc_replies(struct mpii_softc *sc) { DNPRINTF(MPII_D_MISC, "%s: mpii_alloc_replies\n", DEVNAME(sc)); sc->sc_rcbs = malloc(sc->sc_num_reply_frames * sizeof(struct mpii_rcb), M_DEVBUF, M_WAITOK|M_CANFAIL); if (sc->sc_rcbs == NULL) return (1); sc->sc_replies = mpii_dmamem_alloc(sc, MPII_REPLY_SIZE * sc->sc_num_reply_frames); if (sc->sc_replies == NULL) { free(sc->sc_rcbs, M_DEVBUF); return (1); } return (0); } void mpii_push_replies(struct mpii_softc *sc) { struct mpii_rcb *rcb; char *kva = MPII_DMA_KVA(sc->sc_replies); int i; bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_replies), 0, MPII_REPLY_SIZE * sc->sc_num_reply_frames, BUS_DMASYNC_PREREAD); for (i = 0; i < sc->sc_num_reply_frames; i++) { rcb = &sc->sc_rcbs[i]; rcb->rcb_reply = kva + MPII_REPLY_SIZE * i; rcb->rcb_reply_dva = (u_int32_t)MPII_DMA_DVA(sc->sc_replies) + MPII_REPLY_SIZE * i; mpii_push_reply(sc, rcb->rcb_reply_dva); } } void mpii_start(struct mpii_softc *sc, struct mpii_ccb *ccb) { struct mpii_request_header *rhp; struct mpii_request_descriptor descriptor; DNPRINTF(MPII_D_RW, "%s: mpii_start %#x\n", DEVNAME(sc), ccb->ccb_cmd_dva); rhp = ccb->ccb_cmd; bzero(&descriptor, sizeof(struct mpii_request_descriptor)); switch (rhp->function) { case MPII_FUNCTION_SCSI_IO_REQUEST: descriptor.request_flags = MPII_REQ_DESCRIPTOR_FLAGS_SCSI_IO; /* device handle */ descriptor.type_dependent = htole16(ccb->ccb_dev_handle); break; case MPII_FUNCTION_SCSI_TASK_MGMT: descriptor.request_flags = MPII_REQ_DESCRIPTOR_FLAGS_HIGH_PRIORITY; break; default: descriptor.request_flags = MPII_REQ_DESCRIPTOR_FLAGS_DEFAULT; } descriptor.vf_id = sc->sc_vf_id; descriptor.smid = htole16(ccb->ccb_smid); bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_requests), ccb->ccb_offset, MPII_REQUEST_SIZE, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); ccb->ccb_state = MPII_CCB_QUEUED; DNPRINTF(MPII_D_RW, "%s: MPII_REQ_DESC_POST_LOW (0x%08x) write " "0x%08x\n", DEVNAME(sc), MPII_REQ_DESC_POST_LOW, dwordn(&descriptor, 0)); DNPRINTF(MPII_D_RW, "%s: MPII_REQ_DESC_POST_HIGH (0x%08x) write " "0x%08x\n", DEVNAME(sc), MPII_REQ_DESC_POST_HIGH, dwordn(&descriptor, 1)); /* XXX make this 64 bit? */ mpii_write(sc, MPII_REQ_DESC_POST_LOW, htole32(dwordn(&descriptor, 0))); mpii_write(sc, MPII_REQ_DESC_POST_HIGH, htole32(dwordn(&descriptor, 1))); } int mpii_complete(struct mpii_softc *sc, struct mpii_ccb *ccb, int timeout) { int smid = -1; DNPRINTF(MPII_D_INTR, "%s: mpii_complete timeout %d\n", DEVNAME(sc), timeout); do { /* avoid excessive polling */ if (!mpii_reply_waiting(sc)) { if (timeout-- == 0) return (1); delay(1000); continue; } smid = mpii_reply(sc); /* generates PCI write every completed reply, but * prevents deadlock waiting for specific smid */ mpii_write_reply_post(sc, sc->sc_reply_post_host_index); DNPRINTF(MPII_D_INTR, "%s: mpii_complete call to mpii_reply returned: %d\n", DEVNAME(sc), smid); } while (ccb->ccb_smid != smid); return (0); } int mpii_alloc_queues(struct mpii_softc *sc) { u_int32_t *kva; u_int64_t *kva64; int i; DNPRINTF(MPII_D_MISC, "%s: mpii_alloc_queues\n", DEVNAME(sc)); sc->sc_reply_freeq = mpii_dmamem_alloc(sc, sc->sc_reply_free_qdepth * 4); if (sc->sc_reply_freeq == NULL) return (1); kva = MPII_DMA_KVA(sc->sc_reply_freeq); for (i = 0; i < sc->sc_num_reply_frames; i++) { kva[i] = (u_int32_t)MPII_DMA_DVA(sc->sc_replies) + MPII_REPLY_SIZE * i; DNPRINTF(MPII_D_MISC, "%s: %d: 0x%08x = 0x%08x\n", DEVNAME(sc), i, &kva[i], (u_int32_t)MPII_DMA_DVA(sc->sc_replies) + MPII_REPLY_SIZE * i); } sc->sc_reply_postq = mpii_dmamem_alloc(sc, sc->sc_reply_post_qdepth * 8); if (sc->sc_reply_postq == NULL) goto free_reply_freeq; sc->sc_reply_postq_kva = MPII_DMA_KVA(sc->sc_reply_postq); DNPRINTF(MPII_D_MISC, "%s: populating reply post descriptor queue\n", DEVNAME(sc)); kva64 = (u_int64_t *)MPII_DMA_KVA(sc->sc_reply_postq); for (i = 0; i < sc->sc_reply_post_qdepth; i++) { kva64[i] = 0xffffffffffffffffllu; DNPRINTF(MPII_D_MISC, "%s: %d: 0x%08x = 0x%lx\n", DEVNAME(sc), i, &kva64[i], kva64[i]); } return (0); free_reply_freeq: mpii_dmamem_free(sc, sc->sc_reply_freeq); return (1); } void mpii_init_queues(struct mpii_softc *sc) { DNPRINTF(MPII_D_MISC, "%s: mpii_init_queues\n", DEVNAME(sc)); sc->sc_reply_free_host_index = sc->sc_reply_free_qdepth - 1; sc->sc_reply_post_host_index = 0; mpii_write_reply_free(sc, sc->sc_reply_free_host_index); mpii_write_reply_post(sc, sc->sc_reply_post_host_index); } int mpii_poll(struct mpii_softc *sc, struct mpii_ccb *ccb, int timeout) { int error; int s; DNPRINTF(MPII_D_CMD, "%s: mpii_poll\n", DEVNAME(sc)); DNPRINTF(MPII_D_CMD, " ccb->ccb_cmd: 0x%08x\n", DEVNAME(sc), ccb->ccb_cmd); s = splbio(); mpii_start(sc, ccb); error = mpii_complete(sc, ccb, timeout); splx(s); return (error); } int mpii_scsi_cmd(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; struct mpii_softc *sc = link->adapter_softc; struct mpii_ccb *ccb; struct mpii_ccb_bundle *mcb; struct mpii_msg_scsi_io *io; int s; DNPRINTF(MPII_D_CMD, "%s: mpii_scsi_cmd\n", DEVNAME(sc)); if (xs->cmdlen > MPII_CDB_LEN) { DNPRINTF(MPII_D_CMD, "%s: CBD too big %d\n", DEVNAME(sc), xs->cmdlen); bzero(&xs->sense, sizeof(xs->sense)); xs->sense.error_code = SSD_ERRCODE_VALID | 0x70; xs->sense.flags = SKEY_ILLEGAL_REQUEST; xs->sense.add_sense_code = 0x20; xs->error = XS_SENSE; xs->flags |= ITSDONE; s = splbio(); scsi_done(xs); splx(s); return (COMPLETE); } s = splbio(); ccb = mpii_get_ccb(sc); splx(s); if (ccb == NULL) return (NO_CCB); DNPRINTF(MPII_D_CMD, "%s: ccb_smid: %d xs->flags: 0x%x\n", DEVNAME(sc), ccb->ccb_smid, xs->flags); ccb->ccb_xs = xs; ccb->ccb_done = mpii_scsi_cmd_done; mcb = ccb->ccb_cmd; io = &mcb->mcb_io; io->function = MPII_FUNCTION_SCSI_IO_REQUEST; io->sense_buffer_length = sizeof(xs->sense); io->sgl_offset0 = 24; /* XXX fix this */ io->io_flags = htole16(xs->cmdlen); io->dev_handle = htole32(link->target); io->lun[0] = htobe16(link->lun); switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { case SCSI_DATA_IN: io->direction = MPII_SCSIIO_DIR_READ; break; case SCSI_DATA_OUT: io->direction = MPII_SCSIIO_DIR_WRITE; break; default: io->direction = MPII_SCSIIO_DIR_NONE; break; } io->tagging = MPII_SCSIIO_ATTR_SIMPLE_Q; bcopy(xs->cmd, io->cdb, xs->cmdlen); io->data_length = htole32(xs->datalen); io->sense_buffer_low_address = htole32(ccb->ccb_cmd_dva + ((u_int8_t *)&mcb->mcb_sense - (u_int8_t *)mcb)); if (mpii_load_xs(ccb) != 0) { xs->error = XS_DRIVER_STUFFUP; xs->flags |= ITSDONE; s = splbio(); mpii_put_ccb(sc, ccb); scsi_done(xs); splx(s); return (COMPLETE); } timeout_set(&xs->stimeout, mpii_timeout_xs, ccb); DNPRINTF(MPII_D_CMD, "%s: sizeof(mpii_msg_scsi_io): %d " "sizeof(mpii_ccb_bundle): %d sge offset: 0x%02x\n", DEVNAME(sc), sizeof(struct mpii_msg_scsi_io), sizeof(struct mpii_ccb_bundle), (u_int8_t *)&mcb->mcb_sgl[0] - (u_int8_t *)mcb); DNPRINTF(MPII_D_CMD, "%s sgl[0]: 0x%04x 0%04x 0x%04x\n", DEVNAME(sc), mcb->mcb_sgl[0].sg_hdr, mcb->mcb_sgl[0].sg_lo_addr, mcb->mcb_sgl[0].sg_hi_addr); DNPRINTF(MPII_D_CMD, "%s: Offset0: 0x%02x\n", DEVNAME(sc), io->sgl_offset0); if (xs->flags & SCSI_POLL) { if (mpii_poll(sc, ccb, xs->timeout) != 0) { xs->error = XS_DRIVER_STUFFUP; xs->flags |= ITSDONE; s = splbio(); scsi_done(xs); splx(s); } return (COMPLETE); } DNPRINTF(MPII_D_CMD, "%s: mpii_scsi_cmd(): opcode: %02x datalen: %d " "req_sense_len: %d\n", DEVNAME(sc), xs->cmd->opcode, xs->datalen, xs->req_sense_length); s = splbio(); mpii_start(sc, ccb); splx(s); return (SUCCESSFULLY_QUEUED); } void mpii_scsi_cmd_done(struct mpii_ccb *ccb) { struct mpii_msg_scsi_io_error *sie; struct mpii_softc *sc = ccb->ccb_sc; struct scsi_xfer *xs = ccb->ccb_xs; struct mpii_ccb_bundle *mcb = ccb->ccb_cmd; bus_dmamap_t dmap = ccb->ccb_dmamap; if (xs->datalen != 0) { bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_dmat, dmap); } /* timeout_del */ xs->error = XS_NOERROR; xs->resid = 0; xs->flags |= ITSDONE; if (ccb->ccb_rcb == NULL) { /* no scsi error, we're ok so drop out early */ xs->status = SCSI_OK; mpii_put_ccb(sc, ccb); scsi_done(xs); return; } sie = ccb->ccb_rcb->rcb_reply; DNPRINTF(MPII_D_CMD, "%s: mpii_scsi_cmd_done xs cmd: 0x%02x len: %d " "flags 0x%x\n", DEVNAME(sc), xs->cmd->opcode, xs->datalen, xs->flags); DNPRINTF(MPII_D_CMD, "%s: dev_handle: %d msg_length: %d " "function: 0x%02x\n", DEVNAME(sc), letoh16(sie->dev_handle), sie->msg_length, sie->function); DNPRINTF(MPII_D_CMD, "%s: vp_id: 0x%02x vf_id: 0x%02x\n", DEVNAME(sc), sie->vp_id, sie->vf_id); DNPRINTF(MPII_D_CMD, "%s: scsi_status: 0x%02x scsi_state: 0x%02x " "ioc_status: 0x%04x\n", DEVNAME(sc), sie->scsi_status, sie->scsi_state, letoh16(sie->ioc_status)); DNPRINTF(MPII_D_CMD, "%s: ioc_loginfo: 0x%08x\n", DEVNAME(sc), letoh32(sie->ioc_loginfo)); DNPRINTF(MPII_D_CMD, "%s: transfer_count: %d\n", DEVNAME(sc), letoh32(sie->transfer_count)); DNPRINTF(MPII_D_CMD, "%s: sense_count: %d\n", DEVNAME(sc), letoh32(sie->sense_count)); DNPRINTF(MPII_D_CMD, "%s: response_info: 0x%08x\n", DEVNAME(sc), letoh32(sie->response_info)); DNPRINTF(MPII_D_CMD, "%s: task_tag: 0x%04x\n", DEVNAME(sc), letoh16(sie->task_tag)); DNPRINTF(MPII_D_CMD, "%s: bidirectional_transfer_count: 0x%08x\n", DEVNAME(sc), letoh32(sie->bidirectional_transfer_count)); xs->status = sie->scsi_status; switch (letoh16(sie->ioc_status)) { case MPII_IOCSTATUS_SCSI_DATA_UNDERRUN: xs->resid = xs->datalen - letoh32(sie->transfer_count); if (sie->scsi_state & MPII_SCSIIO_ERR_STATE_NO_SCSI_STATUS) { xs->error = XS_DRIVER_STUFFUP; break; } /* FALLTHROUGH */ case MPII_IOCSTATUS_SUCCESS: case MPII_IOCSTATUS_SCSI_RECOVERED_ERROR: switch (xs->status) { case SCSI_OK: xs->resid = 0; break; case SCSI_CHECK: xs->error = XS_SENSE; break; case SCSI_BUSY: case SCSI_QUEUE_FULL: xs->error = XS_BUSY; break; default: xs->error = XS_DRIVER_STUFFUP; break; } break; case MPII_IOCSTATUS_BUSY: case MPII_IOCSTATUS_INSUFFICIENT_RESOURCES: xs->error = XS_BUSY; break; case MPII_IOCSTATUS_SCSI_INVALID_DEVHANDLE: case MPII_IOCSTATUS_SCSI_DEVICE_NOT_THERE: xs->error = XS_SELTIMEOUT; break; default: xs->error = XS_DRIVER_STUFFUP; break; } if (sie->scsi_state & MPII_SCSIIO_ERR_STATE_AUTOSENSE_VALID) bcopy(&mcb->mcb_sense, &xs->sense, sizeof(xs->sense)); DNPRINTF(MPII_D_CMD, "%s: xs err: 0x%02x status: %d\n", DEVNAME(sc), xs->error, xs->status); mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); mpii_put_ccb(sc, ccb); scsi_done(xs); }