diff mbox

[01/12] qla2xxx: Add Laser Control for ISP26XX/27XX

Message ID 20180501160154.27915-2-himanshu.madhani@cavium.com (mailing list archive)
State Rejected
Headers show

Commit Message

Madhani, Himanshu May 1, 2018, 4:01 p.m. UTC
From: Himanshu Madhani <himanshu.madhani@qlogic.com>

This patch disables laser while unloading driver for 16/32G adapters.

Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
---
 drivers/scsi/qla2xxx/qla_def.h    |  7 ++++
 drivers/scsi/qla2xxx/qla_fw.h     |  2 ++
 drivers/scsi/qla2xxx/qla_inline.h | 22 ++++++++++++
 drivers/scsi/qla2xxx/qla_os.c     | 72 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+)
diff mbox

Patch

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index eb2ec1fb07cb..c36e37fdc201 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -201,6 +201,10 @@ 
 #define LASER_ON_2031	0x01800100
 #define LASER_OFF_2031	0x01800180
 
+/* ISP27XX: Values for Laser ON/Off */
+#define LASER_ON_27XX   0x00400000
+#define LASER_OFF_27XX  0x00400040
+
 /*
  * The ISP2312 v2 chip cannot access the FLASH/GPIO registers via MMIO in an
  * 133Mhz slot.
@@ -705,6 +709,8 @@  struct device_reg_2xxx {
 #define GPIO_LED_ALL_OFF		0x0000
 #define GPIO_LED_RED_ON_OTHER_OFF	0x0001	/* isp2322 */
 #define GPIO_LED_RGA_ON			0x00C1	/* isp2322: red green amber */
