32 bit port capabilities are required to support new
speeds which can not be supported using 16 bit
port capabilities.

Signed-off-by: Varun Prakash <va...@chelsio.com>
---
 drivers/scsi/csiostor/csio_attr.c  |  16 ++-
 drivers/scsi/csiostor/csio_hw.c    | 275 ++++++++++++++++++++++++++++++++++++-
 drivers/scsi/csiostor/csio_hw.h    |  59 ++++++++
 drivers/scsi/csiostor/csio_lnode.c |   8 ++
 drivers/scsi/csiostor/csio_mb.c    |  70 ++++++----
 drivers/scsi/csiostor/csio_mb.h    |   9 +-
 6 files changed, 395 insertions(+), 42 deletions(-)

diff --git a/drivers/scsi/csiostor/csio_attr.c 
b/drivers/scsi/csiostor/csio_attr.c
index 2d1c4eb..8a00403 100644
--- a/drivers/scsi/csiostor/csio_attr.c
+++ b/drivers/scsi/csiostor/csio_attr.c
@@ -274,12 +274,24 @@ csio_get_host_speed(struct Scsi_Host *shost)
 
        spin_lock_irq(&hw->lock);
        switch (hw->pport[ln->portid].link_speed) {
-       case FW_PORT_CAP_SPEED_1G:
+       case FW_PORT_CAP32_SPEED_1G:
                fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
                break;
-       case FW_PORT_CAP_SPEED_10G:
+       case FW_PORT_CAP32_SPEED_10G:
                fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
                break;
+       case FW_PORT_CAP32_SPEED_25G:
+               fc_host_speed(shost) = FC_PORTSPEED_25GBIT;
+               break;
+       case FW_PORT_CAP32_SPEED_40G:
+               fc_host_speed(shost) = FC_PORTSPEED_40GBIT;
+               break;
+       case FW_PORT_CAP32_SPEED_50G:
+               fc_host_speed(shost) = FC_PORTSPEED_50GBIT;
+               break;
+       case FW_PORT_CAP32_SPEED_100G:
+               fc_host_speed(shost) = FC_PORTSPEED_100GBIT;
+               break;
        default:
                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
                break;
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
index 0bd1131..96bbb82 100644
--- a/drivers/scsi/csiostor/csio_hw.c
+++ b/drivers/scsi/csiostor/csio_hw.c
@@ -1409,6 +1409,235 @@ csio_config_device_caps(struct csio_hw *hw)
        return rv;
 }
 
