[PATCH 4/6] qla2xxx: Add beacon support via class-device attribute.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Andrew Vasquez <andrew.vasquez@xxxxxxxxxx>

---

 drivers/scsi/qla2xxx/qla_attr.c |   50 +++++++
 drivers/scsi/qla2xxx/qla_def.h  |   21 +++
 drivers/scsi/qla2xxx/qla_gbl.h  |    9 +
 drivers/scsi/qla2xxx/qla_os.c   |   16 ++
 drivers/scsi/qla2xxx/qla_sup.c  |  294 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 387 insertions(+), 3 deletions(-)

46c8c43951dcca82a85e7b0b68cd66cc4b981ee2
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 5a8d5c4..049e5cf 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 
 
 	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_dev
 	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 | 
     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_h
 	&class_device_attr_state,
 	&class_device_attr_zio,
 	&class_device_attr_zio_timer,
+	&class_device_attr_beacon,
 	NULL,
 };
 
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 4145808..7cb8b5a 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -182,6 +182,13 @@
 #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.
  */
 #define WWN_SIZE		8	/* Size of WWPN, WWN & WWNN */
@@ -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;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index f2f5454..eb35198 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 *)
 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
 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.
  */
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 6e133ed..57179da 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 *pd
 		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 *pd
 		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) {
 
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index f4d755a..3105bb9 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
 
 	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;
+}
-- 
1.1.6.g1506


-
: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux