@@ -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 *************************************************************/
@@ -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. */
@@ -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);
+}
@@ -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;