diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_sup.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index f4d755a643e..3105bb93cc1 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -695,3 +695,297 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, return ret; } + + +static inline void +qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags) +{ + if (IS_QLA2322(ha)) { + /* Flip all colors. */ + if (ha->beacon_color_state == QLA_LED_ALL_ON) { + /* Turn off. */ + ha->beacon_color_state = 0; + *pflags = GPIO_LED_ALL_OFF; + } else { + /* Turn on. */ + ha->beacon_color_state = QLA_LED_ALL_ON; + *pflags = GPIO_LED_RGA_ON; + } + } else { + /* Flip green led only. */ + if (ha->beacon_color_state == QLA_LED_GRN_ON) { + /* Turn off. */ + ha->beacon_color_state = 0; + *pflags = GPIO_LED_GREEN_OFF_AMBER_OFF; + } else { + /* Turn on. */ + ha->beacon_color_state = QLA_LED_GRN_ON; + *pflags = GPIO_LED_GREEN_ON_AMBER_OFF; + } + } +} + +void +qla2x00_beacon_blink(struct scsi_qla_host *ha) +{ + uint16_t gpio_enable; + uint16_t gpio_data; + uint16_t led_color = 0; + unsigned long flags; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + + if (ha->pio_address) + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Save the Original GPIOE. */ + if (ha->pio_address) { + gpio_enable = RD_REG_WORD_PIO(®->gpioe); + gpio_data = RD_REG_WORD_PIO(®->gpiod); + } else { + gpio_enable = RD_REG_WORD(®->gpioe); + gpio_data = RD_REG_WORD(®->gpiod); + } + + /* Set the modified gpio_enable values */ + gpio_enable |= GPIO_LED_MASK; + + if (ha->pio_address) { + WRT_REG_WORD_PIO(®->gpioe, gpio_enable); + } else { + WRT_REG_WORD(®->gpioe, gpio_enable); + RD_REG_WORD(®->gpioe); + } + + qla2x00_flip_colors(ha, &led_color); + + /* Clear out any previously set LED color. */ + gpio_data &= ~GPIO_LED_MASK; + + /* Set the new input LED color to GPIOD. */ + gpio_data |= led_color; + + /* Set the modified gpio_data values */ + if (ha->pio_address) { + WRT_REG_WORD_PIO(®->gpiod, gpio_data); + } else { + WRT_REG_WORD(®->gpiod, gpio_data); + RD_REG_WORD(®->gpiod); + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +int +qla2x00_beacon_on(struct scsi_qla_host *ha) +{ + uint16_t gpio_enable; + uint16_t gpio_data; + unsigned long flags; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + + ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; + ha->fw_options[1] |= FO1_DISABLE_GPIO6_7; + + if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to update fw options (beacon on).\n"); + return QLA_FUNCTION_FAILED; + } + + if (ha->pio_address) + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + + /* Turn off LEDs. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + if (ha->pio_address) { + gpio_enable = RD_REG_WORD_PIO(®->gpioe); + gpio_data = RD_REG_WORD_PIO(®->gpiod); + } else { + gpio_enable = RD_REG_WORD(®->gpioe); + gpio_data = RD_REG_WORD(®->gpiod); + } + gpio_enable |= GPIO_LED_MASK; + + /* Set the modified gpio_enable values. */ + if (ha->pio_address) { + WRT_REG_WORD_PIO(®->gpioe, gpio_enable); + } else { + WRT_REG_WORD(®->gpioe, gpio_enable); + RD_REG_WORD(®->gpioe); + } + + /* Clear out previously set LED colour. */ + gpio_data &= ~GPIO_LED_MASK; + if (ha->pio_address) { + WRT_REG_WORD_PIO(®->gpiod, gpio_data); + } else { + WRT_REG_WORD(®->gpiod, gpio_data); + RD_REG_WORD(®->gpiod); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* + * Let the per HBA timer kick off the blinking process based on + * the following flags. No need to do anything else now. + */ + ha->beacon_blink_led = 1; + ha->beacon_color_state = 0; + + return QLA_SUCCESS; +} + +int +qla2x00_beacon_off(struct scsi_qla_host *ha) +{ + int rval = QLA_SUCCESS; + + ha->beacon_blink_led = 0; + + /* Set the on flag so when it gets flipped it will be off. */ + if (IS_QLA2322(ha)) + ha->beacon_color_state = QLA_LED_ALL_ON; + else + ha->beacon_color_state = QLA_LED_GRN_ON; + + ha->isp_ops.beacon_blink(ha); /* This turns green LED off */ + + ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; + ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7; + + rval = qla2x00_set_fw_options(ha, ha->fw_options); + if (rval != QLA_SUCCESS) + qla_printk(KERN_WARNING, ha, + "Unable to update fw options (beacon off).\n"); + return rval; +} + + +static inline void +qla24xx_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags) +{ + /* Flip all colors. */ + if (ha->beacon_color_state == QLA_LED_ALL_ON) { + /* Turn off. */ + ha->beacon_color_state = 0; + *pflags = 0; + } else { + /* Turn on. */ + ha->beacon_color_state = QLA_LED_ALL_ON; + *pflags = GPDX_LED_YELLOW_ON | GPDX_LED_AMBER_ON; + } +} + +void +qla24xx_beacon_blink(struct scsi_qla_host *ha) +{ + uint16_t led_color = 0; + uint32_t gpio_data; + unsigned long flags; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + /* Save the Original GPIOD. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + gpio_data = RD_REG_DWORD(®->gpiod); + + /* Enable the gpio_data reg for update. */ + gpio_data |= GPDX_LED_UPDATE_MASK; + + WRT_REG_DWORD(®->gpiod, gpio_data); + gpio_data = RD_REG_DWORD(®->gpiod); + + /* Set the color bits. */ + qla24xx_flip_colors(ha, &led_color); + + /* Clear out any previously set LED color. */ + gpio_data &= ~GPDX_LED_COLOR_MASK; + + /* Set the new input LED color to GPIOD. */ + gpio_data |= led_color; + + /* Set the modified gpio_data values. */ + WRT_REG_DWORD(®->gpiod, gpio_data); + gpio_data = RD_REG_DWORD(®->gpiod); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +int +qla24xx_beacon_on(struct scsi_qla_host *ha) +{ + uint32_t gpio_data; + unsigned long flags; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + if (ha->beacon_blink_led == 0) { + /* Enable firmware for update */ + ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL; + + if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) + return QLA_FUNCTION_FAILED; + + if (qla2x00_get_fw_options(ha, ha->fw_options) != + QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to update fw options (beacon on).\n"); + return QLA_FUNCTION_FAILED; + } + + spin_lock_irqsave(&ha->hardware_lock, flags); + gpio_data = RD_REG_DWORD(®->gpiod); + + /* Enable the gpio_data reg for update. */ + gpio_data |= GPDX_LED_UPDATE_MASK; + WRT_REG_DWORD(®->gpiod, gpio_data); + RD_REG_DWORD(®->gpiod); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + + /* So all colors blink together. */ + ha->beacon_color_state = 0; + + /* Let the per HBA timer kick off the blinking process. */ + ha->beacon_blink_led = 1; + + return QLA_SUCCESS; +} + +int +qla24xx_beacon_off(struct scsi_qla_host *ha) +{ + uint32_t gpio_data; + unsigned long flags; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + ha->beacon_blink_led = 0; + ha->beacon_color_state = QLA_LED_ALL_ON; + + ha->isp_ops.beacon_blink(ha); /* Will flip to all off. */ + + /* Give control back to firmware. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + gpio_data = RD_REG_DWORD(®->gpiod); + + /* Disable the gpio_data reg for update. */ + gpio_data &= ~GPDX_LED_UPDATE_MASK; + WRT_REG_DWORD(®->gpiod, gpio_data); + RD_REG_DWORD(®->gpiod); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL; + + if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to update fw options (beacon off).\n"); + return QLA_FUNCTION_FAILED; + } + + if (qla2x00_get_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to get fw options (beacon off).\n"); + return QLA_FUNCTION_FAILED; + } + + return QLA_SUCCESS; +} |