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

Commit 4910b524 authored by Anil Gurumurthy's avatar Anil Gurumurthy Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Add support for setting port speed



This patch adds sysfs node

1. There is a new sysfs node port_speed
2. The possible values are 2(Auto neg), 8, 16, 32
3. A value outside of the above defaults to Auto neg
4. Any update to the setting causes a link toggle
5. This feature is currently only for ISP27xx

Signed-off-by: default avatarAnil Gurumurthy <agurumurthy@marvell.com>
Signed-off-by: default avatarQuinn Tran <qtran@marvell.com>
Signed-off-by: default avatarHimanshu Madhani <hmadhani@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 192c4e9b
Loading
Loading
Loading
Loading
+89 −0
Original line number Diff line number Diff line
@@ -1632,6 +1632,92 @@ qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr,
	    ha->max_speed_sup ? "32Gps" : "16Gps");
}

static ssize_t
qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
    const char *buf, size_t count)
{
	struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev));
	ulong type, speed;
	int oldspeed, rval;
	int mode = QLA_SET_DATA_RATE_LR;
	struct qla_hw_data *ha = vha->hw;

	if (!IS_QLA27XX(vha->hw)) {
		ql_log(ql_log_warn, vha, 0x70d8,
		    "Speed setting not supported \n");
		return -EINVAL;
	}

	rval = kstrtol(buf, 10, &type);
	speed = type;
	if (type == 40 || type == 80 || type == 160 ||
	    type == 320) {
		ql_dbg(ql_dbg_user, vha, 0x70d9,
		    "Setting will be affected after a loss of sync\n");
		type = type/10;
		mode = QLA_SET_DATA_RATE_NOLR;
	}

	oldspeed = ha->set_data_rate;

	switch (type) {
	case 0:
		ha->set_data_rate = PORT_SPEED_AUTO;
		break;
	case 4:
		ha->set_data_rate = PORT_SPEED_4GB;
		break;
	case 8:
		ha->set_data_rate = PORT_SPEED_8GB;
		break;
	case 16:
		ha->set_data_rate = PORT_SPEED_16GB;
		break;
	case 32:
		ha->set_data_rate = PORT_SPEED_32GB;
		break;
	default:
		ql_log(ql_log_warn, vha, 0x1199,
		    "Unrecognized speed setting:%lx. Setting Autoneg\n",
		    speed);
		ha->set_data_rate = PORT_SPEED_AUTO;
	}

	if (qla2x00_chip_is_down(vha) || (oldspeed == ha->set_data_rate))
		return -EINVAL;

	ql_log(ql_log_info, vha, 0x70da,
	    "Setting speed to %lx Gbps \n", type);

	rval = qla2x00_set_data_rate(vha, mode);
	if (rval != QLA_SUCCESS)
		return -EIO;

	return strlen(buf);
}

static ssize_t
qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr,
    char *buf)
{
	struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev));
	struct qla_hw_data *ha = vha->hw;
	ssize_t rval;
	char *spd[7] = {"0", "0", "0", "4", "8", "16", "32"};

	rval = qla2x00_get_data_rate(vha);
	if (rval != QLA_SUCCESS) {
		ql_log(ql_log_warn, vha, 0x70db,
		    "Unable to get port speed rval:%zd\n", rval);
		return -EINVAL;
	}

	ql_log(ql_log_info, vha, 0x70d6,
	    "port speed:%d\n", ha->link_data_rate);

	return scnprintf(buf, PAGE_SIZE, "%s\n", spd[ha->link_data_rate]);
}

/* ----- */

static ssize_t
@@ -2128,6 +2214,8 @@ static DEVICE_ATTR_RW(ql2xexchoffld);
static DEVICE_ATTR_RW(ql2xiniexchg);
static DEVICE_ATTR(dif_bundle_statistics, 0444,
    qla2x00_dif_bundle_statistics_show, NULL);
static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show,
    qla2x00_port_speed_store);


