From: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx> This patch disables laser while unloading driver for 16/32G adapters. Signed-off-by: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx> --- 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(®->gpioe); + gpio_data |= GPDX_LASER_MASK | GPDX_LASER_DISABLE; + + WRT_REG_DWORD(®->gpioe, gpio_data); + RD_REG_DWORD(®->gpioe); + + /* Drive GPIO laser pin -- low. */ + gpio_data = RD_REG_DWORD(®->gpiod); + gpio_data |= GPDX_LASER_MASK | GPDX_LASER_DISABLE | LASER_OFF_27XX; + WRT_REG_DWORD(®->gpiod, gpio_data); + RD_REG_DWORD(®->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