diff options
author | andrew.vasquez@qlogic.com <andrew.vasquez@qlogic.com> | 2006-01-31 19:05:07 -0500 |
---|---|---|
committer | <jejb@mulgrave.il.steeleye.com> | 2006-02-04 17:11:57 -0500 |
commit | f6df144cca19cc60dda6dcce65d236b70cc46494 (patch) | |
tree | 2cd4ae47df5808e46e0387c44ff436879b0e0111 | |
parent | 392e2f651c8a83484116a407a9f121e534c22b5a (diff) |
[SCSI] qla2xxx: Add beacon support via class-device attribute.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 50 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 21 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 9 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 16 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 294 |
5 files changed, 387 insertions, 3 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 5a8d5c4c69ba..049e5cf1af7f 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -196,6 +196,9 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) | |||
196 | 196 | ||
197 | sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); | 197 | sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); |
198 | sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); | 198 | sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); |
199 | |||
200 | if (ha->beacon_blink_led == 1) | ||
201 | ha->isp_ops.beacon_off(ha); | ||
199 | } | 202 | } |
200 | 203 | ||
201 | /* Scsi_Host attributes. */ | 204 | /* Scsi_Host attributes. */ |
@@ -383,6 +386,50 @@ qla2x00_zio_timer_store(struct class_device *cdev, const char *buf, | |||
383 | return strlen(buf); | 386 | return strlen(buf); |
384 | } | 387 | } |
385 | 388 | ||
389 | static ssize_t | ||
390 | qla2x00_beacon_show(struct class_device *cdev, char *buf) | ||
391 | { | ||
392 | scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); | ||
393 | int len = 0; | ||
394 | |||
395 | if (ha->beacon_blink_led) | ||
396 | len += snprintf(buf + len, PAGE_SIZE-len, "Enabled\n"); | ||
397 | else | ||
398 | len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n"); | ||
399 | return len; | ||
400 | } | ||
401 | |||
402 | static ssize_t | ||
403 | qla2x00_beacon_store(struct class_device *cdev, const char *buf, | ||
404 | size_t count) | ||
405 | { | ||
406 | scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); | ||
407 | int val = 0; | ||
408 | int rval; | ||
409 | |||
410 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) | ||
411 | return -EPERM; | ||
412 | |||
413 | if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) { | ||
414 | qla_printk(KERN_WARNING, ha, | ||
415 | "Abort ISP active -- ignoring beacon request.\n"); | ||
416 | return -EBUSY; | ||
417 | } | ||
418 | |||
419 | if (sscanf(buf, "%d", &val) != 1) | ||
420 | return -EINVAL; | ||
421 | |||
422 | if (val) | ||
423 | rval = ha->isp_ops.beacon_on(ha); | ||
424 | else | ||
425 | rval = ha->isp_ops.beacon_off(ha); | ||
426 | |||
427 | if (rval != QLA_SUCCESS) | ||
428 | count = 0; | ||
429 | |||
430 | return count; | ||
431 | } | ||
432 | |||
386 | static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, | 433 | static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, |
387 | NULL); | 434 | NULL); |
388 | static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); | 435 | static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); |
@@ -397,6 +444,8 @@ static CLASS_DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show, | |||
397 | qla2x00_zio_store); | 444 | qla2x00_zio_store); |
398 | static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show, | 445 | static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show, |
399 | qla2x00_zio_timer_store); | 446 | qla2x00_zio_timer_store); |
447 | static CLASS_DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show, | ||
448 | qla2x00_beacon_store); | ||
400 | 449 | ||
401 | struct class_device_attribute *qla2x00_host_attrs[] = { | 450 | struct class_device_attribute *qla2x00_host_attrs[] = { |
402 | &class_device_attr_driver_version, | 451 | &class_device_attr_driver_version, |
@@ -410,6 +459,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = { | |||
410 | &class_device_attr_state, | 459 | &class_device_attr_state, |
411 | &class_device_attr_zio, | 460 | &class_device_attr_zio, |
412 | &class_device_attr_zio_timer, | 461 | &class_device_attr_zio_timer, |
462 | &class_device_attr_beacon, | ||
413 | NULL, | 463 | NULL, |
414 | }; | 464 | }; |
415 | 465 | ||
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 414580800dc0..7cb8b5a5e659 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -182,6 +182,13 @@ | |||
182 | #define WRT_REG_DWORD(addr, data) writel(data,addr) | 182 | #define WRT_REG_DWORD(addr, data) writel(data,addr) |
183 | 183 | ||
184 | /* | 184 | /* |
185 | * The ISP2312 v2 chip cannot access the FLASH/GPIO registers via MMIO in an | ||
186 | * 133Mhz slot. | ||
187 | */ | ||
188 | #define RD_REG_WORD_PIO(addr) (inw((unsigned long)addr)) | ||
189 | #define WRT_REG_WORD_PIO(addr, data) (outw(data,(unsigned long)addr)) | ||
190 | |||
191 | /* | ||
185 | * Fibre Channel device definitions. | 192 | * Fibre Channel device definitions. |
186 | */ | 193 | */ |
187 | #define WWN_SIZE 8 /* Size of WWPN, WWN & WWNN */ | 194 | #define WWN_SIZE 8 /* Size of WWPN, WWN & WWNN */ |
@@ -433,6 +440,9 @@ struct device_reg_2xxx { | |||
433 | #define GPIO_LED_GREEN_ON_AMBER_OFF 0x0040 | 440 | #define GPIO_LED_GREEN_ON_AMBER_OFF 0x0040 |
434 | #define GPIO_LED_GREEN_OFF_AMBER_ON 0x0080 | 441 | #define GPIO_LED_GREEN_OFF_AMBER_ON 0x0080 |
435 | #define GPIO_LED_GREEN_ON_AMBER_ON 0x00C0 | 442 | #define GPIO_LED_GREEN_ON_AMBER_ON 0x00C0 |
443 | #define GPIO_LED_ALL_OFF 0x0000 | ||
444 | #define GPIO_LED_RED_ON_OTHER_OFF 0x0001 /* isp2322 */ | ||
445 | #define GPIO_LED_RGA_ON 0x00C1 /* isp2322: red green amber */ | ||
436 | 446 | ||
437 | union { | 447 | union { |
438 | struct { | 448 | struct { |
@@ -2200,6 +2210,10 @@ struct isp_operations { | |||
2200 | 2210 | ||
2201 | void (*fw_dump) (struct scsi_qla_host *, int); | 2211 | void (*fw_dump) (struct scsi_qla_host *, int); |
2202 | void (*ascii_fw_dump) (struct scsi_qla_host *); | 2212 | void (*ascii_fw_dump) (struct scsi_qla_host *); |
2213 | |||
2214 | int (*beacon_on) (struct scsi_qla_host *); | ||
2215 | int (*beacon_off) (struct scsi_qla_host *); | ||
2216 | void (*beacon_blink) (struct scsi_qla_host *); | ||
2203 | }; | 2217 | }; |
2204 | 2218 | ||
2205 | /* | 2219 | /* |
@@ -2493,7 +2507,12 @@ typedef struct scsi_qla_host { | |||
2493 | 2507 | ||
2494 | /* Needed for BEACON */ | 2508 | /* Needed for BEACON */ |
2495 | uint16_t beacon_blink_led; | 2509 | uint16_t beacon_blink_led; |
2496 | uint16_t beacon_green_on; | 2510 | uint8_t beacon_color_state; |
2511 | #define QLA_LED_GRN_ON 0x01 | ||
2512 | #define QLA_LED_YLW_ON 0x02 | ||
2513 | #define QLA_LED_ABR_ON 0x04 | ||
2514 | #define QLA_LED_ALL_ON 0x07 /* yellow, green, amber. */ | ||
2515 | /* ISP2322: red, green, amber. */ | ||
2497 | 2516 | ||
2498 | uint16_t zio_mode; | 2517 | uint16_t zio_mode; |
2499 | uint16_t zio_timer; | 2518 | uint16_t zio_timer; |
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index f2f5454a05e9..eb35198bc8cf 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -75,8 +75,6 @@ extern void qla2x00_cmd_timeout(srb_t *); | |||
75 | extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int); | 75 | extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int); |
76 | extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int); | 76 | extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int); |
77 | 77 | ||
78 | extern void qla2x00_blink_led(scsi_qla_host_t *); | ||
79 | |||
80 | extern int qla2x00_down_timeout(struct semaphore *, unsigned long); | 78 | extern int qla2x00_down_timeout(struct semaphore *, unsigned long); |
81 | 79 | ||
82 | extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); | 80 | extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); |
@@ -235,6 +233,13 @@ extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, | |||
235 | extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, | 233 | extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, |
236 | uint32_t); | 234 | uint32_t); |
237 | 235 | ||
236 | extern int qla2x00_beacon_on(struct scsi_qla_host *); | ||
237 | extern int qla2x00_beacon_off(struct scsi_qla_host *); | ||
238 | extern void qla2x00_beacon_blink(struct scsi_qla_host *); | ||
239 | extern int qla24xx_beacon_on(struct scsi_qla_host *); | ||
240 | extern int qla24xx_beacon_off(struct scsi_qla_host *); | ||
241 | extern void qla24xx_beacon_blink(struct scsi_qla_host *); | ||
242 | |||
238 | /* | 243 | /* |
239 | * Global Function Prototypes in qla_dbg.c source file. | 244 | * Global Function Prototypes in qla_dbg.c source file. |
240 | */ | 245 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 6e133edb2016..57179dabcccf 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -1365,6 +1365,9 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) | |||
1365 | ha->isp_ops.intr_handler = qla2300_intr_handler; | 1365 | ha->isp_ops.intr_handler = qla2300_intr_handler; |
1366 | ha->isp_ops.fw_dump = qla2300_fw_dump; | 1366 | ha->isp_ops.fw_dump = qla2300_fw_dump; |
1367 | ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump; | 1367 | ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump; |
1368 | ha->isp_ops.beacon_on = qla2x00_beacon_on; | ||
1369 | ha->isp_ops.beacon_off = qla2x00_beacon_off; | ||
1370 | ha->isp_ops.beacon_blink = qla2x00_beacon_blink; | ||
1368 | ha->gid_list_info_size = 6; | 1371 | ha->gid_list_info_size = 6; |
1369 | } else if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) { | 1372 | } else if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) { |
1370 | host->max_id = MAX_TARGETS_2200; | 1373 | host->max_id = MAX_TARGETS_2200; |
@@ -1401,6 +1404,9 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) | |||
1401 | ha->isp_ops.write_nvram = qla24xx_write_nvram_data; | 1404 | ha->isp_ops.write_nvram = qla24xx_write_nvram_data; |
1402 | ha->isp_ops.fw_dump = qla24xx_fw_dump; | 1405 | ha->isp_ops.fw_dump = qla24xx_fw_dump; |
1403 | ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump; | 1406 | ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump; |
1407 | ha->isp_ops.beacon_on = qla24xx_beacon_on; | ||
1408 | ha->isp_ops.beacon_off = qla24xx_beacon_off; | ||
1409 | ha->isp_ops.beacon_blink = qla24xx_beacon_blink; | ||
1404 | ha->gid_list_info_size = 8; | 1410 | ha->gid_list_info_size = 8; |
1405 | } | 1411 | } |
1406 | host->can_queue = ha->request_q_length + 128; | 1412 | host->can_queue = ha->request_q_length + 128; |
@@ -2315,6 +2321,9 @@ qla2x00_do_dpc(void *data) | |||
2315 | if (!ha->interrupts_on) | 2321 | if (!ha->interrupts_on) |
2316 | ha->isp_ops.enable_intrs(ha); | 2322 | ha->isp_ops.enable_intrs(ha); |
2317 | 2323 | ||
2324 | if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags)) | ||
2325 | ha->isp_ops.beacon_blink(ha); | ||
2326 | |||
2318 | ha->dpc_active = 0; | 2327 | ha->dpc_active = 0; |
2319 | } /* End of while(1) */ | 2328 | } /* End of while(1) */ |
2320 | 2329 | ||
@@ -2492,6 +2501,12 @@ qla2x00_timer(scsi_qla_host_t *ha) | |||
2492 | atomic_read(&ha->loop_down_timer))); | 2501 | atomic_read(&ha->loop_down_timer))); |
2493 | } | 2502 | } |
2494 | 2503 | ||
2504 | /* Check if beacon LED needs to be blinked */ | ||
2505 | if (ha->beacon_blink_led == 1) { | ||
2506 | set_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags); | ||
2507 | start_dpc++; | ||
2508 | } | ||
2509 | |||
2495 | /* Schedule the DPC routine if needed */ | 2510 | /* Schedule the DPC routine if needed */ |
2496 | if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || | 2511 | if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || |
2497 | test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || | 2512 | test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || |
@@ -2500,6 +2515,7 @@ qla2x00_timer(scsi_qla_host_t *ha) | |||
2500 | start_dpc || | 2515 | start_dpc || |
2501 | test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || | 2516 | test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || |
2502 | test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || | 2517 | test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || |
2518 | test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) || | ||
2503 | test_bit(RELOGIN_NEEDED, &ha->dpc_flags)) && | 2519 | test_bit(RELOGIN_NEEDED, &ha->dpc_flags)) && |
2504 | ha->dpc_wait && !ha->dpc_active) { | 2520 | ha->dpc_wait && !ha->dpc_active) { |
2505 | 2521 | ||
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index f4d755a643e4..3105bb93cc19 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, | |||
695 | 695 | ||
696 | return ret; | 696 | return ret; |
697 | } | 697 | } |
698 | |||
699 | |||
700 | static inline void | ||
701 | qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags) | ||
702 | { | ||
703 | if (IS_QLA2322(ha)) { | ||
704 | /* Flip all colors. */ | ||
705 | if (ha->beacon_color_state == QLA_LED_ALL_ON) { | ||
706 | /* Turn off. */ | ||
707 | ha->beacon_color_state = 0; | ||
708 | *pflags = GPIO_LED_ALL_OFF; | ||
709 | } else { | ||
710 | /* Turn on. */ | ||
711 | ha->beacon_color_state = QLA_LED_ALL_ON; | ||
712 | *pflags = GPIO_LED_RGA_ON; | ||
713 | } | ||
714 | } else { | ||
715 | /* Flip green led only. */ | ||
716 | if (ha->beacon_color_state == QLA_LED_GRN_ON) { | ||
717 | /* Turn off. */ | ||
718 | ha->beacon_color_state = 0; | ||
719 | *pflags = GPIO_LED_GREEN_OFF_AMBER_OFF; | ||
720 | } else { | ||
721 | /* Turn on. */ | ||
722 | ha->beacon_color_state = QLA_LED_GRN_ON; | ||
723 | *pflags = GPIO_LED_GREEN_ON_AMBER_OFF; | ||
724 | } | ||
725 | } | ||
726 | } | ||
727 | |||
728 | void | ||
729 | qla2x00_beacon_blink(struct scsi_qla_host *ha) | ||
730 | { | ||
731 | uint16_t gpio_enable; | ||
732 | uint16_t gpio_data; | ||
733 | uint16_t led_color = 0; | ||
734 | unsigned long flags; | ||
735 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | ||
736 | |||
737 | if (ha->pio_address) | ||
738 | reg = (struct device_reg_2xxx __iomem *)ha->pio_address; | ||
739 | |||
740 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
741 | |||
742 | /* Save the Original GPIOE. */ | ||
743 | if (ha->pio_address) { | ||
744 | gpio_enable = RD_REG_WORD_PIO(®->gpioe); | ||
745 | gpio_data = RD_REG_WORD_PIO(®->gpiod); | ||
746 | } else { | ||
747 | gpio_enable = RD_REG_WORD(®->gpioe); | ||
748 | gpio_data = RD_REG_WORD(®->gpiod); | ||
749 | } | ||
750 | |||
751 | /* Set the modified gpio_enable values */ | ||
752 | gpio_enable |= GPIO_LED_MASK; | ||
753 | |||
754 | if (ha->pio_address) { | ||
755 | WRT_REG_WORD_PIO(®->gpioe, gpio_enable); | ||
756 | } else { | ||
757 | WRT_REG_WORD(®->gpioe, gpio_enable); | ||
758 | RD_REG_WORD(®->gpioe); | ||
759 | } | ||
760 | |||
761 | qla2x00_flip_colors(ha, &led_color); | ||
762 | |||
763 | /* Clear out any previously set LED color. */ | ||
764 | gpio_data &= ~GPIO_LED_MASK; | ||
765 | |||
766 | /* Set the new input LED color to GPIOD. */ | ||
767 | gpio_data |= led_color; | ||
768 | |||
769 | /* Set the modified gpio_data values */ | ||
770 | if (ha->pio_address) { | ||
771 | WRT_REG_WORD_PIO(®->gpiod, gpio_data); | ||
772 | } else { | ||
773 | WRT_REG_WORD(®->gpiod, gpio_data); | ||
774 | RD_REG_WORD(®->gpiod); | ||
775 | } | ||
776 | |||
777 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
778 | } | ||
779 | |||
780 | int | ||
781 | qla2x00_beacon_on(struct scsi_qla_host *ha) | ||
782 | { | ||
783 | uint16_t gpio_enable; | ||
784 | uint16_t gpio_data; | ||
785 | unsigned long flags; | ||
786 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | ||
787 | |||
788 | ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; | ||
789 | ha->fw_options[1] |= FO1_DISABLE_GPIO6_7; | ||
790 | |||
791 | if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { | ||
792 | qla_printk(KERN_WARNING, ha, | ||
793 | "Unable to update fw options (beacon on).\n"); | ||
794 | return QLA_FUNCTION_FAILED; | ||
795 | } | ||
796 | |||
797 | if (ha->pio_address) | ||
798 | reg = (struct device_reg_2xxx __iomem *)ha->pio_address; | ||
799 | |||
800 | /* Turn off LEDs. */ | ||
801 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
802 | if (ha->pio_address) { | ||
803 | gpio_enable = RD_REG_WORD_PIO(®->gpioe); | ||
804 | gpio_data = RD_REG_WORD_PIO(®->gpiod); | ||
805 | } else { | ||
806 | gpio_enable = RD_REG_WORD(®->gpioe); | ||
807 | gpio_data = RD_REG_WORD(®->gpiod); | ||
808 | } | ||
809 | gpio_enable |= GPIO_LED_MASK; | ||
810 | |||
811 | /* Set the modified gpio_enable values. */ | ||
812 | if (ha->pio_address) { | ||
813 | WRT_REG_WORD_PIO(®->gpioe, gpio_enable); | ||
814 | } else { | ||
815 | WRT_REG_WORD(®->gpioe, gpio_enable); | ||
816 | RD_REG_WORD(®->gpioe); | ||
817 | } | ||
818 | |||
819 | /* Clear out previously set LED colour. */ | ||
820 | gpio_data &= ~GPIO_LED_MASK; | ||
821 | if (ha->pio_address) { | ||
822 | WRT_REG_WORD_PIO(®->gpiod, gpio_data); | ||
823 | } else { | ||
824 | WRT_REG_WORD(®->gpiod, gpio_data); | ||
825 | RD_REG_WORD(®->gpiod); | ||
826 | } | ||
827 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
828 | |||
829 | /* | ||
830 | * Let the per HBA timer kick off the blinking process based on | ||
831 | * the following flags. No need to do anything else now. | ||
832 | */ | ||
833 | ha->beacon_blink_led = 1; | ||
834 | ha->beacon_color_state = 0; | ||
835 | |||
836 | return QLA_SUCCESS; | ||
837 | } | ||
838 | |||
839 | int | ||
840 | qla2x00_beacon_off(struct scsi_qla_host *ha) | ||
841 | { | ||
842 | int rval = QLA_SUCCESS; | ||
843 | |||
844 | ha->beacon_blink_led = 0; | ||
845 | |||
846 | /* Set the on flag so when it gets flipped it will be off. */ | ||
847 | if (IS_QLA2322(ha)) | ||
848 | ha->beacon_color_state = QLA_LED_ALL_ON; | ||
849 | else | ||
850 | ha->beacon_color_state = QLA_LED_GRN_ON; | ||
851 | |||
852 | ha->isp_ops.beacon_blink(ha); /* This turns green LED off */ | ||
853 | |||
854 | ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; | ||
855 | ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7; | ||
856 | |||
857 | rval = qla2x00_set_fw_options(ha, ha->fw_options); | ||
858 | if (rval != QLA_SUCCESS) | ||
859 | qla_printk(KERN_WARNING, ha, | ||
860 | "Unable to update fw options (beacon off).\n"); | ||
861 | return rval; | ||
862 | } | ||
863 | |||
864 | |||
865 | static inline void | ||
866 | qla24xx_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags) | ||
867 | { | ||
868 | /* Flip all colors. */ | ||
869 | if (ha->beacon_color_state == QLA_LED_ALL_ON) { | ||
870 | /* Turn off. */ | ||
871 | ha->beacon_color_state = 0; | ||
872 | *pflags = 0; | ||
873 | } else { | ||
874 | /* Turn on. */ | ||
875 | ha->beacon_color_state = QLA_LED_ALL_ON; | ||
876 | *pflags = GPDX_LED_YELLOW_ON | GPDX_LED_AMBER_ON; | ||
877 | } | ||
878 | } | ||
879 | |||
880 | void | ||
881 | qla24xx_beacon_blink(struct scsi_qla_host *ha) | ||
882 | { | ||
883 | uint16_t led_color = 0; | ||
884 | uint32_t gpio_data; | ||
885 | unsigned long flags; | ||
886 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
887 | |||
888 | /* Save the Original GPIOD. */ | ||
889 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
890 | gpio_data = RD_REG_DWORD(®->gpiod); | ||
891 | |||
892 | /* Enable the gpio_data reg for update. */ | ||
893 | gpio_data |= GPDX_LED_UPDATE_MASK; | ||
894 | |||
895 | WRT_REG_DWORD(®->gpiod, gpio_data); | ||
896 | gpio_data = RD_REG_DWORD(®->gpiod); | ||
897 | |||
898 | /* Set the color bits. */ | ||
899 | qla24xx_flip_colors(ha, &led_color); | ||
900 | |||
901 | /* Clear out any previously set LED color. */ | ||
902 | gpio_data &= ~GPDX_LED_COLOR_MASK; | ||
903 | |||
904 | /* Set the new input LED color to GPIOD. */ | ||
905 | gpio_data |= led_color; | ||
906 | |||
907 | /* Set the modified gpio_data values. */ | ||
908 | WRT_REG_DWORD(®->gpiod, gpio_data); | ||
909 | gpio_data = RD_REG_DWORD(®->gpiod); | ||
910 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
911 | } | ||
912 | |||
913 | int | ||
914 | qla24xx_beacon_on(struct scsi_qla_host *ha) | ||
915 | { | ||
916 | uint32_t gpio_data; | ||
917 | unsigned long flags; | ||
918 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
919 | |||
920 | if (ha->beacon_blink_led == 0) { | ||
921 | /* Enable firmware for update */ | ||
922 | ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL; | ||
923 | |||
924 | if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) | ||
925 | return QLA_FUNCTION_FAILED; | ||
926 | |||
927 | if (qla2x00_get_fw_options(ha, ha->fw_options) != | ||
928 | QLA_SUCCESS) { | ||
929 | qla_printk(KERN_WARNING, ha, | ||
930 | "Unable to update fw options (beacon on).\n"); | ||
931 | return QLA_FUNCTION_FAILED; | ||
932 | } | ||
933 | |||
934 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
935 | gpio_data = RD_REG_DWORD(®->gpiod); | ||
936 | |||
937 | /* Enable the gpio_data reg for update. */ | ||
938 | gpio_data |= GPDX_LED_UPDATE_MASK; | ||
939 | WRT_REG_DWORD(®->gpiod, gpio_data); | ||
940 | RD_REG_DWORD(®->gpiod); | ||
941 | |||
942 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
943 | } | ||
944 | |||
945 | /* So all colors blink together. */ | ||
946 | ha->beacon_color_state = 0; | ||
947 | |||
948 | /* Let the per HBA timer kick off the blinking process. */ | ||
949 | ha->beacon_blink_led = 1; | ||
950 | |||
951 | return QLA_SUCCESS; | ||
952 | } | ||
953 | |||
954 | int | ||
955 | qla24xx_beacon_off(struct scsi_qla_host *ha) | ||
956 | { | ||
957 | uint32_t gpio_data; | ||
958 | unsigned long flags; | ||
959 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
960 | |||
961 | ha->beacon_blink_led = 0; | ||
962 | ha->beacon_color_state = QLA_LED_ALL_ON; | ||
963 | |||
964 | ha->isp_ops.beacon_blink(ha); /* Will flip to all off. */ | ||
965 | |||
966 | /* Give control back to firmware. */ | ||
967 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
968 | gpio_data = RD_REG_DWORD(®->gpiod); | ||
969 | |||
970 | /* Disable the gpio_data reg for update. */ | ||
971 | gpio_data &= ~GPDX_LED_UPDATE_MASK; | ||
972 | WRT_REG_DWORD(®->gpiod, gpio_data); | ||
973 | RD_REG_DWORD(®->gpiod); | ||
974 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
975 | |||
976 | ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL; | ||
977 | |||
978 | if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { | ||
979 | qla_printk(KERN_WARNING, ha, | ||
980 | "Unable to update fw options (beacon off).\n"); | ||
981 | return QLA_FUNCTION_FAILED; | ||
982 | } | ||
983 | |||
984 | if (qla2x00_get_fw_options(ha, ha->fw_options) != QLA_SUCCESS) { | ||
985 | qla_printk(KERN_WARNING, ha, | ||
986 | "Unable to get fw options (beacon off).\n"); | ||
987 | return QLA_FUNCTION_FAILED; | ||
988 | } | ||
989 | |||
990 | return QLA_SUCCESS; | ||
991 | } | ||