+static inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec)
+{
+       enum cc_fec cc_fec = 0;
+
+       if (fw_fec & FW_PORT_CAP32_FEC_RS)
+               cc_fec |= FEC_RS;
+       if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
+               cc_fec |= FEC_BASER_RS;
+
+       return cc_fec;
+}
+
+static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause)
+{
+       fw_port_cap32_t fw_pause = 0;
+
+       if (cc_pause & PAUSE_RX)
+               fw_pause |= FW_PORT_CAP32_FC_RX;
+       if (cc_pause & PAUSE_TX)
+               fw_pause |= FW_PORT_CAP32_FC_TX;
+
+       return fw_pause;
+}
+
+static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec)
+{
+       fw_port_cap32_t fw_fec = 0;
+
+       if (cc_fec & FEC_RS)
+               fw_fec |= FW_PORT_CAP32_FEC_RS;
+       if (cc_fec & FEC_BASER_RS)
+               fw_fec |= FW_PORT_CAP32_FEC_BASER_RS;
+
+       return fw_fec;
+}
+
+/**
+ * fwcap_to_fwspeed - return highest speed in Port Capabilities
+ * @acaps: advertised Port Capabilities
+ *
+ * Get the highest speed for the port from the advertised Port
+ * Capabilities.
+ */
+fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps)
+{
+       #define TEST_SPEED_RETURN(__caps_speed) \
+               do { \
+                       if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \
+                               return FW_PORT_CAP32_SPEED_##__caps_speed; \
+               } while (0)
+
+       TEST_SPEED_RETURN(400G);
+       TEST_SPEED_RETURN(200G);
+       TEST_SPEED_RETURN(100G);
+       TEST_SPEED_RETURN(50G);
+       TEST_SPEED_RETURN(40G);
+       TEST_SPEED_RETURN(25G);
+       TEST_SPEED_RETURN(10G);
+       TEST_SPEED_RETURN(1G);
+       TEST_SPEED_RETURN(100M);
+
+       #undef TEST_SPEED_RETURN
+
+       return 0;
+}
+
+/**
+ *      fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits
+ *      @caps16: a 16-bit Port Capabilities value
+ *
+ *      Returns the equivalent 32-bit Port Capabilities value.
+ */
+fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16)
+{
+       fw_port_cap32_t caps32 = 0;
+
+       #define CAP16_TO_CAP32(__cap) \
+               do { \
+                       if (caps16 & FW_PORT_CAP_##__cap) \
+                               caps32 |= FW_PORT_CAP32_##__cap; \
+               } while (0)
+
+       CAP16_TO_CAP32(SPEED_100M);
+       CAP16_TO_CAP32(SPEED_1G);
+       CAP16_TO_CAP32(SPEED_25G);
+       CAP16_TO_CAP32(SPEED_10G);
+       CAP16_TO_CAP32(SPEED_40G);
+       CAP16_TO_CAP32(SPEED_100G);
+       CAP16_TO_CAP32(FC_RX);
+       CAP16_TO_CAP32(FC_TX);
+       CAP16_TO_CAP32(ANEG);
+       CAP16_TO_CAP32(MDIX);
+       CAP16_TO_CAP32(MDIAUTO);
+       CAP16_TO_CAP32(FEC_RS);
+       CAP16_TO_CAP32(FEC_BASER_RS);
+       CAP16_TO_CAP32(802_3_PAUSE);
+       CAP16_TO_CAP32(802_3_ASM_DIR);
+
+       #undef CAP16_TO_CAP32
+
+       return caps32;
+}
+
+/**
+ *      lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities
+ *      @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value
+ *
+ *      Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new
+ *      32-bit Port Capabilities value.
+ */
+fw_port_cap32_t lstatus_to_fwcap(u32 lstatus)
+{
+       fw_port_cap32_t linkattr = 0;
+
+       /* The format of the Link Status in the old
+        * 16-bit Port Information message isn't the same as the
+        * 16-bit Port Capabilities bitfield used everywhere else.
+        */
+       if (lstatus & FW_PORT_CMD_RXPAUSE_F)
+               linkattr |= FW_PORT_CAP32_FC_RX;
+       if (lstatus & FW_PORT_CMD_TXPAUSE_F)
+               linkattr |= FW_PORT_CAP32_FC_TX;
+       if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
+               linkattr |= FW_PORT_CAP32_SPEED_100M;
+       if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
+               linkattr |= FW_PORT_CAP32_SPEED_1G;
+       if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
+               linkattr |= FW_PORT_CAP32_SPEED_10G;
+       if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
+               linkattr |= FW_PORT_CAP32_SPEED_25G;
+       if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
+               linkattr |= FW_PORT_CAP32_SPEED_40G;
+       if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
+               linkattr |= FW_PORT_CAP32_SPEED_100G;
+
+       return linkattr;
+}
+
+/**
+ *      csio_init_link_config - initialize a link's SW state
+ *      @lc: pointer to structure holding the link state
+ *      @pcaps: link Port Capabilities
+ *      @acaps: link current Advertised Port Capabilities
+ *
+ *      Initializes the SW state maintained for each link, including the link's
+ *      capabilities and default speed/flow-control/autonegotiation settings.
+ */
+static void csio_init_link_config(struct link_config *lc, fw_port_cap32_t 
pcaps,
+                                 fw_port_cap32_t acaps)
+{
+       lc->pcaps = pcaps;
+       lc->def_acaps = acaps;
+       lc->lpacaps = 0;
+       lc->speed_caps = 0;
+       lc->speed = 0;
+       lc->requested_fc = PAUSE_RX | PAUSE_TX;
+       lc->fc = lc->requested_fc;
+
+       /*
+        * For Forward Error Control, we default to whatever the Firmware
+        * tells us the Link is currently advertising.
+        */
+       lc->requested_fec = FEC_AUTO;
+       lc->fec = fwcap_to_cc_fec(lc->def_acaps);
+
+       /* If the Port is capable of Auto-Negtotiation, initialize it as
+        * "enabled" and copy over all of the Physical Port Capabilities
+        * to the Advertised Port Capabilities.  Otherwise mark it as
+        * Auto-Negotiate disabled and select the highest supported speed
+        * for the link.  Note parallel structure in t4_link_l1cfg_core()
+        * and t4_handle_get_port_info().
+        */
+       if (lc->pcaps & FW_PORT_CAP32_ANEG) {
+               lc->acaps = lc->pcaps & ADVERT_MASK;
+               lc->autoneg = AUTONEG_ENABLE;
+               lc->requested_fc |= PAUSE_AUTONEG;
+       } else {
+               lc->acaps = 0;
+               lc->autoneg = AUTONEG_DISABLE;
+       }
+}
+
+static void csio_link_l1cfg(struct link_config *lc, uint16_t fw_caps,
+                           uint32_t *rcaps)
+{
+       unsigned int fw_mdi = FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO);
+       fw_port_cap32_t fw_fc, cc_fec, fw_fec, lrcap;
+
+       lc->link_ok = 0;
+
+       /*
+        * Convert driver coding of Pause Frame Flow Control settings into the
+        * Firmware's API.
+        */
+       fw_fc = cc_to_fwcap_pause(lc->requested_fc);
+
+       /*
+        * Convert Common Code Forward Error Control settings into the
+        * Firmware's API.  If the current Requested FEC has "Automatic"
+        * (IEEE 802.3) specified, then we use whatever the Firmware
+        * sent us as part of it's IEEE 802.3-based interpratation of
+        * the Transceiver Module EPROM FEC parameters.  Otherwise we
+        * use whatever is in the current Requested FEC settings.
+        */
+       if (lc->requested_fec & FEC_AUTO)
+               cc_fec = fwcap_to_cc_fec(lc->def_acaps);
+       else
+               cc_fec = lc->requested_fec;
+       fw_fec = cc_to_fwcap_fec(cc_fec);
+
+       /* Figure out what our Requested Port Capabilities are going to be.
+        * Note parallel structure in t4_handle_get_port_info() and
+        * init_link_config().
+        */
+       if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
+               lrcap = (lc->pcaps & ADVERT_MASK) | fw_fc | fw_fec;
+               lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
+               lc->fec = cc_fec;
+       } else if (lc->autoneg == AUTONEG_DISABLE) {
+               lrcap = lc->speed_caps | fw_fc | fw_fec | fw_mdi;
+               lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
+               lc->fec = cc_fec;
+       } else {
+               lrcap = lc->acaps | fw_fc | fw_fec | fw_mdi;
+       }
+
+       *rcaps = lrcap;
+}
+
 /*
  * csio_enable_ports - Bring up all available ports.
  * @hw: HW module.
@@ -1418,8 +1647,10 @@ static int
 csio_enable_ports(struct csio_hw *hw)
 {
        struct csio_mb  *mbp;
+       u16 fw_caps = FW_CAPS_UNKNOWN;
        enum fw_retval retval;
        uint8_t portid;
+       fw_port_cap32_t pcaps, acaps, rcaps;
        int i;
 
        mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
@@ -1431,9 +1662,39 @@ csio_enable_ports(struct csio_hw *hw)
        for (i = 0; i < hw->num_pports; i++) {
                portid = hw->pport[i].portid;
 
+               if (fw_caps == FW_CAPS_UNKNOWN) {
+                       u32 param, val;
+
+                       param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
+                        FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32));
+                       val = 1;
+
+                       csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO,
+                                      hw->pfn, 0, 1, &param, &val, false,
+                                      NULL);
+
+                       if (csio_mb_issue(hw, mbp)) {
+                               csio_err(hw, "failed to issue FW_PARAMS_CMD(r) 
port:%d\n",
+                                        portid);
+                               mempool_free(mbp, hw->mb_mempool);
+                               return -EINVAL;
+                       }
+
+                       csio_mb_process_read_params_rsp(hw, mbp, &retval, 1,
+                                                       &val);
+                       if (retval != FW_SUCCESS) {
+                               csio_err(hw, "FW_PARAMS_CMD(r) port:%d failed: 
0x%x\n",
+                                        portid, retval);
+                               mempool_free(mbp, hw->mb_mempool);
+                               return -EINVAL;
+                       }
+
+                       fw_caps = val;
+               }
+
                /* Read PORT information */
                csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid,
-                            false, 0, 0, NULL);
+                            false, 0, fw_caps, NULL);
 
                if (csio_mb_issue(hw, mbp)) {
                        csio_err(hw, "failed to issue FW_PORT_CMD(r) port:%d\n",
@@ -1442,8 +1703,8 @@ csio_enable_ports(struct csio_hw *hw)
                        return -EINVAL;
                }
 
-               csio_mb_process_read_port_rsp(hw, mbp, &retval,
-                                             &hw->pport[i].pcap);
+               csio_mb_process_read_port_rsp(hw, mbp, &retval, fw_caps,
+                                             &pcaps, &acaps);
                if (retval != FW_SUCCESS) {
                        csio_err(hw, "FW_PORT_CMD(r) port:%d failed: 0x%x\n",
                                 portid, retval);
@@ -1451,9 +1712,13 @@ csio_enable_ports(struct csio_hw *hw)
                        return -EINVAL;
                }
 
+               csio_init_link_config(&hw->pport[i].link_cfg, pcaps, acaps);
+
+               csio_link_l1cfg(&hw->pport[i].link_cfg, fw_caps, &rcaps);
+
                /* Write back PORT information */
-               csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, true,
-                            (PAUSE_RX | PAUSE_TX), hw->pport[i].pcap, NULL);
+               csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid,
+                            true, rcaps, fw_caps, NULL);
 
                if (csio_mb_issue(hw, mbp)) {
                        csio_err(hw, "failed to issue FW_PORT_CMD(w) port:%d\n",
diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h
index 30f5f52..9e73ef7 100644
--- a/drivers/scsi/csiostor/csio_hw.h
+++ b/drivers/scsi/csiostor/csio_hw.h
@@ -268,8 +268,62 @@ struct csio_vpd {
        uint8_t id[ID_LEN + 1];
 };
 
+/* Firmware Port Capabilities types. */
+
+typedef u16 fw_port_cap16_t;    /* 16-bit Port Capabilities integral value */
+typedef u32 fw_port_cap32_t;    /* 32-bit Port Capabilities integral value */
+
+enum fw_caps {
+       FW_CAPS_UNKNOWN = 0,    /* 0'ed out initial state */
+       FW_CAPS16       = 1,    /* old Firmware: 16-bit Port Capabilities */
+       FW_CAPS32       = 2,    /* new Firmware: 32-bit Port Capabilities */
+};
+
+enum cc_pause {
+       PAUSE_RX      = 1 << 0,
+       PAUSE_TX      = 1 << 1,
+       PAUSE_AUTONEG = 1 << 2
+};
+
+enum cc_fec {
+       FEC_AUTO        = 1 << 0,  /* IEEE 802.3 "automatic" */
+       FEC_RS          = 1 << 1,  /* Reed-Solomon */
+       FEC_BASER_RS    = 1 << 2   /* BaseR/Reed-Solomon */
+};
+
+struct link_config {
+       fw_port_cap32_t pcaps;          /* link capabilities */
+       fw_port_cap32_t def_acaps;      /* default advertised capabilities */
+       fw_port_cap32_t acaps;          /* advertised capabilities */
+       fw_port_cap32_t lpacaps;        /* peer advertised capabilities */
+
+       fw_port_cap32_t speed_caps;     /* speed(s) user has requested */
+       unsigned int   speed;           /* actual link speed (Mb/s) */
+
+       enum cc_pause  requested_fc;    /* flow control user has requested */
+       enum cc_pause  fc;              /* actual link flow control */
+
+       enum cc_fec    requested_fec;   /* Forward Error Correction: */
+       enum cc_fec    fec;             /* requested and actual in use */
+
+       unsigned char  autoneg;         /* autonegotiating? */
+
+       unsigned char  link_ok;         /* link up? */
+       unsigned char  link_down_rc;    /* link down reason */
+};
+
+#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
+
+#define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \
+                    FW_PORT_CAP32_ANEG)
+
+/* Enable or disable autonegotiation. */
+#define AUTONEG_DISABLE        0x00
+#define AUTONEG_ENABLE 0x01
+
 struct csio_pport {
        uint16_t        pcap;
+       uint16_t        acap;
        uint8_t         portid;
        uint8_t         link_status;
        uint16_t        link_speed;
@@ -278,6 +332,7 @@ struct csio_pport {
        uint8_t         rsvd1;
        uint8_t         rsvd2;
        uint8_t         rsvd3;
+       struct link_config link_cfg;
 };
 
 /* fcoe resource information */
@@ -582,6 +637,10 @@ int csio_hw_slow_intr_handler(struct csio_hw *);
 int csio_handle_intr_status(struct csio_hw *, unsigned int,
                            const struct intr_info *);
 
+fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps);
+fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16);
+fw_port_cap32_t lstatus_to_fwcap(u32 lstatus);
+
 int csio_hw_start(struct csio_hw *);
 int csio_hw_stop(struct csio_hw *);
 int csio_hw_reset(struct csio_hw *);
