Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1735d9a authored by Varun Prakash's avatar Varun Prakash Committed by Martin K. Petersen
Browse files

scsi: csiostor: add support for 32 bit port capabilities



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

Signed-off-by: default avatarVarun Prakash <varun@chelsio.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 1929e82e
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -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;
+270 −5
Original line number Diff line number Diff line
@@ -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",
+59 −0
Original line number Diff line number Diff line
@@ -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 *);
+8 −0
Original line number Diff line number Diff line
@@ -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,
+42 −28
Original line number Diff line number Diff line
@@ -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;
		}

		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);
		hw->pport[port_id].link_speed =
			FW_PORT_CMD_LSPEED_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_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;
Loading