Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6df144c authored by Andrew Vasquez's avatar Andrew Vasquez Committed by
Browse files

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

parent 392e2f65
Loading
Loading
Loading
Loading
+50 −0
Original line number Original line Diff line number Diff line
@@ -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_fw_dump_attr);
	sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_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. */
/* Scsi_Host attributes. */
@@ -383,6 +386,50 @@ qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
	return strlen(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,
static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
	NULL);
	NULL);
static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_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);
    qla2x00_zio_store);
static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
    qla2x00_zio_timer_store);
    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[] = {
struct class_device_attribute *qla2x00_host_attrs[] = {
	&class_device_attr_driver_version,
	&class_device_attr_driver_version,
@@ -410,6 +459,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
	&class_device_attr_state,
	&class_device_attr_state,
	&class_device_attr_zio,
	&class_device_attr_zio,
	&class_device_attr_zio_timer,
	&class_device_attr_zio_timer,
	&class_device_attr_beacon,
	NULL,
	NULL,
};
};


+20 −1
Original line number Original line Diff line number Diff line
@@ -181,6 +181,13 @@
#define WRT_REG_WORD(addr, data)	writew(data,addr)
#define WRT_REG_WORD(addr, data)	writew(data,addr)
#define WRT_REG_DWORD(addr, data)	writel(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.
 * Fibre Channel device definitions.
 */
 */
@@ -433,6 +440,9 @@ struct device_reg_2xxx {
#define GPIO_LED_GREEN_ON_AMBER_OFF	0x0040
#define GPIO_LED_GREEN_ON_AMBER_OFF	0x0040
#define GPIO_LED_GREEN_OFF_AMBER_ON	0x0080
#define GPIO_LED_GREEN_OFF_AMBER_ON	0x0080
#define GPIO_LED_GREEN_ON_AMBER_ON	0x00C0
#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 {
	union {
		struct {
		struct {
@@ -2200,6 +2210,10 @@ struct isp_operations {


	void (*fw_dump) (struct scsi_qla_host *, int);
	void (*fw_dump) (struct scsi_qla_host *, int);
	void (*ascii_fw_dump) (struct scsi_qla_host *);
	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 */
	/* Needed for BEACON */
	uint16_t	beacon_blink_led;
	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_mode;
	uint16_t	zio_timer;
	uint16_t	zio_timer;
+7 −2
Original line number Original line Diff line number Diff line
@@ -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_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_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 int qla2x00_down_timeout(struct semaphore *, unsigned long);


extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
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,
extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_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.
 * Global Function Prototypes in qla_dbg.c source file.
 */
 */
+16 −0
Original line number Original line Diff line number Diff line
@@ -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.intr_handler = qla2300_intr_handler;
		ha->isp_ops.fw_dump = qla2300_fw_dump;
		ha->isp_ops.fw_dump = qla2300_fw_dump;
		ha->isp_ops.ascii_fw_dump = qla2300_ascii_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;
		ha->gid_list_info_size = 6;
	} else if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
	} else if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
		host->max_id = MAX_TARGETS_2200;
		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.write_nvram = qla24xx_write_nvram_data;
		ha->isp_ops.fw_dump = qla24xx_fw_dump;
		ha->isp_ops.fw_dump = qla24xx_fw_dump;
		ha->isp_ops.ascii_fw_dump = qla24xx_ascii_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;
		ha->gid_list_info_size = 8;
	}
	}
	host->can_queue = ha->request_q_length + 128;
	host->can_queue = ha->request_q_length + 128;
@@ -2315,6 +2321,9 @@ qla2x00_do_dpc(void *data)
		if (!ha->interrupts_on)
		if (!ha->interrupts_on)
			ha->isp_ops.enable_intrs(ha);
			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;
		ha->dpc_active = 0;
	} /* End of while(1) */
	} /* End of while(1) */


@@ -2492,6 +2501,12 @@ qla2x00_timer(scsi_qla_host_t *ha)
		    atomic_read(&ha->loop_down_timer)));
		    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 */
	/* Schedule the DPC routine if needed */
	if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
	if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
	    test_bit(LOOP_RESYNC_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 ||
	    start_dpc ||
	    test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
	    test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
	    test_bit(RESET_MARKER_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)) &&
	    test_bit(RELOGIN_NEEDED, &ha->dpc_flags)) &&
	    ha->dpc_wait && !ha->dpc_active) {
	    ha->dpc_wait && !ha->dpc_active) {


+294 −0
Original line number Original line Diff line number Diff line
@@ -695,3 +695,297 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,


	return ret;
	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;
}