diff --git a/drivers/scsi/csiostor/csio_lnode.c 
b/drivers/scsi/csiostor/csio_lnode.c
index 7dbbbb8..cc5611e 100644
--- a/drivers/scsi/csiostor/csio_lnode.c
+++ b/drivers/scsi/csiostor/csio_lnode.c
@@ -352,6 +352,14 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct 
csio_ioreq *fdmi_req)
                val = htonl(FC_PORTSPEED_1GBIT);
        else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_10G)
                val = htonl(FC_PORTSPEED_10GBIT);
+       else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_25G)
+               val = htonl(FC_PORTSPEED_25GBIT);
+       else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_40G)
+               val = htonl(FC_PORTSPEED_40GBIT);
+       else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_50G)
+               val = htonl(FC_PORTSPEED_50GBIT);
+       else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_100G)
+               val = htonl(FC_PORTSPEED_100GBIT);
        else
                val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN);
        csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c
index 5f4e0a7..c026417 100644
--- a/drivers/scsi/csiostor/csio_mb.c
+++ b/drivers/scsi/csiostor/csio_mb.c
@@ -326,10 +326,6 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb 
*mbp, uint32_t tmo,
                cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_TARGET);
 }
 
-#define CSIO_ADVERT_MASK     (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
-                             FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G |\
-                             FW_PORT_CAP_ANEG)
-
 /*
  * csio_mb_port- FW PORT command helper
  * @hw: The HW structure
@@ -344,11 +340,10 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb 
*mbp, uint32_t tmo,
  */
 void
 csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