+#define GPIO_LASER_MASK			BIT_6
+#define GPIO_LASER_DISABLE		BIT_2
 
 	union {
 		struct {
@@ -3161,6 +3167,7 @@  struct isp_operations {
 	int (*abort_isp) (struct scsi_qla_host *);
 	int (*iospace_config)(struct qla_hw_data*);
 	int (*initialize_adapter)(struct scsi_qla_host *);
+	void (*disable_laser)(struct scsi_qla_host *);
 };
 
 /* MSI-X Support *************************************************************/
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 5d8688e5bc7c..b11ae7d04c43 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1096,6 +1096,8 @@  struct device_reg_24xx {
 #define GPDX_LED_AMBER_ON	BIT_4
 					/* Data in/out. */
 #define GPDX_DATA_INOUT		(BIT_1|BIT_0)
+#define GPDX_LASER_MASK		BIT_22
+#define GPDX_LASER_DISABLE	BIT_6
 
 	uint32_t gpioe;			/* GPIO Enable register. */
 					/* Enable update mask. */
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 37ae0f6d8ae5..6ac96322fec1 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -367,3 +367,25 @@  qla_83xx_start_iocbs(struct qla_qpair *qpair)
 
 	WRT_REG_DWORD(req->req_q_in, req->ring_index);
 }
+
+static inline void
+qla24xx_drive_gpio(scsi_qla_host_t *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Take control of GPIO register. */
+	ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL;
+	qla2x00_set_fw_options(vha, ha->fw_options);
+	qla2x00_get_fw_options(vha, ha->fw_options);
+}
+
+static inline void
+qla24xx_relinquish_gpio(scsi_qla_host_t *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Restore control of GPIO register. */
+	ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL;
+	qla2x00_set_fw_options(vha, ha->fw_options);
+	qla2x00_get_fw_options(vha, ha->fw_options);
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 15eaa6dded04..bec8459523bd 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -302,6 +302,8 @@  static void qla2x00_clear_drv_active(struct qla_hw_data *);
 static void qla2x00_free_device(scsi_qla_host_t *);
 static int qla2xxx_map_queues(struct Scsi_Host *shost);
 static void qla2x00_destroy_deferred_work(struct qla_hw_data *);
+static void qla83xx_disable_laser(scsi_qla_host_t *);
+static void qla27xx_disable_laser(scsi_qla_host_t *);
 
 struct scsi_host_template qla2xxx_driver_template = {
 	.module			= THIS_MODULE,
@@ -2156,6 +2158,7 @@  static struct isp_operations qla2100_isp_ops = {
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config     	= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla2300_isp_ops = {
@@ -2195,6 +2198,7 @@  static struct isp_operations qla2300_isp_ops = {
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla24xx_isp_ops = {
@@ -2234,6 +2238,7 @@  static struct isp_operations qla24xx_isp_ops = {
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla25xx_isp_ops = {
@@ -2273,6 +2278,7 @@  static struct isp_operations qla25xx_isp_ops = {
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla81xx_isp_ops = {
@@ -2312,6 +2318,7 @@  static struct isp_operations qla81xx_isp_ops = {
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla82xx_isp_ops = {
@@ -2351,6 +2358,7 @@  static struct isp_operations qla82xx_isp_ops = {
 	.abort_isp		= qla82xx_abort_isp,
 	.iospace_config     	= qla82xx_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla8044_isp_ops = {
@@ -2390,6 +2398,7 @@  static struct isp_operations qla8044_isp_ops = {
 	.abort_isp		= qla8044_abort_isp,
 	.iospace_config		= qla82xx_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla83xx_isp_ops = {
@@ -2429,6 +2438,7 @@  static struct isp_operations qla83xx_isp_ops = {
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config		= qla83xx_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= qla83xx_disable_laser,
 };
 
 static struct isp_operations qlafx00_isp_ops = {
@@ -2468,6 +2478,7 @@  static struct isp_operations qlafx00_isp_ops = {
 	.abort_isp		= qlafx00_abort_isp,
 	.iospace_config		= qlafx00_iospace_config,
 	.initialize_adapter	= qlafx00_initialize_adapter,
+	.disable_laser		= NULL,
 };
 
 static struct isp_operations qla27xx_isp_ops = {
@@ -2507,6 +2518,7 @@  static struct isp_operations qla27xx_isp_ops = {
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config		= qla83xx_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
+	.disable_laser		= qla27xx_disable_laser,
 };
 
 static inline void
@@ -3662,6 +3674,8 @@  qla2x00_remove_one(struct pci_dev *pdev)
 
 	qla84xx_put_chip(base_vha);
 
+	ha->isp_ops->disable_laser(base_vha);
+
 	/* Disable timer */
 	if (base_vha->timer_active)
 		qla2x00_stop_timer(base_vha);
@@ -6822,6 +6836,64 @@  qla2xxx_pci_resume(struct pci_dev *pdev)
 	ha->flags.eeh_busy = 0;
 }
 
+static void
+qla27xx_disable_laser(scsi_qla_host_t *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+	uint32_t gpio_data;
+	unsigned long flags;
+
+	ql_dbg(ql_dbg_init, vha, 0x0190,
+	    "Disabling Laser for hba: %p\n", vha);
+
+	qla24xx_drive_gpio(vha);
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Prepare GPIO enable  mask. */
+	gpio_data = RD_REG_DWORD(&reg->gpioe);
+	gpio_data |= GPDX_LASER_MASK | GPDX_LASER_DISABLE;
+
+	WRT_REG_DWORD(&reg->gpioe, gpio_data);
+	RD_REG_DWORD(&reg->gpioe);
+
+	/* Drive GPIO laser pin --  low.  */
+	gpio_data = RD_REG_DWORD(&reg->gpiod);
+	gpio_data |= GPDX_LASER_MASK | GPDX_LASER_DISABLE | LASER_OFF_27XX;
+	WRT_REG_DWORD(&reg->gpiod, gpio_data);
+	RD_REG_DWORD(&reg->gpiod);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	qla24xx_relinquish_gpio(vha);
+}
+
+static void
+qla83xx_disable_laser(scsi_qla_host_t *vha)
+{
+	uint32_t reg, data, fn;
+	struct qla_hw_data *ha = vha->hw;
+	struct device_reg_24xx __iomem *isp_reg = &ha->iobase->isp24;
+
+	/* pci func #/port # */
+	ql_dbg(ql_dbg_init, vha, 0x004b,
+	    "Disabling Laser for hba: %p\n", vha);
+
+	fn = (RD_REG_DWORD(&isp_reg->ctrl_status) &
+		(BIT_15|BIT_14|BIT_13|BIT_12));
+
+	fn = (fn >> 12);
+
+	if (fn & 1)
+		reg = PORT_1_2031;
+	else
+		reg = PORT_0_2031;
+
+	data = LASER_OFF_2031;
+
+	qla83xx_wr_reg(vha, reg, data);
+}
+
 static int qla2xxx_map_queues(struct Scsi_Host *shost)
 {
 	int rc;