+uint8_t *
+qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+ uint32_t bytes)
+{
+ uint32_t i;
+ uint32_t *dwptr;
+
+ /* Dword reads to flash. */
+ dwptr = (uint32_t *)buf;
+ for (i = 0; i < bytes >> 2; i++, naddr++)
+ dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+ nvram_data_to_access_addr(naddr)));
+
+ return buf;
+}
+
+int
+qla2x00_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+ uint32_t bytes)
+{
+ int ret, stat;
+ uint32_t i;
+ uint16_t *wptr;
+
+ ret = QLA_SUCCESS;
+
+ qla2x00_lock_nvram_access(ha);
+
+ /* Disable NVRAM write-protection. */
+ stat = qla2x00_clear_nvram_protection(ha);
+
+ wptr = (uint16_t *)buf;
+ for (i = 0; i < bytes >> 1; i++, naddr++) {
+ qla2x00_write_nvram_word(ha, naddr,
+ cpu_to_le16(*wptr));
+ wptr++;
+ }
+
+ /* Enable NVRAM write-protection. */
+ qla2x00_set_nvram_protection(ha, stat);
+
+ qla2x00_unlock_nvram_access(ha);
+
+ return ret;
+}
+
+int
+qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+ uint32_t bytes)
+{
+ int ret;
+ uint32_t i;
+ uint32_t *dwptr;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ ret = QLA_SUCCESS;
+
+ /* Enable flash write. */
+ WRT_REG_DWORD(®->ctrl_status,
+ RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE);
+ RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
+
+ /* Disable NVRAM write-protection. */
+ qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
+ 0);
+ qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
+ 0);
+
+ /* Dword writes to flash. */
+ dwptr = (uint32_t *)buf;
+ for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) {
+ ret = qla24xx_write_flash_dword(ha,
+ nvram_data_to_access_addr(naddr),
+ cpu_to_le32(*dwptr));
+ if (ret != QLA_SUCCESS) {
+ DEBUG9(printk("%s(%ld) Unable to program "
+ "nvram address=%x data=%x.\n", __func__,
+ ha->host_no, naddr, *dwptr));
+ break;
+ }
+ }
+
+ /* Enable NVRAM write-protection. */
+ qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
+ 0x8c);
+
+ /* Disable flash write. */
+ WRT_REG_DWORD(®->ctrl_status,
+ RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
+ RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
+
+ 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;
+}
+
+