-            uint8_t portid, bool wr, uint32_t fc, uint16_t caps,
+            u8 portid, bool wr, uint32_t fc, uint16_t fw_caps,
             void (*cbfn) (struct csio_hw *, struct csio_mb *))
 {
        struct fw_port_cmd *cmdp = (struct fw_port_cmd *)(mbp->mb);
-       unsigned int lfc = 0, mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO);
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn,  1);
 
@@ -358,26 +353,24 @@ csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, 
uint32_t tmo,
                                   FW_PORT_CMD_PORTID_V(portid));
        if (!wr) {
                cmdp->action_to_len16 = htonl(
-                       FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
+                       FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
+                       ? FW_PORT_ACTION_GET_PORT_INFO
+                       : FW_PORT_ACTION_GET_PORT_INFO32) |
                        FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
                return;
        }
 
        /* Set port */
        cmdp->action_to_len16 = htonl(
-                       FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
+                       FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
+                       ? FW_PORT_ACTION_L1_CFG
+                       : FW_PORT_ACTION_L1_CFG32) |
                        FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
-       if (fc & PAUSE_RX)
-               lfc |= FW_PORT_CAP_FC_RX;
-       if (fc & PAUSE_TX)
-               lfc |= FW_PORT_CAP_FC_TX;
-
-       if (!(caps & FW_PORT_CAP_ANEG))
-               cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) | lfc);
+       if (fw_caps == FW_CAPS16)
+               cmdp->u.l1cfg.rcap = cpu_to_be32(fc);
        else
-               cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) |
-                                                               lfc | mdi);
+               cmdp->u.l1cfg32.rcap32 = cpu_to_be32(fc);
 }
 
 /*
@@ -390,14 +383,22 @@ csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, 
uint32_t tmo,
  */
 void
 csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp,
-                        enum fw_retval *retval, uint16_t *caps)
+                        enum fw_retval *retval, uint16_t fw_caps,
+                        u32 *pcaps, u32 *acaps)
 {
        struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
 
        *retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16));
 
-       if (*retval == FW_SUCCESS)
-               *caps = ntohs(rsp->u.info.pcap);
+       if (*retval == FW_SUCCESS) {
+               if (fw_caps == FW_CAPS16) {
+                       *pcaps = fwcaps16_to_caps32(ntohs(rsp->u.info.pcap));
+                       *acaps = fwcaps16_to_caps32(ntohs(rsp->u.info.acap));
+               } else {
+                       *pcaps = ntohs(rsp->u.info32.pcaps32);
+                       *acaps = ntohs(rsp->u.info32.acaps32);
+               }
+       }
 }
 
 /*
@@ -1409,6 +1410,7 @@ csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd)
        uint32_t link_status;
        uint16_t action;
        uint8_t mod_type;
+       fw_port_cap32_t linkattr;
 
        if (opcode == FW_PORT_CMD) {
                pcmd = (struct fw_port_cmd *)cmd;
@@ -1416,22 +1418,34 @@ csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd)
                                ntohl(pcmd->op_to_portid));
                action = FW_PORT_CMD_ACTION_G(
                                ntohl(pcmd->action_to_len16));
-               if (action != FW_PORT_ACTION_GET_PORT_INFO) {
+               if (action != FW_PORT_ACTION_GET_PORT_INFO &&
+                   action != FW_PORT_ACTION_GET_PORT_INFO32) {
                        csio_err(hw, "Unhandled FW_PORT_CMD action: %u\n",
                                action);
                        return -EINVAL;
                }
 
-               link_status = ntohl(pcmd->u.info.lstatus_to_modtype);
-               mod_type = FW_PORT_CMD_MODTYPE_G(link_status);
+               if (action == FW_PORT_ACTION_GET_PORT_INFO) {
+                       link_status = ntohl(pcmd->u.info.lstatus_to_modtype);
+                       mod_type = FW_PORT_CMD_MODTYPE_G(link_status);
+                       linkattr = lstatus_to_fwcap(link_status);
+
+                       hw->pport[port_id].link_status =
+                               FW_PORT_CMD_LSTATUS_G(link_status);
+               } else {
+                       link_status =
+                               ntohl(pcmd->u.info32.lstatus32_to_cbllen32);
+                       mod_type = FW_PORT_CMD_MODTYPE32_G(link_status);
+                       linkattr = ntohl(pcmd->u.info32.linkattr32);
+
+                       hw->pport[port_id].link_status =
+                               FW_PORT_CMD_LSTATUS32_G(link_status);
+               }
 
-               hw->pport[port_id].link_status =
-                       FW_PORT_CMD_LSTATUS_G(link_status);
-               hw->pport[port_id].link_speed =
-                       FW_PORT_CMD_LSPEED_G(link_status);
+               hw->pport[port_id].link_speed = fwcap_to_fwspeed(linkattr);
 
                csio_info(hw, "Port:%x - LINK %s\n", port_id,
-                       FW_PORT_CMD_LSTATUS_G(link_status) ? "UP" : "DOWN");
+                       hw->pport[port_id].link_status ? "UP" : "DOWN");
 
                if (mod_type != hw->pport[port_id].mod_type) {
                        hw->pport[port_id].mod_type = mod_type;
diff --git a/drivers/scsi/csiostor/csio_mb.h b/drivers/scsi/csiostor/csio_mb.h
index a6823df..b07e891 100644
--- a/drivers/scsi/csiostor/csio_mb.h
+++ b/drivers/scsi/csiostor/csio_mb.h
@@ -88,12 +88,6 @@ enum csio_dev_state {
         FW_PARAMS_PARAM_Y_V(0) | \
         FW_PARAMS_PARAM_Z_V(0))
 
-enum {
-       PAUSE_RX      = 1 << 0,
-       PAUSE_TX      = 1 << 1,
-       PAUSE_AUTONEG = 1 << 2
-};
-
 #define CSIO_INIT_MBP(__mbp, __cp,  __tmo, __priv, __fn, __clear)      \
 do {                                                                   \
        if (__clear)                                                    \
@@ -189,7 +183,8 @@ void csio_mb_port(struct csio_hw *, struct csio_mb *, 
uint32_t,
                  void (*) (struct csio_hw *, struct csio_mb *));
 
 void csio_mb_process_read_port_rsp(struct csio_hw *, struct csio_mb *,
-                                  enum fw_retval *, uint16_t *);
+                                  enum fw_retval *, uint16_t,
+                                  uint32_t *, uint32_t *);
 
 void csio_mb_initialize(struct csio_hw *, struct csio_mb *, uint32_t,
                        void (*)(struct csio_hw *, struct csio_mb *));
-- 
2.0.2

Reply via email to