struct device_attribute *qla2x00_host_attrs[] = {
@@ -2167,6 +2255,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
	&dev_attr_max_speed_sup,
	&dev_attr_zio_threshold,
	&dev_attr_dif_bundle_statistics,
	&dev_attr_port_speed,
	NULL, /* reserve for qlini_mode */
	NULL, /* reserve for ql2xiniexchg */
	NULL, /* reserve for ql2xexchoffld */
+6 −0
Original line number Diff line number Diff line
@@ -3698,12 +3698,14 @@ struct qla_hw_data {
#define PORT_SPEED_UNKNOWN 0xFFFF
#define PORT_SPEED_1GB  0x00
#define PORT_SPEED_2GB  0x01
#define PORT_SPEED_AUTO 0x02
#define PORT_SPEED_4GB  0x03
#define PORT_SPEED_8GB  0x04
#define PORT_SPEED_16GB 0x05
#define PORT_SPEED_32GB 0x06
#define PORT_SPEED_10GB	0x13
	uint16_t	link_data_rate;         /* F/W operating speed */
	uint16_t	set_data_rate;		/* Set by user */

	uint8_t		current_topology;
	uint8_t		prev_topology;
@@ -4232,6 +4234,10 @@ struct qla_hw_data {
#define FW_ABILITY_MAX_SPEED(ha)	\
	(ha->fw_ability_mask & FW_ABILITY_MAX_SPEED_MASK)

#define QLA_GET_DATA_RATE	0
#define QLA_SET_DATA_RATE_NOLR	1
#define QLA_SET_DATA_RATE_LR	2 /* Set speed and initiate LR */

/*
 * Qlogic scsi host structure
 */
+1 −0
Original line number Diff line number Diff line
@@ -899,5 +899,6 @@ void qlt_update_host_map(struct scsi_qla_host *, port_id_t);
void qlt_remove_target_resources(struct qla_hw_data *);
void qlt_clr_qp_table(struct scsi_qla_host *vha);
void qlt_set_mode(struct scsi_qla_host *);
int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);

#endif /* _QLA_GBL_H */
+9 −0
Original line number Diff line number Diff line
@@ -3882,8 +3882,17 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
		WRT_REG_DWORD(&reg->isp24.rsp_q_in, 0);
		WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0);
	}

	qlt_24xx_config_rings(vha);

	/* If the user has configured the speed, set it here */
	if (ha->set_data_rate) {
		ql_dbg(ql_dbg_init, vha, 0x00fd,
		    "Speed set by user : %s Gbps \n",
		    qla2x00_get_link_speed_str(ha, ha->set_data_rate));
		icb->firmware_options_3 = (ha->set_data_rate << 13);
	}

	/* PCI posting */
	RD_REG_DWORD(&ioreg->hccr);
}
+61 −1
Original line number Diff line number Diff line
@@ -5250,6 +5250,66 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb)
	return rval;
}

/* Set the specified data rate */
int
qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
{
	int rval;
	mbx_cmd_t mc;
	mbx_cmd_t *mcp = &mc;
	struct qla_hw_data *ha = vha->hw;
	uint16_t val;

	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1106,
	    "Entered %s speed:0x%x mode:0x%x.\n", __func__, ha->set_data_rate,
	    mode);

	if (!IS_FWI2_CAPABLE(ha))
		return QLA_FUNCTION_FAILED;

	memset(mcp, 0, sizeof(*mcp));
	switch (ha->set_data_rate) {
	case PORT_SPEED_AUTO:
	case PORT_SPEED_4GB:
	case PORT_SPEED_8GB:
	case PORT_SPEED_16GB:
	case PORT_SPEED_32GB:
		val = ha->set_data_rate;
		break;
	default:
		ql_log(ql_log_warn, vha, 0x1199,
		    "Unrecognized speed setting:%d. Setting Autoneg\n",
		    ha->set_data_rate);
		val = ha->set_data_rate = PORT_SPEED_AUTO;
		break;
	}

	mcp->mb[0] = MBC_DATA_RATE;
	mcp->mb[1] = mode;
	mcp->mb[2] = val;

	mcp->out_mb = MBX_2|MBX_1|MBX_0;
	mcp->in_mb = MBX_2|MBX_1|MBX_0;
	if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
		mcp->in_mb |= MBX_4|MBX_3;
	mcp->tov = MBX_TOV_SECONDS;
	mcp->flags = 0;
	rval = qla2x00_mailbox_command(vha, mcp);
	if (rval != QLA_SUCCESS) {
		ql_dbg(ql_dbg_mbx, vha, 0x1107,
		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
	} else {
		if (mcp->mb[1] != 0x7)
			ql_dbg(ql_dbg_mbx, vha, 0x1179,
				"Speed set:0x%x\n", mcp->mb[1]);

		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108,
		    "Done %s.\n", __func__);
	}

	return rval;
}

int
qla2x00_get_data_rate(scsi_qla_host_t *vha)
{
@@ -5265,7 +5325,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
		return QLA_FUNCTION_FAILED;

	mcp->mb[0] = MBC_DATA_RATE;
	mcp->mb[1] = 0;
	mcp->mb[1] = QLA_GET_DATA_RATE;
	mcp->out_mb = MBX_1|MBX_0;
	mcp->in_mb = MBX_2|MBX_1|MBX_0;
	if (IS_QLA83XX(ha) || IS_QLA27XX(ha))