This patch continues the libefc_sli SLI-4 library population. This patch adds routines to create mailbox commands used during adapter initialization and adds APIs to issue mailbox commands to the adapter through the bootstrap mailbox register. Signed-off-by: Ram Vegesna <ram.vegesna@xxxxxxxxxxxx> Signed-off-by: James Smart <jsmart2021@xxxxxxxxx> --- drivers/scsi/elx/libefc_sli/sli4.c | 1767 ++++++++++++++++++++++++++++++++++++ drivers/scsi/elx/libefc_sli/sli4.h | 2 + 2 files changed, 1769 insertions(+) diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c index 9e57fa850da6..1306d0a335c6 100644 --- a/drivers/scsi/elx/libefc_sli/sli4.c +++ b/drivers/scsi/elx/libefc_sli/sli4.c @@ -4281,3 +4281,1770 @@ sli_fc_rqe_rqid_and_index(struct sli4_s *sli4, u8 *cqe, return rc; } + +/* + * @brief Wait for the bootstrap mailbox to report "ready". + * + * @param sli4 SLI context pointer. + * @param msec Number of milliseconds to wait. + * + * @return Returns 0 if BMBX is ready, or non-zero otherwise + * (i.e. time out occurred). + */ +static int +sli_bmbx_wait(struct sli4_s *sli4, u32 msec) +{ + u32 val = 0; + + do { + mdelay(1); /* 1 ms */ + val = readl(sli4->reg[0] + SLI4_BMBX_REG); + msec--; + } while (msec && !(val & SLI4_BMBX_RDY)); + + val = (!(val & SLI4_BMBX_RDY)); + return val; +} + +/** + * @brief Write bootstrap mailbox. + * + * @param sli4 SLI context pointer. + * + * @return Returns 0 if command succeeded, or non-zero otherwise. + */ +static int +sli_bmbx_write(struct sli4_s *sli4) +{ + u32 val = 0; + + /* write buffer location to bootstrap mailbox register */ + val = SLI4_BMBX_WRITE_HI(sli4->bmbx.phys); + writel(val, (sli4->reg[0] + SLI4_BMBX_REG)); + + if (sli_bmbx_wait(sli4, SLI4_BMBX_DELAY_US)) { + efc_log_crit(sli4, "BMBX WRITE_HI failed\n"); + return -1; + } + val = SLI4_BMBX_WRITE_LO(sli4->bmbx.phys); + writel(val, (sli4->reg[0] + SLI4_BMBX_REG)); + + /* wait for SLI Port to set ready bit */ + return sli_bmbx_wait(sli4, SLI4_BMBX_TIMEOUT_MSEC); +} + +/** + * @ingroup sli + * @brief Submit a command to the bootstrap mailbox and check the status. + * + * @param sli4 SLI context pointer. + * + * @return Returns 0 on success, or a non-zero value on failure. + */ +int +sli_bmbx_command(struct sli4_s *sli4) +{ + void *cqe = (u8 *)sli4->bmbx.virt + SLI4_BMBX_SIZE; + + if (sli_fw_error_status(sli4) > 0) { + efc_log_crit(sli4, "Chip is in an error state -Mailbox command rejected"); + efc_log_crit(sli4, " status=%#x error1=%#x error2=%#x\n", + sli_reg_read_status(sli4), + sli_reg_read_err1(sli4), + sli_reg_read_err2(sli4)); + return -1; + } + + if (sli_bmbx_write(sli4)) { + efc_log_crit(sli4, "bootstrap mailbox write fail phys=%p reg=%#x\n", + (void *)sli4->bmbx.phys, + readl(sli4->reg[0] + SLI4_BMBX_REG)); + return -1; + } + + /* check completion queue entry status */ + if (le32_to_cpu(((struct sli4_mcqe_s *)cqe)->dw3_flags) & + SLI4_MCQE_VALID) { + return sli_cqe_mq(sli4, cqe); + } + efc_log_crit(sli4, "invalid or wrong type\n"); + return -1; +} + +/** + * @ingroup sli + * @brief Write a CONFIG_LINK command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_config_link(struct sli4_s *sli4, void *buf, size_t size) +{ + struct sli4_cmd_config_link_s *config_link = buf; + + memset(buf, 0, size); + + config_link->hdr.command = MBX_CMD_CONFIG_LINK; + + /* Port interprets zero in a field as "use default value" */ + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a DOWN_LINK command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_down_link(struct sli4_s *sli4, void *buf, size_t size) +{ + struct sli4_mbox_command_header_s *hdr = buf; + + memset(buf, 0, size); + + hdr->command = MBX_CMD_DOWN_LINK; + + /* Port interprets zero in a field as "use default value" */ + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a DUMP Type 4 command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param wki The well known item ID. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_dump_type4(struct sli4_s *sli4, void *buf, + size_t size, u16 wki) +{ + struct sli4_cmd_dump4_s *cmd = buf; + + memset(buf, 0, size); + + cmd->hdr.command = MBX_CMD_DUMP; + cmd->type_dword = cpu_to_le32(0x4); + cmd->wki_selection = cpu_to_le16(wki); + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_READ_TRANSCEIVER_DATA command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param page_num The page of SFP data to retrieve (0xa0 or 0xa2). + * @param dma DMA structure from which the data will be copied. + * + * @note This creates a Version 0 message. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_read_transceiver_data(struct sli4_s *sli4, void *buf, + size_t size, u32 page_num, + struct efc_dma_s *dma) +{ + struct sli4_rqst_cmn_read_transceiver_data_s *req = NULL; + u32 psize; + + if (!dma) + psize = SLI_CONFIG_PYLD_LENGTH(cmn_read_transceiver_data); + else + psize = dma->size; + + req = sli_config_cmd_init(sli4, buf, size, + psize, dma); + if (!req) + return EFC_FAIL; + + req->hdr.opcode = CMN_READ_TRANS_DATA; + req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + req->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_read_transceiver_data); + + req->page_number = cpu_to_le32(page_num); + req->port = cpu_to_le32(sli4->port_number); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a READ_LINK_STAT command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param req_ext_counters If TRUE, + * then the extended counters will be requested. + * @param clear_overflow_flags If TRUE, then overflow flags will be cleared. + * @param clear_all_counters If TRUE, the counters will be cleared. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_read_link_stats(struct sli4_s *sli4, void *buf, size_t size, + u8 req_ext_counters, + u8 clear_overflow_flags, + u8 clear_all_counters) +{ + struct sli4_cmd_read_link_stats_s *cmd = buf; + u32 flags; + + memset(buf, 0, size); + + cmd->hdr.command = MBX_CMD_READ_LNK_STAT; + + flags = 0; + if (req_ext_counters) + flags |= SLI4_READ_LNKSTAT_REC; + if (clear_all_counters) + flags |= SLI4_READ_LNKSTAT_CLRC; + if (clear_overflow_flags) + flags |= SLI4_READ_LNKSTAT_CLOF; + + cmd->dw1_flags = cpu_to_le32(flags); + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a READ_STATUS command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param clear_counters If TRUE, the counters will be cleared. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_read_status(struct sli4_s *sli4, void *buf, size_t size, + u8 clear_counters) +{ + struct sli4_cmd_read_status_s *cmd = buf; + u32 flags = 0; + + memset(buf, 0, size); + + cmd->hdr.command = MBX_CMD_READ_STATUS; + if (clear_counters) + flags |= SLI4_READSTATUS_CLEAR_COUNTERS; + else + flags &= ~SLI4_READSTATUS_CLEAR_COUNTERS; + + cmd->dw1_flags = cpu_to_le32(flags); + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write an INIT_LINK command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param speed Link speed. + * @param reset_alpa For native FC, this is the selective reset AL_PA + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_init_link(struct sli4_s *sli4, void *buf, size_t size, + u32 speed, u8 reset_alpa) +{ + struct sli4_cmd_init_link_s *init_link = buf; + u32 flags = 0; + + memset(buf, 0, size); + + init_link->hdr.command = MBX_CMD_INIT_LINK; + + init_link->sel_reset_al_pa_dword = + cpu_to_le32(reset_alpa); + flags &= ~SLI4_INIT_LINK_FLAG_LOOPBACK; + + init_link->link_speed_sel_code = cpu_to_le32(speed); + switch (speed) { + case FC_LINK_SPEED_1G: + case FC_LINK_SPEED_2G: + case FC_LINK_SPEED_4G: + case FC_LINK_SPEED_8G: + case FC_LINK_SPEED_16G: + case FC_LINK_SPEED_32G: + flags |= SLI4_INIT_LINK_FLAG_FIXED_SPEED; + break; + case FC_LINK_SPEED_10G: + efc_log_info(sli4, "unsupported FC speed %d\n", speed); + init_link->flags0 = cpu_to_le32(flags); + return EFC_FAIL; + } + + switch (sli4->topology) { + case SLI4_READ_CFG_TOPO_FC: + /* Attempt P2P but failover to FC-AL */ + flags |= SLI4_INIT_LINK_FLAG_EN_TOPO_FAILOVER; + + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY; + flags |= (SLI4_INIT_LINK_F_P2P_FAIL_OVER << 1); + break; + case SLI4_READ_CFG_TOPO_FC_AL: + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY; + flags |= (SLI4_INIT_LINK_F_FCAL_ONLY << 1); + if (speed == FC_LINK_SPEED_16G || + speed == FC_LINK_SPEED_32G) { + efc_log_info(sli4, "unsupported FC-AL speed %d\n", + speed); + init_link->flags0 = cpu_to_le32(flags); + return EFC_FAIL; + } + break; + case SLI4_READ_CFG_TOPO_FC_DA: + flags &= ~SLI4_INIT_LINK_FLAG_TOPOLOGY; + flags |= (FC_TOPOLOGY_P2P << 1); + break; + default: + + efc_log_info(sli4, "unsupported topology %#x\n", + sli4->topology); + + init_link->flags0 = cpu_to_le32(flags); + return EFC_FAIL; + } + + flags &= (~SLI4_INIT_LINK_FLAG_UNFAIR); + flags &= (~SLI4_INIT_LINK_FLAG_SKIP_LIRP_LILP); + flags &= (~SLI4_INIT_LINK_FLAG_LOOP_VALIDITY); + flags &= (~SLI4_INIT_LINK_FLAG_SKIP_LISA); + flags &= (~SLI4_INIT_LINK_FLAG_SEL_HIGHTEST_AL_PA); + init_link->flags0 = cpu_to_le32(flags); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write an INIT_VFI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param vfi VFI + * @param fcfi FCFI + * @param vpi VPI (Set to -1 if unused.) + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_init_vfi(struct sli4_s *sli4, void *buf, size_t size, + u16 vfi, u16 fcfi, u16 vpi) +{ + struct sli4_cmd_init_vfi_s *init_vfi = buf; + u16 flags = 0; + + memset(buf, 0, size); + + init_vfi->hdr.command = MBX_CMD_INIT_VFI; + + init_vfi->vfi = cpu_to_le16(vfi); + init_vfi->fcfi = cpu_to_le16(fcfi); + + /* + * If the VPI is valid, initialize it at the same time as + * the VFI + */ + if (vpi != U16_MAX) { + flags |= SLI4_INIT_VFI_FLAG_VP; + init_vfi->flags0_word = cpu_to_le16(flags); + init_vfi->vpi = cpu_to_le16(vpi); + } + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write an INIT_VPI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param vpi VPI allocated. + * @param vfi VFI associated with this VPI. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_init_vpi(struct sli4_s *sli4, void *buf, size_t size, + u16 vpi, u16 vfi) +{ + struct sli4_cmd_init_vpi_s *init_vpi = buf; + + memset(buf, 0, size); + + init_vpi->hdr.command = MBX_CMD_INIT_VPI; + init_vpi->vpi = cpu_to_le16(vpi); + init_vpi->vfi = cpu_to_le16(vfi); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a POST_XRI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param xri_base Starting XRI value for range of XRI given to SLI Port. + * @param xri_count Number of XRIs provided to the SLI Port. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_post_xri(struct sli4_s *sli4, void *buf, size_t size, + u16 xri_base, u16 xri_count) +{ + struct sli4_cmd_post_xri_s *post_xri = buf; + u16 xri_count_flags = 0; + + memset(buf, 0, size); + + post_xri->hdr.command = MBX_CMD_POST_XRI; + post_xri->xri_base = cpu_to_le16(xri_base); + xri_count_flags = (xri_count & SLI4_POST_XRI_COUNT); + xri_count_flags |= SLI4_POST_XRI_FLAG_ENX; + xri_count_flags |= SLI4_POST_XRI_FLAG_VAL; + post_xri->xri_count_flags = cpu_to_le16(xri_count_flags); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a RELEASE_XRI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param num_xri The number of XRIs to be released. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_release_xri(struct sli4_s *sli4, void *buf, size_t size, + u8 num_xri) +{ + struct sli4_cmd_release_xri_s *release_xri = buf; + + memset(buf, 0, size); + + release_xri->hdr.command = MBX_CMD_RELEASE_XRI; + release_xri->xri_count_word = cpu_to_le16(num_xri & + SLI4_RELEASE_XRI_COUNT); + + return EFC_SUCCESS; +} + +/** + * @brief Write a READ_CONFIG command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes + * + * @return Returns the number of bytes written. + */ +static int +sli_cmd_read_config(struct sli4_s *sli4, void *buf, size_t size) +{ + struct sli4_cmd_read_config_s *read_config = buf; + + memset(buf, 0, size); + + read_config->hdr.command = MBX_CMD_READ_CONFIG; + + return EFC_SUCCESS; +} + +/** + * @brief Write a READ_NVPARMS command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_read_nvparms(struct sli4_s *sli4, void *buf, size_t size) +{ + struct sli4_cmd_read_nvparms_s *read_nvparms = buf; + + memset(buf, 0, size); + + read_nvparms->hdr.command = MBX_CMD_READ_NVPARMS; + + return EFC_SUCCESS; +} + +/** + * @brief Write a WRITE_NVPARMS command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param wwpn WWPN to write - pointer to array of 8 u8. + * @param wwnn WWNN to write - pointer to array of 8 u8. + * @param hard_alpa Hard ALPA to write. + * @param preferred_d_id Preferred D_ID to write. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_write_nvparms(struct sli4_s *sli4, void *buf, size_t size, + u8 *wwpn, u8 *wwnn, u8 hard_alpa, + u32 preferred_d_id) +{ + struct sli4_cmd_write_nvparms_s *write_nvparms = buf; + + memset(buf, 0, size); + + write_nvparms->hdr.command = MBX_CMD_WRITE_NVPARMS; + memcpy(write_nvparms->wwpn, wwpn, 8); + memcpy(write_nvparms->wwnn, wwnn, 8); + + write_nvparms->hard_alpa_d_id = + cpu_to_le32((preferred_d_id << 8) | hard_alpa); + return EFC_SUCCESS; +} + +/** + * @brief Write a READ_REV command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param vpd Pointer to the buffer. + * + * @return Returns the number of bytes written. + */ +static int +sli_cmd_read_rev(struct sli4_s *sli4, void *buf, size_t size, + struct efc_dma_s *vpd) +{ + struct sli4_cmd_read_rev_s *read_rev = buf; + + memset(buf, 0, size); + + read_rev->hdr.command = MBX_CMD_READ_REV; + + if (vpd && vpd->size) { + read_rev->flags0_word |= cpu_to_le16(SLI4_READ_REV_FLAG_VPD); + + read_rev->available_length_dword = + cpu_to_le16(vpd->size & + SLI4_READ_REV_AVAILABLE_LENGTH); + + read_rev->hostbuf.low = + cpu_to_le32(lower_32_bits(vpd->phys)); + read_rev->hostbuf.high = + cpu_to_le32(upper_32_bits(vpd->phys)); + } + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a READ_SPARM64 command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param dma DMA buffer for the service parameters. + * @param vpi VPI used to determine the WWN. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_read_sparm64(struct sli4_s *sli4, void *buf, size_t size, + struct efc_dma_s *dma, + u16 vpi) +{ + struct sli4_cmd_read_sparm64_s *read_sparm64 = buf; + + memset(buf, 0, size); + + if (vpi == SLI4_READ_SPARM64_VPI_SPECIAL) { + efc_log_info(sli4, "special VPI not supported!!!\n"); + return -1; + } + + if (!dma || !dma->phys) { + efc_log_info(sli4, "bad DMA buffer\n"); + return -1; + } + + read_sparm64->hdr.command = MBX_CMD_READ_SPARM64; + + read_sparm64->bde_64.bde_type_buflen = + cpu_to_le32((BDE_TYPE_BDE_64 << BDE_TYPE_SHIFT) | + (dma->size & SLI4_BDE_MASK_BUFFER_LEN)); + read_sparm64->bde_64.u.data.low = + cpu_to_le32(lower_32_bits(dma->phys)); + read_sparm64->bde_64.u.data.high = + cpu_to_le32(upper_32_bits(dma->phys)); + + read_sparm64->vpi = cpu_to_le16(vpi); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a READ_TOPOLOGY command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param dma DMA buffer for loop map (optional). + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_read_topology(struct sli4_s *sli4, void *buf, size_t size, + struct efc_dma_s *dma) +{ + struct sli4_cmd_read_topology_s *read_topo = buf; + + memset(buf, 0, size); + + read_topo->hdr.command = MBX_CMD_READ_TOPOLOGY; + + if (dma && dma->size) { + if (dma->size < SLI4_MIN_LOOP_MAP_BYTES) { + efc_log_info(sli4, "loop map buffer too small %jd\n", + dma->size); + return 0; + } + + memset(dma->virt, 0, dma->size); + + read_topo->bde_loop_map.bde_type_buflen = + cpu_to_le32((BDE_TYPE_BDE_64 << BDE_TYPE_SHIFT) | + (dma->size & SLI4_BDE_MASK_BUFFER_LEN)); + read_topo->bde_loop_map.u.data.low = + cpu_to_le32(lower_32_bits(dma->phys)); + read_topo->bde_loop_map.u.data.high = + cpu_to_le32(upper_32_bits(dma->phys)); + } + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a REG_FCFI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param index FCF index returned by READ_FCF_TABLE. + * @param rq_cfg RQ_ID/R_CTL/TYPE routing information + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_reg_fcfi(struct sli4_s *sli4, void *buf, size_t size, + u16 index, + struct sli4_cmd_rq_cfg_s rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG]) +{ + struct sli4_cmd_reg_fcfi_s *reg_fcfi = buf; + u32 i; + + memset(buf, 0, size); + + reg_fcfi->hdr.command = MBX_CMD_REG_FCFI; + + reg_fcfi->fcf_index = cpu_to_le16(index); + + for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) { + switch (i) { + case 0: + reg_fcfi->rqid0 = cpu_to_le16(rq_cfg[0].rq_id); + break; + case 1: + reg_fcfi->rqid1 = cpu_to_le16(rq_cfg[1].rq_id); + break; + case 2: + reg_fcfi->rqid2 = cpu_to_le16(rq_cfg[2].rq_id); + break; + case 3: + reg_fcfi->rqid3 = cpu_to_le16(rq_cfg[3].rq_id); + break; + } + reg_fcfi->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask; + reg_fcfi->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match; + reg_fcfi->rq_cfg[i].type_mask = rq_cfg[i].type_mask; + reg_fcfi->rq_cfg[i].type_match = rq_cfg[i].type_match; + } + + return EFC_SUCCESS; +} + +/** + * @brief Write REG_FCFI_MRQ to provided command buffer + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param fcf_index FCF index returned by READ_FCF_TABLE. + * @param rr_quant Round robin quanta if RQ selection policy is 2 + * @param rq_selection_policy RQ selection policy + * @param num_rqs Array of count of RQs per filter + * @param rq_ids Array of RQ ids per filter + * @param rq_cfg RQ_ID/R_CTL/TYPE routing information + * + * @return returns 0 for success, a negative error code value for failure. + */ +int +sli_cmd_reg_fcfi_mrq(struct sli4_s *sli4, void *buf, size_t size, + u8 mode, u16 fcf_index, + u8 rq_selection_policy, u8 mrq_bit_mask, + u16 num_mrqs, + struct sli4_cmd_rq_cfg_s rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG]) +{ + struct sli4_cmd_reg_fcfi_mrq_s *reg_fcfi_mrq = buf; + u32 i; + u32 mrq_flags = 0; + + memset(buf, 0, size); + + reg_fcfi_mrq->hdr.command = MBX_CMD_REG_FCFI_MRQ; + if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE) { + reg_fcfi_mrq->fcf_index = cpu_to_le16(fcf_index); + goto done; + } + + for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) { + reg_fcfi_mrq->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask; + reg_fcfi_mrq->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match; + reg_fcfi_mrq->rq_cfg[i].type_mask = rq_cfg[i].type_mask; + reg_fcfi_mrq->rq_cfg[i].type_match = rq_cfg[i].type_match; + + switch (i) { + case 3: + reg_fcfi_mrq->rqid3 = cpu_to_le16(rq_cfg[i].rq_id); + break; + case 2: + reg_fcfi_mrq->rqid2 = cpu_to_le16(rq_cfg[i].rq_id); + break; + case 1: + reg_fcfi_mrq->rqid1 = cpu_to_le16(rq_cfg[i].rq_id); + break; + case 0: + reg_fcfi_mrq->rqid0 = cpu_to_le16(rq_cfg[i].rq_id); + break; + } + } + + mrq_flags = num_mrqs & SLI4_REGFCFI_MRQ_MASK_NUM_PAIRS; + mrq_flags |= (mrq_bit_mask << 8); + mrq_flags |= (rq_selection_policy << 12); + reg_fcfi_mrq->dw9_mrqflags = cpu_to_le32(mrq_flags); +done: + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a REG_RPI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param nport_id Remote F/N_Port_ID. + * @param rpi Previously-allocated Remote Port Indicator. + * @param vpi Previously-allocated Virtual Port Indicator. + * @param dma DMA buffer that contains the remote port's service parameters. + * @param update Boolean indicating an update to an existing RPI (TRUE) + * or a new registration (FALSE). + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_reg_rpi(struct sli4_s *sli4, void *buf, size_t size, + u32 nport_id, u16 rpi, u16 vpi, + struct efc_dma_s *dma, u8 update, + u8 enable_t10_pi) +{ + struct sli4_cmd_reg_rpi_s *reg_rpi = buf; + u32 rportid_flags = 0; + + memset(buf, 0, size); + + reg_rpi->hdr.command = MBX_CMD_REG_RPI; + + reg_rpi->rpi = cpu_to_le16(rpi); + + rportid_flags = nport_id & SLI4_REGRPI_REMOTE_N_PORTID; + + if (update) + rportid_flags |= SLI4_REGRPI_UPD; + else + rportid_flags &= ~SLI4_REGRPI_UPD; + + if (enable_t10_pi) + rportid_flags |= SLI4_REGRPI_ETOW; + else + rportid_flags &= ~SLI4_REGRPI_ETOW; + + reg_rpi->dw2_rportid_flags = cpu_to_le32(rportid_flags); + + reg_rpi->bde_64.bde_type_buflen = + cpu_to_le32((BDE_TYPE_BDE_64 << BDE_TYPE_SHIFT) | + (SLI4_REG_RPI_BUF_LEN & SLI4_BDE_MASK_BUFFER_LEN)); + reg_rpi->bde_64.u.data.low = + cpu_to_le32(lower_32_bits(dma->phys)); + reg_rpi->bde_64.u.data.high = + cpu_to_le32(upper_32_bits(dma->phys)); + + reg_rpi->vpi = cpu_to_le16(vpi); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a REG_VFI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param domain Pointer to the domain object. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_reg_vfi(struct sli4_s *sli4, void *buf, size_t size, + u16 vfi, u16 fcfi, struct efc_dma_s dma, + u16 vpi, __be64 sli_wwpn, u32 fc_id) +{ + struct sli4_cmd_reg_vfi_s *reg_vfi = buf; + + if (!sli4 || !buf) + return 0; + + memset(buf, 0, size); + + reg_vfi->hdr.command = MBX_CMD_REG_VFI; + + reg_vfi->vfi = cpu_to_le16(vfi); + + reg_vfi->fcfi = cpu_to_le16(fcfi); + + reg_vfi->sparm.bde_type_buflen = + cpu_to_le32((BDE_TYPE_BDE_64 << BDE_TYPE_SHIFT) | + (SLI4_REG_RPI_BUF_LEN & SLI4_BDE_MASK_BUFFER_LEN)); + reg_vfi->sparm.u.data.low = + cpu_to_le32(lower_32_bits(dma.phys)); + reg_vfi->sparm.u.data.high = + cpu_to_le32(upper_32_bits(dma.phys)); + + reg_vfi->e_d_tov = cpu_to_le32(sli4->e_d_tov); + reg_vfi->r_a_tov = cpu_to_le32(sli4->r_a_tov); + + reg_vfi->dw0w1_flags |= SLI4_REGVFI_VP; + reg_vfi->vpi = cpu_to_le16(vpi); + memcpy(reg_vfi->wwpn, &sli_wwpn, sizeof(reg_vfi->wwpn)); + reg_vfi->dw10_lportid_flags = cpu_to_le32(fc_id); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a REG_VPI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param sport Point to SLI Port object. + * @param update Boolean indicating whether to update the existing VPI (true) + * or create a new VPI (false). + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_reg_vpi(struct sli4_s *sli4, void *buf, size_t size, + u32 fc_id, __be64 sli_wwpn, u16 vpi, u16 vfi, + bool update) +{ + struct sli4_cmd_reg_vpi_s *reg_vpi = buf; + u32 flags = 0; + + if (!sli4 || !buf) + return 0; + + memset(buf, 0, size); + + reg_vpi->hdr.command = MBX_CMD_REG_VPI; + + flags = (fc_id & SLI4_REGVPI_LOCAL_N_PORTID); + if (update) + flags |= SLI4_REGVPI_UPD; + else + flags &= ~SLI4_REGVPI_UPD; + + reg_vpi->dw2_lportid_flags = cpu_to_le32(flags); + memcpy(reg_vpi->wwpn, &sli_wwpn, sizeof(reg_vpi->wwpn)); + reg_vpi->vpi = cpu_to_le16(vpi); + reg_vpi->vfi = cpu_to_le16(vfi); + + return EFC_SUCCESS; +} + +/** + * @brief Write a REQUEST_FEATURES command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param mask Features to request. + * @param query Use feature query mode (does not change FW). + * + * @return Returns the number of bytes written. + */ +static int +sli_cmd_request_features(struct sli4_s *sli4, void *buf, size_t size, + u32 features_mask, bool query) +{ + struct sli4_cmd_request_features_s *req_features = buf; + + memset(buf, 0, size); + + req_features->hdr.command = MBX_CMD_RQST_FEATURES; + + if (query) + req_features->dw1_qry = cpu_to_le32(SLI4_REQFEAT_QRY); + + req_features->cmd = cpu_to_le32(features_mask); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a UNREG_FCFI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param indicator Indicator value. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_unreg_fcfi(struct sli4_s *sli4, void *buf, size_t size, + u16 indicator) +{ + struct sli4_cmd_unreg_fcfi_s *unreg_fcfi = buf; + + if (!sli4 || !buf) + return 0; + + memset(buf, 0, size); + + unreg_fcfi->hdr.command = MBX_CMD_UNREG_FCFI; + + unreg_fcfi->fcfi = cpu_to_le16(indicator); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write an UNREG_RPI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param indicator Indicator value. + * @param which Type of unregister, such as node, port, domain, or FCF. + * @param fc_id FC address. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_unreg_rpi(struct sli4_s *sli4, void *buf, size_t size, + u16 indicator, + enum sli4_resource_e which, u32 fc_id) +{ + struct sli4_cmd_unreg_rpi_s *unreg_rpi = buf; + u32 flags = 0; + + memset(buf, 0, size); + + unreg_rpi->hdr.command = MBX_CMD_UNREG_RPI; + + switch (which) { + case SLI_RSRC_RPI: + flags |= UNREG_RPI_II_RPI; + if (fc_id == U32_MAX) + break; + + flags |= UNREG_RPI_DP; + unreg_rpi->dw2_dest_n_portid = + cpu_to_le32(fc_id & UNREG_RPI_DEST_N_PORTID_MASK); + break; + case SLI_RSRC_VPI: + flags |= UNREG_RPI_II_VPI; + break; + case SLI_RSRC_VFI: + flags |= UNREG_RPI_II_VFI; + break; + case SLI_RSRC_FCFI: + flags |= UNREG_RPI_II_FCFI; + break; + default: + efc_log_info(sli4, "unknown type %#x\n", which); + return EFC_FAIL; + } + + unreg_rpi->dw1w1_flags = cpu_to_le16(flags); + unreg_rpi->index = cpu_to_le16(indicator); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write an UNREG_VFI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param domain Pointer to the domain object + * @param which Type of unregister, such as domain, FCFI, or everything. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_unreg_vfi(struct sli4_s *sli4, void *buf, size_t size, + u16 index, u32 which) +{ + struct sli4_cmd_unreg_vfi_s *unreg_vfi = buf; + + memset(buf, 0, size); + + unreg_vfi->hdr.command = MBX_CMD_UNREG_VFI; + switch (which) { + case SLI4_UNREG_TYPE_DOMAIN: + unreg_vfi->index = cpu_to_le16(index); + break; + case SLI4_UNREG_TYPE_FCF: + unreg_vfi->index = cpu_to_le16(index); + break; + case SLI4_UNREG_TYPE_ALL: + unreg_vfi->index = cpu_to_le16(U32_MAX); + break; + default: + return 0; + } + + if (which != SLI4_UNREG_TYPE_DOMAIN) + unreg_vfi->dw2_flags = + cpu_to_le16(UNREG_VFI_II_FCFI); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write an UNREG_VPI command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to the destination buffer. + * @param size Buffer size, in bytes. + * @param indicator Indicator value. + * @param which Type of unregister: port, domain, FCFI, everything + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_unreg_vpi(struct sli4_s *sli4, void *buf, size_t size, + u16 indicator, u32 which) +{ + struct sli4_cmd_unreg_vpi_s *unreg_vpi = buf; + u32 flags = 0; + + memset(buf, 0, size); + + unreg_vpi->hdr.command = MBX_CMD_UNREG_VPI; + unreg_vpi->index = cpu_to_le16(indicator); + switch (which) { + case SLI4_UNREG_TYPE_PORT: + flags |= UNREG_VPI_II_VPI; + break; + case SLI4_UNREG_TYPE_DOMAIN: + flags |= UNREG_VPI_II_VFI; + break; + case SLI4_UNREG_TYPE_FCF: + flags |= UNREG_VPI_II_FCFI; + break; + case SLI4_UNREG_TYPE_ALL: + /* override indicator */ + unreg_vpi->index = cpu_to_le16(U32_MAX); + flags |= UNREG_VPI_II_FCFI; + break; + default: + return EFC_FAIL; + } + + unreg_vpi->dw2w0_flags = cpu_to_le16(flags); + return EFC_SUCCESS; +} + +/** + * @brief Write a COMMON_MODIFY_EQ_DELAY command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param q Queue object array. + * @param num_q Queue object array count. + * @param shift Phase shift for staggering interrupts. + * @param delay_mult Delay multiplier for limiting interrupt frequency. + * + * @return Returns the number of bytes written. + */ +static int +sli_cmd_common_modify_eq_delay(struct sli4_s *sli4, void *buf, size_t size, + struct sli4_queue_s *q, int num_q, u32 shift, + u32 delay_mult) +{ + struct sli4_rqst_cmn_modify_eq_delay_s *modify_delay = NULL; + int i; + + modify_delay = sli_config_cmd_init(sli4, buf, size, + SLI_CONFIG_PYLD_LENGTH(cmn_modify_eq_delay), + NULL); + if (!modify_delay) + return EFC_FAIL; + + modify_delay->hdr.opcode = CMN_MODIFY_EQ_DELAY; + modify_delay->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + modify_delay->hdr.request_length = + CFG_RQST_PYLD_LEN(cmn_modify_eq_delay); + modify_delay->num_eq = cpu_to_le32(num_q); + + for (i = 0; i < num_q; i++) { + modify_delay->eq_delay_record[i].eq_id = cpu_to_le32(q[i].id); + modify_delay->eq_delay_record[i].phase = cpu_to_le32(shift); + modify_delay->eq_delay_record[i].delay_multiplier = + cpu_to_le32(delay_mult); + } + + return EFC_SUCCESS; +} + +/** + * @brief Write a LOWLEVEL_SET_WATCHDOG command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param timeout watchdog timer timeout in seconds + * + * @return void + */ +void +sli4_cmd_lowlevel_set_watchdog(struct sli4_s *sli4, void *buf, + size_t size, u16 timeout) +{ + struct sli4_rqst_lowlevel_set_watchdog_s *req = NULL; + + req = sli_config_cmd_init(sli4, buf, size, + SLI_CONFIG_PYLD_LENGTH(lowlevel_set_watchdog), + NULL); + if (!req) + return; + + req->hdr.opcode = SLI4_OPC_LOWLEVEL_SET_WATCHDOG; + req->hdr.subsystem = SLI4_SUBSYSTEM_LOWLEVEL; + req->hdr.request_length = CFG_RQST_PYLD_LEN(lowlevel_set_watchdog); + req->watchdog_timeout = cpu_to_le16(timeout); +} + +static int +sli_cmd_common_get_cntl_attributes(struct sli4_s *sli4, void *buf, size_t size, + struct efc_dma_s *dma) +{ + struct sli4_rqst_hdr_s *hdr = NULL; + + hdr = sli_config_cmd_init(sli4, buf, size, CFG_RQST_CMDSZ(hdr), dma); + if (!hdr) + return EFC_FAIL; + + hdr->opcode = CMN_GET_CNTL_ATTRIBUTES; + hdr->subsystem = SLI4_SUBSYSTEM_COMMON; + hdr->request_length = cpu_to_le32(dma->size); + + return EFC_SUCCESS; +} + +/** + * @brief Write a COMMON_GET_CNTL_ADDL_ATTRIBUTES command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param dma DMA structure from which the data will be copied. + * + * @note This creates a Version 0 message. + * + * @return Returns the number of bytes written. + */ +static int +sli_cmd_common_get_cntl_addl_attributes(struct sli4_s *sli4, void *buf, + size_t size, struct efc_dma_s *dma) +{ + struct sli4_rqst_hdr_s *hdr = NULL; + + hdr = sli_config_cmd_init(sli4, buf, size, CFG_RQST_CMDSZ(hdr), dma); + if (!hdr) + return EFC_FAIL; + + hdr->opcode = CMN_GET_CNTL_ADDL_ATTRS; + hdr->subsystem = SLI4_SUBSYSTEM_COMMON; + hdr->request_length = cpu_to_le32(dma->size); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_NOP command + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param context NOP context value (passed to response, except on FC/FCoE). + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_nop(struct sli4_s *sli4, void *buf, + size_t size, uint64_t context) +{ + struct sli4_rqst_cmn_nop_s *nop = NULL; + + nop = sli_config_cmd_init(sli4, buf, size, + SLI_CONFIG_PYLD_LENGTH(cmn_nop), NULL); + if (!nop) + return EFC_FAIL; + + nop->hdr.opcode = CMN_NOP; + nop->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + nop->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_nop); + + memcpy(&nop->context, &context, sizeof(context)); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_GET_RESOURCE_EXTENT_INFO command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param rtype Resource type (for example, XRI, VFI, VPI, and RPI). + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_get_resource_extent_info(struct sli4_s *sli4, void *buf, + size_t size, u16 rtype) +{ + struct sli4_rqst_cmn_get_resource_extent_info_s *extent = NULL; + + extent = sli_config_cmd_init(sli4, buf, size, + CFG_RQST_CMDSZ(cmn_get_resource_extent_info), + NULL); + if (extent) + return EFC_FAIL; + + extent->hdr.opcode = CMN_GET_RSC_EXTENT_INFO; + extent->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + extent->hdr.request_length = + CFG_RQST_PYLD_LEN(cmn_get_resource_extent_info); + + extent->resource_type = cpu_to_le16(rtype); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_GET_SLI4_PARAMETERS command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_get_sli4_parameters(struct sli4_s *sli4, void *buf, + size_t size) +{ + struct sli4_rqst_hdr_s *hdr = NULL; + + hdr = sli_config_cmd_init(sli4, buf, size, + SLI_CONFIG_PYLD_LENGTH(cmn_get_sli4_params), + NULL); + if (!hdr) + return EFC_FAIL; + + hdr->opcode = CMN_GET_SLI4_PARAMS; + hdr->subsystem = SLI4_SUBSYSTEM_COMMON; + hdr->request_length = CFG_RQST_PYLD_LEN(cmn_get_sli4_params); + + return EFC_SUCCESS; +} + +/** + * @brief Write a COMMON_GET_PORT_NAME command to the provided buffer. + * + * @param sli4 SLI context pointer. + * @param buf Virtual pointer to destination buffer. + * @param size Buffer size in bytes. + * + * @note Function supports both version 0 and 1 forms of this command via + * the IF_TYPE. + * + * @return Returns the number of bytes written. + */ +static int +sli_cmd_common_get_port_name(struct sli4_s *sli4, void *buf, size_t size) +{ + struct sli4_rqst_cmn_get_port_name_s *pname; + + pname = sli_config_cmd_init(sli4, buf, size, + SLI_CONFIG_PYLD_LENGTH(cmn_get_port_name), + NULL); + if (!pname) + return EFC_FAIL; + + pname->hdr.opcode = CMN_GET_PORT_NAME; + pname->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + pname->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_get_port_name); + pname->hdr.dw3_version = cpu_to_le32(CMD_V1); + + /* Set the port type value (ethernet=0, FC=1) for V1 commands */ + pname->port_type = PORT_TYPE_FC; + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_WRITE_OBJECT command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param noc True if the object should be written but not committed to flash. + * @param eof True if this is the last write for this object. + * @param desired_write_length Number of bytes of data to write to the object. + * @param offset Offset, in bytes, from the start of the object. + * @param object_name Name of the object to write. + * @param dma DMA structure from which the data will be copied. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_write_object(struct sli4_s *sli4, void *buf, size_t size, + u16 noc, + u16 eof, u32 desired_write_length, + u32 offset, char *object_name, + struct efc_dma_s *dma) +{ + struct sli4_rqst_cmn_write_object_s *wr_obj = NULL; + struct sli4_bde_s *host_buf; + u32 dwflags = 0; + + wr_obj = sli_config_cmd_init(sli4, buf, size, + CFG_RQST_CMDSZ(cmn_write_object) + + sizeof(*host_buf), NULL); + if (!wr_obj) + return EFC_FAIL; + + wr_obj->hdr.opcode = CMN_WRITE_OBJECT; + wr_obj->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + wr_obj->hdr.request_length = CFG_RQST_PYLD_LEN_VAR(cmn_write_object, + sizeof(*host_buf)); + wr_obj->hdr.timeout = 0; + wr_obj->hdr.dw3_version = CMD_V0; + + if (noc) + dwflags |= SLI4_RQ_DES_WRITE_LEN_NOC; + if (eof) + dwflags |= SLI4_RQ_DES_WRITE_LEN_EOF; + dwflags |= (desired_write_length & SLI4_RQ_DES_WRITE_LEN); + + wr_obj->desired_write_len_dword = cpu_to_le32(dwflags); + + wr_obj->write_offset = cpu_to_le32(offset); + strncpy(wr_obj->object_name, object_name, + sizeof(wr_obj->object_name)); + wr_obj->host_buffer_descriptor_count = cpu_to_le32(1); + + host_buf = (struct sli4_bde_s *)wr_obj->host_buffer_descriptor; + + /* Setup to transfer xfer_size bytes to device */ + host_buf->bde_type_buflen = + cpu_to_le32((BDE_TYPE_BDE_64 << BDE_TYPE_SHIFT) | + (desired_write_length & SLI4_BDE_MASK_BUFFER_LEN)); + host_buf->u.data.low = + cpu_to_le32(lower_32_bits(dma->phys)); + host_buf->u.data.high = + cpu_to_le32(upper_32_bits(dma->phys)); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_DELETE_OBJECT command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param object_name Name of the object to write. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_delete_object(struct sli4_s *sli4, void *buf, size_t size, + char *object_name) +{ + struct sli4_rqst_cmn_delete_object_s *del_obj = NULL; + + del_obj = sli_config_cmd_init(sli4, buf, size, + CFG_RQST_CMDSZ(cmn_delete_object), NULL); + if (!del_obj) + return EFC_FAIL; + + del_obj->hdr.opcode = CMN_DELETE_OBJECT; + del_obj->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + del_obj->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_delete_object); + del_obj->hdr.timeout = 0; + del_obj->hdr.dw3_version = CMD_V0; + + strncpy(del_obj->object_name, object_name, + sizeof(del_obj->object_name)); + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_READ_OBJECT command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param desired_read_length Number of bytes of data to read from the object. + * @param offset Offset, in bytes, from the start of the object. + * @param object_name Name of the object to read. + * @param dma DMA structure from which the data will be copied. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_read_object(struct sli4_s *sli4, void *buf, size_t size, + u32 desired_read_length, u32 offset, + char *object_name, struct efc_dma_s *dma) +{ + struct sli4_rqst_cmn_read_object_s *rd_obj = NULL; + struct sli4_bde_s *host_buf; + + rd_obj = sli_config_cmd_init(sli4, buf, size, + CFG_RQST_CMDSZ(cmn_read_object) + + sizeof(*host_buf), NULL); + if (!rd_obj) + return EFC_FAIL; + + rd_obj->hdr.opcode = CMN_READ_OBJECT; + rd_obj->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + rd_obj->hdr.request_length = CFG_RQST_PYLD_LEN_VAR(cmn_read_object, + sizeof(*host_buf)); + rd_obj->hdr.timeout = 0; + rd_obj->hdr.dw3_version = CMD_V0; + + rd_obj->desired_read_length_dword = + cpu_to_le32(desired_read_length & SLI4_REQ_DESIRE_READLEN); + + rd_obj->read_offset = cpu_to_le32(offset); + strncpy(rd_obj->object_name, object_name, + sizeof(rd_obj->object_name)); + rd_obj->host_buffer_descriptor_count = cpu_to_le32(1); + + host_buf = (struct sli4_bde_s *)rd_obj->host_buffer_descriptor; + + /* Setup to transfer xfer_size bytes to device */ + host_buf->bde_type_buflen = + cpu_to_le32((BDE_TYPE_BDE_64 << BDE_TYPE_SHIFT) | + (desired_read_length & SLI4_BDE_MASK_BUFFER_LEN)); + if (dma) { + host_buf->u.data.low = + cpu_to_le32(lower_32_bits(dma->phys)); + host_buf->u.data.high = + cpu_to_le32(upper_32_bits(dma->phys)); + } else { + host_buf->u.data.low = 0; + host_buf->u.data.high = 0; + } + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a DMTF_EXEC_CLP_CMD command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param cmd DMA structure that describes the buffer for the command. + * @param resp DMA structure that describes the buffer for the response. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_dmtf_exec_clp_cmd(struct sli4_s *sli4, void *buf, size_t size, + struct efc_dma_s *cmd, + struct efc_dma_s *resp) +{ + struct sli4_rqst_dmtf_exec_clp_cmd_s *clp_cmd = NULL; + + clp_cmd = sli_config_cmd_init(sli4, buf, size, + CFG_RQST_CMDSZ(dmtf_exec_clp_cmd), NULL); + if (!clp_cmd) + return EFC_FAIL; + + clp_cmd->hdr.opcode = DMTF_EXEC_CLP_CMD; + clp_cmd->hdr.subsystem = SLI4_SUBSYSTEM_DMTF; + clp_cmd->hdr.request_length = CFG_RQST_PYLD_LEN(dmtf_exec_clp_cmd); + clp_cmd->hdr.timeout = 0; + clp_cmd->hdr.dw3_version = CMD_V0; + clp_cmd->cmd_buf_length = cpu_to_le32(cmd->size); + clp_cmd->cmd_buf_addr_low = cpu_to_le32(lower_32_bits(cmd->phys)); + clp_cmd->cmd_buf_addr_high = cpu_to_le32(upper_32_bits(cmd->phys)); + clp_cmd->resp_buf_length = cpu_to_le32(resp->size); + clp_cmd->resp_buf_addr_low = cpu_to_le32(lower_32_bits(resp->phys)); + clp_cmd->resp_buf_addr_high = cpu_to_le32(upper_32_bits(resp->phys)); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_SET_DUMP_LOCATION command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param query Zero to set dump location, non-zero to query dump size + * @param is_buffer_list Set to one if the buffer + * is a set of buffer descriptors or + * set to 0 if the buffer is a contiguous dump area. + * @param buffer DMA structure to which the dump will be copied. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_set_dump_location(struct sli4_s *sli4, void *buf, + size_t size, bool query, + bool is_buffer_list, + struct efc_dma_s *buffer, u8 fdb) +{ + struct sli4_rqst_cmn_set_dump_location_s *set_dump_loc = NULL; + u32 buffer_length_flag = 0; + + set_dump_loc = sli_config_cmd_init(sli4, buf, size, + CFG_RQST_CMDSZ(cmn_set_dump_location), + NULL); + if (!set_dump_loc) + return EFC_FAIL; + + set_dump_loc->hdr.opcode = CMN_SET_DUMP_LOCATION; + set_dump_loc->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + set_dump_loc->hdr.request_length = + CFG_RQST_PYLD_LEN(cmn_set_dump_location); + set_dump_loc->hdr.timeout = 0; + set_dump_loc->hdr.dw3_version = CMD_V0; + + if (is_buffer_list) + buffer_length_flag |= SLI4_RQ_COM_SET_DUMP_BLP; + + if (query) + buffer_length_flag |= SLI4_RQ_COM_SET_DUMP_QRY; + + if (fdb) + buffer_length_flag |= SLI4_RQ_COM_SET_DUMP_FDB; + + if (buffer) { + set_dump_loc->buf_addr_low = + cpu_to_le32(lower_32_bits(buffer->phys)); + set_dump_loc->buf_addr_high = + cpu_to_le32(upper_32_bits(buffer->phys)); + + buffer_length_flag |= (buffer->len & + SLI4_RQ_COM_SET_DUMP_BUFFER_LEN); + } else { + set_dump_loc->buf_addr_low = 0; + set_dump_loc->buf_addr_high = 0; + set_dump_loc->buffer_length_dword = 0; + } + set_dump_loc->buffer_length_dword = cpu_to_le32(buffer_length_flag); + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Write a COMMON_SET_FEATURES command. + * + * @param sli4 SLI context. + * @param buf Destination buffer for the command. + * @param size Buffer size, in bytes. + * @param feature Feature to set. + * @param param_len Length of the parameter (must be a multiple of 4 bytes). + * @param parameter Pointer to the parameter value. + * + * @return Returns the number of bytes written. + */ +int +sli_cmd_common_set_features(struct sli4_s *sli4, void *buf, size_t size, + u32 feature, + u32 param_len, + void *parameter) +{ + struct sli4_rqst_cmn_set_features_s *cmd = NULL; + + cmd = sli_config_cmd_init(sli4, buf, size, + CFG_RQST_CMDSZ(cmn_set_features), NULL); + if (!cmd) + return EFC_FAIL; + + cmd->hdr.opcode = CMN_SET_FEATURES; + cmd->hdr.subsystem = SLI4_SUBSYSTEM_COMMON; + cmd->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_set_features); + cmd->hdr.timeout = 0; + cmd->hdr.dw3_version = CMD_V0; + + cmd->feature = cpu_to_le32(feature); + cmd->param_len = cpu_to_le32(param_len); + memcpy(cmd->params, parameter, param_len); + + return EFC_SUCCESS; +} + +/** + * @ingroup sli + * @brief Check the mailbox/queue completion entry. + * + * @param buf Pointer to the MCQE. + * + * @return Returns 0 on success, or a non-zero value on failure. + */ +int +sli_cqe_mq(struct sli4_s *sli4, void *buf) +{ + struct sli4_mcqe_s *mcqe = buf; + u32 dwflags = le32_to_cpu(mcqe->dw3_flags); + /* + * Firmware can split mbx completions into two MCQEs: first with only + * the "consumed" bit set and a second with the "complete" bit set. + * Thus, ignore MCQE unless "complete" is set. + */ + if (!(dwflags & SLI4_MCQE_COMPLETED)) + return -2; + + if (le16_to_cpu(mcqe->completion_status)) { + efc_log_info(sli4, "status(st=%#x ext=%#x con=%d cmp=%d ae=%d val=%d)\n", + le16_to_cpu(mcqe->completion_status), + le16_to_cpu(mcqe->extended_status), + (dwflags & SLI4_MCQE_CONSUMED), + (dwflags & SLI4_MCQE_COMPLETED), + (dwflags & SLI4_MCQE_AE), + (dwflags & SLI4_MCQE_VALID)); + } + + return le16_to_cpu(mcqe->completion_status); +} + +/** + * @ingroup sli + * @brief Check the asynchronous event completion entry. + * + * @param sli4 SLI context. + * @param buf Pointer to the ACQE. + * + * @return Returns 0 on success, or a non-zero value on failure. + */ +int +sli_cqe_async(struct sli4_s *sli4, void *buf) +{ + struct sli4_acqe_s *acqe = buf; + int rc = -1; + + if (!buf) { + efc_log_err(sli4, "bad parameter sli4=%p buf=%p\n", sli4, buf); + return -1; + } + + switch (acqe->event_code) { + case SLI4_ACQE_EVENT_CODE_LINK_STATE: + rc = sli_fc_process_link_state(sli4, buf); + break; + case SLI4_ACQE_EVENT_CODE_GRP_5: + efc_log_info(sli4, "ACQE GRP5\n"); + break; + case SLI4_ACQE_EVENT_CODE_SLI_PORT_EVENT: + efc_log_info(sli4, "ACQE SLI Port, type=0x%x, data1,2=0x%08x,0x%08x\n", + acqe->event_type, + le32_to_cpu(acqe->event_data[0]), + le32_to_cpu(acqe->event_data[1])); + break; + case SLI4_ACQE_EVENT_CODE_FC_LINK_EVENT: + rc = sli_fc_process_link_attention(sli4, buf); + break; + default: + efc_log_info(sli4, "ACQE unknown=%#x\n", + acqe->event_code); + } + + return rc; +} diff --git a/drivers/scsi/elx/libefc_sli/sli4.h b/drivers/scsi/elx/libefc_sli/sli4.h index 20ab558db2d2..24ae702f9427 100644 --- a/drivers/scsi/elx/libefc_sli/sli4.h +++ b/drivers/scsi/elx/libefc_sli/sli4.h @@ -12,6 +12,8 @@ #ifndef _SLI4_H #define _SLI4_H +#include <linux/pci.h> +#include <linux/delay.h> #include "scsi/fc/fc_els.h" #include "scsi/fc/fc_fs.h" #include "../include/efc_common.h" -- 2.13.7