Commit f6df144c authored by andrew.vasquez@qlogic.com's avatar andrew.vasquez@qlogic.com Committed by

[SCSI] qla2xxx: Add beacon support via class-device attribute.

Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 392e2f65
......@@ -196,6 +196,9 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
if (ha->beacon_blink_led == 1)
ha->isp_ops.beacon_off(ha);
}
/* Scsi_Host attributes. */
......@@ -383,6 +386,50 @@ qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
return strlen(buf);
}
static ssize_t
qla2x00_beacon_show(struct class_device *cdev, char *buf)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
int len = 0;
if (ha->beacon_blink_led)
len += snprintf(buf + len, PAGE_SIZE-len, "Enabled\n");
else
len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
return len;
}
static ssize_t
qla2x00_beacon_store(struct class_device *cdev, const char *buf,
size_t count)
{
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
int val = 0;
int rval;
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return -EPERM;
if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) {
qla_printk(KERN_WARNING, ha,
"Abort ISP active -- ignoring beacon request.\n");
return -EBUSY;
}
if (sscanf(buf, "%d", &val) != 1)
return -EINVAL;
if (val)
rval = ha->isp_ops.beacon_on(ha);
else
rval = ha->isp_ops.beacon_off(ha);
if (rval != QLA_SUCCESS)
count = 0;
return count;
}
static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
NULL);
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,
qla2x00_zio_store);
static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
qla2x00_zio_timer_store);
static CLASS_DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show,
qla2x00_beacon_store);
struct class_device_attribute *qla2x00_host_attrs[] = {
&class_device_attr_driver_version,
......@@ -410,6 +459,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
&class_device_attr_state,
&class_device_attr_zio,
&class_device_attr_zio_timer,
&class_device_attr_beacon,
NULL,
};
......
......@@ -181,6 +181,13 @@
#define WRT_REG_WORD(addr, data) writew(data,addr)
#define WRT_REG_DWORD(addr, data) writel(data,addr)
/*
* The ISP2312 v2 chip cannot access the FLASH/GPIO registers via MMIO in an
* 133Mhz slot.
*/
#define RD_REG_WORD_PIO(addr) (inw((unsigned long)addr))
#define WRT_REG_WORD_PIO(addr, data) (outw(data,(unsigned long)addr))
/*
* Fibre Channel device definitions.
*/
......@@ -433,6 +440,9 @@ struct device_reg_2xxx {
#define GPIO_LED_GREEN_ON_AMBER_OFF 0x0040
#define GPIO_LED_GREEN_OFF_AMBER_ON 0x0080
#define GPIO_LED_GREEN_ON_AMBER_ON 0x00C0
#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 */
union {
struct {
......@@ -2200,6 +2210,10 @@ struct isp_operations {
void (*fw_dump) (struct scsi_qla_host *, int);
void (*ascii_fw_dump) (struct scsi_qla_host *);
int (*beacon_on) (struct scsi_qla_host *);
int (*beacon_off) (struct scsi_qla_host *);
void (*beacon_blink) (struct scsi_qla_host *);
};
/*
......@@ -2493,7 +2507,12 @@ typedef struct scsi_qla_host {
/* Needed for BEACON */
uint16_t beacon_blink_led;
uint16_t beacon_green_on;
uint8_t beacon_color_state;
#define QLA_LED_GRN_ON 0x01
#define QLA_LED_YLW_ON 0x02
#define QLA_LED_ABR_ON 0x04
#define QLA_LED_ALL_ON 0x07 /* yellow, green, amber. */
/* ISP2322: red, green, amber. */
uint16_t zio_mode;
uint16_t zio_timer;
......
......@@ -75,8 +75,6 @@ extern void qla2x00_cmd_timeout(srb_t *);
extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
extern void qla2x00_blink_led(scsi_qla_host_t *);
extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
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,
extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern int qla2x00_beacon_on(struct scsi_qla_host *);
extern int qla2x00_beacon_off(struct scsi_qla_host *);
extern void qla2x00_beacon_blink(struct scsi_qla_host *);
extern int qla24xx_beacon_on(struct scsi_qla_host *);
extern int qla24xx_beacon_off(struct scsi_qla_host *);
extern void qla24xx_beacon_blink(struct scsi_qla_host *);
/*
* Global Function Prototypes in qla_dbg.c source file.
*/
......
......@@ -1365,6 +1365,9 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
ha->isp_ops.intr_handler = qla2300_intr_handler;
ha->isp_ops.fw_dump = qla2300_fw_dump;
ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump;
ha->isp_ops.beacon_on = qla2x00_beacon_on;
ha->isp_ops.beacon_off = qla2x00_beacon_off;
ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
ha->gid_list_info_size = 6;
} else if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
host->max_id = MAX_TARGETS_2200;
......@@ -1401,6 +1404,9 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
ha->isp_ops.fw_dump = qla24xx_fw_dump;
ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump;
ha->isp_ops.beacon_on = qla24xx_beacon_on;
ha->isp_ops.beacon_off = qla24xx_beacon_off;
ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
ha->gid_list_info_size = 8;
}
host->can_queue = ha->request_q_length + 128;
......@@ -2315,6 +2321,9 @@ qla2x00_do_dpc(void *data)
if (!ha->interrupts_on)
ha->isp_ops.enable_intrs(ha);
if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
ha->isp_ops.beacon_blink(ha);
ha->dpc_active = 0;
} /* End of while(1) */
......@@ -2492,6 +2501,12 @@ qla2x00_timer(scsi_qla_host_t *ha)
atomic_read(&ha->loop_down_timer)));
}
/* Check if beacon LED needs to be blinked */
if (ha->beacon_blink_led == 1) {
set_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags);
start_dpc++;
}
/* Schedule the DPC routine if needed */
if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
......@@ -2500,6 +2515,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
start_dpc ||
test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
test_bit(RELOGIN_NEEDED, &ha->dpc_flags)) &&
ha->dpc_wait && !ha->dpc_active) {
......
......@@ -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(&reg->gpioe);
gpio_data = RD_REG_WORD_PIO(&reg->gpiod);
} else {
gpio_enable = RD_REG_WORD(&reg->gpioe);
gpio_data = RD_REG_WORD(&reg->gpiod);
}
/* Set the modified gpio_enable values */
gpio_enable |= GPIO_LED_MASK;
if (ha->pio_address) {
WRT_REG_WORD_PIO(&reg->gpioe, gpio_enable);
} else {
WRT_REG_WORD(&reg->gpioe, gpio_enable);
RD_REG_WORD(&reg->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(&reg->gpiod, gpio_data);
} else {
WRT_REG_WORD(&reg->gpiod, gpio_data);
RD_REG_WORD(&reg->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(&reg->gpioe);
gpio_data = RD_REG_WORD_PIO(&reg->gpiod);
} else {
gpio_enable = RD_REG_WORD(&reg->gpioe);
gpio_data = RD_REG_WORD(&reg->gpiod);
}
gpio_enable |= GPIO_LED_MASK;
/* Set the modified gpio_enable values. */
if (ha->pio_address) {
WRT_REG_WORD_PIO(&reg->gpioe, gpio_enable);
} else {
WRT_REG_WORD(&reg->gpioe, gpio_enable);
RD_REG_WORD(&reg->gpioe);
}
/* Clear out previously set LED colour. */
gpio_data &= ~GPIO_LED_MASK;
if (ha->pio_address) {
WRT_REG_WORD_PIO(&reg->gpiod, gpio_data);
} else {
WRT_REG_WORD(&reg->gpiod, gpio_data);
RD_REG_WORD(&reg->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(&reg->gpiod);
/* Enable the gpio_data reg for update. */
gpio_data |= GPDX_LED_UPDATE_MASK;
WRT_REG_DWORD(&reg->gpiod, gpio_data);
gpio_data = RD_REG_DWORD(&reg->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(&reg->gpiod, gpio_data);
gpio_data = RD_REG_DWORD(&reg->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(&reg->gpiod);
/* Enable the gpio_data reg for update. */
gpio_data |= GPDX_LED_UPDATE_MASK;
WRT_REG_DWORD(&reg->gpiod, gpio_data);
RD_REG_DWORD(&reg->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(&reg->gpiod);
/* Disable the gpio_data reg for update. */
gpio_data &= ~GPDX_LED_UPDATE_MASK;
WRT_REG_DWORD(&reg->gpiod, gpio_data);
RD_REG_DWORD(&reg->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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment