Blame SOURCES/0021-scsi-scsi-qla2xxx-Add-support-for-setting-port-speed.patch

3d7c23
From 355c29e25d3d41e2be04292b08f1d26b985df25a Mon Sep 17 00:00:00 2001
3d7c23
From: Himanshu Madhani <hmadhani@redhat.com>
3d7c23
Date: Thu, 1 Aug 2019 15:54:41 -0400
3d7c23
Subject: [PATCH 021/124] [scsi] scsi: qla2xxx: Add support for setting port
3d7c23
 speed
3d7c23
3d7c23
Message-id: <20190801155618.12650-22-hmadhani@redhat.com>
3d7c23
Patchwork-id: 267798
3d7c23
O-Subject: [RHEL 7.8 e-stor PATCH 021/118] scsi: qla2xxx: Add support for setting port speed
3d7c23
Bugzilla: 1729270
3d7c23
RH-Acked-by: Jarod Wilson <jarod@redhat.com>
3d7c23
RH-Acked-by: Tony Camuso <tcamuso@redhat.com>
3d7c23
3d7c23
From: Anil Gurumurthy <agurumurthy@marvell.com>
3d7c23
3d7c23
Bugzilla 1729270
3d7c23
3d7c23
This patch adds sysfs node
3d7c23
3d7c23
1. There is a new sysfs node port_speed
3d7c23
2. The possible values are 2(Auto neg), 8, 16, 32
3d7c23
3. A value outside of the above defaults to Auto neg
3d7c23
4. Any update to the setting causes a link toggle
3d7c23
5. This feature is currently only for ISP27xx
3d7c23
3d7c23
Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
3d7c23
Signed-off-by: Quinn Tran <qtran@marvell.com>
3d7c23
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
3d7c23
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
3d7c23
(cherry picked from commit 4910b524ac9e61b70e35280877361b790a657d48)
3d7c23
Signed-off-by: Himanshu Madhani <hmadhani@redhat.com>
3d7c23
Signed-off-by: Jan Stancek <jstancek@redhat.com>
3d7c23
---
3d7c23
 drivers/scsi/qla2xxx/qla_attr.c | 89 +++++++++++++++++++++++++++++++++++++++++
3d7c23
 drivers/scsi/qla2xxx/qla_def.h  |  6 +++
3d7c23
 drivers/scsi/qla2xxx/qla_gbl.h  |  1 +
3d7c23
 drivers/scsi/qla2xxx/qla_init.c |  9 +++++
3d7c23
 drivers/scsi/qla2xxx/qla_mbx.c  | 62 +++++++++++++++++++++++++++-
3d7c23
 5 files changed, 166 insertions(+), 1 deletion(-)
3d7c23
3d7c23
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
3d7c23
index da8b16469836..037016290044 100644
3d7c23
--- a/drivers/scsi/qla2xxx/qla_attr.c
3d7c23
+++ b/drivers/scsi/qla2xxx/qla_attr.c
3d7c23
@@ -1633,6 +1633,92 @@ qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr,
3d7c23
 	    ha->max_speed_sup ? "32Gps" : "16Gps");
3d7c23
 }
3d7c23
 
3d7c23
+static ssize_t
3d7c23
+qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
3d7c23
+    const char *buf, size_t count)
3d7c23
+{
3d7c23
+	struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev));
3d7c23
+	ulong type, speed;
3d7c23
+	int oldspeed, rval;
3d7c23
+	int mode = QLA_SET_DATA_RATE_LR;
3d7c23
+	struct qla_hw_data *ha = vha->hw;
3d7c23
+
3d7c23
+	if (!IS_QLA27XX(vha->hw)) {
3d7c23
+		ql_log(ql_log_warn, vha, 0x70d8,
3d7c23
+		    "Speed setting not supported \n");
3d7c23
+		return -EINVAL;
3d7c23
+	}
3d7c23
+
3d7c23
+	rval = kstrtol(buf, 10, &type);
3d7c23
+	speed = type;
3d7c23
+	if (type == 40 || type == 80 || type == 160 ||
3d7c23
+	    type == 320) {
3d7c23
+		ql_dbg(ql_dbg_user, vha, 0x70d9,
3d7c23
+		    "Setting will be affected after a loss of sync\n");
3d7c23
+		type = type/10;
3d7c23
+		mode = QLA_SET_DATA_RATE_NOLR;
3d7c23
+	}
3d7c23
+
3d7c23
+	oldspeed = ha->set_data_rate;
3d7c23
+
3d7c23
+	switch (type) {
3d7c23
+	case 0:
3d7c23
+		ha->set_data_rate = PORT_SPEED_AUTO;
3d7c23
+		break;
3d7c23
+	case 4:
3d7c23
+		ha->set_data_rate = PORT_SPEED_4GB;
3d7c23
+		break;
3d7c23
+	case 8:
3d7c23
+		ha->set_data_rate = PORT_SPEED_8GB;
3d7c23
+		break;
3d7c23
+	case 16:
3d7c23
+		ha->set_data_rate = PORT_SPEED_16GB;
3d7c23
+		break;
3d7c23
+	case 32:
3d7c23
+		ha->set_data_rate = PORT_SPEED_32GB;
3d7c23
+		break;
3d7c23
+	default:
3d7c23
+		ql_log(ql_log_warn, vha, 0x1199,
3d7c23
+		    "Unrecognized speed setting:%lx. Setting Autoneg\n",
3d7c23
+		    speed);
3d7c23
+		ha->set_data_rate = PORT_SPEED_AUTO;
3d7c23
+	}
3d7c23
+
3d7c23
+	if (qla2x00_chip_is_down(vha) || (oldspeed == ha->set_data_rate))
3d7c23
+		return -EINVAL;
3d7c23
+
3d7c23
+	ql_log(ql_log_info, vha, 0x70da,
3d7c23
+	    "Setting speed to %lx Gbps \n", type);
3d7c23
+
3d7c23
+	rval = qla2x00_set_data_rate(vha, mode);
3d7c23
+	if (rval != QLA_SUCCESS)
3d7c23
+		return -EIO;
3d7c23
+
3d7c23
+	return strlen(buf);
3d7c23
+}
3d7c23
+
3d7c23
+static ssize_t
3d7c23
+qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr,
3d7c23
+    char *buf)
3d7c23
+{
3d7c23
+	struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev));
3d7c23
+	struct qla_hw_data *ha = vha->hw;
3d7c23
+	ssize_t rval;
3d7c23
+	char *spd[7] = {"0", "0", "0", "4", "8", "16", "32"};
3d7c23
+
3d7c23
+	rval = qla2x00_get_data_rate(vha);
3d7c23
+	if (rval != QLA_SUCCESS) {
3d7c23
+		ql_log(ql_log_warn, vha, 0x70db,
3d7c23
+		    "Unable to get port speed rval:%zd\n", rval);
3d7c23
+		return -EINVAL;
3d7c23
+	}
3d7c23
+
3d7c23
+	ql_log(ql_log_info, vha, 0x70d6,
3d7c23
+	    "port speed:%d\n", ha->link_data_rate);
3d7c23
+
3d7c23
+	return scnprintf(buf, PAGE_SIZE, "%s\n", spd[ha->link_data_rate]);
3d7c23
+}
3d7c23
+
3d7c23
 /* ----- */
3d7c23
 
3d7c23
 static ssize_t
3d7c23
@@ -2129,6 +2215,8 @@ static DEVICE_ATTR_RW(ql2xexchoffld);
3d7c23
 static DEVICE_ATTR_RW(ql2xiniexchg);
3d7c23
 static DEVICE_ATTR(dif_bundle_statistics, 0444,
3d7c23
     qla2x00_dif_bundle_statistics_show, NULL);
3d7c23
+static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show,
3d7c23
+    qla2x00_port_speed_store);
3d7c23
 
3d7c23
 
3d7c23
 struct device_attribute *qla2x00_host_attrs[] = {
3d7c23
@@ -2168,6 +2256,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
3d7c23
 	&dev_attr_max_speed_sup,
3d7c23
 	&dev_attr_zio_threshold,
3d7c23
 	&dev_attr_dif_bundle_statistics,
3d7c23
+	&dev_attr_port_speed,
3d7c23
 	NULL, /* reserve for qlini_mode */
3d7c23
 	NULL, /* reserve for ql2xiniexchg */
3d7c23
 	NULL, /* reserve for ql2xexchoffld */
3d7c23
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
3d7c23
index bcb7ad530240..416307fab71e 100644
3d7c23
--- a/drivers/scsi/qla2xxx/qla_def.h
3d7c23
+++ b/drivers/scsi/qla2xxx/qla_def.h
3d7c23
@@ -3705,12 +3705,14 @@ struct qla_hw_data {
3d7c23
 #define PORT_SPEED_UNKNOWN 0xFFFF
3d7c23
 #define PORT_SPEED_1GB  0x00
3d7c23
 #define PORT_SPEED_2GB  0x01
3d7c23
+#define PORT_SPEED_AUTO 0x02
3d7c23
 #define PORT_SPEED_4GB  0x03
3d7c23
 #define PORT_SPEED_8GB  0x04
3d7c23
 #define PORT_SPEED_16GB 0x05
3d7c23
 #define PORT_SPEED_32GB 0x06
3d7c23
 #define PORT_SPEED_10GB	0x13
3d7c23
 	uint16_t	link_data_rate;         /* F/W operating speed */
3d7c23
+	uint16_t	set_data_rate;		/* Set by user */
3d7c23
 
3d7c23
 	uint8_t		current_topology;
3d7c23
 	uint8_t		prev_topology;
3d7c23
@@ -4239,6 +4241,10 @@ struct qla_hw_data {
3d7c23
 #define FW_ABILITY_MAX_SPEED(ha)	\
3d7c23
 	(ha->fw_ability_mask & FW_ABILITY_MAX_SPEED_MASK)
3d7c23
 
3d7c23
+#define QLA_GET_DATA_RATE	0
3d7c23
+#define QLA_SET_DATA_RATE_NOLR	1
3d7c23
+#define QLA_SET_DATA_RATE_LR	2 /* Set speed and initiate LR */
3d7c23
+
3d7c23
 /*
3d7c23
  * Qlogic scsi host structure
3d7c23
  */
3d7c23
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
3d7c23
index 1e00e93d4066..522865df61cc 100644
3d7c23
--- a/drivers/scsi/qla2xxx/qla_gbl.h
3d7c23
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
3d7c23
@@ -897,5 +897,6 @@ void qlt_unknown_atio_work_fn(struct work_struct *);
3d7c23
 void qlt_update_host_map(struct scsi_qla_host *, port_id_t);
3d7c23
 void qlt_remove_target_resources(struct qla_hw_data *);
3d7c23
 void qlt_set_mode(struct scsi_qla_host *);
3d7c23
+int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);
3d7c23
 
3d7c23
 #endif /* _QLA_GBL_H */
3d7c23
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
3d7c23
index 63b035882651..04d38d0dfb69 100644
3d7c23
--- a/drivers/scsi/qla2xxx/qla_init.c
3d7c23
+++ b/drivers/scsi/qla2xxx/qla_init.c
3d7c23
@@ -3896,8 +3896,17 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
3d7c23
 		WRT_REG_DWORD(&reg->isp24.rsp_q_in, 0);
3d7c23
 		WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0);
3d7c23
 	}
3d7c23
+
3d7c23
 	qlt_24xx_config_rings(vha);
3d7c23
 
3d7c23
+	/* If the user has configured the speed, set it here */
3d7c23
+	if (ha->set_data_rate) {
3d7c23
+		ql_dbg(ql_dbg_init, vha, 0x00fd,
3d7c23
+		    "Speed set by user : %s Gbps \n",
3d7c23
+		    qla2x00_get_link_speed_str(ha, ha->set_data_rate));
3d7c23
+		icb->firmware_options_3 = (ha->set_data_rate << 13);
3d7c23
+	}
3d7c23
+
3d7c23
 	/* PCI posting */
3d7c23
 	RD_REG_DWORD(&ioreg->hccr);
3d7c23
 }
3d7c23
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
3d7c23
index 731fa37603d5..3068422cd7a5 100644
3d7c23
--- a/drivers/scsi/qla2xxx/qla_mbx.c
3d7c23
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
3d7c23
@@ -5252,6 +5252,66 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb)
3d7c23
 	return rval;
3d7c23
 }
3d7c23
 
3d7c23
+/* Set the specified data rate */
3d7c23
+int
3d7c23
+qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
3d7c23
+{
3d7c23
+	int rval;
3d7c23
+	mbx_cmd_t mc;
3d7c23
+	mbx_cmd_t *mcp = &mc;
3d7c23
+	struct qla_hw_data *ha = vha->hw;
3d7c23
+	uint16_t val;
3d7c23
+
3d7c23
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1106,
3d7c23
+	    "Entered %s speed:0x%x mode:0x%x.\n", __func__, ha->set_data_rate,
3d7c23
+	    mode);
3d7c23
+
3d7c23
+	if (!IS_FWI2_CAPABLE(ha))
3d7c23
+		return QLA_FUNCTION_FAILED;
3d7c23
+
3d7c23
+	memset(mcp, 0, sizeof(*mcp));
3d7c23
+	switch (ha->set_data_rate) {
3d7c23
+	case PORT_SPEED_AUTO:
3d7c23
+	case PORT_SPEED_4GB:
3d7c23
+	case PORT_SPEED_8GB:
3d7c23
+	case PORT_SPEED_16GB:
3d7c23
+	case PORT_SPEED_32GB:
3d7c23
+		val = ha->set_data_rate;
3d7c23
+		break;
3d7c23
+	default:
3d7c23
+		ql_log(ql_log_warn, vha, 0x1199,
3d7c23
+		    "Unrecognized speed setting:%d. Setting Autoneg\n",
3d7c23
+		    ha->set_data_rate);
3d7c23
+		val = ha->set_data_rate = PORT_SPEED_AUTO;
3d7c23
+		break;
3d7c23
+	}
3d7c23
+
3d7c23
+	mcp->mb[0] = MBC_DATA_RATE;
3d7c23
+	mcp->mb[1] = mode;
3d7c23
+	mcp->mb[2] = val;
3d7c23
+
3d7c23
+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
3d7c23
+	mcp->in_mb = MBX_2|MBX_1|MBX_0;
3d7c23
+	if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
3d7c23
+		mcp->in_mb |= MBX_4|MBX_3;
3d7c23
+	mcp->tov = MBX_TOV_SECONDS;
3d7c23
+	mcp->flags = 0;
3d7c23
+	rval = qla2x00_mailbox_command(vha, mcp);
3d7c23
+	if (rval != QLA_SUCCESS) {
3d7c23
+		ql_dbg(ql_dbg_mbx, vha, 0x1107,
3d7c23
+		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
3d7c23
+	} else {
3d7c23
+		if (mcp->mb[1] != 0x7)
3d7c23
+			ql_dbg(ql_dbg_mbx, vha, 0x1179,
3d7c23
+				"Speed set:0x%x\n", mcp->mb[1]);
3d7c23
+
3d7c23
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108,
3d7c23
+		    "Done %s.\n", __func__);
3d7c23
+	}
3d7c23
+
3d7c23
+	return rval;
3d7c23
+}
3d7c23
+
3d7c23
 int
3d7c23
 qla2x00_get_data_rate(scsi_qla_host_t *vha)
3d7c23
 {
3d7c23
@@ -5267,7 +5327,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
3d7c23
 		return QLA_FUNCTION_FAILED;
3d7c23
 
3d7c23
 	mcp->mb[0] = MBC_DATA_RATE;
3d7c23
-	mcp->mb[1] = 0;
3d7c23
+	mcp->mb[1] = QLA_GET_DATA_RATE;
3d7c23
 	mcp->out_mb = MBX_1|MBX_0;
3d7c23
 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
3d7c23
 	if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
3d7c23
-- 
3d7c23
2.13.6
3d7c23