Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is part of the Chelsio FCoE driver for Linux.
0003  *
0004  * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
0005  *
0006  * This software is available to you under a choice of one of two
0007  * licenses.  You may choose to be licensed under the terms of the GNU
0008  * General Public License (GPL) Version 2, available from the file
0009  * COPYING in the main directory of this source tree, or the
0010  * OpenIB.org BSD license below:
0011  *
0012  *     Redistribution and use in source and binary forms, with or
0013  *     without modification, are permitted provided that the following
0014  *     conditions are met:
0015  *
0016  *      - Redistributions of source code must retain the above
0017  *        copyright notice, this list of conditions and the following
0018  *        disclaimer.
0019  *
0020  *      - Redistributions in binary form must reproduce the above
0021  *        copyright notice, this list of conditions and the following
0022  *        disclaimer in the documentation and/or other materials
0023  *        provided with the distribution.
0024  *
0025  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0026  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0027  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0028  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0029  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0030  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0031  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0032  * SOFTWARE.
0033  */
0034 
0035 #include <linux/delay.h>
0036 #include <linux/jiffies.h>
0037 #include <linux/string.h>
0038 #include <scsi/scsi_device.h>
0039 #include <scsi/scsi_transport_fc.h>
0040 
0041 #include "csio_hw.h"
0042 #include "csio_lnode.h"
0043 #include "csio_rnode.h"
0044 #include "csio_mb.h"
0045 #include "csio_wr.h"
0046 
0047 #define csio_mb_is_host_owner(__owner)      ((__owner) == CSIO_MBOWNER_PL)
0048 
0049 /* MB Command/Response Helpers */
0050 /*
0051  * csio_mb_fw_retval - FW return value from a mailbox response.
0052  * @mbp: Mailbox structure
0053  *
0054  */
0055 enum fw_retval
0056 csio_mb_fw_retval(struct csio_mb *mbp)
0057 {
0058     struct fw_cmd_hdr *hdr;
0059 
0060     hdr = (struct fw_cmd_hdr *)(mbp->mb);
0061 
0062     return FW_CMD_RETVAL_G(ntohl(hdr->lo));
0063 }
0064 
0065 /*
0066  * csio_mb_hello - FW HELLO command helper
0067  * @hw: The HW structure
0068  * @mbp: Mailbox structure
0069  * @m_mbox: Master mailbox number, if any.
0070  * @a_mbox: Mailbox number for asycn notifications.
0071  * @master: Device mastership.
0072  * @cbfn: Callback, if any.
0073  *
0074  */
0075 void
0076 csio_mb_hello(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0077           uint32_t m_mbox, uint32_t a_mbox, enum csio_dev_master master,
0078           void (*cbfn) (struct csio_hw *, struct csio_mb *))
0079 {
0080     struct fw_hello_cmd *cmdp = (struct fw_hello_cmd *)(mbp->mb);
0081 
0082     CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0083 
0084     cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_HELLO_CMD) |
0085                        FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0086     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0087     cmdp->err_to_clearinit = htonl(
0088         FW_HELLO_CMD_MASTERDIS_V(master == CSIO_MASTER_CANT)    |
0089         FW_HELLO_CMD_MASTERFORCE_V(master == CSIO_MASTER_MUST)  |
0090         FW_HELLO_CMD_MBMASTER_V(master == CSIO_MASTER_MUST ?
0091                 m_mbox : FW_HELLO_CMD_MBMASTER_M)   |
0092         FW_HELLO_CMD_MBASYNCNOT_V(a_mbox) |
0093         FW_HELLO_CMD_STAGE_V(fw_hello_cmd_stage_os) |
0094         FW_HELLO_CMD_CLEARINIT_F);
0095 
0096 }
0097 
0098 /*
0099  * csio_mb_process_hello_rsp - FW HELLO response processing helper
0100  * @hw: The HW structure
0101  * @mbp: Mailbox structure
0102  * @retval: Mailbox return value from Firmware
0103  * @state: State that the function is in.
0104  * @mpfn: Master pfn
0105  *
0106  */
0107 void
0108 csio_mb_process_hello_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0109               enum fw_retval *retval, enum csio_dev_state *state,
0110               uint8_t *mpfn)
0111 {
0112     struct fw_hello_cmd *rsp = (struct fw_hello_cmd *)(mbp->mb);
0113     uint32_t value;
0114 
0115     *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
0116 
0117     if (*retval == FW_SUCCESS) {
0118         hw->fwrev = ntohl(rsp->fwrev);
0119 
0120         value = ntohl(rsp->err_to_clearinit);
0121         *mpfn = FW_HELLO_CMD_MBMASTER_G(value);
0122 
0123         if (value & FW_HELLO_CMD_INIT_F)
0124             *state = CSIO_DEV_STATE_INIT;
0125         else if (value & FW_HELLO_CMD_ERR_F)
0126             *state = CSIO_DEV_STATE_ERR;
0127         else
0128             *state = CSIO_DEV_STATE_UNINIT;
0129     }
0130 }
0131 
0132 /*
0133  * csio_mb_bye - FW BYE command helper
0134  * @hw: The HW structure
0135  * @mbp: Mailbox structure
0136  * @cbfn: Callback, if any.
0137  *
0138  */
0139 void
0140 csio_mb_bye(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0141         void (*cbfn) (struct csio_hw *, struct csio_mb *))
0142 {
0143     struct fw_bye_cmd *cmdp = (struct fw_bye_cmd *)(mbp->mb);
0144 
0145     CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0146 
0147     cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_BYE_CMD) |
0148                        FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0149     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0150 
0151 }
0152 
0153 /*
0154  * csio_mb_reset - FW RESET command helper
0155  * @hw: The HW structure
0156  * @mbp: Mailbox structure
0157  * @reset: Type of reset.
0158  * @cbfn: Callback, if any.
0159  *
0160  */
0161 void
0162 csio_mb_reset(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0163           int reset, int halt,
0164           void (*cbfn) (struct csio_hw *, struct csio_mb *))
0165 {
0166     struct fw_reset_cmd *cmdp = (struct fw_reset_cmd *)(mbp->mb);
0167 
0168     CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0169 
0170     cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_RESET_CMD) |
0171                   FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0172     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0173     cmdp->val = htonl(reset);
0174     cmdp->halt_pkd = htonl(halt);
0175 
0176 }
0177 
0178 /*
0179  * csio_mb_params - FW PARAMS command helper
0180  * @hw: The HW structure
0181  * @mbp: Mailbox structure
0182  * @tmo: Command timeout.
0183  * @pf: PF number.
0184  * @vf: VF number.
0185  * @nparams: Number of parameters
0186  * @params: Parameter mnemonic array.
0187  * @val: Parameter value array.
0188  * @wr: Write/Read PARAMS.
0189  * @cbfn: Callback, if any.
0190  *
0191  */
0192 void
0193 csio_mb_params(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0194            unsigned int pf, unsigned int vf, unsigned int nparams,
0195            const u32 *params, u32 *val, bool wr,
0196            void (*cbfn)(struct csio_hw *, struct csio_mb *))
0197 {
0198     uint32_t i;
0199     uint32_t temp_params = 0, temp_val = 0;
0200     struct fw_params_cmd *cmdp = (struct fw_params_cmd *)(mbp->mb);
0201     __be32 *p = &cmdp->param[0].mnem;
0202 
0203     CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0204 
0205     cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD)      |
0206                 FW_CMD_REQUEST_F            |
0207                 (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F)   |
0208                 FW_PARAMS_CMD_PFN_V(pf)         |
0209                 FW_PARAMS_CMD_VFN_V(vf));
0210     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0211 
0212     /* Write Params */
0213     if (wr) {
0214         while (nparams--) {
0215             temp_params = *params++;
0216             temp_val = *val++;
0217 
0218             *p++ = htonl(temp_params);
0219             *p++ = htonl(temp_val);
0220         }
0221     } else {
0222         for (i = 0; i < nparams; i++, p += 2) {
0223             temp_params = *params++;
0224             *p = htonl(temp_params);
0225         }
0226     }
0227 
0228 }
0229 
0230 /*
0231  * csio_mb_process_read_params_rsp - FW PARAMS response processing helper
0232  * @hw: The HW structure
0233  * @mbp: Mailbox structure
0234  * @retval: Mailbox return value from Firmware
0235  * @nparams: Number of parameters
0236  * @val: Parameter value array.
0237  *
0238  */
0239 void
0240 csio_mb_process_read_params_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0241                enum fw_retval *retval, unsigned int nparams,
0242                u32 *val)
0243 {
0244     struct fw_params_cmd *rsp = (struct fw_params_cmd *)(mbp->mb);
0245     uint32_t i;
0246     __be32 *p = &rsp->param[0].val;
0247 
0248     *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
0249 
0250     if (*retval == FW_SUCCESS)
0251         for (i = 0; i < nparams; i++, p += 2)
0252             *val++ = ntohl(*p);
0253 }
0254 
0255 /*
0256  * csio_mb_ldst - FW LDST command
0257  * @hw: The HW structure
0258  * @mbp: Mailbox structure
0259  * @tmo: timeout
0260  * @reg: register
0261  *
0262  */
0263 void
0264 csio_mb_ldst(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, int reg)
0265 {
0266     struct fw_ldst_cmd *ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
0267     CSIO_INIT_MBP(mbp, ldst_cmd, tmo, hw, NULL, 1);
0268 
0269     /*
0270      * Construct and send the Firmware LDST Command to retrieve the
0271      * specified PCI-E Configuration Space register.
0272      */
0273     ldst_cmd->op_to_addrspace =
0274             htonl(FW_CMD_OP_V(FW_LDST_CMD)  |
0275             FW_CMD_REQUEST_F            |
0276             FW_CMD_READ_F           |
0277             FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FUNC_PCIE));
0278     ldst_cmd->cycles_to_len16 = htonl(FW_LEN16(struct fw_ldst_cmd));
0279     ldst_cmd->u.pcie.select_naccess = FW_LDST_CMD_NACCESS_V(1);
0280     ldst_cmd->u.pcie.ctrl_to_fn =
0281         (FW_LDST_CMD_LC_F | FW_LDST_CMD_FN_V(hw->pfn));
0282     ldst_cmd->u.pcie.r = (uint8_t)reg;
0283 }
0284 
0285 /*
0286  *
0287  * csio_mb_caps_config - FW Read/Write Capabilities command helper
0288  * @hw: The HW structure
0289  * @mbp: Mailbox structure
0290  * @wr: Write if 1, Read if 0
0291  * @init: Turn on initiator mode.
0292  * @tgt: Turn on target mode.
0293  * @cofld:  If 1, Control Offload for FCoE
0294  * @cbfn: Callback, if any.
0295  *
0296  * This helper assumes that cmdp has MB payload from a previous CAPS
0297  * read command.
0298  */
0299 void
0300 csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0301             bool wr, bool init, bool tgt, bool cofld,
0302             void (*cbfn) (struct csio_hw *, struct csio_mb *))
0303 {
0304     struct fw_caps_config_cmd *cmdp =
0305                 (struct fw_caps_config_cmd *)(mbp->mb);
0306 
0307     CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, wr ? 0 : 1);
0308 
0309     cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
0310                   FW_CMD_REQUEST_F      |
0311                   (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F));
0312     cmdp->cfvalid_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0313 
0314     /* Read config */
0315     if (!wr)
0316         return;
0317 
0318     /* Write config */
0319     cmdp->fcoecaps = 0;
0320 
0321     if (cofld)
0322         cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_CTRL_OFLD);
0323     if (init)
0324         cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_INITIATOR);
0325     if (tgt)
0326         cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_TARGET);
0327 }
0328 
0329 /*
0330  * csio_mb_port- FW PORT command helper
0331  * @hw: The HW structure
0332  * @mbp: Mailbox structure
0333  * @tmo: COmmand timeout
0334  * @portid: Port ID to get/set info
0335  * @wr: Write/Read PORT information.
0336  * @fc: Flow control
0337  * @caps: Port capabilites to set.
0338  * @cbfn: Callback, if any.
0339  *
0340  */
0341 void
0342 csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0343          u8 portid, bool wr, uint32_t fc, uint16_t fw_caps,
0344          void (*cbfn) (struct csio_hw *, struct csio_mb *))
0345 {
0346     struct fw_port_cmd *cmdp = (struct fw_port_cmd *)(mbp->mb);
0347 
0348     CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn,  1);
0349 
0350     cmdp->op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD)     |
0351                    FW_CMD_REQUEST_F         |
0352                    (wr ? FW_CMD_EXEC_F : FW_CMD_READ_F) |
0353                    FW_PORT_CMD_PORTID_V(portid));
0354     if (!wr) {
0355         cmdp->action_to_len16 = htonl(
0356             FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
0357             ? FW_PORT_ACTION_GET_PORT_INFO
0358             : FW_PORT_ACTION_GET_PORT_INFO32) |
0359             FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0360         return;
0361     }
0362 
0363     /* Set port */
0364     cmdp->action_to_len16 = htonl(
0365             FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
0366             ? FW_PORT_ACTION_L1_CFG
0367             : FW_PORT_ACTION_L1_CFG32) |
0368             FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0369 
0370     if (fw_caps == FW_CAPS16)
0371         cmdp->u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(fc));
0372     else
0373         cmdp->u.l1cfg32.rcap32 = cpu_to_be32(fc);
0374 }
0375 
0376 /*
0377  * csio_mb_process_read_port_rsp - FW PORT command response processing helper
0378  * @hw: The HW structure
0379  * @mbp: Mailbox structure
0380  * @retval: Mailbox return value from Firmware
0381  * @caps: port capabilities
0382  *
0383  */
0384 void
0385 csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0386              enum fw_retval *retval, uint16_t fw_caps,
0387              u32 *pcaps, u32 *acaps)
0388 {
0389     struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
0390 
0391     *retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16));
0392 
0393     if (*retval == FW_SUCCESS) {
0394         if (fw_caps == FW_CAPS16) {
0395             *pcaps = fwcaps16_to_caps32(ntohs(rsp->u.info.pcap));
0396             *acaps = fwcaps16_to_caps32(ntohs(rsp->u.info.acap));
0397         } else {
0398             *pcaps = be32_to_cpu(rsp->u.info32.pcaps32);
0399             *acaps = be32_to_cpu(rsp->u.info32.acaps32);
0400         }
0401     }
0402 }
0403 
0404 /*
0405  * csio_mb_initialize - FW INITIALIZE command helper
0406  * @hw: The HW structure
0407  * @mbp: Mailbox structure
0408  * @tmo: COmmand timeout
0409  * @cbfn: Callback, if any.
0410  *
0411  */
0412 void
0413 csio_mb_initialize(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0414            void (*cbfn) (struct csio_hw *, struct csio_mb *))
0415 {
0416     struct fw_initialize_cmd *cmdp = (struct fw_initialize_cmd *)(mbp->mb);
0417 
0418     CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0419 
0420     cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_INITIALIZE_CMD)    |
0421                   FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0422     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0423 
0424 }
0425 
0426 /*
0427  * csio_mb_iq_alloc - Initializes the mailbox to allocate an
0428  *              Ingress DMA queue in the firmware.
0429  *
0430  * @hw: The hw structure
0431  * @mbp: Mailbox structure to initialize
0432  * @priv: Private object
0433  * @mb_tmo: Mailbox time-out period (in ms).
0434  * @iq_params: Ingress queue params needed for allocation.
0435  * @cbfn: The call-back function
0436  *
0437  *
0438  */
0439 static void
0440 csio_mb_iq_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0441          uint32_t mb_tmo, struct csio_iq_params *iq_params,
0442          void (*cbfn) (struct csio_hw *, struct csio_mb *))
0443 {
0444     struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
0445 
0446     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0447 
0448     cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD)      |
0449                 FW_CMD_REQUEST_F | FW_CMD_EXEC_F    |
0450                 FW_IQ_CMD_PFN_V(iq_params->pfn) |
0451                 FW_IQ_CMD_VFN_V(iq_params->vfn));
0452 
0453     cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC_F      |
0454                 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0455 
0456     cmdp->type_to_iqandstindex = htonl(
0457                 FW_IQ_CMD_VIID_V(iq_params->viid)   |
0458                 FW_IQ_CMD_TYPE_V(iq_params->type)   |
0459                 FW_IQ_CMD_IQASYNCH_V(iq_params->iqasynch));
0460 
0461     cmdp->fl0size = htons(iq_params->fl0size);
0462     cmdp->fl0size = htons(iq_params->fl1size);
0463 
0464 } /* csio_mb_iq_alloc */
0465 
0466 /*
0467  * csio_mb_iq_write - Initializes the mailbox for writing into an
0468  *              Ingress DMA Queue.
0469  *
0470  * @hw: The HW structure
0471  * @mbp: Mailbox structure to initialize
0472  * @priv: Private object
0473  * @mb_tmo: Mailbox time-out period (in ms).
0474  * @cascaded_req: TRUE - if this request is cascased with iq-alloc request.
0475  * @iq_params: Ingress queue params needed for writing.
0476  * @cbfn: The call-back function
0477  *
0478  * NOTE: We OR relevant bits with cmdp->XXX, instead of just equating,
0479  * because this IQ write request can be cascaded with a previous
0480  * IQ alloc request, and we dont want to over-write the bits set by
0481  * that request. This logic will work even in a non-cascaded case, since the
0482  * cmdp structure is zeroed out by CSIO_INIT_MBP.
0483  */
0484 static void
0485 csio_mb_iq_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0486          uint32_t mb_tmo, bool cascaded_req,
0487          struct csio_iq_params *iq_params,
0488          void (*cbfn) (struct csio_hw *, struct csio_mb *))
0489 {
0490     struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
0491 
0492     uint32_t iq_start_stop = (iq_params->iq_start)  ?
0493                     FW_IQ_CMD_IQSTART_F :
0494                     FW_IQ_CMD_IQSTOP_F;
0495     int relaxed = !(hw->flags & CSIO_HWF_ROOT_NO_RELAXED_ORDERING);
0496 
0497     /*
0498      * If this IQ write is cascaded with IQ alloc request, do not
0499      * re-initialize with 0's.
0500      *
0501      */
0502     if (!cascaded_req)
0503         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0504 
0505     cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_IQ_CMD)     |
0506                 FW_CMD_REQUEST_F | FW_CMD_WRITE_F   |
0507                 FW_IQ_CMD_PFN_V(iq_params->pfn) |
0508                 FW_IQ_CMD_VFN_V(iq_params->vfn));
0509     cmdp->alloc_to_len16 |= htonl(iq_start_stop |
0510                 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0511     cmdp->iqid |= htons(iq_params->iqid);
0512     cmdp->fl0id |= htons(iq_params->fl0id);
0513     cmdp->fl1id |= htons(iq_params->fl1id);
0514     cmdp->type_to_iqandstindex |= htonl(
0515             FW_IQ_CMD_IQANDST_V(iq_params->iqandst) |
0516             FW_IQ_CMD_IQANUS_V(iq_params->iqanus)   |
0517             FW_IQ_CMD_IQANUD_V(iq_params->iqanud)   |
0518             FW_IQ_CMD_IQANDSTINDEX_V(iq_params->iqandstindex));
0519     cmdp->iqdroprss_to_iqesize |= htons(
0520             FW_IQ_CMD_IQPCIECH_V(iq_params->iqpciech)   |
0521             FW_IQ_CMD_IQDCAEN_V(iq_params->iqdcaen)     |
0522             FW_IQ_CMD_IQDCACPU_V(iq_params->iqdcacpu)   |
0523             FW_IQ_CMD_IQINTCNTTHRESH_V(iq_params->iqintcntthresh) |
0524             FW_IQ_CMD_IQCPRIO_V(iq_params->iqcprio)     |
0525             FW_IQ_CMD_IQESIZE_V(iq_params->iqesize));
0526 
0527     cmdp->iqsize |= htons(iq_params->iqsize);
0528     cmdp->iqaddr |= cpu_to_be64(iq_params->iqaddr);
0529 
0530     if (iq_params->type == 0) {
0531         cmdp->iqns_to_fl0congen |= htonl(
0532             FW_IQ_CMD_IQFLINTIQHSEN_V(iq_params->iqflintiqhsen)|
0533             FW_IQ_CMD_IQFLINTCONGEN_V(iq_params->iqflintcongen));
0534     }
0535 
0536     if (iq_params->fl0size && iq_params->fl0addr &&
0537         (iq_params->fl0id != 0xFFFF)) {
0538 
0539         cmdp->iqns_to_fl0congen |= htonl(
0540             FW_IQ_CMD_FL0HOSTFCMODE_V(iq_params->fl0hostfcmode)|
0541             FW_IQ_CMD_FL0CPRIO_V(iq_params->fl0cprio)   |
0542             FW_IQ_CMD_FL0FETCHRO_V(relaxed)         |
0543             FW_IQ_CMD_FL0DATARO_V(relaxed)          |
0544             FW_IQ_CMD_FL0PADEN_V(iq_params->fl0paden)   |
0545             FW_IQ_CMD_FL0PACKEN_V(iq_params->fl0packen));
0546         cmdp->fl0dcaen_to_fl0cidxfthresh |= htons(
0547             FW_IQ_CMD_FL0DCAEN_V(iq_params->fl0dcaen)   |
0548             FW_IQ_CMD_FL0DCACPU_V(iq_params->fl0dcacpu) |
0549             FW_IQ_CMD_FL0FBMIN_V(iq_params->fl0fbmin)   |
0550             FW_IQ_CMD_FL0FBMAX_V(iq_params->fl0fbmax)   |
0551             FW_IQ_CMD_FL0CIDXFTHRESH_V(iq_params->fl0cidxfthresh));
0552         cmdp->fl0size |= htons(iq_params->fl0size);
0553         cmdp->fl0addr |= cpu_to_be64(iq_params->fl0addr);
0554     }
0555 } /* csio_mb_iq_write */
0556 
0557 /*
0558  * csio_mb_iq_alloc_write - Initializes the mailbox for allocating an
0559  *              Ingress DMA Queue.
0560  *
0561  * @hw: The HW structure
0562  * @mbp: Mailbox structure to initialize
0563  * @priv: Private data.
0564  * @mb_tmo: Mailbox time-out period (in ms).
0565  * @iq_params: Ingress queue params needed for allocation & writing.
0566  * @cbfn: The call-back function
0567  *
0568  *
0569  */
0570 void
0571 csio_mb_iq_alloc_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0572                uint32_t mb_tmo, struct csio_iq_params *iq_params,
0573                void (*cbfn) (struct csio_hw *, struct csio_mb *))
0574 {
0575     csio_mb_iq_alloc(hw, mbp, priv, mb_tmo, iq_params, cbfn);
0576     csio_mb_iq_write(hw, mbp, priv, mb_tmo, true, iq_params, cbfn);
0577 } /* csio_mb_iq_alloc_write */
0578 
0579 /*
0580  * csio_mb_iq_alloc_write_rsp - Process the allocation & writing
0581  *              of ingress DMA queue mailbox's response.
0582  *
0583  * @hw: The HW structure.
0584  * @mbp: Mailbox structure to initialize.
0585  * @retval: Firmware return value.
0586  * @iq_params: Ingress queue parameters, after allocation and write.
0587  *
0588  */
0589 void
0590 csio_mb_iq_alloc_write_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0591                enum fw_retval *ret_val,
0592                struct csio_iq_params *iq_params)
0593 {
0594     struct fw_iq_cmd *rsp = (struct fw_iq_cmd *)(mbp->mb);
0595 
0596     *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
0597     if (*ret_val == FW_SUCCESS) {
0598         iq_params->physiqid = ntohs(rsp->physiqid);
0599         iq_params->iqid = ntohs(rsp->iqid);
0600         iq_params->fl0id = ntohs(rsp->fl0id);
0601         iq_params->fl1id = ntohs(rsp->fl1id);
0602     } else {
0603         iq_params->physiqid = iq_params->iqid =
0604         iq_params->fl0id = iq_params->fl1id = 0;
0605     }
0606 } /* csio_mb_iq_alloc_write_rsp */
0607 
0608 /*
0609  * csio_mb_iq_free - Initializes the mailbox for freeing a
0610  *              specified Ingress DMA Queue.
0611  *
0612  * @hw: The HW structure
0613  * @mbp: Mailbox structure to initialize
0614  * @priv: Private data
0615  * @mb_tmo: Mailbox time-out period (in ms).
0616  * @iq_params: Parameters of ingress queue, that is to be freed.
0617  * @cbfn: The call-back function
0618  *
0619  *
0620  */
0621 void
0622 csio_mb_iq_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0623         uint32_t mb_tmo, struct csio_iq_params *iq_params,
0624         void (*cbfn) (struct csio_hw *, struct csio_mb *))
0625 {
0626     struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
0627 
0628     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0629 
0630     cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD)      |
0631                 FW_CMD_REQUEST_F | FW_CMD_EXEC_F    |
0632                 FW_IQ_CMD_PFN_V(iq_params->pfn) |
0633                 FW_IQ_CMD_VFN_V(iq_params->vfn));
0634     cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_FREE_F       |
0635                 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0636     cmdp->type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE_V(iq_params->type));
0637 
0638     cmdp->iqid = htons(iq_params->iqid);
0639     cmdp->fl0id = htons(iq_params->fl0id);
0640     cmdp->fl1id = htons(iq_params->fl1id);
0641 
0642 } /* csio_mb_iq_free */
0643 
0644 /*
0645  * csio_mb_eq_ofld_alloc - Initializes the mailbox for allocating
0646  *              an offload-egress queue.
0647  *
0648  * @hw: The HW  structure
0649  * @mbp: Mailbox structure to initialize
0650  * @priv: Private data
0651  * @mb_tmo: Mailbox time-out period (in ms).
0652  * @eq_ofld_params: (Offload) Egress queue parameters.
0653  * @cbfn: The call-back function
0654  *
0655  *
0656  */
0657 static void
0658 csio_mb_eq_ofld_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0659         uint32_t mb_tmo, struct csio_eq_params *eq_ofld_params,
0660         void (*cbfn) (struct csio_hw *, struct csio_mb *))
0661 {
0662     struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0663 
0664     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0665     cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD)     |
0666                 FW_CMD_REQUEST_F | FW_CMD_EXEC_F    |
0667                 FW_EQ_OFLD_CMD_PFN_V(eq_ofld_params->pfn) |
0668                 FW_EQ_OFLD_CMD_VFN_V(eq_ofld_params->vfn));
0669     cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC_F |
0670                 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0671 
0672 } /* csio_mb_eq_ofld_alloc */
0673 
0674 /*
0675  * csio_mb_eq_ofld_write - Initializes the mailbox for writing
0676  *              an alloacted offload-egress queue.
0677  *
0678  * @hw: The HW structure
0679  * @mbp: Mailbox structure to initialize
0680  * @priv: Private data
0681  * @mb_tmo: Mailbox time-out period (in ms).
0682  * @cascaded_req: TRUE - if this request is cascased with Eq-alloc request.
0683  * @eq_ofld_params: (Offload) Egress queue parameters.
0684  * @cbfn: The call-back function
0685  *
0686  *
0687  * NOTE: We OR relevant bits with cmdp->XXX, instead of just equating,
0688  * because this EQ write request can be cascaded with a previous
0689  * EQ alloc request, and we dont want to over-write the bits set by
0690  * that request. This logic will work even in a non-cascaded case, since the
0691  * cmdp structure is zeroed out by CSIO_INIT_MBP.
0692  */
0693 static void
0694 csio_mb_eq_ofld_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0695               uint32_t mb_tmo, bool cascaded_req,
0696               struct csio_eq_params *eq_ofld_params,
0697               void (*cbfn) (struct csio_hw *, struct csio_mb *))
0698 {
0699     struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0700 
0701     uint32_t eq_start_stop = (eq_ofld_params->eqstart)  ?
0702                 FW_EQ_OFLD_CMD_EQSTART_F :
0703                 FW_EQ_OFLD_CMD_EQSTOP_F;
0704 
0705     /*
0706      * If this EQ write is cascaded with EQ alloc request, do not
0707      * re-initialize with 0's.
0708      *
0709      */
0710     if (!cascaded_req)
0711         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0712 
0713     cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD)    |
0714                 FW_CMD_REQUEST_F | FW_CMD_WRITE_F   |
0715                 FW_EQ_OFLD_CMD_PFN_V(eq_ofld_params->pfn) |
0716                 FW_EQ_OFLD_CMD_VFN_V(eq_ofld_params->vfn));
0717     cmdp->alloc_to_len16 |= htonl(eq_start_stop     |
0718                       FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0719 
0720     cmdp->eqid_pkd |= htonl(FW_EQ_OFLD_CMD_EQID_V(eq_ofld_params->eqid));
0721 
0722     cmdp->fetchszm_to_iqid |= htonl(
0723         FW_EQ_OFLD_CMD_HOSTFCMODE_V(eq_ofld_params->hostfcmode) |
0724         FW_EQ_OFLD_CMD_CPRIO_V(eq_ofld_params->cprio)       |
0725         FW_EQ_OFLD_CMD_PCIECHN_V(eq_ofld_params->pciechn)   |
0726         FW_EQ_OFLD_CMD_IQID_V(eq_ofld_params->iqid));
0727 
0728     cmdp->dcaen_to_eqsize |= htonl(
0729         FW_EQ_OFLD_CMD_DCAEN_V(eq_ofld_params->dcaen)       |
0730         FW_EQ_OFLD_CMD_DCACPU_V(eq_ofld_params->dcacpu)     |
0731         FW_EQ_OFLD_CMD_FBMIN_V(eq_ofld_params->fbmin)       |
0732         FW_EQ_OFLD_CMD_FBMAX_V(eq_ofld_params->fbmax)       |
0733         FW_EQ_OFLD_CMD_CIDXFTHRESHO_V(eq_ofld_params->cidxfthresho) |
0734         FW_EQ_OFLD_CMD_CIDXFTHRESH_V(eq_ofld_params->cidxfthresh) |
0735         FW_EQ_OFLD_CMD_EQSIZE_V(eq_ofld_params->eqsize));
0736 
0737     cmdp->eqaddr |= cpu_to_be64(eq_ofld_params->eqaddr);
0738 
0739 } /* csio_mb_eq_ofld_write */
0740 
0741 /*
0742  * csio_mb_eq_ofld_alloc_write - Initializes the mailbox for allocation
0743  *              writing into an Engress DMA Queue.
0744  *
0745  * @hw: The HW structure
0746  * @mbp: Mailbox structure to initialize
0747  * @priv: Private data.
0748  * @mb_tmo: Mailbox time-out period (in ms).
0749  * @eq_ofld_params: (Offload) Egress queue parameters.
0750  * @cbfn: The call-back function
0751  *
0752  *
0753  */
0754 void
0755 csio_mb_eq_ofld_alloc_write(struct csio_hw *hw, struct csio_mb *mbp,
0756                 void *priv, uint32_t mb_tmo,
0757                 struct csio_eq_params *eq_ofld_params,
0758                 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0759 {
0760     csio_mb_eq_ofld_alloc(hw, mbp, priv, mb_tmo, eq_ofld_params, cbfn);
0761     csio_mb_eq_ofld_write(hw, mbp, priv, mb_tmo, true,
0762                   eq_ofld_params, cbfn);
0763 } /* csio_mb_eq_ofld_alloc_write */
0764 
0765 /*
0766  * csio_mb_eq_ofld_alloc_write_rsp - Process the allocation
0767  *              & write egress DMA queue mailbox's response.
0768  *
0769  * @hw: The HW structure.
0770  * @mbp: Mailbox structure to initialize.
0771  * @retval: Firmware return value.
0772  * @eq_ofld_params: (Offload) Egress queue parameters.
0773  *
0774  */
0775 void
0776 csio_mb_eq_ofld_alloc_write_rsp(struct csio_hw *hw,
0777                 struct csio_mb *mbp, enum fw_retval *ret_val,
0778                 struct csio_eq_params *eq_ofld_params)
0779 {
0780     struct fw_eq_ofld_cmd *rsp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0781 
0782     *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
0783 
0784     if (*ret_val == FW_SUCCESS) {
0785         eq_ofld_params->eqid = FW_EQ_OFLD_CMD_EQID_G(
0786                         ntohl(rsp->eqid_pkd));
0787         eq_ofld_params->physeqid = FW_EQ_OFLD_CMD_PHYSEQID_G(
0788                         ntohl(rsp->physeqid_pkd));
0789     } else
0790         eq_ofld_params->eqid = 0;
0791 
0792 } /* csio_mb_eq_ofld_alloc_write_rsp */
0793 
0794 /*
0795  * csio_mb_eq_ofld_free - Initializes the mailbox for freeing a
0796  *              specified Engress DMA Queue.
0797  *
0798  * @hw: The HW structure
0799  * @mbp: Mailbox structure to initialize
0800  * @priv: Private data area.
0801  * @mb_tmo: Mailbox time-out period (in ms).
0802  * @eq_ofld_params: (Offload) Egress queue parameters, that is to be freed.
0803  * @cbfn: The call-back function
0804  *
0805  *
0806  */
0807 void
0808 csio_mb_eq_ofld_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0809              uint32_t mb_tmo, struct csio_eq_params *eq_ofld_params,
0810              void (*cbfn) (struct csio_hw *, struct csio_mb *))
0811 {
0812     struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0813 
0814     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0815 
0816     cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
0817                 FW_CMD_REQUEST_F | FW_CMD_EXEC_F    |
0818                 FW_EQ_OFLD_CMD_PFN_V(eq_ofld_params->pfn) |
0819                 FW_EQ_OFLD_CMD_VFN_V(eq_ofld_params->vfn));
0820     cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE_F |
0821                 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0822     cmdp->eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID_V(eq_ofld_params->eqid));
0823 
0824 } /* csio_mb_eq_ofld_free */
0825 
0826 /*
0827  * csio_write_fcoe_link_cond_init_mb - Initialize Mailbox to write FCoE link
0828  *               condition.
0829  *
0830  * @ln: The Lnode structure
0831  * @mbp: Mailbox structure to initialize
0832  * @mb_tmo: Mailbox time-out period (in ms).
0833  * @cbfn: The call back function.
0834  *
0835  *
0836  */
0837 void
0838 csio_write_fcoe_link_cond_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0839             uint32_t mb_tmo, uint8_t port_id, uint32_t sub_opcode,
0840             uint8_t cos, bool link_status, uint32_t fcfi,
0841             void (*cbfn) (struct csio_hw *, struct csio_mb *))
0842 {
0843     struct fw_fcoe_link_cmd *cmdp =
0844                 (struct fw_fcoe_link_cmd *)(mbp->mb);
0845 
0846     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0847 
0848     cmdp->op_to_portid = htonl((
0849             FW_CMD_OP_V(FW_FCOE_LINK_CMD)       |
0850             FW_CMD_REQUEST_F                |
0851             FW_CMD_WRITE_F              |
0852             FW_FCOE_LINK_CMD_PORTID(port_id)));
0853     cmdp->sub_opcode_fcfi = htonl(
0854             FW_FCOE_LINK_CMD_SUB_OPCODE(sub_opcode) |
0855             FW_FCOE_LINK_CMD_FCFI(fcfi));
0856     cmdp->lstatus = link_status;
0857     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0858 
0859 } /* csio_write_fcoe_link_cond_init_mb */
0860 
0861 /*
0862  * csio_fcoe_read_res_info_init_mb - Initializes the mailbox for reading FCoE
0863  *              resource information(FW_GET_RES_INFO_CMD).
0864  *
0865  * @hw: The HW structure
0866  * @mbp: Mailbox structure to initialize
0867  * @mb_tmo: Mailbox time-out period (in ms).
0868  * @cbfn: The call-back function
0869  *
0870  *
0871  */
0872 void
0873 csio_fcoe_read_res_info_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
0874             uint32_t mb_tmo,
0875             void (*cbfn) (struct csio_hw *, struct csio_mb *))
0876 {
0877     struct fw_fcoe_res_info_cmd *cmdp =
0878             (struct fw_fcoe_res_info_cmd *)(mbp->mb);
0879 
0880     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
0881 
0882     cmdp->op_to_read = htonl((FW_CMD_OP_V(FW_FCOE_RES_INFO_CMD) |
0883                   FW_CMD_REQUEST_F          |
0884                   FW_CMD_READ_F));
0885 
0886     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0887 
0888 } /* csio_fcoe_read_res_info_init_mb */
0889 
0890 /*
0891  * csio_fcoe_vnp_alloc_init_mb - Initializes the mailbox for allocating VNP
0892  *              in the firmware (FW_FCOE_VNP_CMD).
0893  *
0894  * @ln: The Lnode structure.
0895  * @mbp: Mailbox structure to initialize.
0896  * @mb_tmo: Mailbox time-out period (in ms).
0897  * @fcfi: FCF Index.
0898  * @vnpi: vnpi
0899  * @iqid: iqid
0900  * @vnport_wwnn: vnport WWNN
0901  * @vnport_wwpn: vnport WWPN
0902  * @cbfn: The call-back function.
0903  *
0904  *
0905  */
0906 void
0907 csio_fcoe_vnp_alloc_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0908         uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi, uint16_t iqid,
0909         uint8_t vnport_wwnn[8], uint8_t vnport_wwpn[8],
0910         void (*cbfn) (struct csio_hw *, struct csio_mb *))
0911 {
0912     struct fw_fcoe_vnp_cmd *cmdp =
0913             (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0914 
0915     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0916 
0917     cmdp->op_to_fcfi = htonl((FW_CMD_OP_V(FW_FCOE_VNP_CMD)      |
0918                   FW_CMD_REQUEST_F          |
0919                   FW_CMD_EXEC_F             |
0920                   FW_FCOE_VNP_CMD_FCFI(fcfi)));
0921 
0922     cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_ALLOC      |
0923                      FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0924 
0925     cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
0926 
0927     cmdp->iqid = htons(iqid);
0928 
0929     if (!wwn_to_u64(vnport_wwnn) && !wwn_to_u64(vnport_wwpn))
0930         cmdp->gen_wwn_to_vnpi |= htonl(FW_FCOE_VNP_CMD_GEN_WWN);
0931 
0932     if (vnport_wwnn)
0933         memcpy(cmdp->vnport_wwnn, vnport_wwnn, 8);
0934     if (vnport_wwpn)
0935         memcpy(cmdp->vnport_wwpn, vnport_wwpn, 8);
0936 
0937 } /* csio_fcoe_vnp_alloc_init_mb */
0938 
0939 /*
0940  * csio_fcoe_vnp_read_init_mb - Prepares VNP read cmd.
0941  * @ln: The Lnode structure.
0942  * @mbp: Mailbox structure to initialize.
0943  * @mb_tmo: Mailbox time-out period (in ms).
0944  * @fcfi: FCF Index.
0945  * @vnpi: vnpi
0946  * @cbfn: The call-back handler.
0947  */
0948 void
0949 csio_fcoe_vnp_read_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0950         uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi,
0951         void (*cbfn) (struct csio_hw *, struct csio_mb *))
0952 {
0953     struct fw_fcoe_vnp_cmd *cmdp =
0954             (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0955 
0956     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0957     cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD)   |
0958                  FW_CMD_REQUEST_F           |
0959                  FW_CMD_READ_F          |
0960                  FW_FCOE_VNP_CMD_FCFI(fcfi));
0961     cmdp->alloc_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0962     cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
0963 }
0964 
0965 /*
0966  * csio_fcoe_vnp_free_init_mb - Initializes the mailbox for freeing an
0967  *          alloacted VNP in the firmware (FW_FCOE_VNP_CMD).
0968  *
0969  * @ln: The Lnode structure.
0970  * @mbp: Mailbox structure to initialize.
0971  * @mb_tmo: Mailbox time-out period (in ms).
0972  * @fcfi: FCF flow id
0973  * @vnpi: VNP flow id
0974  * @cbfn: The call-back function.
0975  * Return: None
0976  */
0977 void
0978 csio_fcoe_vnp_free_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0979         uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi,
0980         void (*cbfn) (struct csio_hw *, struct csio_mb *))
0981 {
0982     struct fw_fcoe_vnp_cmd *cmdp =
0983             (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0984 
0985     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0986 
0987     cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD)   |
0988                  FW_CMD_REQUEST_F           |
0989                  FW_CMD_EXEC_F          |
0990                  FW_FCOE_VNP_CMD_FCFI(fcfi));
0991     cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_FREE   |
0992                      FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0993     cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
0994 }
0995 
0996 /*
0997  * csio_fcoe_read_fcf_init_mb - Initializes the mailbox to read the
0998  *              FCF records.
0999  *
1000  * @ln: The Lnode structure
1001  * @mbp: Mailbox structure to initialize
1002  * @mb_tmo: Mailbox time-out period (in ms).
1003  * @fcf_params: FC-Forwarder parameters.
1004  * @cbfn: The call-back function
1005  *
1006  *
1007  */
1008 void
1009 csio_fcoe_read_fcf_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
1010         uint32_t mb_tmo, uint32_t portid, uint32_t fcfi,
1011         void (*cbfn) (struct csio_hw *, struct csio_mb *))
1012 {
1013     struct fw_fcoe_fcf_cmd *cmdp =
1014             (struct fw_fcoe_fcf_cmd *)(mbp->mb);
1015 
1016     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
1017 
1018     cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_FCF_CMD)   |
1019                  FW_CMD_REQUEST_F           |
1020                  FW_CMD_READ_F          |
1021                  FW_FCOE_FCF_CMD_FCFI(fcfi));
1022     cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
1023 
1024 } /* csio_fcoe_read_fcf_init_mb */
1025 
1026 void
1027 csio_fcoe_read_portparams_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
1028                 uint32_t mb_tmo,
1029                 struct fw_fcoe_port_cmd_params *portparams,
1030                 void (*cbfn)(struct csio_hw *,
1031                          struct csio_mb *))
1032 {
1033     struct fw_fcoe_stats_cmd *cmdp = (struct fw_fcoe_stats_cmd *)(mbp->mb);
1034 
1035     CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
1036     mbp->mb_size = 64;
1037 
1038     cmdp->op_to_flowid = htonl(FW_CMD_OP_V(FW_FCOE_STATS_CMD)         |
1039                    FW_CMD_REQUEST_F | FW_CMD_READ_F);
1040     cmdp->free_to_len16 = htonl(FW_CMD_LEN16_V(CSIO_MAX_MB_SIZE/16));
1041 
1042     cmdp->u.ctl.nstats_port = FW_FCOE_STATS_CMD_NSTATS(portparams->nstats) |
1043                   FW_FCOE_STATS_CMD_PORT(portparams->portid);
1044 
1045     cmdp->u.ctl.port_valid_ix = FW_FCOE_STATS_CMD_IX(portparams->idx)    |
1046                     FW_FCOE_STATS_CMD_PORT_VALID;
1047 
1048 } /* csio_fcoe_read_portparams_init_mb */
1049 
1050 void
1051 csio_mb_process_portparams_rsp(struct csio_hw *hw,
1052                 struct csio_mb *mbp,
1053                 enum fw_retval *retval,
1054                 struct fw_fcoe_port_cmd_params *portparams,
1055                 struct fw_fcoe_port_stats *portstats)
1056 {
1057     struct fw_fcoe_stats_cmd *rsp = (struct fw_fcoe_stats_cmd *)(mbp->mb);
1058     struct fw_fcoe_port_stats stats;
1059     uint8_t *src;
1060     uint8_t *dst;
1061 
1062     *retval = FW_CMD_RETVAL_G(ntohl(rsp->free_to_len16));
1063 
1064     memset(&stats, 0, sizeof(struct fw_fcoe_port_stats));
1065 
1066     if (*retval == FW_SUCCESS) {
1067         dst = (uint8_t *)(&stats) + ((portparams->idx - 1) * 8);
1068         src = (uint8_t *)rsp + (CSIO_STATS_OFFSET * 8);
1069         memcpy(dst, src, (portparams->nstats * 8));
1070         if (portparams->idx == 1) {
1071             /* Get the first 6 flits from the Mailbox */
1072             portstats->tx_bcast_bytes = stats.tx_bcast_bytes;
1073             portstats->tx_bcast_frames = stats.tx_bcast_frames;
1074             portstats->tx_mcast_bytes = stats.tx_mcast_bytes;
1075             portstats->tx_mcast_frames = stats.tx_mcast_frames;
1076             portstats->tx_ucast_bytes = stats.tx_ucast_bytes;
1077             portstats->tx_ucast_frames = stats.tx_ucast_frames;
1078         }
1079         if (portparams->idx == 7) {
1080             /* Get the second 6 flits from the Mailbox */
1081             portstats->tx_drop_frames = stats.tx_drop_frames;
1082             portstats->tx_offload_bytes = stats.tx_offload_bytes;
1083             portstats->tx_offload_frames = stats.tx_offload_frames;
1084 #if 0
1085             portstats->rx_pf_bytes = stats.rx_pf_bytes;
1086             portstats->rx_pf_frames = stats.rx_pf_frames;
1087 #endif
1088             portstats->rx_bcast_bytes = stats.rx_bcast_bytes;
1089             portstats->rx_bcast_frames = stats.rx_bcast_frames;
1090             portstats->rx_mcast_bytes = stats.rx_mcast_bytes;
1091         }
1092         if (portparams->idx == 13) {
1093             /* Get the last 4 flits from the Mailbox */
1094             portstats->rx_mcast_frames = stats.rx_mcast_frames;
1095             portstats->rx_ucast_bytes = stats.rx_ucast_bytes;
1096             portstats->rx_ucast_frames = stats.rx_ucast_frames;
1097             portstats->rx_err_frames = stats.rx_err_frames;
1098         }
1099     }
1100 }
1101 
1102 /* Entry points/APIs for MB module                       */
1103 /*
1104  * csio_mb_intr_enable - Enable Interrupts from mailboxes.
1105  * @hw: The HW structure
1106  *
1107  * Enables CIM interrupt bit in appropriate INT_ENABLE registers.
1108  */
1109 void
1110 csio_mb_intr_enable(struct csio_hw *hw)
1111 {
1112     csio_wr_reg32(hw, MBMSGRDYINTEN_F, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1113     csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1114 }
1115 
1116 /*
1117  * csio_mb_intr_disable - Disable Interrupts from mailboxes.
1118  * @hw: The HW structure
1119  *
1120  * Disable bit in HostInterruptEnable CIM register.
1121  */
1122 void
1123 csio_mb_intr_disable(struct csio_hw *hw)
1124 {
1125     csio_wr_reg32(hw, MBMSGRDYINTEN_V(0),
1126               MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1127     csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1128 }
1129 
1130 static void
1131 csio_mb_dump_fw_dbg(struct csio_hw *hw, __be64 *cmd)
1132 {
1133     struct fw_debug_cmd *dbg = (struct fw_debug_cmd *)cmd;
1134 
1135     if ((FW_DEBUG_CMD_TYPE_G(ntohl(dbg->op_type))) == 1) {
1136         csio_info(hw, "FW print message:\n");
1137         csio_info(hw, "\tdebug->dprtstridx = %d\n",
1138                 ntohs(dbg->u.prt.dprtstridx));
1139         csio_info(hw, "\tdebug->dprtstrparam0 = 0x%x\n",
1140                 ntohl(dbg->u.prt.dprtstrparam0));
1141         csio_info(hw, "\tdebug->dprtstrparam1 = 0x%x\n",
1142                 ntohl(dbg->u.prt.dprtstrparam1));
1143         csio_info(hw, "\tdebug->dprtstrparam2 = 0x%x\n",
1144                 ntohl(dbg->u.prt.dprtstrparam2));
1145         csio_info(hw, "\tdebug->dprtstrparam3 = 0x%x\n",
1146                 ntohl(dbg->u.prt.dprtstrparam3));
1147     } else {
1148         /* This is a FW assertion */
1149         csio_fatal(hw, "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
1150                 dbg->u.assert.filename_0_7,
1151                 ntohl(dbg->u.assert.line),
1152                 ntohl(dbg->u.assert.x),
1153                 ntohl(dbg->u.assert.y));
1154     }
1155 }
1156 
1157 static void
1158 csio_mb_debug_cmd_handler(struct csio_hw *hw)
1159 {
1160     int i;
1161     __be64 cmd[CSIO_MB_MAX_REGS];
1162     uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
1163     uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
1164     int size = sizeof(struct fw_debug_cmd);
1165 
1166     /* Copy mailbox data */
1167     for (i = 0; i < size; i += 8)
1168         cmd[i / 8] = cpu_to_be64(csio_rd_reg64(hw, data_reg + i));
1169 
1170     csio_mb_dump_fw_dbg(hw, cmd);
1171 
1172     /* Notify FW of mailbox by setting owner as UP */
1173     csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F |
1174               MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg);
1175 
1176     csio_rd_reg32(hw, ctl_reg);
1177     wmb();
1178 }
1179 
1180 /*
1181  * csio_mb_issue - generic routine for issuing Mailbox commands.
1182  * @hw: The HW structure
1183  * @mbp: Mailbox command to issue
1184  *
1185  *  Caller should hold hw lock across this call.
1186  */
1187 int
1188 csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
1189 {
1190     uint32_t owner, ctl;
1191     int i;
1192     uint32_t ii;
1193     __be64 *cmd = mbp->mb;
1194     __be64 hdr;
1195     struct csio_mbm *mbm = &hw->mbm;
1196     uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
1197     uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
1198     int size = mbp->mb_size;
1199     int rv = -EINVAL;
1200     struct fw_cmd_hdr *fw_hdr;
1201 
1202     /* Determine mode */
1203     if (mbp->mb_cbfn == NULL) {
1204         /* Need to issue/get results in the same context */
1205         if (mbp->tmo < CSIO_MB_POLL_FREQ) {
1206             csio_err(hw, "Invalid tmo: 0x%x\n", mbp->tmo);
1207             goto error_out;
1208         }
1209     } else if (!csio_is_host_intr_enabled(hw) ||
1210            !csio_is_hw_intr_enabled(hw)) {
1211         csio_err(hw, "Cannot issue mailbox in interrupt mode 0x%x\n",
1212              *((uint8_t *)mbp->mb));
1213         goto error_out;
1214     }
1215 
1216     if (mbm->mcurrent != NULL) {
1217         /* Queue mbox cmd, if another mbox cmd is active */
1218         if (mbp->mb_cbfn == NULL) {
1219             rv = -EBUSY;
1220             csio_dbg(hw, "Couldn't own Mailbox %x op:0x%x\n",
1221                     hw->pfn, *((uint8_t *)mbp->mb));
1222 
1223             goto error_out;
1224         } else {
1225             list_add_tail(&mbp->list, &mbm->req_q);
1226             CSIO_INC_STATS(mbm, n_activeq);
1227 
1228             return 0;
1229         }
1230     }
1231 
1232     /* Now get ownership of mailbox */
1233     owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg));
1234 
1235     if (!csio_mb_is_host_owner(owner)) {
1236 
1237         for (i = 0; (owner == CSIO_MBOWNER_NONE) && (i < 3); i++)
1238             owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg));
1239         /*
1240          * Mailbox unavailable. In immediate mode, fail the command.
1241          * In other modes, enqueue the request.
1242          */
1243         if (!csio_mb_is_host_owner(owner)) {
1244             if (mbp->mb_cbfn == NULL) {
1245                 rv = owner ? -EBUSY : -ETIMEDOUT;
1246 
1247                 csio_dbg(hw,
1248                      "Couldn't own Mailbox %x op:0x%x "
1249                      "owner:%x\n",
1250                      hw->pfn, *((uint8_t *)mbp->mb), owner);
1251                 goto error_out;
1252             } else {
1253                 if (mbm->mcurrent == NULL) {
1254                     csio_err(hw,
1255                          "Couldn't own Mailbox %x "
1256                          "op:0x%x owner:%x\n",
1257                          hw->pfn, *((uint8_t *)mbp->mb),
1258                          owner);
1259                     csio_err(hw,
1260                          "No outstanding driver"
1261                          " mailbox as well\n");
1262                     goto error_out;
1263                 }
1264             }
1265         }
1266     }
1267 
1268     /* Mailbox is available, copy mailbox data into it */
1269     for (i = 0; i < size; i += 8) {
1270         csio_wr_reg64(hw, be64_to_cpu(*cmd), data_reg + i);
1271         cmd++;
1272     }
1273 
1274     CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1275 
1276     /* Start completion timers in non-immediate modes and notify FW */
1277     if (mbp->mb_cbfn != NULL) {
1278         mbm->mcurrent = mbp;
1279         mod_timer(&mbm->timer, jiffies + msecs_to_jiffies(mbp->tmo));
1280         csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F |
1281                   MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg);
1282     } else
1283         csio_wr_reg32(hw, MBMSGVALID_F | MBOWNER_V(CSIO_MBOWNER_FW),
1284                   ctl_reg);
1285 
1286     /* Flush posted writes */
1287     csio_rd_reg32(hw, ctl_reg);
1288     wmb();
1289 
1290     CSIO_INC_STATS(mbm, n_req);
1291 
1292     if (mbp->mb_cbfn)
1293         return 0;
1294 
1295     /* Poll for completion in immediate mode */
1296     cmd = mbp->mb;
1297 
1298     for (ii = 0; ii < mbp->tmo; ii += CSIO_MB_POLL_FREQ) {
1299         mdelay(CSIO_MB_POLL_FREQ);
1300 
1301         /* Check for response */
1302         ctl = csio_rd_reg32(hw, ctl_reg);
1303         if (csio_mb_is_host_owner(MBOWNER_G(ctl))) {
1304 
1305             if (!(ctl & MBMSGVALID_F)) {
1306                 csio_wr_reg32(hw, 0, ctl_reg);
1307                 continue;
1308             }
1309 
1310             CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1311 
1312             hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
1313             fw_hdr = (struct fw_cmd_hdr *)&hdr;
1314 
1315             switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
1316             case FW_DEBUG_CMD:
1317                 csio_mb_debug_cmd_handler(hw);
1318                 continue;
1319             }
1320 
1321             /* Copy response */
1322             for (i = 0; i < size; i += 8)
1323                 *cmd++ = cpu_to_be64(csio_rd_reg64
1324                               (hw, data_reg + i));
1325             csio_wr_reg32(hw, 0, ctl_reg);
1326 
1327             if (csio_mb_fw_retval(mbp) != FW_SUCCESS)
1328                 CSIO_INC_STATS(mbm, n_err);
1329 
1330             CSIO_INC_STATS(mbm, n_rsp);
1331             return 0;
1332         }
1333     }
1334 
1335     CSIO_INC_STATS(mbm, n_tmo);
1336 
1337     csio_err(hw, "Mailbox %x op:0x%x timed out!\n",
1338          hw->pfn, *((uint8_t *)cmd));
1339 
1340     return -ETIMEDOUT;
1341 
1342 error_out:
1343     CSIO_INC_STATS(mbm, n_err);
1344     return rv;
1345 }
1346 
1347 /*
1348  * csio_mb_completions - Completion handler for Mailbox commands
1349  * @hw: The HW structure
1350  * @cbfn_q: Completion queue.
1351  *
1352  */
1353 void
1354 csio_mb_completions(struct csio_hw *hw, struct list_head *cbfn_q)
1355 {
1356     struct csio_mb *mbp;
1357     struct csio_mbm *mbm = &hw->mbm;
1358     enum fw_retval rv;
1359 
1360     while (!list_empty(cbfn_q)) {
1361         mbp = list_first_entry(cbfn_q, struct csio_mb, list);
1362         list_del_init(&mbp->list);
1363 
1364         rv = csio_mb_fw_retval(mbp);
1365         if ((rv != FW_SUCCESS) && (rv != FW_HOSTERROR))
1366             CSIO_INC_STATS(mbm, n_err);
1367         else if (rv != FW_HOSTERROR)
1368             CSIO_INC_STATS(mbm, n_rsp);
1369 
1370         if (mbp->mb_cbfn)
1371             mbp->mb_cbfn(hw, mbp);
1372     }
1373 }
1374 
1375 static void
1376 csio_mb_portmod_changed(struct csio_hw *hw, uint8_t port_id)
1377 {
1378     static char *mod_str[] = {
1379         NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
1380     };
1381 
1382     struct csio_pport *port = &hw->pport[port_id];
1383 
1384     if (port->mod_type == FW_PORT_MOD_TYPE_NONE)
1385         csio_info(hw, "Port:%d - port module unplugged\n", port_id);
1386     else if (port->mod_type < ARRAY_SIZE(mod_str))
1387         csio_info(hw, "Port:%d - %s port module inserted\n", port_id,
1388               mod_str[port->mod_type]);
1389     else if (port->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
1390         csio_info(hw,
1391               "Port:%d - unsupported optical port module "
1392               "inserted\n", port_id);
1393     else if (port->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
1394         csio_info(hw,
1395               "Port:%d - unknown port module inserted, forcing "
1396               "TWINAX\n", port_id);
1397     else if (port->mod_type == FW_PORT_MOD_TYPE_ERROR)
1398         csio_info(hw, "Port:%d - transceiver module error\n", port_id);
1399     else
1400         csio_info(hw, "Port:%d - unknown module type %d inserted\n",
1401               port_id, port->mod_type);
1402 }
1403 
1404 int
1405 csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd)
1406 {
1407     uint8_t opcode = *(uint8_t *)cmd;
1408     struct fw_port_cmd *pcmd;
1409     uint8_t port_id;
1410     uint32_t link_status;
1411     uint16_t action;
1412     uint8_t mod_type;
1413     fw_port_cap32_t linkattr;
1414 
1415     if (opcode == FW_PORT_CMD) {
1416         pcmd = (struct fw_port_cmd *)cmd;
1417         port_id = FW_PORT_CMD_PORTID_G(
1418                 ntohl(pcmd->op_to_portid));
1419         action = FW_PORT_CMD_ACTION_G(
1420                 ntohl(pcmd->action_to_len16));
1421         if (action != FW_PORT_ACTION_GET_PORT_INFO &&
1422             action != FW_PORT_ACTION_GET_PORT_INFO32) {
1423             csio_err(hw, "Unhandled FW_PORT_CMD action: %u\n",
1424                 action);
1425             return -EINVAL;
1426         }
1427 
1428         if (action == FW_PORT_ACTION_GET_PORT_INFO) {
1429             link_status = ntohl(pcmd->u.info.lstatus_to_modtype);
1430             mod_type = FW_PORT_CMD_MODTYPE_G(link_status);
1431             linkattr = lstatus_to_fwcap(link_status);
1432 
1433             hw->pport[port_id].link_status =
1434                 FW_PORT_CMD_LSTATUS_G(link_status);
1435         } else {
1436             link_status =
1437                 ntohl(pcmd->u.info32.lstatus32_to_cbllen32);
1438             mod_type = FW_PORT_CMD_MODTYPE32_G(link_status);
1439             linkattr = ntohl(pcmd->u.info32.linkattr32);
1440 
1441             hw->pport[port_id].link_status =
1442                 FW_PORT_CMD_LSTATUS32_G(link_status);
1443         }
1444 
1445         hw->pport[port_id].link_speed = fwcap_to_fwspeed(linkattr);
1446 
1447         csio_info(hw, "Port:%x - LINK %s\n", port_id,
1448             hw->pport[port_id].link_status ? "UP" : "DOWN");
1449 
1450         if (mod_type != hw->pport[port_id].mod_type) {
1451             hw->pport[port_id].mod_type = mod_type;
1452             csio_mb_portmod_changed(hw, port_id);
1453         }
1454     } else if (opcode == FW_DEBUG_CMD) {
1455         csio_mb_dump_fw_dbg(hw, cmd);
1456     } else {
1457         csio_dbg(hw, "Gen MB can't handle op:0x%x on evtq.\n", opcode);
1458         return -EINVAL;
1459     }
1460 
1461     return 0;
1462 }
1463 
1464 /*
1465  * csio_mb_isr_handler - Handle mailboxes related interrupts.
1466  * @hw: The HW structure
1467  *
1468  * Called from the ISR to handle Mailbox related interrupts.
1469  * HW Lock should be held across this call.
1470  */
1471 int
1472 csio_mb_isr_handler(struct csio_hw *hw)
1473 {
1474     struct csio_mbm     *mbm = &hw->mbm;
1475     struct csio_mb      *mbp =  mbm->mcurrent;
1476     __be64          *cmd;
1477     uint32_t        ctl, cim_cause, pl_cause;
1478     int         i;
1479     uint32_t    ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
1480     uint32_t    data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
1481     int         size;
1482     __be64          hdr;
1483     struct fw_cmd_hdr   *fw_hdr;
1484 
1485     pl_cause = csio_rd_reg32(hw, MYPF_REG(PL_PF_INT_CAUSE_A));
1486     cim_cause = csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A));
1487 
1488     if (!(pl_cause & PFCIM_F) || !(cim_cause & MBMSGRDYINT_F)) {
1489         CSIO_INC_STATS(hw, n_mbint_unexp);
1490         return -EINVAL;
1491     }
1492 
1493     /*
1494      * The cause registers below HAVE to be cleared in the SAME
1495      * order as below: The low level cause register followed by
1496      * the upper level cause register. In other words, CIM-cause
1497      * first followed by PL-Cause next.
1498      */
1499     csio_wr_reg32(hw, MBMSGRDYINT_F, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A));
1500     csio_wr_reg32(hw, PFCIM_F, MYPF_REG(PL_PF_INT_CAUSE_A));
1501 
1502     ctl = csio_rd_reg32(hw, ctl_reg);
1503 
1504     if (csio_mb_is_host_owner(MBOWNER_G(ctl))) {
1505 
1506         CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1507 
1508         if (!(ctl & MBMSGVALID_F)) {
1509             csio_warn(hw,
1510                   "Stray mailbox interrupt recvd,"
1511                   " mailbox data not valid\n");
1512             csio_wr_reg32(hw, 0, ctl_reg);
1513             /* Flush */
1514             csio_rd_reg32(hw, ctl_reg);
1515             return -EINVAL;
1516         }
1517 
1518         hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
1519         fw_hdr = (struct fw_cmd_hdr *)&hdr;
1520 
1521         switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
1522         case FW_DEBUG_CMD:
1523             csio_mb_debug_cmd_handler(hw);
1524             return -EINVAL;
1525 #if 0
1526         case FW_ERROR_CMD:
1527         case FW_INITIALIZE_CMD: /* When we are not master */
1528 #endif
1529         }
1530 
1531         CSIO_ASSERT(mbp != NULL);
1532 
1533         cmd = mbp->mb;
1534         size = mbp->mb_size;
1535         /* Get response */
1536         for (i = 0; i < size; i += 8)
1537             *cmd++ = cpu_to_be64(csio_rd_reg64
1538                           (hw, data_reg + i));
1539 
1540         csio_wr_reg32(hw, 0, ctl_reg);
1541         /* Flush */
1542         csio_rd_reg32(hw, ctl_reg);
1543 
1544         mbm->mcurrent = NULL;
1545 
1546         /* Add completion to tail of cbfn queue */
1547         list_add_tail(&mbp->list, &mbm->cbfn_q);
1548         CSIO_INC_STATS(mbm, n_cbfnq);
1549 
1550         /*
1551          * Enqueue event to EventQ. Events processing happens
1552          * in Event worker thread context
1553          */
1554         if (csio_enqueue_evt(hw, CSIO_EVT_MBX, mbp, sizeof(mbp)))
1555             CSIO_INC_STATS(hw, n_evt_drop);
1556 
1557         return 0;
1558 
1559     } else {
1560         /*
1561          * We can get here if mailbox MSIX vector is shared,
1562          * or in INTx case. Or a stray interrupt.
1563          */
1564         csio_dbg(hw, "Host not owner, no mailbox interrupt\n");
1565         CSIO_INC_STATS(hw, n_int_stray);
1566         return -EINVAL;
1567     }
1568 }
1569 
1570 /*
1571  * csio_mb_tmo_handler - Timeout handler
1572  * @hw: The HW structure
1573  *
1574  */
1575 struct csio_mb *
1576 csio_mb_tmo_handler(struct csio_hw *hw)
1577 {
1578     struct csio_mbm *mbm = &hw->mbm;
1579     struct csio_mb *mbp =  mbm->mcurrent;
1580     struct fw_cmd_hdr *fw_hdr;
1581 
1582     /*
1583      * Could be a race b/w the completion handler and the timer
1584      * and the completion handler won that race.
1585      */
1586     if (mbp == NULL) {
1587         CSIO_DB_ASSERT(0);
1588         return NULL;
1589     }
1590 
1591     fw_hdr = (struct fw_cmd_hdr *)(mbp->mb);
1592 
1593     csio_dbg(hw, "Mailbox num:%x op:0x%x timed out\n", hw->pfn,
1594             FW_CMD_OP_G(ntohl(fw_hdr->hi)));
1595 
1596     mbm->mcurrent = NULL;
1597     CSIO_INC_STATS(mbm, n_tmo);
1598     fw_hdr->lo = htonl(FW_CMD_RETVAL_V(FW_ETIMEDOUT));
1599 
1600     return mbp;
1601 }
1602 
1603 /*
1604  * csio_mb_cancel_all - Cancel all waiting commands.
1605  * @hw: The HW structure
1606  * @cbfn_q: The callback queue.
1607  *
1608  * Caller should hold hw lock across this call.
1609  */
1610 void
1611 csio_mb_cancel_all(struct csio_hw *hw, struct list_head *cbfn_q)
1612 {
1613     struct csio_mb *mbp;
1614     struct csio_mbm *mbm = &hw->mbm;
1615     struct fw_cmd_hdr *hdr;
1616     struct list_head *tmp;
1617 
1618     if (mbm->mcurrent) {
1619         mbp = mbm->mcurrent;
1620 
1621         /* Stop mailbox completion timer */
1622         del_timer_sync(&mbm->timer);
1623 
1624         /* Add completion to tail of cbfn queue */
1625         list_add_tail(&mbp->list, cbfn_q);
1626         mbm->mcurrent = NULL;
1627     }
1628 
1629     if (!list_empty(&mbm->req_q)) {
1630         list_splice_tail_init(&mbm->req_q, cbfn_q);
1631         mbm->stats.n_activeq = 0;
1632     }
1633 
1634     if (!list_empty(&mbm->cbfn_q)) {
1635         list_splice_tail_init(&mbm->cbfn_q, cbfn_q);
1636         mbm->stats.n_cbfnq = 0;
1637     }
1638 
1639     if (list_empty(cbfn_q))
1640         return;
1641 
1642     list_for_each(tmp, cbfn_q) {
1643         mbp = (struct csio_mb *)tmp;
1644         hdr = (struct fw_cmd_hdr *)(mbp->mb);
1645 
1646         csio_dbg(hw, "Cancelling pending mailbox num %x op:%x\n",
1647                 hw->pfn, FW_CMD_OP_G(ntohl(hdr->hi)));
1648 
1649         CSIO_INC_STATS(mbm, n_cancel);
1650         hdr->lo = htonl(FW_CMD_RETVAL_V(FW_HOSTERROR));
1651     }
1652 }
1653 
1654 /*
1655  * csio_mbm_init - Initialize Mailbox module
1656  * @mbm: Mailbox module
1657  * @hw: The HW structure
1658  * @timer: Timing function for interrupting mailboxes
1659  *
1660  * Initialize timer and the request/response queues.
1661  */
1662 int
1663 csio_mbm_init(struct csio_mbm *mbm, struct csio_hw *hw,
1664           void (*timer_fn)(struct timer_list *))
1665 {
1666     mbm->hw = hw;
1667     timer_setup(&mbm->timer, timer_fn, 0);
1668 
1669     INIT_LIST_HEAD(&mbm->req_q);
1670     INIT_LIST_HEAD(&mbm->cbfn_q);
1671     csio_set_mb_intr_idx(mbm, -1);
1672 
1673     return 0;
1674 }
1675 
1676 /*
1677  * csio_mbm_exit - Uninitialize mailbox module
1678  * @mbm: Mailbox module
1679  *
1680  * Stop timer.
1681  */
1682 void
1683 csio_mbm_exit(struct csio_mbm *mbm)
1684 {
1685     del_timer_sync(&mbm->timer);
1686 
1687     CSIO_DB_ASSERT(mbm->mcurrent == NULL);
1688     CSIO_DB_ASSERT(list_empty(&mbm->req_q));
1689     CSIO_DB_ASSERT(list_empty(&mbm->cbfn_q));
1690 }