From: Himanshu Madhani <himanshu.madh...@qlogic.com>

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

Signed-off-by: Himanshu Madhani <himanshu.madh...@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 --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;
-- 
2.12.0

Reply via email to