[PATCH 10/12] qla4xxx: Added support for ISP83XX

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

 



From: Vikas Chaudhary <vikas.chaudhary@xxxxxxxxxx>

Signed-off-by: Poornima Vonti <poornima.vonti@xxxxxxxxxx>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@xxxxxxxxxx>
---
 drivers/scsi/qla4xxx/Kconfig    |    4 +-
 drivers/scsi/qla4xxx/Makefile   |    2 +-
 drivers/scsi/qla4xxx/ql4_83xx.c | 1468 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla4xxx/ql4_83xx.h |  262 +++++++
 drivers/scsi/qla4xxx/ql4_attr.c |    2 +-
 drivers/scsi/qla4xxx/ql4_dbg.c  |   28 +
 drivers/scsi/qla4xxx/ql4_def.h  |   27 +-
 drivers/scsi/qla4xxx/ql4_fw.h   |   38 +
 drivers/scsi/qla4xxx/ql4_glbl.h |   41 ++
 drivers/scsi/qla4xxx/ql4_init.c |   15 +-
 drivers/scsi/qla4xxx/ql4_iocb.c |   12 +
 drivers/scsi/qla4xxx/ql4_isr.c  |  202 +++++-
 drivers/scsi/qla4xxx/ql4_mbx.c  |    6 +-
 drivers/scsi/qla4xxx/ql4_nx.c   |  488 ++++++++++++--
 drivers/scsi/qla4xxx/ql4_nx.h   |   17 +
 drivers/scsi/qla4xxx/ql4_os.c   |  262 +++++---
 16 files changed, 2689 insertions(+), 185 deletions(-)
 create mode 100644 drivers/scsi/qla4xxx/ql4_83xx.c
 create mode 100644 drivers/scsi/qla4xxx/ql4_83xx.h

diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
index f1ad02e..e4dc7c7 100644
--- a/drivers/scsi/qla4xxx/Kconfig
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -4,5 +4,5 @@ config SCSI_QLA_ISCSI
 	select SCSI_ISCSI_ATTRS
 	select ISCSI_BOOT_SYSFS
 	---help---
-	This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX)
-	iSCSI host adapter family.
+	This driver supports the QLogic 40xx (ISP4XXX), 8022 (ISP82XX)
+	and 8032 (ISP83XX) iSCSI host adapter family.
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
index 5b44139..4230977 100644
--- a/drivers/scsi/qla4xxx/Makefile
+++ b/drivers/scsi/qla4xxx/Makefile
@@ -1,5 +1,5 @@
 qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
-		ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o
+		ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o ql4_83xx.o
 
 obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
 
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
new file mode 100644
index 0000000..f963b06
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -0,0 +1,1468 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c)   2003-2012 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include <linux/ratelimit.h>
+
+#include "ql4_def.h"
+#include "ql4_version.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
+
+uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr)
+{
+	return readl((void __iomem *)(ha->nx_pcibase + addr));
+}
+
+void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val)
+{
+	writel(val, (void __iomem *)(ha->nx_pcibase + addr));
+}
+
+static int qla4_83xx_set_win_base(struct scsi_qla_host *ha, uint32_t addr)
+{
+	uint32_t val;
+	int ret_val = QLA_SUCCESS;
+
+	qla4_83xx_wr_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num), addr);
+	val = qla4_83xx_rd_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num));
+	if (val != addr) {
+		ql4_printk(KERN_ERR, ha, "%s: Failed to set register window : addr written 0x%x, read 0x%x!\n",
+			   __func__, addr, val);
+		ret_val = QLA_ERROR;
+	}
+
+	return ret_val;
+}
+
+int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
+			      uint32_t *data)
+{
+	int ret_val;
+
+	ret_val = qla4_83xx_set_win_base(ha, addr);
+
+	if (ret_val == QLA_SUCCESS)
+		*data = qla4_83xx_rd_reg(ha, QLA83XX_WILDCARD);
+	else
+		ql4_printk(KERN_ERR, ha, "%s: failed read of addr 0x%x!\n",
+			   __func__, addr);
+
+	return ret_val;
+}
+
+int qla4_83xx_wr_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
+			      uint32_t data)
+{
+	int ret_val;
+
+	ret_val = qla4_83xx_set_win_base(ha, addr);
+
+	if (ret_val == QLA_SUCCESS)
+		qla4_83xx_wr_reg(ha, QLA83XX_WILDCARD, data);
+	else
+		ql4_printk(KERN_ERR, ha, "%s: failed wrt to addr 0x%x, data 0x%x\n",
+			   __func__, addr, data);
+
+	return ret_val;
+}
+
+static int qla4_83xx_flash_lock(struct scsi_qla_host *ha)
+{
+	int lock_owner;
+	int timeout = 0;
+	uint32_t lock_status = 0;
+	int ret_val = QLA_SUCCESS;
+
+	while (lock_status == 0) {
+		lock_status = qla4_83xx_rd_reg(ha, QLA83XX_FLASH_LOCK);
+		if (lock_status)
+			break;
+
+		if (++timeout >= QLA83XX_FLASH_LOCK_TIMEOUT / 20) {
+			lock_owner = qla4_83xx_rd_reg(ha,
+						      QLA83XX_FLASH_LOCK_ID);
+			ql4_printk(KERN_ERR, ha, "%s: flash lock by func %d failed, held by func %d\n",
+				   __func__, ha->func_num, lock_owner);
+			ret_val = QLA_ERROR;
+			break;
+		}
+		msleep(20);
+	}
+
+	qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, ha->func_num);
+	return ret_val;
+}
+
+static void qla4_83xx_flash_unlock(struct scsi_qla_host *ha)
+{
+	/* Reading FLASH_UNLOCK register unlocks the Flash */
+	qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, 0xFF);
+	qla4_83xx_rd_reg(ha, QLA83XX_FLASH_UNLOCK);
+}
+
+int qla4_83xx_flash_read_u32(struct scsi_qla_host *ha, uint32_t flash_addr,
+			     uint8_t *p_data, int u32_word_count)
+{
+	int i;
+	uint32_t u32_word;
+	uint32_t addr = flash_addr;
+	int ret_val = QLA_SUCCESS;
+
+	ret_val = qla4_83xx_flash_lock(ha);
+	if (ret_val == QLA_ERROR)
+		goto exit_lock_error;
+
+	if (addr & 0x03) {
+		ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n",
+			   __func__, addr);
+		ret_val = QLA_ERROR;
+		goto exit_flash_read;
+	}
+
+	for (i = 0; i < u32_word_count; i++) {
+		ret_val = qla4_83xx_wr_reg_indirect(ha,
+						    QLA83XX_FLASH_DIRECT_WINDOW,
+						    (addr & 0xFFFF0000));
+		if (ret_val == QLA_ERROR) {
+			ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW\n!",
+				   __func__, addr);
+			goto exit_flash_read;
+		}
+
+		ret_val = qla4_83xx_rd_reg_indirect(ha,
+						QLA83XX_FLASH_DIRECT_DATA(addr),
+						&u32_word);
+		if (ret_val == QLA_ERROR) {
+			ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
+				   __func__, addr);
+			goto exit_flash_read;
+		}
+
+		*(__le32 *)p_data = le32_to_cpu(u32_word);
+		p_data = p_data + 4;
+		addr = addr + 4;
+	}
+
+exit_flash_read:
+	qla4_83xx_flash_unlock(ha);
+
+exit_lock_error:
+	return ret_val;
+}
+
+int qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host *ha,
+				      uint32_t flash_addr, uint8_t *p_data,
+				      int u32_word_count)
+{
+	uint32_t i;
+	uint32_t u32_word;
+	uint32_t flash_offset;
+	uint32_t addr = flash_addr;
+	int ret_val = QLA_SUCCESS;
+
+	flash_offset = addr & (QLA83XX_FLASH_SECTOR_SIZE - 1);
+
+	if (addr & 0x3) {
+		ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n",
+			   __func__, addr);
+		ret_val = QLA_ERROR;
+		goto exit_lockless_read;
+	}
+
+	ret_val = qla4_83xx_wr_reg_indirect(ha, QLA83XX_FLASH_DIRECT_WINDOW,
+					    addr);
+	if (ret_val == QLA_ERROR) {
+		ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
+			   __func__, addr);
+		goto exit_lockless_read;
+	}
+
+	/* Check if data is spread across multiple sectors  */
+	if ((flash_offset + (u32_word_count * sizeof(uint32_t))) >
+	    (QLA83XX_FLASH_SECTOR_SIZE - 1)) {
+
+		/* Multi sector read */
+		for (i = 0; i < u32_word_count; i++) {
+			ret_val = qla4_83xx_rd_reg_indirect(ha,
+						QLA83XX_FLASH_DIRECT_DATA(addr),
+						&u32_word);
+			if (ret_val == QLA_ERROR) {
+				ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
+					   __func__, addr);
+				goto exit_lockless_read;
+			}
+
+			*(__le32 *)p_data  = le32_to_cpu(u32_word);
+			p_data = p_data + 4;
+			addr = addr + 4;
+			flash_offset = flash_offset + 4;
+
+			if (flash_offset > (QLA83XX_FLASH_SECTOR_SIZE - 1)) {
+				/* This write is needed once for each sector */
+				ret_val = qla4_83xx_wr_reg_indirect(ha,
+						   QLA83XX_FLASH_DIRECT_WINDOW,
+						   addr);
+				if (ret_val == QLA_ERROR) {
+					ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
+						   __func__, addr);
+					goto exit_lockless_read;
+				}
+				flash_offset = 0;
+			}
+		}
+	} else {
+		/* Single sector read */
+		for (i = 0; i < u32_word_count; i++) {
+			ret_val = qla4_83xx_rd_reg_indirect(ha,
+						QLA83XX_FLASH_DIRECT_DATA(addr),
+						&u32_word);
+			if (ret_val == QLA_ERROR) {
+				ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
+					   __func__, addr);
+				goto exit_lockless_read;
+			}
+
+			*(__le32 *)p_data = le32_to_cpu(u32_word);
+			p_data = p_data + 4;
+			addr = addr + 4;
+		}
+	}
+
+exit_lockless_read:
+	return ret_val;
+}
+
+void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha)
+{
+	if (qla4_83xx_flash_lock(ha))
+		ql4_printk(KERN_INFO, ha, "%s: Resetting rom lock\n", __func__);
+
+	/*
+	 * We got the lock, or someone else is holding the lock
+	 * since we are restting, forcefully unlock
+	 */
+	qla4_83xx_flash_unlock(ha);
+}
+
+/**
+ * qla4_83xx_ms_mem_write_128b - Writes data to MS/off-chip memory
+ * @ha: Pointer to adapter structure
+ * @addr: Flash address to write to
+ * @data: Data to be written
+ * @count: word_count to be written
+ *
+ * Return: On success return QLA_SUCCESS
+ *	   On error return QLA_ERROR
+ **/
+static int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
+				       uint32_t *data, uint32_t count)
+{
+	int i, j;
+	uint32_t agt_ctrl;
+	unsigned long flags;
+	int ret_val = QLA_SUCCESS;
+
+	/* Only 128-bit aligned access */
+	if (addr & 0xF) {
+		ret_val = QLA_ERROR;
+		goto exit_ms_mem_write;
+	}
+
+	write_lock_irqsave(&ha->hw_lock, flags);
+
+	/* Write address */
+	ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_HI, 0);
+	if (ret_val == QLA_ERROR) {
+		ql4_printk(KERN_ERR, ha, "%s: write to AGT_ADDR_HI failed\n",
+			   __func__);
+		goto exit_ms_mem_write_unlock;
+	}
+
+	for (i = 0; i < count; i++, addr += 16) {
+		if (!((QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_QDR_NET,
+					     QLA8XXX_ADDR_QDR_NET_MAX)) ||
+		      (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_DDR_NET,
+					     QLA8XXX_ADDR_DDR_NET_MAX)))) {
+			ret_val = QLA_ERROR;
+			goto exit_ms_mem_write_unlock;
+		}
+
+		ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_LO,
+						    addr);
+		/* Write data */
+		ret_val |= qla4_83xx_wr_reg_indirect(ha,
+						     MD_MIU_TEST_AGT_WRDATA_LO,
+						     *data++);
+		ret_val |= qla4_83xx_wr_reg_indirect(ha,
+						     MD_MIU_TEST_AGT_WRDATA_HI,
+						     *data++);
+		ret_val |= qla4_83xx_wr_reg_indirect(ha,
+						     MD_MIU_TEST_AGT_WRDATA_ULO,
+						     *data++);
+		ret_val |= qla4_83xx_wr_reg_indirect(ha,
+						     MD_MIU_TEST_AGT_WRDATA_UHI,
+						     *data++);
+		if (ret_val == QLA_ERROR) {
+			ql4_printk(KERN_ERR, ha, "%s: write to AGT_WRDATA failed\n",
+				   __func__);
+			goto exit_ms_mem_write_unlock;
+		}
+
+		/* Check write status */
+		ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL,
+						    MIU_TA_CTL_WRITE_ENABLE);
+		ret_val |= qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL,
+						     MIU_TA_CTL_WRITE_START);
+		if (ret_val == QLA_ERROR) {
+			ql4_printk(KERN_ERR, ha, "%s: write to AGT_CTRL failed\n",
+				   __func__);
+			goto exit_ms_mem_write_unlock;
+		}
+
+		for (j = 0; j < MAX_CTL_CHECK; j++) {
+			ret_val = qla4_83xx_rd_reg_indirect(ha,
+							MD_MIU_TEST_AGT_CTRL,
+							&agt_ctrl);
+			if (ret_val == QLA_ERROR) {
+				ql4_printk(KERN_ERR, ha, "%s: failed to read MD_MIU_TEST_AGT_CTRL\n",
+					   __func__);
+				goto exit_ms_mem_write_unlock;
+			}
+			if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0)
+				break;
+		}
+
+		/* Status check failed */
+		if (j >= MAX_CTL_CHECK) {
+			printk_ratelimited(KERN_ERR "%s: MS memory write failed!\n",
+					   __func__);
+			ret_val = QLA_ERROR;
+			goto exit_ms_mem_write_unlock;
+		}
+	}
+
+exit_ms_mem_write_unlock:
+	write_unlock_irqrestore(&ha->hw_lock, flags);
+
+exit_ms_mem_write:
+	return ret_val;
+}
+
+#define INTENT_TO_RECOVER	0x01
+#define PROCEED_TO_RECOVER	0x02
+
+static int qla4_83xx_lock_recovery(struct scsi_qla_host *ha)
+{
+
+	uint32_t lock = 0, lockid;
+	int ret_val = QLA_ERROR;
+
+	lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY);
+
+	/* Check for other Recovery in progress, go wait */
+	if ((lockid & 0x3) != 0)
+		goto exit_lock_recovery;
+
+	/* Intent to Recover */
+	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY,
+				   (ha->func_num << 2) | INTENT_TO_RECOVER);
+
+	msleep(200);
+
+	/* Check Intent to Recover is advertised */
+	lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY);
+	if ((lockid & 0x3C) != (ha->func_num << 2))
+		goto exit_lock_recovery;
+
+	ql4_printk(KERN_INFO, ha, "%s: IDC Lock recovery initiated for func %d\n",
+		   __func__, ha->func_num);
+
+	/* Proceed to Recover */
+	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY,
+				   (ha->func_num << 2) | PROCEED_TO_RECOVER);
+
+	/* Force Unlock */
+	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, 0xFF);
+	ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_UNLOCK);
+
+	/* Clear bits 0-5 in IDC_RECOVERY register*/
+	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, 0);
+
+	/* Get lock */
+	lock = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK);
+	if (lock) {
+		lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK_ID);
+		lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->func_num;
+		ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, lockid);
+		ret_val = QLA_SUCCESS;
+	}
+
+exit_lock_recovery:
+	return ret_val;
+}
+
+#define	QLA83XX_DRV_LOCK_MSLEEP		200
+
+int qla4_83xx_drv_lock(struct scsi_qla_host *ha)
+{
+	int timeout = 0;
+	uint32_t status = 0;
+	int ret_val = QLA_SUCCESS;
+	uint32_t first_owner = 0;
+	uint32_t tmo_owner = 0;
+	uint32_t lock_id;
+	uint32_t func_num;
+	uint32_t lock_cnt;
+
+	while (status == 0) {
+		status = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK);
+		if (status) {
+			/* Increment Counter (8-31) and update func_num (0-7) on
+			 * getting a successful lock  */
+			lock_id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
+			lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->func_num;
+			qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, lock_id);
+			break;
+		}
+
+		if (timeout == 0)
+			/* Save counter + ID of function holding the lock for
+			 * first failure */
+			first_owner = ha->isp_ops->rd_reg_direct(ha,
+							  QLA83XX_DRV_LOCK_ID);
+
+		if (++timeout >=
+		    (QLA83XX_DRV_LOCK_TIMEOUT / QLA83XX_DRV_LOCK_MSLEEP)) {
+			tmo_owner = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
+			func_num = tmo_owner & 0xFF;
+			lock_cnt = tmo_owner >> 8;
+			ql4_printk(KERN_INFO, ha, "%s: Lock by func %d failed after 2s, lock held by func %d, lock count %d, first_owner %d\n",
+				   __func__, ha->func_num, func_num, lock_cnt,
+				   (first_owner & 0xFF));
+
+			if (first_owner != tmo_owner) {
+				/* Some other driver got lock, OR same driver
+				 * got lock again (counter value changed), when
+				 * we were waiting for lock.
+				 * Retry for another 2 sec */
+				ql4_printk(KERN_INFO, ha, "%s: IDC lock failed for func %d\n",
+					   __func__, ha->func_num);
+				timeout = 0;
+			} else {
+				/* Same driver holding lock > 2sec.
+				 * Force Recovery */
+				ret_val = qla4_83xx_lock_recovery(ha);
+				if (ret_val == QLA_SUCCESS) {
+					/* Recovered and got lock */
+					ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d successful\n",
+						   __func__, ha->func_num);
+					break;
+				}
+				/* Recovery Failed, some other function
+				 * has the lock, wait for 2secs and retry */
+				ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d failed, Retrying timout\n",
+					   __func__, ha->func_num);
+				timeout = 0;
+			}
+		}
+		msleep(QLA83XX_DRV_LOCK_MSLEEP);
+	}
+
+	return ret_val;
+}
+
+void qla4_83xx_drv_unlock(struct scsi_qla_host *ha)
+{
+	int id;
+
+	id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
+
+	if ((id & 0xFF) != ha->func_num) {
+		ql4_printk(KERN_ERR, ha, "%s: IDC Unlock by %d failed, lock owner is %d\n",
+			   __func__, ha->func_num, (id & 0xFF));
+		return;
+	}
+
+	/* Keep lock counter value, update the ha->func_num to 0xFF */
+	qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, (id | 0xFF));
+	qla4_83xx_rd_reg(ha, QLA83XX_DRV_UNLOCK);
+}
+
+void qla4_83xx_set_idc_dontreset(struct scsi_qla_host *ha)
+{
+	uint32_t idc_ctrl;
+
+	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
+	idc_ctrl |= DONTRESET_BIT0;
+	qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl);
+	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__,
+			  idc_ctrl));
+}
+
+void qla4_83xx_clear_idc_dontreset(struct scsi_qla_host *ha)
+{
+	uint32_t idc_ctrl;
+
+	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
+	idc_ctrl &= ~DONTRESET_BIT0;
+	qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl);
+	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__,
+			  idc_ctrl));
+}
+
+int qla4_83xx_idc_dontreset(struct scsi_qla_host *ha)
+{
+	uint32_t idc_ctrl;
+
+	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
+	return idc_ctrl & DONTRESET_BIT0;
+}
+
+/*-------------------------IDC State Machine ---------------------*/
+
+enum {
+	UNKNOWN_CLASS = 0,
+	NIC_CLASS,
+	FCOE_CLASS,
+	ISCSI_CLASS
+};
+
+struct device_info {
+	int func_num;
+	int device_type;
+	int port_num;
+};
+
+static int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha)
+{
+	uint32_t drv_active;
+	uint32_t dev_part, dev_part1, dev_part2;
+	int i;
+	struct device_info device_map[16];
+	int func_nibble;
+	int nibble;
+	int nic_present = 0;
+	int iscsi_present = 0;
+	int iscsi_func_low = 0;
+
+	/* Use the dev_partition register to determine the PCI function number
+	 * and then check drv_active register to see which driver is loaded */
+	dev_part1 = qla4_83xx_rd_reg(ha,
+				     ha->reg_tbl[QLA8XXX_CRB_DEV_PART_INFO]);
+	dev_part2 = qla4_83xx_rd_reg(ha, QLA83XX_CRB_DEV_PART_INFO2);
+	drv_active = qla4_83xx_rd_reg(ha, ha->reg_tbl[QLA8XXX_CRB_DRV_ACTIVE]);
+
+	/* Each function has 4 bits in dev_partition Info register,
+	 * Lower 2 bits - device type, Upper 2 bits - physical port number */
+	dev_part = dev_part1;
+	for (i = nibble = 0; i <= 15; i++, nibble++) {
+		func_nibble = dev_part & (0xF << (nibble * 4));
+		func_nibble >>= (nibble * 4);
+		device_map[i].func_num = i;
+		device_map[i].device_type = func_nibble & 0x3;
+		device_map[i].port_num = func_nibble & 0xC;
+
+		if (device_map[i].device_type == NIC_CLASS) {
+			if (drv_active & (1 << device_map[i].func_num)) {
+				nic_present++;
+				break;
+			}
+		} else if (device_map[i].device_type == ISCSI_CLASS) {
+			if (drv_active & (1 << device_map[i].func_num)) {
+				if (!iscsi_present ||
+				    (iscsi_present &&
+				     (iscsi_func_low > device_map[i].func_num)))
+					iscsi_func_low = device_map[i].func_num;
+
+				iscsi_present++;
+			}
+		}
+
+		/* For function_num[8..15] get info from dev_part2 register */
+		if (nibble == 7) {
+			nibble = 0;
+			dev_part = dev_part2;
+		}
+	}
+
+	/* NIC, iSCSI and FCOE are the Reset owners based on order, NIC gets
+	 * precedence over iSCSI and FCOE and iSCSI over FCOE, based on drivers
+	 * present. */
+	if (!nic_present && (ha->func_num == iscsi_func_low)) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				  "%s: can reset - NIC not present and lower iSCSI function is %d\n",
+				  __func__, ha->func_num));
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * qla4_83xx_need_reset_handler - Code to start reset sequence
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha)
+{
+	uint32_t dev_state, drv_state, drv_active;
+	unsigned long reset_timeout, dev_init_timeout;
+
+	ql4_printk(KERN_INFO, ha, "%s: Performing ISP error recovery\n",
+		   __func__);
+
+	if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: reset acknowledged\n",
+				  __func__));
+		qla4_8xxx_set_rst_ready(ha);
+
+		/* Non-reset owners ACK Reset and wait for device INIT state
+		 * as part of Reset Recovery by Reset Owner */
+		dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
+
+		do {
+			if (time_after_eq(jiffies, dev_init_timeout)) {
+				ql4_printk(KERN_INFO, ha, "%s: Non Reset owner dev init timeout\n",
+					   __func__);
+				break;
+			}
+
+			ha->isp_ops->idc_unlock(ha);
+			msleep(1000);
+			ha->isp_ops->idc_lock(ha);
+
+			dev_state = qla4_8xxx_rd_direct(ha,
+							QLA8XXX_CRB_DEV_STATE);
+		} while (dev_state == QLA8XXX_DEV_NEED_RESET);
+	} else {
+		qla4_8xxx_set_rst_ready(ha);
+		reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
+		drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
+		drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
+
+		ql4_printk(KERN_INFO, ha, "%s: drv_state = 0x%x, drv_active = 0x%x\n",
+			   __func__, drv_state, drv_active);
+
+		while (drv_state != drv_active) {
+			if (time_after_eq(jiffies, reset_timeout)) {
+				ql4_printk(KERN_INFO, ha, "%s: %s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n",
+					   __func__, DRIVER_NAME, drv_state,
+					   drv_active);
+				break;
+			}
+
+			ha->isp_ops->idc_unlock(ha);
+			msleep(1000);
+			ha->isp_ops->idc_lock(ha);
+
+			drv_state = qla4_8xxx_rd_direct(ha,
+							QLA8XXX_CRB_DRV_STATE);
+			drv_active = qla4_8xxx_rd_direct(ha,
+							QLA8XXX_CRB_DRV_ACTIVE);
+		}
+
+		if (drv_state != drv_active) {
+			ql4_printk(KERN_INFO, ha, "%s: Reset_owner turning off drv_active of non-acking function 0x%x\n",
+				   __func__, (drv_active ^ drv_state));
+			drv_active = drv_active & drv_state;
+			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE,
+					    drv_active);
+		}
+
+		clear_bit(AF_8XXX_RST_OWNER, &ha->flags);
+		/* Start Reset Recovery */
+		qla4_8xxx_device_bootstrap(ha);
+	}
+}
+
+void qla4_83xx_get_idc_param(struct scsi_qla_host *ha)
+{
+	uint32_t idc_params, ret_val;
+
+	ret_val = qla4_83xx_flash_read_u32(ha, QLA83XX_IDC_PARAM_ADDR,
+					   (uint8_t *)&idc_params, 1);
+	if (ret_val == QLA_SUCCESS) {
+		ha->nx_dev_init_timeout = idc_params & 0xFFFF;
+		ha->nx_reset_timeout = (idc_params >> 16) & 0xFFFF;
+	} else {
+		ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT;
+		ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT;
+	}
+
+	DEBUG2(ql4_printk(KERN_DEBUG, ha,
+			  "%s: ha->nx_dev_init_timeout = %d, ha->nx_reset_timeout = %d\n",
+			  __func__, ha->nx_dev_init_timeout,
+			  ha->nx_reset_timeout));
+}
+
+/*-------------------------Reset Sequence Functions-----------------------*/
+
+static void qla4_83xx_dump_reset_seq_hdr(struct scsi_qla_host *ha)
+{
+	uint8_t *phdr;
+
+	if (!ha->reset_tmplt.buff) {
+		ql4_printk(KERN_ERR, ha, "%s: Error: Invalid reset_seq_template\n",
+			   __func__);
+		return;
+	}
+
+	phdr = ha->reset_tmplt.buff;
+
+	DEBUG2(ql4_printk(KERN_INFO, ha,
+			  "Reset Template: 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",
+			  *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4),
+			  *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8),
+			  *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12),
+			  *(phdr+13), *(phdr+14), *(phdr+15)));
+}
+
+static int qla4_83xx_copy_bootloader(struct scsi_qla_host *ha)
+{
+	uint8_t *p_cache;
+	uint32_t src, count, size;
+	uint64_t dest;
+	int ret_val = QLA_SUCCESS;
+
+	src = QLA83XX_BOOTLOADER_FLASH_ADDR;
+	dest = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_ADDR);
+	size = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_SIZE);
+
+	/* 128 bit alignment check */
+	if (size & 0xF)
+		size = (size + 16) & ~0xF;
+
+	/* 16 byte count */
+	count = size/16;
+
+	p_cache = vmalloc(size);
+	if (p_cache == NULL) {
+		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate memory for boot loader cache\n",
+			   __func__);
+		ret_val = QLA_ERROR;
+		goto exit_copy_bootloader;
+	}
+
+	ret_val = qla4_83xx_lockless_flash_read_u32(ha, src, p_cache,
+						    size / sizeof(uint32_t));
+	if (ret_val == QLA_ERROR) {
+		ql4_printk(KERN_ERR, ha, "%s: Error reading firmware from flash\n",
+			   __func__);
+		goto exit_copy_error;
+	}
+	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Read firmware from flash\n",
+			  __func__));
+
+	/* 128 bit/16 byte write to MS memory */
+	ret_val = qla4_83xx_ms_mem_write_128b(ha, dest, (uint32_t *)p_cache,
+					      count);
+	if (ret_val == QLA_ERROR) {
+		ql4_printk(KERN_ERR, ha, "%s: Error writing firmware to MS\n",
+			   __func__);
+		goto exit_copy_error;
+	}
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Wrote firmware size %d to MS\n",
+			  __func__, size));
+
+exit_copy_error:
+	vfree(p_cache);
+
+exit_copy_bootloader:
+	return ret_val;
+}
+
+static int qla4_83xx_check_cmd_peg_status(struct scsi_qla_host *ha)
+{
+	uint32_t val, ret_val = QLA_ERROR;
+	int retries = CRB_CMDPEG_CHECK_RETRY_COUNT;
+
+	do {
+		val = qla4_83xx_rd_reg(ha, QLA83XX_CMDPEG_STATE);
+		if (val == PHAN_INITIALIZE_COMPLETE) {
+			DEBUG2(ql4_printk(KERN_INFO, ha,
+					  "%s: Command Peg initialization complete. State=0x%x\n",
+					  __func__, val));
+			ret_val = QLA_SUCCESS;
+			break;
+		}
+		msleep(CRB_CMDPEG_CHECK_DELAY);
+	} while (--retries);
+
+	return ret_val;
+}
+
+/**
+ * qla4_83xx_poll_reg - Poll the given CRB addr for duration msecs till
+ * value read ANDed with test_mask is equal to test_result.
+ *
+ * @ha : Pointer to adapter structure
+ * @addr : CRB register address
+ * @duration : Poll for total of "duration" msecs
+ * @test_mask : Mask value read with "test_mask"
+ * @test_result : Compare (value&test_mask) with test_result.
+ **/
+static int qla4_83xx_poll_reg(struct scsi_qla_host *ha, uint32_t addr,
+			      int duration, uint32_t test_mask,
+			      uint32_t test_result)
+{
+	uint32_t value;
+	uint8_t retries;
+	int ret_val = QLA_SUCCESS;
+
+	ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
+	if (ret_val == QLA_ERROR)
+		goto exit_poll_reg;
+
+	retries = duration / 10;
+	do {
+		if ((value & test_mask) != test_result) {
+			msleep(duration / 10);
+			ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
+			if (ret_val == QLA_ERROR)
+				goto exit_poll_reg;
+
+			ret_val = QLA_ERROR;
+		} else {
+			ret_val = QLA_SUCCESS;
+			break;
+		}
+	} while (retries--);
+
+exit_poll_reg:
+	if (ret_val == QLA_ERROR) {
+		ha->reset_tmplt.seq_error++;
+		ql4_printk(KERN_ERR, ha, "%s: Poll Failed:  0x%08x 0x%08x 0x%08x\n",
+			   __func__, value, test_mask, test_result);
+	}
+
+	return ret_val;
+}
+
+static int qla4_83xx_reset_seq_checksum_test(struct scsi_qla_host *ha)
+{
+	uint32_t sum =  0;
+	uint16_t *buff = (uint16_t *)ha->reset_tmplt.buff;
+	int u16_count =  ha->reset_tmplt.hdr->size / sizeof(uint16_t);
+	int ret_val;
+
+	while (u16_count-- > 0)
+		sum += *buff++;
+
+	while (sum >> 16)
+		sum = (sum & 0xFFFF) +  (sum >> 16);
+
+	/* checksum of 0 indicates a valid template */
+	if (~sum) {
+		ret_val = QLA_SUCCESS;
+	} else {
+		ql4_printk(KERN_ERR, ha, "%s: Reset seq checksum failed\n",
+			   __func__);
+		ret_val = QLA_ERROR;
+	}
+
+	return ret_val;
+}
+
+/**
+ * qla4_83xx_read_reset_template - Read Reset Template from Flash
+ * @ha: Pointer to adapter structure
+ **/
+void qla4_83xx_read_reset_template(struct scsi_qla_host *ha)
+{
+	uint8_t *p_buff;
+	uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size;
+	uint32_t ret_val;
+
+	ha->reset_tmplt.seq_error = 0;
+	ha->reset_tmplt.buff = vmalloc(QLA83XX_RESTART_TEMPLATE_SIZE);
+	if (ha->reset_tmplt.buff == NULL) {
+		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate reset template resources\n",
+			   __func__);
+		goto exit_read_reset_template;
+	}
+
+	p_buff = ha->reset_tmplt.buff;
+	addr = QLA83XX_RESET_TEMPLATE_ADDR;
+
+	tmplt_hdr_def_size = sizeof(struct qla4_83xx_reset_template_hdr) /
+				    sizeof(uint32_t);
+
+	DEBUG2(ql4_printk(KERN_INFO, ha,
+			  "%s: Read template hdr size %d from Flash\n",
+			  __func__, tmplt_hdr_def_size));
+
+	/* Copy template header from flash */
+	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
+					   tmplt_hdr_def_size);
+	if (ret_val != QLA_SUCCESS) {
+		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n",
+			   __func__);
+		goto exit_read_template_error;
+	}
+
+	ha->reset_tmplt.hdr =
+		(struct qla4_83xx_reset_template_hdr *)ha->reset_tmplt.buff;
+
+	/* Validate the template header size and signature */
+	tmplt_hdr_size = ha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t);
+	if ((tmplt_hdr_size != tmplt_hdr_def_size) ||
+	    (ha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) {
+		ql4_printk(KERN_ERR, ha, "%s: Template Header size %d is invalid, tmplt_hdr_def_size %d\n",
+			   __func__, tmplt_hdr_size, tmplt_hdr_def_size);
+		goto exit_read_template_error;
+	}
+
+	addr = QLA83XX_RESET_TEMPLATE_ADDR + ha->reset_tmplt.hdr->hdr_size;
+	p_buff = ha->reset_tmplt.buff + ha->reset_tmplt.hdr->hdr_size;
+	tmplt_hdr_def_size = (ha->reset_tmplt.hdr->size -
+			      ha->reset_tmplt.hdr->hdr_size) / sizeof(uint32_t);
+
+	DEBUG2(ql4_printk(KERN_INFO, ha,
+			  "%s: Read rest of the template size %d\n",
+			  __func__, ha->reset_tmplt.hdr->size));
+
+	/* Copy rest of the template */
+	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
+					   tmplt_hdr_def_size);
+	if (ret_val != QLA_SUCCESS) {
+		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset tempelate\n",
+			   __func__);
+		goto exit_read_template_error;
+	}
+
+	/* Integrity check */
+	if (qla4_83xx_reset_seq_checksum_test(ha)) {
+		ql4_printk(KERN_ERR, ha, "%s: Reset Seq checksum failed!\n",
+			   __func__);
+		goto exit_read_template_error;
+	}
+	DEBUG2(ql4_printk(KERN_INFO, ha,
+			  "%s: Reset Seq checksum passed, Get stop, start and init seq offsets\n",
+			  __func__));
+
+	/* Get STOP, START, INIT sequence offsets */
+	ha->reset_tmplt.init_offset = ha->reset_tmplt.buff +
+				      ha->reset_tmplt.hdr->init_seq_offset;
+	ha->reset_tmplt.start_offset = ha->reset_tmplt.buff +
+				       ha->reset_tmplt.hdr->start_seq_offset;
+	ha->reset_tmplt.stop_offset = ha->reset_tmplt.buff +
+				      ha->reset_tmplt.hdr->hdr_size;
+	qla4_83xx_dump_reset_seq_hdr(ha);
+
+	goto exit_read_reset_template;
+
+exit_read_template_error:
+	vfree(ha->reset_tmplt.buff);
+
+exit_read_reset_template:
+	return;
+}
+
+/**
+ * qla4_83xx_read_write_crb_reg - Read from raddr and write value to waddr.
+ *
+ * @ha : Pointer to adapter structure
+ * @raddr : CRB address to read from
+ * @waddr : CRB address to write to
+ **/
+static void qla4_83xx_read_write_crb_reg(struct scsi_qla_host *ha,
+					 uint32_t raddr, uint32_t waddr)
+{
+	uint32_t value;
+
+	qla4_83xx_rd_reg_indirect(ha, raddr, &value);
+	qla4_83xx_wr_reg_indirect(ha, waddr, value);
+}
+
+/**
+ * qla4_83xx_rmw_crb_reg - Read Modify Write crb register
+ *
+ * This function read value from raddr, AND with test_mask,
+ * Shift Left,Right/OR/XOR with values RMW header and write value to waddr.
+ *
+ * @ha : Pointer to adapter structure
+ * @raddr : CRB address to read from
+ * @waddr : CRB address to write to
+ * @p_rmw_hdr : header with shift/or/xor values.
+ **/
+static void qla4_83xx_rmw_crb_reg(struct scsi_qla_host *ha, uint32_t raddr,
+				  uint32_t waddr,
+				  struct qla4_83xx_rmw *p_rmw_hdr)
+{
+	uint32_t value;
+
+	if (p_rmw_hdr->index_a)
+		value = ha->reset_tmplt.array[p_rmw_hdr->index_a];
+	else
+		qla4_83xx_rd_reg_indirect(ha, raddr, &value);
+
+	value &= p_rmw_hdr->test_mask;
+	value <<= p_rmw_hdr->shl;
+	value >>= p_rmw_hdr->shr;
+	value |= p_rmw_hdr->or_value;
+	value ^= p_rmw_hdr->xor_value;
+
+	qla4_83xx_wr_reg_indirect(ha, waddr, value);
+
+	return;
+}
+
+static void qla4_83xx_write_list(struct scsi_qla_host *ha,
+				 struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	struct qla4_83xx_entry *p_entry;
+	uint32_t i;
+
+	p_entry = (struct qla4_83xx_entry *)
+		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla4_83xx_wr_reg_indirect(ha, p_entry->arg1, p_entry->arg2);
+		if (p_hdr->delay)
+			udelay((uint32_t)(p_hdr->delay));
+	}
+}
+
+static void qla4_83xx_read_write_list(struct scsi_qla_host *ha,
+				      struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	struct qla4_83xx_entry *p_entry;
+	uint32_t i;
+
+	p_entry = (struct qla4_83xx_entry *)
+		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla4_83xx_read_write_crb_reg(ha, p_entry->arg1, p_entry->arg2);
+		if (p_hdr->delay)
+			udelay((uint32_t)(p_hdr->delay));
+	}
+}
+
+static void qla4_83xx_poll_list(struct scsi_qla_host *ha,
+				struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	long delay;
+	struct qla4_83xx_entry *p_entry;
+	struct qla4_83xx_poll *p_poll;
+	uint32_t i;
+	uint32_t value;
+
+	p_poll = (struct qla4_83xx_poll *)
+		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
+
+	/* Entries start after 8 byte qla4_83xx_poll, poll header contains
+	 * the test_mask, test_value. */
+	p_entry = (struct qla4_83xx_entry *)((char *)p_poll +
+					     sizeof(struct qla4_83xx_poll));
+
+	delay = (long)p_hdr->delay;
+	if (!delay) {
+		for (i = 0; i < p_hdr->count; i++, p_entry++) {
+			qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
+					   p_poll->test_mask,
+					   p_poll->test_value);
+		}
+	} else {
+		for (i = 0; i < p_hdr->count; i++, p_entry++) {
+			if (qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
+					       p_poll->test_mask,
+					       p_poll->test_value)) {
+				qla4_83xx_rd_reg_indirect(ha, p_entry->arg1,
+							  &value);
+				qla4_83xx_rd_reg_indirect(ha, p_entry->arg2,
+							  &value);
+			}
+		}
+	}
+}
+
+static void qla4_83xx_poll_write_list(struct scsi_qla_host *ha,
+				      struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	long delay;
+	struct qla4_83xx_quad_entry *p_entry;
+	struct qla4_83xx_poll *p_poll;
+	uint32_t i;
+
+	p_poll = (struct qla4_83xx_poll *)
+		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
+	p_entry = (struct qla4_83xx_quad_entry *)
+		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
+	delay = (long)p_hdr->delay;
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla4_83xx_wr_reg_indirect(ha, p_entry->dr_addr,
+					  p_entry->dr_value);
+		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
+					  p_entry->ar_value);
+		if (delay) {
+			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
+					       p_poll->test_mask,
+					       p_poll->test_value)) {
+				DEBUG2(ql4_printk(KERN_INFO, ha,
+						  "%s: Timeout Error: poll list, item_num %d, entry_num %d\n",
+						  __func__, i,
+						  ha->reset_tmplt.seq_index));
+			}
+		}
+	}
+}
+
+static void qla4_83xx_read_modify_write(struct scsi_qla_host *ha,
+					struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	struct qla4_83xx_entry *p_entry;
+	struct qla4_83xx_rmw *p_rmw_hdr;
+	uint32_t i;
+
+	p_rmw_hdr = (struct qla4_83xx_rmw *)
+		    ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
+	p_entry = (struct qla4_83xx_entry *)
+		  ((char *)p_rmw_hdr + sizeof(struct qla4_83xx_rmw));
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla4_83xx_rmw_crb_reg(ha, p_entry->arg1, p_entry->arg2,
+				      p_rmw_hdr);
+		if (p_hdr->delay)
+			udelay((uint32_t)(p_hdr->delay));
+	}
+}
+
+static void qla4_83xx_pause(struct scsi_qla_host *ha,
+			    struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	if (p_hdr->delay)
+		mdelay((uint32_t)((long)p_hdr->delay));
+}
+
+static void qla4_83xx_poll_read_list(struct scsi_qla_host *ha,
+				     struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	long delay;
+	int index;
+	struct qla4_83xx_quad_entry *p_entry;
+	struct qla4_83xx_poll *p_poll;
+	uint32_t i;
+	uint32_t value;
+
+	p_poll = (struct qla4_83xx_poll *)
+		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
+	p_entry = (struct qla4_83xx_quad_entry *)
+		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
+	delay = (long)p_hdr->delay;
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
+					  p_entry->ar_value);
+		if (delay) {
+			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
+					       p_poll->test_mask,
+					       p_poll->test_value)) {
+				DEBUG2(ql4_printk(KERN_INFO, ha,
+						  "%s: Timeout Error: poll list, Item_num %d, entry_num %d\n",
+						  __func__, i,
+						  ha->reset_tmplt.seq_index));
+			} else {
+				index = ha->reset_tmplt.array_index;
+				qla4_83xx_rd_reg_indirect(ha, p_entry->dr_addr,
+							  &value);
+				ha->reset_tmplt.array[index++] = value;
+
+				if (index == QLA83XX_MAX_RESET_SEQ_ENTRIES)
+					ha->reset_tmplt.array_index = 1;
+			}
+		}
+	}
+}
+
+static void qla4_83xx_seq_end(struct scsi_qla_host *ha,
+			      struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	ha->reset_tmplt.seq_end = 1;
+}
+
+static void qla4_83xx_template_end(struct scsi_qla_host *ha,
+				   struct qla4_83xx_reset_entry_hdr *p_hdr)
+{
+	ha->reset_tmplt.template_end = 1;
+
+	if (ha->reset_tmplt.seq_error == 0) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				  "%s: Reset sequence completed SUCCESSFULLY.\n",
+				  __func__));
+	} else {
+		ql4_printk(KERN_ERR, ha, "%s: Reset sequence completed with some timeout errors.\n",
+			   __func__);
+	}
+}
+
+/**
+ * qla4_83xx_process_reset_template - Process reset template.
+ *
+ * Process all entries in reset template till entry with SEQ_END opcode,
+ * which indicates end of the reset template processing. Each entry has a
+ * Reset Entry header, entry opcode/command, with size of the entry, number
+ * of entries in sub-sequence and delay in microsecs or timeout in millisecs.
+ *
+ * @ha : Pointer to adapter structure
+ * @p_buff : Common reset entry header.
+ **/
+static void qla4_83xx_process_reset_template(struct scsi_qla_host *ha,
+					     char *p_buff)
+{
+	int index, entries;
+	struct qla4_83xx_reset_entry_hdr *p_hdr;
+	char *p_entry = p_buff;
+
+	ha->reset_tmplt.seq_end = 0;
+	ha->reset_tmplt.template_end = 0;
+	entries = ha->reset_tmplt.hdr->entries;
+	index = ha->reset_tmplt.seq_index;
+
+	for (; (!ha->reset_tmplt.seq_end) && (index  < entries); index++) {
+
+		p_hdr = (struct qla4_83xx_reset_entry_hdr *)p_entry;
+		switch (p_hdr->cmd) {
+		case OPCODE_NOP:
+			break;
+		case OPCODE_WRITE_LIST:
+			qla4_83xx_write_list(ha, p_hdr);
+			break;
+		case OPCODE_READ_WRITE_LIST:
+			qla4_83xx_read_write_list(ha, p_hdr);
+			break;
+		case OPCODE_POLL_LIST:
+			qla4_83xx_poll_list(ha, p_hdr);
+			break;
+		case OPCODE_POLL_WRITE_LIST:
+			qla4_83xx_poll_write_list(ha, p_hdr);
+			break;
+		case OPCODE_READ_MODIFY_WRITE:
+			qla4_83xx_read_modify_write(ha, p_hdr);
+			break;
+		case OPCODE_SEQ_PAUSE:
+			qla4_83xx_pause(ha, p_hdr);
+			break;
+		case OPCODE_SEQ_END:
+			qla4_83xx_seq_end(ha, p_hdr);
+			break;
+		case OPCODE_TMPL_END:
+			qla4_83xx_template_end(ha, p_hdr);
+			break;
+		case OPCODE_POLL_READ_LIST:
+			qla4_83xx_poll_read_list(ha, p_hdr);
+			break;
+		default:
+			ql4_printk(KERN_ERR, ha, "%s: Unknown command ==> 0x%04x on entry = %d\n",
+				   __func__, p_hdr->cmd, index);
+			break;
+		}
+
+		/* Set pointer to next entry in the sequence. */
+		p_entry += p_hdr->size;
+	}
+
+	ha->reset_tmplt.seq_index = index;
+}
+
+static void qla4_83xx_process_stop_seq(struct scsi_qla_host *ha)
+{
+	ha->reset_tmplt.seq_index = 0;
+	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.stop_offset);
+
+	if (ha->reset_tmplt.seq_end != 1)
+		ql4_printk(KERN_ERR, ha, "%s: Abrupt STOP Sub-Sequence end.\n",
+			   __func__);
+}
+
+static void qla4_83xx_process_start_seq(struct scsi_qla_host *ha)
+{
+	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.start_offset);
+
+	if (ha->reset_tmplt.template_end != 1)
+		ql4_printk(KERN_ERR, ha, "%s: Abrupt START Sub-Sequence end.\n",
+			   __func__);
+}
+
+static void qla4_83xx_process_init_seq(struct scsi_qla_host *ha)
+{
+	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.init_offset);
+
+	if (ha->reset_tmplt.seq_end != 1)
+		ql4_printk(KERN_ERR, ha, "%s: Abrupt INIT Sub-Sequence end.\n",
+			   __func__);
+}
+
+static int qla4_83xx_restart(struct scsi_qla_host *ha)
+{
+	int ret_val = QLA_SUCCESS;
+
+	qla4_83xx_process_stop_seq(ha);
+
+	/* Collect minidump*/
+	if (!test_and_clear_bit(AF_83XX_NO_FW_DUMP, &ha->flags))
+		qla4_8xxx_get_minidump(ha);
+
+	qla4_83xx_process_init_seq(ha);
+
+	if (qla4_83xx_copy_bootloader(ha)) {
+		ql4_printk(KERN_ERR, ha, "%s: Copy bootloader, firmware restart failed!\n",
+			   __func__);
+		ret_val = QLA_ERROR;
+		goto exit_restart;
+	}
+
+	qla4_83xx_wr_reg(ha, QLA83XX_FW_IMAGE_VALID, QLA83XX_BOOT_FROM_FLASH);
+	qla4_83xx_process_start_seq(ha);
+
+exit_restart:
+	return ret_val;
+}
+
+int qla4_83xx_start_firmware(struct scsi_qla_host *ha)
+{
+	int ret_val = QLA_SUCCESS;
+
+	ret_val = qla4_83xx_restart(ha);
+	if (ret_val == QLA_ERROR) {
+		ql4_printk(KERN_ERR, ha, "%s: Restart error\n", __func__);
+		goto exit_start_fw;
+	} else {
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Restart done\n",
+				  __func__));
+	}
+
+	ret_val = qla4_83xx_check_cmd_peg_status(ha);
+	if (ret_val == QLA_ERROR)
+		ql4_printk(KERN_ERR, ha, "%s: Peg not initialized\n",
+			   __func__);
+
+exit_start_fw:
+	return ret_val;
+}
+
+/*----------------------Interrupt Related functions ---------------------*/
+
+void qla4_83xx_disable_intrs(struct scsi_qla_host *ha)
+{
+	uint32_t mb_int, ret;
+
+	if (test_and_clear_bit(AF_INTERRUPTS_ON, &ha->flags))
+		qla4_8xxx_mbx_intr_disable(ha);
+
+	ret = readl(&ha->qla4_83xx_reg->mbox_int);
+	mb_int = ret & ~INT_ENABLE_FW_MB;
+	writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
+	writel(1, &ha->qla4_83xx_reg->leg_int_mask);
+}
+
+void qla4_83xx_enable_intrs(struct scsi_qla_host *ha)
+{
+	uint32_t mb_int;
+
+	qla4_8xxx_mbx_intr_enable(ha);
+	mb_int = INT_ENABLE_FW_MB;
+	writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
+	writel(0, &ha->qla4_83xx_reg->leg_int_mask);
+
+	set_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
+			      int incount)
+{
+	int i;
+
+	/* Load all mailbox registers, except mailbox 0. */
+	for (i = 1; i < incount; i++)
+		writel(mbx_cmd[i], &ha->qla4_83xx_reg->mailbox_in[i]);
+
+	writel(mbx_cmd[0], &ha->qla4_83xx_reg->mailbox_in[0]);
+
+	/* Set Host Interrupt register to 1, to tell the firmware that
+	 * a mailbox command is pending. Firmware after reading the
+	 * mailbox command, clears the host interrupt register */
+	writel(HINT_MBX_INT_PENDING, &ha->qla4_83xx_reg->host_intr);
+}
+
+void qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount)
+{
+	int intr_status;
+
+	intr_status = readl(&ha->qla4_83xx_reg->risc_intr);
+	if (intr_status) {
+		ha->mbox_status_count = outcount;
+		ha->isp_ops->interrupt_service_routine(ha, intr_status);
+	}
+	writel(0, &ha->qla4_83xx_reg->risc_intr);
+}
+
+/**
+ * qla4_83xx_isp_reset - Resets ISP and aborts all outstanding commands.
+ * @ha: pointer to host adapter structure.
+ **/
+int qla4_83xx_isp_reset(struct scsi_qla_host *ha)
+{
+	int rval;
+	uint32_t dev_state;
+
+	ha->isp_ops->idc_lock(ha);
+	dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
+
+	if (ql4xdontresethba)
+		qla4_83xx_set_idc_dontreset(ha);
+
+	if (dev_state == QLA8XXX_DEV_READY) {
+		/* If IDC_CTRL DONTRESETHBA_BIT0 is set dont do reset
+		 * recovery */
+		if (qla4_83xx_idc_dontreset(ha) == DONTRESET_BIT0) {
+			ql4_printk(KERN_ERR, ha, "%s: Reset recovery disabled\n",
+				   __func__);
+			rval = QLA_ERROR;
+			goto exit_isp_reset;
+		}
+
+		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET\n",
+				  __func__));
+		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
+				    QLA8XXX_DEV_NEED_RESET);
+
+	} else {
+		/* If device_state is NEED_RESET, go ahead with
+		 * Reset,irrespective of ql4xdontresethba. This is to allow a
+		 * non-reset-owner to force a reset. Non-reset-owner sets
+		 * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset
+		 * and then forces a Reset by setting device_state to
+		 * NEED_RESET. */
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				  "%s: HW state already set to NEED_RESET\n",
+				  __func__));
+	}
+
+	/* For ISP8324, Reset owner is NIC, iSCSI or FCOE based on priority
+	 * and which drivers are present. Unlike ISP8022, the function setting
+	 * NEED_RESET, may not be the Reset owner. */
+	if (qla4_83xx_can_perform_reset(ha))
+		set_bit(AF_8XXX_RST_OWNER, &ha->flags);
+
+	ha->isp_ops->idc_unlock(ha);
+	rval = qla4_8xxx_device_state_handler(ha);
+
+	ha->isp_ops->idc_lock(ha);
+	qla4_8xxx_clear_rst_ready(ha);
+exit_isp_reset:
+	ha->isp_ops->idc_unlock(ha);
+
+	if (rval == QLA_SUCCESS)
+		clear_bit(AF_FW_RECOVERY, &ha->flags);
+
+	return rval;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h
new file mode 100644
index 0000000..a679263
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_83xx.h
@@ -0,0 +1,262 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c)  2003-2012 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef __QL483XX_H
+#define __QL483XX_H
+
+/* Indirectly Mapped Registers */
+#define QLA83XX_FLASH_SPI_STATUS	0x2808E010
+#define QLA83XX_FLASH_SPI_CONTROL	0x2808E014
+#define QLA83XX_FLASH_STATUS		0x42100004
+#define QLA83XX_FLASH_CONTROL		0x42110004
+#define QLA83XX_FLASH_ADDR		0x42110008
+#define QLA83XX_FLASH_WRDATA		0x4211000C
+#define QLA83XX_FLASH_RDDATA		0x42110018
+#define QLA83XX_FLASH_DIRECT_WINDOW	0x42110030
+#define QLA83XX_FLASH_DIRECT_DATA(DATA) (0x42150000 | (0x0000FFFF&DATA))
+
+/* Directly Mapped Registers in 83xx register table */
+
+/* Flash access regs */
+#define QLA83XX_FLASH_LOCK		0x3850
+#define QLA83XX_FLASH_UNLOCK		0x3854
+#define QLA83XX_FLASH_LOCK_ID		0x3500
+
+/* Driver Lock regs */
+#define QLA83XX_DRV_LOCK		0x3868
+#define QLA83XX_DRV_UNLOCK		0x386C
+#define QLA83XX_DRV_LOCK_ID		0x3504
+#define QLA83XX_DRV_LOCKRECOVERY	0x379C
+
+/* IDC version */
+#define QLA83XX_IDC_VER_MAJ_VALUE       0x1
+#define QLA83XX_IDC_VER_MIN_VALUE       0x0
+
+/* IDC Registers : Driver Coexistence Defines */
+#define QLA83XX_CRB_IDC_VER_MAJOR	0x3780
+#define QLA83XX_CRB_IDC_VER_MINOR	0x3798
+#define QLA83XX_IDC_DRV_CTRL		0x3790
+#define QLA83XX_IDC_DRV_AUDIT		0x3794
+
+/* qla_83xx_reg_tbl registers */
+#define QLA83XX_PEG_HALT_STATUS1	0x34A8
+#define QLA83XX_PEG_HALT_STATUS2	0x34AC
+#define QLA83XX_PEG_ALIVE_COUNTER	0x34B0 /* FW_HEARTBEAT */
+#define QLA83XX_FW_CAPABILITIES		0x3528
+#define QLA83XX_CRB_DRV_ACTIVE		0x3788 /* IDC_DRV_PRESENCE */
+#define QLA83XX_CRB_DEV_STATE		0x3784 /* IDC_DEV_STATE */
+#define QLA83XX_CRB_DRV_STATE		0x378C /* IDC_DRV_ACK */
+#define QLA83XX_CRB_DRV_SCRATCH		0x3548
+#define QLA83XX_CRB_DEV_PART_INFO1	0x37E0
+#define QLA83XX_CRB_DEV_PART_INFO2	0x37E4
+
+#define QLA83XX_FW_VER_MAJOR		0x3550
+#define QLA83XX_FW_VER_MINOR		0x3554
+#define QLA83XX_FW_VER_SUB		0x3558
+#define QLA83XX_NPAR_STATE		0x359C
+#define QLA83XX_FW_IMAGE_VALID		0x35FC
+#define QLA83XX_CMDPEG_STATE		0x3650
+#define QLA83XX_ASIC_TEMP		0x37B4
+#define QLA83XX_FW_API			0x356C
+#define QLA83XX_DRV_OP_MODE		0x3570
+
+static const uint32_t qla4_83xx_reg_tbl[] = {
+	QLA83XX_PEG_HALT_STATUS1,
+	QLA83XX_PEG_HALT_STATUS2,
+	QLA83XX_PEG_ALIVE_COUNTER,
+	QLA83XX_CRB_DRV_ACTIVE,
+	QLA83XX_CRB_DEV_STATE,
+	QLA83XX_CRB_DRV_STATE,
+	QLA83XX_CRB_DRV_SCRATCH,
+	QLA83XX_CRB_DEV_PART_INFO1,
+	QLA83XX_CRB_IDC_VER_MAJOR,
+	QLA83XX_FW_VER_MAJOR,
+	QLA83XX_FW_VER_MINOR,
+	QLA83XX_FW_VER_SUB,
+	QLA83XX_CMDPEG_STATE,
+	QLA83XX_ASIC_TEMP,
+};
+
+#define QLA83XX_CRB_WIN_BASE		0x3800
+#define QLA83XX_CRB_WIN_FUNC(f)		(QLA83XX_CRB_WIN_BASE+((f)*4))
+#define QLA83XX_SEM_LOCK_BASE		0x3840
+#define QLA83XX_SEM_UNLOCK_BASE		0x3844
+#define QLA83XX_SEM_LOCK_FUNC(f)	(QLA83XX_SEM_LOCK_BASE+((f)*8))
+#define QLA83XX_SEM_UNLOCK_FUNC(f)	(QLA83XX_SEM_UNLOCK_BASE+((f)*8))
+#define QLA83XX_LINK_STATE(f)		(0x3698+((f) > 7 ? 4 : 0))
+#define QLA83XX_LINK_SPEED(f)		(0x36E0+(((f) >> 2) * 4))
+#define QLA83XX_MAX_LINK_SPEED(f)       (0x36F0+(((f) / 4) * 4))
+#define QLA83XX_LINK_SPEED_FACTOR	10
+
+/* FLASH API Defines */
+#define QLA83xx_FLASH_MAX_WAIT_USEC	100
+#define QLA83XX_FLASH_LOCK_TIMEOUT	10000
+#define QLA83XX_FLASH_SECTOR_SIZE	65536
+#define QLA83XX_DRV_LOCK_TIMEOUT	2000
+#define QLA83XX_FLASH_SECTOR_ERASE_CMD	0xdeadbeef
+#define QLA83XX_FLASH_WRITE_CMD		0xdacdacda
+#define QLA83XX_FLASH_BUFFER_WRITE_CMD	0xcadcadca
+#define QLA83XX_FLASH_READ_RETRY_COUNT	2000
+#define QLA83XX_FLASH_STATUS_READY	0x6
+#define QLA83XX_FLASH_BUFFER_WRITE_MIN	2
+#define QLA83XX_FLASH_BUFFER_WRITE_MAX	64
+#define QLA83XX_FLASH_STATUS_REG_POLL_DELAY 1
+#define QLA83XX_ERASE_MODE		1
+#define QLA83XX_WRITE_MODE		2
+#define QLA83XX_DWORD_WRITE_MODE	3
+
+#define QLA83XX_GLOBAL_RESET		0x38CC
+#define QLA83XX_WILDCARD		0x38F0
+#define QLA83XX_INFORMANT		0x38FC
+#define QLA83XX_HOST_MBX_CTRL		0x3038
+#define QLA83XX_FW_MBX_CTRL		0x303C
+#define QLA83XX_BOOTLOADER_ADDR		0x355C
+#define QLA83XX_BOOTLOADER_SIZE		0x3560
+#define QLA83XX_FW_IMAGE_ADDR		0x3564
+#define QLA83XX_MBX_INTR_ENABLE		0x1000
+#define QLA83XX_MBX_INTR_MASK		0x1200
+
+/* IDC Control Register bit defines */
+#define DONTRESET_BIT0		0x1
+#define GRACEFUL_RESET_BIT1	0x2
+
+#define QLA83XX_HALT_STATUS_INFORMATIONAL	(0x1 << 29)
+#define QLA83XX_HALT_STATUS_FW_RESET		(0x2 << 29)
+#define QLA83XX_HALT_STATUS_UNRECOVERABLE	(0x4 << 29)
+
+/* Firmware image definitions */
+#define QLA83XX_BOOTLOADER_FLASH_ADDR	0x10000
+#define QLA83XX_BOOT_FROM_FLASH		0
+
+#define QLA83XX_IDC_PARAM_ADDR		0x3e8020
+/* Reset template definitions */
+#define QLA83XX_MAX_RESET_SEQ_ENTRIES	16
+#define QLA83XX_RESTART_TEMPLATE_SIZE	0x2000
+#define QLA83XX_RESET_TEMPLATE_ADDR	0x4F0000
+#define QLA83XX_RESET_SEQ_VERSION	0x0101
+
+/* Reset template entry opcodes */
+#define OPCODE_NOP			0x0000
+#define OPCODE_WRITE_LIST		0x0001
+#define OPCODE_READ_WRITE_LIST		0x0002
+#define OPCODE_POLL_LIST		0x0004
+#define OPCODE_POLL_WRITE_LIST		0x0008
+#define OPCODE_READ_MODIFY_WRITE	0x0010
+#define OPCODE_SEQ_PAUSE		0x0020
+#define OPCODE_SEQ_END			0x0040
+#define OPCODE_TMPL_END			0x0080
+#define OPCODE_POLL_READ_LIST		0x0100
+
+/* Template Header */
+#define RESET_TMPLT_HDR_SIGNATURE	0xCAFE
+struct qla4_83xx_reset_template_hdr {
+	__le16	version;
+	__le16	signature;
+	__le16	size;
+	__le16	entries;
+	__le16	hdr_size;
+	__le16	checksum;
+	__le16	init_seq_offset;
+	__le16	start_seq_offset;
+} __packed;
+
+/* Common Entry Header. */
+struct qla4_83xx_reset_entry_hdr {
+	__le16 cmd;
+	__le16 size;
+	__le16 count;
+	__le16 delay;
+} __packed;
+
+/* Generic poll entry type. */
+struct qla4_83xx_poll {
+	__le32  test_mask;
+	__le32  test_value;
+} __packed;
+
+/* Read modify write entry type. */
+struct qla4_83xx_rmw {
+	__le32  test_mask;
+	__le32  xor_value;
+	__le32  or_value;
+	uint8_t shl;
+	uint8_t shr;
+	uint8_t index_a;
+	uint8_t rsvd;
+} __packed;
+
+/* Generic Entry Item with 2 DWords. */
+struct qla4_83xx_entry {
+	__le32 arg1;
+	__le32 arg2;
+} __packed;
+
+/* Generic Entry Item with 4 DWords.*/
+struct qla4_83xx_quad_entry {
+	__le32 dr_addr;
+	__le32 dr_value;
+	__le32 ar_addr;
+	__le32 ar_value;
+} __packed;
+
+struct qla4_83xx_reset_template {
+	int seq_index;
+	int seq_error;
+	int array_index;
+	uint32_t array[QLA83XX_MAX_RESET_SEQ_ENTRIES];
+	uint8_t *buff;
+	uint8_t *stop_offset;
+	uint8_t *start_offset;
+	uint8_t *init_offset;
+	struct qla4_83xx_reset_template_hdr *hdr;
+	uint8_t seq_end;
+	uint8_t template_end;
+};
+
+/* POLLRD Entry */
+struct qla83xx_minidump_entry_pollrd {
+	struct qla8xxx_minidump_entry_hdr h;
+	uint32_t select_addr;
+	uint32_t read_addr;
+	uint32_t select_value;
+	uint16_t select_value_stride;
+	uint16_t op_count;
+	uint32_t poll_wait;
+	uint32_t poll_mask;
+	uint32_t data_size;
+	uint32_t rsvd_1;
+};
+
+/* RDMUX2 Entry */
+struct qla83xx_minidump_entry_rdmux2 {
+	struct qla8xxx_minidump_entry_hdr h;
+	uint32_t select_addr_1;
+	uint32_t select_addr_2;
+	uint32_t select_value_1;
+	uint32_t select_value_2;
+	uint32_t op_count;
+	uint32_t select_value_mask;
+	uint32_t read_addr;
+	uint8_t select_value_stride;
+	uint8_t data_size;
+	uint8_t rsvd[2];
+};
+
+/* POLLRDMWR Entry */
+struct qla83xx_minidump_entry_pollrdmwr {
+	struct qla8xxx_minidump_entry_hdr h;
+	uint32_t addr_1;
+	uint32_t addr_2;
+	uint32_t value_1;
+	uint32_t value_2;
+	uint32_t poll_wait;
+	uint32_t poll_mask;
+	uint32_t modify_mask;
+	uint32_t data_size;
+};
+
+#endif
diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c
index a24008f..76819b7 100644
--- a/drivers/scsi/qla4xxx/ql4_attr.c
+++ b/drivers/scsi/qla4xxx/ql4_attr.c
@@ -150,7 +150,7 @@ qla4xxx_fw_version_show(struct device *dev,
 {
 	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
 
-	if (is_qla8022(ha))
+	if (is_qla80XX(ha))
 		return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
 				ha->firmware_version[0],
 				ha->firmware_version[1],
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index ea6af8c..f2a841f 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -131,3 +131,31 @@ void qla4xxx_dump_registers(struct scsi_qla_host *ha)
 		    &ha->reg->ctrl_status);
 	}
 }
+
+void qla4_8xxx_dump_peg_reg(struct scsi_qla_host *ha)
+{
+	uint32_t halt_status1, halt_status2;
+
+	halt_status1 = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1);
+	halt_status2 = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS2);
+
+	if (is_qla8022(ha)) {
+		ql4_printk(KERN_INFO, ha,
+			   "scsi(%ld): %s, ISP8022 Dumping hw/fw registers:\n"
+			   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+			   " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+			   " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+			   " PEG_NET_4_PC: 0x%x\n", ha->host_no,
+			   __func__, halt_status1, halt_status2,
+			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c),
+			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c),
+			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c),
+			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c),
+			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c));
+	} else if (is_qla8032(ha)) {
+		ql4_printk(KERN_INFO, ha,
+			   "scsi(%ld): %s, ISP8324 Dumping hw/fw registers:\n"
+			   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n",
+			   ha->host_no, __func__, halt_status1, halt_status2);
+	}
+}
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 11271a2..58b52cf 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -42,6 +42,7 @@
 #include "ql4_nx.h"
 #include "ql4_fw.h"
 #include "ql4_nvram.h"
+#include "ql4_83xx.h"
 
 #ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
 #define PCI_DEVICE_ID_QLOGIC_ISP4010	0x4010
@@ -59,6 +60,10 @@
 #define PCI_DEVICE_ID_QLOGIC_ISP8022	0x8022
 #endif
 
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP8324
+#define PCI_DEVICE_ID_QLOGIC_ISP8324	0x8032
+#endif
+
 #define ISP4XXX_PCI_FN_1	0x1
 #define ISP4XXX_PCI_FN_2	0x3
 
@@ -510,6 +515,7 @@ struct scsi_qla_host {
 #define AF_82XX_FW_DUMPED		24 /* 0x01000000 */
 #define AF_8XXX_RST_OWNER		25 /* 0x02000000 */
 #define AF_82XX_DUMP_READING		26 /* 0x04000000 */
+#define AF_83XX_NO_FW_DUMP		27 /* 0x08000000 */
 
 	unsigned long dpc_flags;
 
@@ -746,6 +752,10 @@ struct scsi_qla_host {
 	uint32_t mrb_index;
 
 	uint32_t *reg_tbl;
+	struct qla4_83xx_reset_template reset_tmplt;
+	struct device_reg_83xx  __iomem *qla4_83xx_reg; /* Base I/O address
+							   for ISP8324 */
+	uint32_t pf_bit;
 };
 
 struct ql4_task_data {
@@ -808,13 +818,20 @@ static inline int is_qla8022(struct scsi_qla_host *ha)
 	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022;
 }
 
-/* Note: Currently AER/EEH is now supported only for 8022 cards
- * This function needs to be updated when AER/EEH is enabled
- * for other cards.
- */
+static inline int is_qla8032(struct scsi_qla_host *ha)
+{
+	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324;
+}
+
+static inline int is_qla80XX(struct scsi_qla_host *ha)
+{
+	return is_qla8022(ha) || is_qla8032(ha);
+}
+
 static inline int is_aer_supported(struct scsi_qla_host *ha)
 {
-	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022;
+	return ((ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022) ||
+		(ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324));
 }
 
 static inline int adapter_up(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 037d380..3f36950 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -65,6 +65,40 @@ struct device_reg_82xx {
 #define ISRX_82XX_RISC_INT	BIT_0 /* RISC interrupt. */
 };
 
+/* ISP 83xx I/O Register Set structure */
+struct device_reg_83xx {
+	__le32 mailbox_in[16];	/* 0x0000 */
+	__le32 reserve1[496];	/* 0x0040 */
+	__le32 mailbox_out[16];	/* 0x0800 */
+	__le32 reserve2[496];
+	__le32 mbox_int;	/* 0x1000 */
+	__le32 reserve3[63];
+	__le32 req_q_out;	/* 0x1100 */
+	__le32 reserve4[63];
+
+	__le32 rsp_q_in;	/* 0x1200 */
+	__le32 reserve5[1919];
+
+	__le32 req_q_in;	/* 0x3000 */
+	__le32 reserve6[3];
+	__le32 iocb_int_mask;	/* 0x3010 */
+	__le32 reserve7[3];
+	__le32 rsp_q_out;	/* 0x3020 */
+	__le32 reserve8[3];
+	__le32 anonymousbuff;	/* 0x3030 */
+	__le32 mb_int_mask;	/* 0x3034 */
+
+	__le32 host_intr;	/* 0x3038 - Host Interrupt Register */
+	__le32 risc_intr;	/* 0x303C - RISC Interrupt Register */
+	__le32 reserve9[544];
+	__le32 leg_int_ptr;	/* 0x38C0 - Legacy Interrupt Pointer Register */
+	__le32 leg_int_trig;	/* 0x38C4 - Legacy Interrupt Trigger Control */
+	__le32 leg_int_mask;	/* 0x38C8 - Legacy Interrupt Mask Register */
+};
+
+#define INT_ENABLE_FW_MB	(1 << 2)
+#define INT_MASK_FW_MB		(1 << 2)
+
 /*  remote register set (access via PCI memory read/write) */
 struct isp_reg {
 #define MBOX_REG_COUNT 8
@@ -1198,6 +1232,9 @@ struct ql_iscsi_stats {
 #define QLA8XXX_DBG_STATE_ARRAY_LEN		16
 #define QLA8XXX_DBG_CAP_SIZE_ARRAY_LEN		8
 #define QLA8XXX_DBG_RSVD_ARRAY_LEN		8
+#define QLA83XX_DBG_OCM_WNDREG_ARRAY_LEN	16
+#define QLA83XX_SS_OCM_WNDREG_INDEX		3
+#define QLA83XX_SS_PCI_INDEX			0
 
 struct qla4_8xxx_minidump_template_hdr {
 	uint32_t entry_type;
@@ -1216,6 +1253,7 @@ struct qla4_8xxx_minidump_template_hdr {
 
 	uint32_t saved_state_array[QLA8XXX_DBG_STATE_ARRAY_LEN];
 	uint32_t capture_size_array[QLA8XXX_DBG_CAP_SIZE_ARRAY_LEN];
+	uint32_t ocm_window_reg[QLA83XX_DBG_OCM_WNDREG_ARRAY_LEN];
 };
 
 #endif /*  _QLA4X_FW_H */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 1010d71..0c6acad 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -214,6 +214,47 @@ void qla4_82xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount);
 void qla4xxx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
 			    int incount);
 void qla4xxx_process_mbox_intr(struct scsi_qla_host *ha, int outcount);
+void qla4_8xxx_dump_peg_reg(struct scsi_qla_host *ha);
+void qla4_83xx_disable_intrs(struct scsi_qla_host *ha);
+void qla4_83xx_enable_intrs(struct scsi_qla_host *ha);
+int qla4_83xx_start_firmware(struct scsi_qla_host *ha);
+irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id);
+void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha,
+					 uint32_t intr_status);
+int qla4_83xx_isp_reset(struct scsi_qla_host *ha);
+void qla4_83xx_queue_iocb(struct scsi_qla_host *ha);
+void qla4_83xx_complete_iocb(struct scsi_qla_host *ha);
+uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha);
+uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha);
+uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr);
+void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val);
+int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
+			      uint32_t *data);
+int qla4_83xx_wr_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
+			      uint32_t data);
+int qla4_83xx_drv_lock(struct scsi_qla_host *ha);
+void qla4_83xx_drv_unlock(struct scsi_qla_host *ha);
+void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha);
+void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
+			      int incount);
+void qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount);
+void qla4_83xx_read_reset_template(struct scsi_qla_host *ha);
+void qla4_83xx_set_idc_dontreset(struct scsi_qla_host *ha);
+int qla4_83xx_idc_dontreset(struct scsi_qla_host *ha);
+int qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host *ha,
+				      uint32_t flash_addr, uint8_t *p_data,
+				      int u32_word_count);
+void qla4_83xx_clear_idc_dontreset(struct scsi_qla_host *ha);
+void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha);
+int qla4_83xx_flash_read_u32(struct scsi_qla_host *ha, uint32_t flash_addr,
+			     uint8_t *p_data, int u32_word_count);
+void qla4_83xx_get_idc_param(struct scsi_qla_host *ha);
+void qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha);
+void qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha);
+int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha);
+void qla4_8xxx_get_minidump(struct scsi_qla_host *ha);
+int qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha);
+int qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha);
 
 extern int ql4xextended_error_logging;
 extern int ql4xdontresethba;
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 6bc983d..a1881d0 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -107,6 +107,13 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha)
 		    (unsigned long  __iomem *)&ha->qla4_82xx_reg->rsp_q_in);
 		writel(0,
 		    (unsigned long  __iomem *)&ha->qla4_82xx_reg->rsp_q_out);
+	} else if (is_qla8032(ha)) {
+		writel(0,
+		       (unsigned long __iomem *)&ha->qla4_83xx_reg->req_q_in);
+		writel(0,
+		       (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_in);
+		writel(0,
+		       (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_out);
 	} else {
 		/*
 		 * Initialize DMA Shadow registers.  The firmware is really
@@ -524,7 +531,7 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
 	/* For 82xx, stop firmware before initializing because if BIOS
 	 * has previously initialized firmware, then driver's initialize
 	 * firmware will fail. */
-	if (is_qla8022(ha))
+	if (is_qla80XX(ha))
 		qla4_8xxx_stop_firmware(ha);
 
 	ql4_printk(KERN_INFO, ha, "Initializing firmware..\n");
@@ -537,7 +544,7 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
 	if (!qla4xxx_fw_ready(ha))
 		return status;
 
-	if (is_qla8022(ha) && !test_bit(AF_INIT_DONE, &ha->flags))
+	if (is_qla80XX(ha) && !test_bit(AF_INIT_DONE, &ha->flags))
 		qla4xxx_alloc_fw_dump(ha);
 
 	return qla4xxx_get_firmware_status(ha);
@@ -946,9 +953,9 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset)
 
 	set_bit(AF_ONLINE, &ha->flags);
 exit_init_hba:
-	if (is_qla8022(ha) && (status == QLA_ERROR)) {
+	if (is_qla80XX(ha) && (status == QLA_ERROR)) {
 		/* Since interrupts are registered in start_firmware for
-		 * 82xx, release them here if initialize_adapter fails */
+		 * 80XX, release them here if initialize_adapter fails */
 		qla4xxx_free_irqs(ha);
 	}
 
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 1def688..b6a4e36 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -192,6 +192,18 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb,
 	}
 }
 
+void qla4_83xx_queue_iocb(struct scsi_qla_host *ha)
+{
+	writel(ha->request_in, &ha->qla4_83xx_reg->req_q_in);
+	readl(&ha->qla4_83xx_reg->req_q_in);
+}
+
+void qla4_83xx_complete_iocb(struct scsi_qla_host *ha)
+{
+	writel(ha->response_out, &ha->qla4_83xx_reg->rsp_q_out);
+	readl(&ha->qla4_83xx_reg->rsp_q_out);
+}
+
 /**
  * qla4_82xx_queue_iocb - Tell ISP it's got new request(s)
  * @ha: pointer to host adapter structure.
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 55d366b..cb78e9c 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -126,7 +126,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
 		ql4_printk(KERN_WARNING, ha, "%s invalid status entry: "
 			   "handle=0x%0x, srb=%p\n", __func__,
 			   sts_entry->handle, srb);
-		if (is_qla8022(ha))
+		if (is_qla80XX(ha))
 			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
 		else
 			set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -594,6 +594,14 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
 {
 	int i;
 	uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+	__le32 __iomem *mailbox_out;
+
+	if (is_qla8032(ha))
+		mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0];
+	else if (is_qla8022(ha))
+		mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0];
+	else
+		mailbox_out = &ha->reg->mailbox[0];
 
 	if ((mbox_status == MBOX_STS_BUSY) ||
 	    (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
@@ -606,9 +614,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
 			 * location and set mailbox command done flag
 			 */
 			for (i = 0; i < ha->mbox_status_count; i++)
-				ha->mbox_status[i] = is_qla8022(ha)
-				    ? readl(&ha->qla4_82xx_reg->mailbox_out[i])
-				    : readl(&ha->reg->mailbox[i]);
+				ha->mbox_status[i] = readl(&mailbox_out[i]);
 
 			set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
 
@@ -617,9 +623,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
 		}
 	} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
 		for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
-			mbox_sts[i] = is_qla8022(ha)
-			    ? readl(&ha->qla4_82xx_reg->mailbox_out[i])
-			    : readl(&ha->reg->mailbox[i]);
+			mbox_sts[i] = readl(&mailbox_out[i]);
 
 		/* Immediately process the AENs that don't require much work.
 		 * Only queue the database_changed AENs */
@@ -635,7 +639,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
 			ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__);
 			qla4xxx_dump_registers(ha);
 
-			if (ql4xdontresethba) {
+			if ((is_qla8022(ha) && ql4xdontresethba) ||
+			    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
 				DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
 				    ha->host_no, __func__));
 			} else {
@@ -651,7 +656,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
 		case MBOX_ASTS_DHCP_LEASE_EXPIRED:
 			DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, "
 				      "Reset HA\n", ha->host_no, mbox_status));
-			if (is_qla8022(ha))
+			if (is_qla80XX(ha))
 				set_bit(DPC_RESET_HA_FW_CONTEXT,
 					&ha->dpc_flags);
 			else
@@ -716,7 +721,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
 				set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
 			else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
 				 (mbox_sts[2] == ACB_STATE_VALID)) {
-				if (is_qla8022(ha))
+				if (is_qla80XX(ha))
 					set_bit(DPC_RESET_HA_FW_CONTEXT,
 						&ha->dpc_flags);
 				else
@@ -815,6 +820,23 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
 	}
 }
 
+void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha,
+					 uint32_t intr_status)
+{
+	/* Process mailbox/asynch event interrupt.*/
+	if (intr_status) {
+		qla4xxx_isr_decode_mailbox(ha,
+				readl(&ha->qla4_83xx_reg->mailbox_out[0]));
+		/* clear the interrupt */
+		writel(0, &ha->qla4_83xx_reg->risc_intr);
+	} else {
+		qla4xxx_process_response_queue(ha);
+	}
+
+	/* clear the interrupt */
+	writel(0, &ha->qla4_83xx_reg->mb_int_mask);
+}
+
 /**
  * qla4_82xx_interrupt_service_routine - isr
  * @ha: pointer to host adapter structure.
@@ -1045,6 +1067,59 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+#define LEG_INT_PTR_B31		(1 << 31)
+#define LEG_INT_PTR_B30		(1 << 30)
+#define PF_BITS_MASK		(0xF << 16)
+
+/**
+ * qla4_83xx_intr_handler - hardware interrupt handler.
+ * @irq: Unused
+ * @dev_id: Pointer to host adapter structure
+ **/
+irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id)
+{
+	struct scsi_qla_host *ha = dev_id;
+	uint32_t leg_int_ptr = 0;
+	unsigned long flags = 0;
+
+	ha->isr_count++;
+	leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr);
+
+	/* Legacy interrupt is valid if bit31 of leg_int_ptr is set */
+	if (!(leg_int_ptr & LEG_INT_PTR_B31)) {
+		ql4_printk(KERN_ERR, ha,
+			   "%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n",
+			   __func__);
+		return IRQ_NONE;
+	}
+
+	/* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */
+	if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) {
+		ql4_printk(KERN_ERR, ha,
+			   "%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n",
+			   __func__, (leg_int_ptr & PF_BITS_MASK), ha->pf_bit);
+		return IRQ_NONE;
+	}
+
+	/* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger
+	 * Control register and poll till Legacy Interrupt Pointer register
+	 * bit30 is 0.
+	 */
+	writel(0, &ha->qla4_83xx_reg->leg_int_trig);
+	do {
+		leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr);
+		if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit)
+			break;
+	} while (leg_int_ptr & LEG_INT_PTR_B30);
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	leg_int_ptr = readl(&ha->qla4_83xx_reg->risc_intr);
+	ha->isp_ops->interrupt_service_routine(ha, leg_int_ptr);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
 irqreturn_t
 qla4_8xxx_msi_handler(int irq, void *dev_id)
 {
@@ -1068,6 +1143,37 @@ qla4_8xxx_msi_handler(int irq, void *dev_id)
 	return qla4_8xxx_default_intr_handler(irq, dev_id);
 }
 
+static irqreturn_t qla4_83xx_mailbox_intr_handler(int irq, void *dev_id)
+{
+	struct scsi_qla_host *ha = dev_id;
+	unsigned long flags;
+	uint32_t ival = 0;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	ival = readl(&ha->qla4_83xx_reg->risc_intr);
+	if (ival == 0) {
+		ql4_printk(KERN_INFO, ha,
+			   "%s: It is a spurious mailbox interrupt!\n",
+			   __func__);
+		ival = readl(&ha->qla4_83xx_reg->mb_int_mask);
+		ival &= ~INT_MASK_FW_MB;
+		writel(ival, &ha->qla4_83xx_reg->mb_int_mask);
+		goto exit;
+	}
+
+	qla4xxx_isr_decode_mailbox(ha,
+				   readl(&ha->qla4_83xx_reg->mailbox_out[0]));
+	writel(0, &ha->qla4_83xx_reg->risc_intr);
+	ival = readl(&ha->qla4_83xx_reg->mb_int_mask);
+	ival &= ~INT_MASK_FW_MB;
+	writel(ival, &ha->qla4_83xx_reg->mb_int_mask);
+	ha->isr_count++;
+exit:
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	return IRQ_HANDLED;
+}
+
 /**
  * qla4_8xxx_default_intr_handler - hardware interrupt handler.
  * @irq: Unused
@@ -1084,29 +1190,32 @@ qla4_8xxx_default_intr_handler(int irq, void *dev_id)
 	uint32_t intr_status;
 	uint8_t reqs_count = 0;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	while (1) {
-		if (!(readl(&ha->qla4_82xx_reg->host_int) &
-		    ISRX_82XX_RISC_INT)) {
-			qla4_82xx_spurious_interrupt(ha, reqs_count);
-			break;
-		}
+	if (is_qla8032(ha)) {
+		qla4_83xx_mailbox_intr_handler(irq, dev_id);
+	} else {
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+		while (1) {
+			if (!(readl(&ha->qla4_82xx_reg->host_int) &
+			    ISRX_82XX_RISC_INT)) {
+				qla4_82xx_spurious_interrupt(ha, reqs_count);
+				break;
+			}
 
-		intr_status =  readl(&ha->qla4_82xx_reg->host_status);
-		if ((intr_status &
-		    (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) {
-			qla4_82xx_spurious_interrupt(ha, reqs_count);
-			break;
-		}
+			intr_status =  readl(&ha->qla4_82xx_reg->host_status);
+			if ((intr_status &
+			    (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) {
+				qla4_82xx_spurious_interrupt(ha, reqs_count);
+				break;
+			}
 
-		ha->isp_ops->interrupt_service_routine(ha, intr_status);
+			ha->isp_ops->interrupt_service_routine(ha, intr_status);
 
-		if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
-			break;
+			if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
+				break;
+		}
+		ha->isr_count++;
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	}
-
-	ha->isr_count++;
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -1115,13 +1224,25 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
 {
 	struct scsi_qla_host *ha = dev_id;
 	unsigned long flags;
+	uint32_t ival = 0;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qla4xxx_process_response_queue(ha);
-	writel(0, &ha->qla4_82xx_reg->host_int);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
+	if (is_qla8032(ha)) {
+		ival = readl(&ha->qla4_83xx_reg->iocb_int_mask);
+		if (ival == 0) {
+			ql4_printk(KERN_INFO, ha, "%s: It is a spurious iocb interrupt!\n",
+				   __func__);
+			goto exit_msix_rsp_q;
+		}
+		qla4xxx_process_response_queue(ha);
+		writel(0, &ha->qla4_83xx_reg->iocb_int_mask);
+	} else {
+		qla4xxx_process_response_queue(ha);
+		writel(0, &ha->qla4_82xx_reg->host_int);
+	}
 	ha->isr_count++;
+exit_msix_rsp_q:
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -1196,8 +1317,15 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha)
 	if (is_qla40XX(ha))
 		goto try_intx;
 
-	if (ql4xenablemsix == 2)
+	if (ql4xenablemsix == 2) {
+		/* Note: MSI Interrupts not supported for ISP8324 */
+		if (is_qla8032(ha)) {
+			ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP8324, Falling back-to INTx mode\n",
+				   __func__);
+			goto try_intx;
+		}
 		goto try_msi;
+	}
 
 	if (ql4xenablemsix == 0 || ql4xenablemsix != 1)
 		goto try_intx;
@@ -1208,6 +1336,12 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha)
 		DEBUG2(ql4_printk(KERN_INFO, ha,
 		    "MSI-X: Enabled (0x%X).\n", ha->revision_id));
 		goto irq_attached;
+	} else {
+		if (is_qla8032(ha)) {
+			ql4_printk(KERN_INFO, ha, "%s: ISP8324: MSI-X: Falling back-to INTx mode. ret = %d\n",
+				   __func__, ret);
+			goto try_intx;
+		}
 	}
 
 	ql4_printk(KERN_WARNING, ha,
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 73324fb..80fa20d 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -107,7 +107,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
 		msleep(10);
 	}
 
-	if (is_qla8022(ha)) {
+	if (is_qla80XX(ha)) {
 		if (test_bit(AF_FW_RECOVERY, &ha->flags)) {
 			DEBUG2(ql4_printk(KERN_WARNING, ha,
 					  "scsi%ld: %s: prematurely completing mbx cmd as firmware recovery detected\n",
@@ -183,7 +183,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
 
 	/* Check for mailbox timeout. */
 	if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
-		if (is_qla8022(ha) &&
+		if (is_qla80XX(ha) &&
 		    test_bit(AF_FW_RECOVERY, &ha->flags)) {
 			DEBUG2(ql4_printk(KERN_INFO, ha,
 			    "scsi%ld: %s: prematurely completing mbx cmd as "
@@ -544,7 +544,7 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
 		__constant_cpu_to_le16(FWOPT_SESSION_MODE |
 				       FWOPT_INITIATOR_MODE);
 
-	if (is_qla8022(ha))
+	if (is_qla80XX(ha))
 		init_fw_cb->fw_options |=
 		    __constant_cpu_to_le16(FWOPT_ENABLE_CRBDB);
 
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index 6daa25c..3e55608 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -10,6 +10,7 @@
 #include <linux/ratelimit.h>
 #include "ql4_def.h"
 #include "ql4_glbl.h"
+#include "ql4_inline.h"
 
 #include <asm-generic/io-64-nonatomic-lo-hi.h>
 
@@ -1511,7 +1512,17 @@ qla4_8xxx_set_drv_active(struct scsi_qla_host *ha)
 	uint32_t drv_active;
 
 	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
-	drv_active |= (1 << (ha->func_num * 4));
+
+	/*
+	 * For ISP8324, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.
+	 * For ISP8022, drv_active has 4 bits per function
+	 */
+	if (is_qla8032(ha))
+		drv_active |= (1 << ha->func_num);
+	else
+		drv_active |= (1 << (ha->func_num * 4));
+
 	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n",
 		   __func__, ha->host_no, drv_active);
 	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active);
@@ -1523,7 +1534,17 @@ qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha)
 	uint32_t drv_active;
 
 	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
-	drv_active &= ~(1 << (ha->func_num * 4));
+
+	/*
+	 * For ISP8324, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.
+	 * For ISP8022, drv_active has 4 bits per function
+	 */
+	if (is_qla8032(ha))
+		drv_active &= ~(1 << (ha->func_num));
+	else
+		drv_active &= ~(1 << (ha->func_num * 4));
+
 	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n",
 		   __func__, ha->host_no, drv_active);
 	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active);
@@ -1536,32 +1557,60 @@ inline int qla4_8xxx_need_reset(struct scsi_qla_host *ha)
 
 	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
 	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
-	rval = drv_state & (1 << (ha->func_num * 4));
+
+	/*
+	 * For ISP8324, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.
+	 * For ISP8022, drv_active has 4 bits per function
+	 */
+	if (is_qla8032(ha))
+		rval = drv_state & (1 << ha->func_num);
+	else
+		rval = drv_state & (1 << (ha->func_num * 4));
+
 	if ((test_bit(AF_EEH_BUSY, &ha->flags)) && drv_active)
 		rval = 1;
 
 	return rval;
 }
 
-static inline void
-qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha)
+void qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha)
 {
 	uint32_t drv_state;
 
 	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
-	drv_state |= (1 << (ha->func_num * 4));
+
+	/*
+	 * For ISP8324, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.
+	 * For ISP8022, drv_active has 4 bits per function
+	 */
+	if (is_qla8032(ha))
+		drv_state |= (1 << ha->func_num);
+	else
+		drv_state |= (1 << (ha->func_num * 4));
+
 	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n",
 		   __func__, ha->host_no, drv_state);
 	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state);
 }
 
-static inline void
-qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha)
+void qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha)
 {
 	uint32_t drv_state;
 
 	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
-	drv_state &= ~(1 << (ha->func_num * 4));
+
+	/*
+	 * For ISP8324, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.
+	 * For ISP8022, drv_active has 4 bits per function
+	 */
+	if (is_qla8032(ha))
+		drv_state &= ~(1 << ha->func_num);
+	else
+		drv_state &= ~(1 << (ha->func_num * 4));
+
 	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n",
 		   __func__, ha->host_no, drv_state);
 	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state);
@@ -1573,7 +1622,17 @@ qla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha)
 	uint32_t qsnt_state;
 
 	qsnt_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
-	qsnt_state |= (2 << (ha->func_num * 4));
+
+	/*
+	 * For ISP8324, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.
+	 * For ISP8022, drv_active has 4 bits per function.
+	 */
+	if (is_qla8032(ha))
+		qsnt_state |= (1 << ha->func_num);
+	else
+		qsnt_state |= (2 << (ha->func_num * 4));
+
 	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, qsnt_state);
 }
 
@@ -2104,6 +2163,196 @@ static void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha,
 			  entry_hdr->d_ctrl.entry_capture_mask));
 }
 
+/* ISP83xx functions to process new minidump entries... */
+static uint32_t qla83xx_minidump_process_pollrd(struct scsi_qla_host *ha,
+				struct qla8xxx_minidump_entry_hdr *entry_hdr,
+				uint32_t **d_ptr)
+{
+	uint32_t r_addr, s_addr, s_value, r_value, poll_wait, poll_mask;
+	uint16_t s_stride, i;
+	uint32_t *data_ptr = *d_ptr;
+	uint32_t rval = QLA_SUCCESS;
+	struct qla83xx_minidump_entry_pollrd *pollrd_hdr;
+
+	pollrd_hdr = (struct qla83xx_minidump_entry_pollrd *)entry_hdr;
+	s_addr = le32_to_cpu(pollrd_hdr->select_addr);
+	r_addr = le32_to_cpu(pollrd_hdr->read_addr);
+	s_value = le32_to_cpu(pollrd_hdr->select_value);
+	s_stride = le32_to_cpu(pollrd_hdr->select_value_stride);
+
+	poll_wait = le32_to_cpu(pollrd_hdr->poll_wait);
+	poll_mask = le32_to_cpu(pollrd_hdr->poll_mask);
+
+	for (i = 0; i < le32_to_cpu(pollrd_hdr->op_count); i++) {
+		ha->isp_ops->wr_reg_indirect(ha, s_addr, s_value);
+		poll_wait = le32_to_cpu(pollrd_hdr->poll_wait);
+		while (1) {
+			ha->isp_ops->rd_reg_indirect(ha, s_addr, &r_value);
+
+			if ((r_value & poll_mask) != 0) {
+				break;
+			} else {
+				msleep(1);
+				if (--poll_wait == 0) {
+					ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n",
+						   __func__);
+					rval = QLA_ERROR;
+					goto exit_process_pollrd;
+				}
+			}
+		}
+		ha->isp_ops->rd_reg_indirect(ha, r_addr, &r_value);
+		*data_ptr++ = cpu_to_le32(s_value);
+		*data_ptr++ = cpu_to_le32(r_value);
+		s_value += s_stride;
+	}
+
+	*d_ptr = data_ptr;
+
+exit_process_pollrd:
+	return rval;
+}
+
+static void qla83xx_minidump_process_rdmux2(struct scsi_qla_host *ha,
+				struct qla8xxx_minidump_entry_hdr *entry_hdr,
+				uint32_t **d_ptr)
+{
+	uint32_t sel_val1, sel_val2, t_sel_val, data, i;
+	uint32_t sel_addr1, sel_addr2, sel_val_mask, read_addr;
+	struct qla83xx_minidump_entry_rdmux2 *rdmux2_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	rdmux2_hdr = (struct qla83xx_minidump_entry_rdmux2 *)entry_hdr;
+	sel_val1 = le32_to_cpu(rdmux2_hdr->select_value_1);
+	sel_val2 = le32_to_cpu(rdmux2_hdr->select_value_2);
+	sel_addr1 = le32_to_cpu(rdmux2_hdr->select_addr_1);
+	sel_addr2 = le32_to_cpu(rdmux2_hdr->select_addr_2);
+	sel_val_mask = le32_to_cpu(rdmux2_hdr->select_value_mask);
+	read_addr = le32_to_cpu(rdmux2_hdr->read_addr);
+
+	for (i = 0; i < rdmux2_hdr->op_count; i++) {
+		ha->isp_ops->wr_reg_indirect(ha, sel_addr1, sel_val1);
+		t_sel_val = sel_val1 & sel_val_mask;
+		*data_ptr++ = cpu_to_le32(t_sel_val);
+
+		ha->isp_ops->wr_reg_indirect(ha, sel_addr2, t_sel_val);
+		ha->isp_ops->rd_reg_indirect(ha, read_addr, &data);
+
+		*data_ptr++ = cpu_to_le32(data);
+
+		ha->isp_ops->wr_reg_indirect(ha, sel_addr1, sel_val2);
+		t_sel_val = sel_val2 & sel_val_mask;
+		*data_ptr++ = cpu_to_le32(t_sel_val);
+
+		ha->isp_ops->wr_reg_indirect(ha, sel_addr2, t_sel_val);
+		ha->isp_ops->rd_reg_indirect(ha, read_addr, &data);
+
+		*data_ptr++ = cpu_to_le32(data);
+
+		sel_val1 += rdmux2_hdr->select_value_stride;
+		sel_val2 += rdmux2_hdr->select_value_stride;
+	}
+
+	*d_ptr = data_ptr;
+}
+
+static uint32_t qla83xx_minidump_process_pollrdmwr(struct scsi_qla_host *ha,
+				struct qla8xxx_minidump_entry_hdr *entry_hdr,
+				uint32_t **d_ptr)
+{
+	uint32_t poll_wait, poll_mask, r_value, data;
+	uint32_t addr_1, addr_2, value_1, value_2;
+	uint32_t *data_ptr = *d_ptr;
+	uint32_t rval = QLA_SUCCESS;
+	struct qla83xx_minidump_entry_pollrdmwr *poll_hdr;
+
+	poll_hdr = (struct qla83xx_minidump_entry_pollrdmwr *)entry_hdr;
+	addr_1 = le32_to_cpu(poll_hdr->addr_1);
+	addr_2 = le32_to_cpu(poll_hdr->addr_2);
+	value_1 = le32_to_cpu(poll_hdr->value_1);
+	value_2 = le32_to_cpu(poll_hdr->value_2);
+	poll_mask = le32_to_cpu(poll_hdr->poll_mask);
+
+	ha->isp_ops->wr_reg_indirect(ha, addr_1, value_1);
+
+	poll_wait = le32_to_cpu(poll_hdr->poll_wait);
+	while (1) {
+		ha->isp_ops->rd_reg_indirect(ha, addr_1, &r_value);
+
+		if ((r_value & poll_mask) != 0) {
+			break;
+		} else {
+			msleep(1);
+			if (--poll_wait == 0) {
+				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT_1\n",
+					   __func__);
+				rval = QLA_ERROR;
+				goto exit_process_pollrdmwr;
+			}
+		}
+	}
+
+	ha->isp_ops->rd_reg_indirect(ha, addr_2, &data);
+	data &= le32_to_cpu(poll_hdr->modify_mask);
+	ha->isp_ops->wr_reg_indirect(ha, addr_2, data);
+	ha->isp_ops->wr_reg_indirect(ha, addr_1, value_2);
+
+	poll_wait = le32_to_cpu(poll_hdr->poll_wait);
+	while (1) {
+		ha->isp_ops->rd_reg_indirect(ha, addr_1, &r_value);
+
+		if ((r_value & poll_mask) != 0) {
+			break;
+		} else {
+			msleep(1);
+			if (--poll_wait == 0) {
+				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT_2\n",
+					   __func__);
+				rval = QLA_ERROR;
+				goto exit_process_pollrdmwr;
+			}
+		}
+	}
+
+	*data_ptr++ = cpu_to_le32(addr_2);
+	*data_ptr++ = cpu_to_le32(data);
+	*d_ptr = data_ptr;
+
+exit_process_pollrdmwr:
+	return rval;
+}
+
+static uint32_t qla4_83xx_minidump_process_rdrom(struct scsi_qla_host *ha,
+				struct qla8xxx_minidump_entry_hdr *entry_hdr,
+				uint32_t **d_ptr)
+{
+	uint32_t fl_addr, u32_count, rval;
+	struct qla8xxx_minidump_entry_rdrom *rom_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	rom_hdr = (struct qla8xxx_minidump_entry_rdrom *)entry_hdr;
+	fl_addr = le32_to_cpu(rom_hdr->read_addr);
+	u32_count = le32_to_cpu(rom_hdr->read_data_size)/sizeof(uint32_t);
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "[%s]: fl_addr: 0x%x, count: 0x%x\n",
+			  __func__, fl_addr, u32_count));
+
+	rval = qla4_83xx_lockless_flash_read_u32(ha, fl_addr,
+						 (u8 *)(data_ptr), u32_count);
+
+	if (rval == QLA_ERROR) {
+		ql4_printk(KERN_ERR, ha, "%s: Flash Read Error,Count=%d\n",
+			   __func__, u32_count);
+		goto exit_process_rdrom;
+	}
+
+	data_ptr += u32_count;
+	*d_ptr = data_ptr;
+
+exit_process_rdrom:
+	return rval;
+}
+
 /**
  * qla4_8xxx_collect_md_data - Retrieve firmware minidump data.
  * @ha: pointer to adapter structure
@@ -2151,6 +2400,10 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
 					(((uint8_t *)ha->fw_dump_tmplt_hdr) +
 					 tmplt_hdr->first_entry_offset);
 
+	if (is_qla8032(ha))
+		tmplt_hdr->saved_state_array[QLA83XX_SS_OCM_WNDREG_INDEX] =
+					tmplt_hdr->ocm_window_reg[ha->func_num];
+
 	/* Walk through the entry headers - validate/perform required action */
 	for (i = 0; i < num_entry_hdr; i++) {
 		if (data_collected >= ha->fw_dump_size) {
@@ -2201,8 +2454,18 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
 			break;
 		case QLA8XXX_BOARD:
 		case QLA8XXX_RDROM:
-			qla4_82xx_minidump_process_rdrom(ha, entry_hdr,
-							 &data_ptr);
+			if (is_qla8022(ha)) {
+				qla4_82xx_minidump_process_rdrom(ha, entry_hdr,
+								 &data_ptr);
+			} else if (is_qla8032(ha)) {
+				rval = qla4_83xx_minidump_process_rdrom(ha,
+								    entry_hdr,
+								    &data_ptr);
+				if (rval != QLA_SUCCESS)
+					qla4_8xxx_mark_entry_skipped(ha,
+								     entry_hdr,
+								     i);
+			}
 			break;
 		case QLA8XXX_L2DTG:
 		case QLA8XXX_L2ITG:
@@ -2215,6 +2478,8 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
 				goto md_failed;
 			}
 			break;
+		case QLA8XXX_L1DTG:
+		case QLA8XXX_L1ITG:
 		case QLA8XXX_L1DAT:
 		case QLA8XXX_L1INS:
 			qla4_8xxx_minidump_process_l1cache(ha, entry_hdr,
@@ -2232,6 +2497,34 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
 			qla4_8xxx_minidump_process_queue(ha, entry_hdr,
 							 &data_ptr);
 			break;
+		case QLA83XX_POLLRD:
+			if (!is_qla8032(ha)) {
+				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
+				break;
+			}
+			rval = qla83xx_minidump_process_pollrd(ha, entry_hdr,
+							       &data_ptr);
+			if (rval != QLA_SUCCESS)
+				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
+			break;
+		case QLA83XX_RDMUX2:
+			if (!is_qla8032(ha)) {
+				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
+				break;
+			}
+			qla83xx_minidump_process_rdmux2(ha, entry_hdr,
+							&data_ptr);
+			break;
+		case QLA83XX_POLLRDMWR:
+			if (!is_qla8032(ha)) {
+				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
+				break;
+			}
+			rval = qla83xx_minidump_process_pollrdmwr(ha, entry_hdr,
+								  &data_ptr);
+			if (rval != QLA_SUCCESS)
+				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
+			break;
 		case QLA8XXX_RDNOP:
 		default:
 			qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
@@ -2283,7 +2576,7 @@ static void qla4_8xxx_uevent_emit(struct scsi_qla_host *ha, u32 code)
 	kobject_uevent_env(&(&ha->pdev->dev)->kobj, KOBJ_CHANGE, envp);
 }
 
-static void qla4_8xxx_get_minidump(struct scsi_qla_host *ha)
+void qla4_8xxx_get_minidump(struct scsi_qla_host *ha)
 {
 	if (ql4xenablemd && test_bit(AF_FW_RECOVERY, &ha->flags) &&
 	    !test_bit(AF_82XX_FW_DUMPED, &ha->flags)) {
@@ -2303,12 +2596,11 @@ static void qla4_8xxx_get_minidump(struct scsi_qla_host *ha)
  *
  * Note: IDC lock must be held upon entry
  **/
-static int
-qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
+int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
 {
 	int rval = QLA_ERROR;
 	int i, timeout;
-	uint32_t old_count, count;
+	uint32_t old_count, count, idc_ctrl;
 	int need_reset = 0, peg_stuck = 1;
 
 	need_reset = ha->isp_ops->need_reset(ha);
@@ -2351,8 +2643,24 @@ dev_initialize:
 	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
 			    QLA8XXX_DEV_INITIALIZING);
 
+	/*
+	 * For ISP8324, if IDC_CTRL GRACEFUL_RESET_BIT1 is set, reset it after
+	 * device goes to INIT state.
+	 */
+	if (is_qla8032(ha)) {
+		idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
+		if (idc_ctrl & GRACEFUL_RESET_BIT1) {
+			qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
+					 (idc_ctrl & ~GRACEFUL_RESET_BIT1));
+			set_bit(AF_83XX_NO_FW_DUMP, &ha->flags);
+		}
+	}
+
 	ha->isp_ops->idc_unlock(ha);
-	qla4_8xxx_get_minidump(ha);
+
+	if (is_qla8022(ha))
+		qla4_8xxx_get_minidump(ha);
+
 	rval = ha->isp_ops->restart_firmware(ha);
 	ha->isp_ops->idc_lock(ha);
 
@@ -2487,14 +2795,77 @@ static void qla4_82xx_set_idc_ver(struct scsi_qla_host *ha)
 	}
 }
 
-static void qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha)
+static int qla4_83xx_set_idc_ver(struct scsi_qla_host *ha)
 {
-	if (!test_bit(AF_INIT_DONE, &ha->flags)) {
-		ha->isp_ops->idc_lock(ha);
-		qla4_8xxx_set_drv_active(ha);
+	int idc_ver;
+	uint32_t drv_active;
+	int rval = QLA_SUCCESS;
+
+	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
+	if (drv_active == (1 << ha->func_num)) {
+		idc_ver = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION);
+		idc_ver &= (~0xFF);
+		idc_ver |= QLA83XX_IDC_VER_MAJ_VALUE;
+		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION, idc_ver);
+		ql4_printk(KERN_INFO, ha,
+			   "%s: IDC version updated to %d\n", __func__,
+			   QLA83XX_IDC_VER_MAJ_VALUE);
+	} else {
+		idc_ver = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION);
+		idc_ver &= 0xFF;
+		if (QLA83XX_IDC_VER_MAJ_VALUE != idc_ver) {
+			ql4_printk(KERN_INFO, ha,
+				   "%s: qla4xxx driver IDC version %d is not compatible with IDC version %d of other drivers!\n",
+				   __func__, QLA83XX_IDC_VER_MAJ_VALUE,
+				   idc_ver);
+			rval = QLA_ERROR;
+			goto exit_set_idc_ver;
+		}
+	}
+
+	/* Update IDC_MINOR_VERSION */
+	idc_ver = qla4_83xx_rd_reg(ha, QLA83XX_CRB_IDC_VER_MINOR);
+	idc_ver &= ~(0x03 << (ha->func_num * 2));
+	idc_ver |= (QLA83XX_IDC_VER_MIN_VALUE << (ha->func_num * 2));
+	qla4_83xx_wr_reg(ha, QLA83XX_CRB_IDC_VER_MINOR, idc_ver);
+
+exit_set_idc_ver:
+	return rval;
+}
+
+static int qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha)
+{
+	uint32_t drv_active;
+	int rval = QLA_SUCCESS;
+
+	if (test_bit(AF_INIT_DONE, &ha->flags))
+		goto exit_update_idc_reg;
+
+	ha->isp_ops->idc_lock(ha);
+	qla4_8xxx_set_drv_active(ha);
+
+	/*
+	 * If we are the first driver to load and
+	 * ql4xdontresethba is not set, clear IDC_CTRL BIT0.
+	 */
+	if (is_qla8032(ha)) {
+		drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
+		if ((drv_active == (1 << ha->func_num)) && !ql4xdontresethba)
+			qla4_83xx_clear_idc_dontreset(ha);
+	}
+
+	if (is_qla8022(ha)) {
 		qla4_82xx_set_idc_ver(ha);
-		ha->isp_ops->idc_unlock(ha);
+	} else if (is_qla8032(ha)) {
+		rval = qla4_83xx_set_idc_ver(ha);
+		if (rval == QLA_ERROR)
+			qla4_8xxx_clear_drv_active(ha);
 	}
+
+	ha->isp_ops->idc_unlock(ha);
+
+exit_update_idc_reg:
+	return rval;
 }
 
 /**
@@ -2509,7 +2880,9 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha)
 	int rval = QLA_SUCCESS;
 	unsigned long dev_init_timeout;
 
-	qla4_8xxx_update_idc_reg(ha);
+	rval = qla4_8xxx_update_idc_reg(ha);
+	if (rval == QLA_ERROR)
+		goto exit_state_handler;
 
 	dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
 	DEBUG2(ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n",
@@ -2550,16 +2923,25 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha)
 			ha->isp_ops->idc_lock(ha);
 			break;
 		case QLA8XXX_DEV_NEED_RESET:
-			if (!ql4xdontresethba) {
-				qla4_82xx_need_reset_handler(ha);
-				/* Update timeout value after need
-				 * reset handler */
-				dev_init_timeout = jiffies +
-					(ha->nx_dev_init_timeout * HZ);
-			} else {
-				ha->isp_ops->idc_unlock(ha);
-				msleep(1000);
-				ha->isp_ops->idc_lock(ha);
+			/*
+			 * For ISP8324, if NEED_RESET is set by any driver,
+			 * it should be honored, irrespective of IDC_CTRL
+			 * DONTRESET_BIT0
+			 */
+			if (is_qla8032(ha)) {
+				qla4_83xx_need_reset_handler(ha);
+			} else if (is_qla8022(ha)) {
+				if (!ql4xdontresethba) {
+					qla4_82xx_need_reset_handler(ha);
+					/* Update timeout value after need
+					 * reset handler */
+					dev_init_timeout = jiffies +
+						(ha->nx_dev_init_timeout * HZ);
+				} else {
+					ha->isp_ops->idc_unlock(ha);
+					msleep(1000);
+					ha->isp_ops->idc_lock(ha);
+				}
 			}
 			break;
 		case QLA8XXX_DEV_NEED_QUIESCENT:
@@ -2587,6 +2969,7 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha)
 	}
 exit:
 	ha->isp_ops->idc_unlock(ha);
+exit_state_handler:
 	return rval;
 }
 
@@ -2595,8 +2978,13 @@ int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
 	int retval;
 
 	/* clear the interrupt */
-	writel(0, &ha->qla4_82xx_reg->host_int);
-	readl(&ha->qla4_82xx_reg->host_int);
+	if (is_qla8032(ha)) {
+		writel(0, &ha->qla4_83xx_reg->risc_intr);
+		readl(&ha->qla4_83xx_reg->risc_intr);
+	} else if (is_qla8022(ha)) {
+		writel(0, &ha->qla4_82xx_reg->host_int);
+		readl(&ha->qla4_82xx_reg->host_int);
+	}
 
 	retval = qla4_8xxx_device_state_handler(ha);
 
@@ -2695,7 +3083,7 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
 	const char *loc, *locations[] = { "DEF", "FLT" };
 	uint16_t *wptr;
 	uint16_t cnt, chksum;
-	uint32_t start;
+	uint32_t start, status;
 	struct qla_flt_header *flt;
 	struct qla_flt_region *region;
 	struct ql82xx_hw_data *hw = &ha->hw;
@@ -2704,8 +3092,18 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
 	wptr = (uint16_t *)ha->request_ring;
 	flt = (struct qla_flt_header *)ha->request_ring;
 	region = (struct qla_flt_region *)&flt[1];
-	qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
-			flt_addr << 2, OPTROM_BURST_SIZE);
+
+	if (is_qla8022(ha)) {
+		qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
+					   flt_addr << 2, OPTROM_BURST_SIZE);
+	} else if (is_qla8032(ha)) {
+		status = qla4_83xx_flash_read_u32(ha, flt_addr << 2,
+						  (uint8_t *)ha->request_ring,
+						  0x400);
+		if (status != QLA_SUCCESS)
+			goto no_flash_data;
+	}
+
 	if (*wptr == __constant_cpu_to_le16(0xffff))
 		goto no_flash_data;
 	if (flt->version != __constant_cpu_to_le16(1)) {
@@ -2918,8 +3316,12 @@ qla4_8xxx_get_flash_info(struct scsi_qla_host *ha)
 		return ret;
 
 	qla4_8xxx_get_flt_info(ha, flt_addr);
-	qla4_82xx_get_fdt_info(ha);
-	qla4_82xx_get_idc_param(ha);
+	if (is_qla8022(ha)) {
+		qla4_82xx_get_fdt_info(ha);
+		qla4_82xx_get_idc_param(ha);
+	} else if (is_qla8032(ha)) {
+		qla4_83xx_get_idc_param(ha);
+	}
 
 	return QLA_SUCCESS;
 }
@@ -3063,8 +3465,7 @@ exit_validate_mac82:
 
 /* Interrupt handling helpers. */
 
-static int
-qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha)
+int qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha)
 {
 	uint32_t mbox_cmd[MBOX_REG_COUNT];
 	uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -3085,8 +3486,7 @@ qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha)
 	return QLA_SUCCESS;
 }
 
-static int
-qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha)
+int qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha)
 {
 	uint32_t mbox_cmd[MBOX_REG_COUNT];
 	uint32_t mbox_sts[MBOX_REG_COUNT];
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
index 1894de0..ec5cbd0 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.h
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -25,6 +25,8 @@
 #define CRB_RCVPEG_STATE		QLA82XX_REG(0x13c)
 #define CRB_DMA_SHIFT			QLA82XX_REG(0xcc)
 #define CRB_TEMP_STATE			QLA82XX_REG(0x1b4)
+#define CRB_CMDPEG_CHECK_RETRY_COUNT	60
+#define CRB_CMDPEG_CHECK_DELAY		500
 
 #define qla82xx_get_temp_val(x)		((x) >> 16)
 #define qla82xx_get_temp_state(x)	((x) & 0xffff)
@@ -508,6 +510,7 @@ enum {
 
 #define QLA82XX_P2_ADDR_QDR_NET_MAX	(0x00000003001fffffULL)
 #define QLA82XX_P3_ADDR_QDR_NET_MAX	(0x0000000303ffffffULL)
+#define QLA8XXX_ADDR_QDR_NET_MAX	(0x0000000307ffffffULL)
 
 #define QLA82XX_PCI_CRBSPACE		(unsigned long)0x06000000
 #define QLA82XX_PCI_DIRECT_CRB		(unsigned long)0x04400000
@@ -852,9 +855,13 @@ struct crb_addr_pair {
 #define QLA8XXX_L2ITG	22
 #define QLA8XXX_L2DAT	23
 #define QLA8XXX_L2INS	24
+#define QLA83XX_POLLRD	35
+#define QLA83XX_RDMUX2	36
+#define QLA83XX_POLLRDMWR  37
 #define QLA8XXX_RDROM	71
 #define QLA8XXX_RDMEM	72
 #define QLA8XXX_CNTRL	98
+#define QLA83XX_TLHDR	99
 #define QLA8XXX_RDEND	255
 
 /* Opcodes for Control Entries.
@@ -1007,6 +1014,16 @@ struct qla8xxx_minidump_entry_queue {
 #define MD_MIU_TEST_AGT_ADDR_LO			0x41000094
 #define MD_MIU_TEST_AGT_ADDR_HI			0x41000098
 
+#define MD_MIU_TEST_AGT_WRDATA_LO		0x410000A0
+#define MD_MIU_TEST_AGT_WRDATA_HI		0x410000A4
+#define MD_MIU_TEST_AGT_WRDATA_ULO		0x410000B0
+#define MD_MIU_TEST_AGT_WRDATA_UHI		0x410000B4
+
+#define MD_MIU_TEST_AGT_RDDATA_LO		0x410000A8
+#define MD_MIU_TEST_AGT_RDDATA_HI		0x410000AC
+#define MD_MIU_TEST_AGT_RDDATA_ULO		0x410000B8
+#define MD_MIU_TEST_AGT_RDDATA_UHI		0x410000BC
+
 static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8,
 				0x410000AC, 0x410000B8, 0x410000BC };
 #endif
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 519f666..3e0e5de 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -18,6 +18,7 @@
 #include "ql4_glbl.h"
 #include "ql4_dbg.h"
 #include "ql4_inline.h"
+#include "ql4_83xx.h"
 
 /*
  * Driver version
@@ -2315,8 +2316,17 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
 		if (ha->nx_pcibase)
 			iounmap(
 			    (struct device_reg_82xx __iomem *)ha->nx_pcibase);
-	} else if (ha->reg)
+	} else if (is_qla8032(ha)) {
+		if (ha->nx_pcibase)
+			iounmap(
+			    (struct device_reg_83xx __iomem *)ha->nx_pcibase);
+	} else if (ha->reg) {
 		iounmap(ha->reg);
+	}
+
+	if (ha->reset_tmplt.buff)
+		vfree(ha->reset_tmplt.buff);
+
 	pci_release_regions(ha->pdev);
 }
 
@@ -2454,7 +2464,6 @@ static int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
 static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
 {
 	uint32_t fw_heartbeat_counter;
-	uint32_t halt_status1, halt_status2;
 	int status = QLA_SUCCESS;
 
 	fw_heartbeat_counter = qla4_8xxx_rd_direct(ha,
@@ -2472,28 +2481,7 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
 		/* FW not alive after 2 seconds */
 		if (ha->seconds_since_last_heartbeat == 2) {
 			ha->seconds_since_last_heartbeat = 0;
-			halt_status1 = qla4_8xxx_rd_direct(ha,
-						QLA8XXX_PEG_HALT_STATUS1);
-			halt_status2 = qla4_8xxx_rd_direct(ha,
-						QLA8XXX_PEG_HALT_STATUS2);
-
-			ql4_printk(KERN_INFO, ha,
-				   "scsi(%ld): %s, Dumping hw/fw registers:\n "
-				   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:"
-				   " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:"
-				   " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:"
-				   " 0x%x,\n PEG_NET_4_PC: 0x%x\n", ha->host_no,
-				   __func__, halt_status1, halt_status2,
-				   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 +
-						   0x3c),
-				   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 +
-						   0x3c),
-				   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 +
-						   0x3c),
-				   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 +
-						   0x3c),
-				   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 +
-						   0x3c));
+			qla4_8xxx_dump_peg_reg(ha);
 			status = QLA_ERROR;
 		}
 	} else
@@ -2503,6 +2491,48 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
 	return status;
 }
 
+static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
+{
+	uint32_t halt_status;
+	int halt_status_unrecoverable = 0;
+
+	halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1);
+
+	if (is_qla8022(ha)) {
+		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
+			   __func__);
+		qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
+				CRB_NIU_XG_PAUSE_CTL_P0 |
+				CRB_NIU_XG_PAUSE_CTL_P1);
+
+		if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
+			ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n",
+				   __func__);
+		if (halt_status & HALT_STATUS_UNRECOVERABLE)
+			halt_status_unrecoverable = 1;
+	} else if (is_qla8032(ha)) {
+		if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
+			ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
+				   __func__);
+		else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE)
+			halt_status_unrecoverable = 1;
+	}
+
+	/*
+	 * Since we cannot change dev_state in interrupt context,
+	 * set appropriate DPC flag then wakeup DPC
+	 */
+	if (halt_status_unrecoverable) {
+		set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
+	} else {
+		ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n",
+			   __func__);
+		set_bit(DPC_RESET_HA, &ha->dpc_flags);
+	}
+	qla4xxx_mailbox_premature_completion(ha);
+	qla4xxx_wake_dpc(ha);
+}
+
 /**
  * qla4_8xxx_watchdog - Poll dev state
  * @ha: Pointer to host adapter structure.
@@ -2511,7 +2541,7 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
  **/
 void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
 {
-	uint32_t dev_state, halt_status;
+	uint32_t dev_state;
 
 	/* don't poll if reset is going on */
 	if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
@@ -2520,16 +2550,18 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
 		dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
 
 		if (qla4_8xxx_check_temp(ha)) {
-			ql4_printk(KERN_INFO, ha, "disabling pause"
-				   " transmit on port 0 & 1.\n");
-			qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
-					CRB_NIU_XG_PAUSE_CTL_P0 |
-					CRB_NIU_XG_PAUSE_CTL_P1);
+			if (is_qla8022(ha)) {
+				ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n");
+				qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
+						CRB_NIU_XG_PAUSE_CTL_P0 |
+						CRB_NIU_XG_PAUSE_CTL_P1);
+			}
 			set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
 			qla4xxx_wake_dpc(ha);
 		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
-		    !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
-			if (!ql4xdontresethba) {
+			   !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+			if (is_qla8032(ha) ||
+			    (is_qla8022(ha) && !ql4xdontresethba)) {
 				ql4_printk(KERN_INFO, ha, "%s: HW State: "
 				    "NEED RESET!\n", __func__);
 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -2543,36 +2575,8 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
 			qla4xxx_wake_dpc(ha);
 		} else  {
 			/* Check firmware health */
-			if (qla4_8xxx_check_fw_alive(ha)) {
-				ql4_printk(KERN_INFO, ha, "disabling pause"
-					   " transmit on port 0 & 1.\n");
-				qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
-						CRB_NIU_XG_PAUSE_CTL_P0 |
-						CRB_NIU_XG_PAUSE_CTL_P1);
-				halt_status = qla4_8xxx_rd_direct(ha,
-						   QLA8XXX_PEG_HALT_STATUS1);
-
-				if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
-					ql4_printk(KERN_ERR, ha, "%s:"
-						   " Firmware aborted with"
-						   " error code 0x00006700."
-						   " Device is being reset\n",
-						   __func__);
-
-				/* Since we cannot change dev_state in interrupt
-				 * context, set appropriate DPC flag then wakeup
-				 * DPC */
-				if (halt_status & HALT_STATUS_UNRECOVERABLE)
-					set_bit(DPC_HA_UNRECOVERABLE,
-						&ha->dpc_flags);
-				else {
-					ql4_printk(KERN_INFO, ha, "%s: detect "
-						   "abort needed!\n", __func__);
-					set_bit(DPC_RESET_HA, &ha->dpc_flags);
-				}
-				qla4xxx_mailbox_premature_completion(ha);
-				qla4xxx_wake_dpc(ha);
-			}
+			if (qla4_8xxx_check_fw_alive(ha))
+				qla4_8xxx_process_fw_error(ha);
 		}
 	}
 }
@@ -2654,9 +2658,8 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
 	if (!pci_channel_offline(ha->pdev))
 		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
 
-	if (is_qla8022(ha)) {
+	if (is_qla80XX(ha))
 		qla4_8xxx_watchdog(ha);
-	}
 
 	if (is_qla40XX(ha)) {
 		/* Check for heartbeat interval. */
@@ -2955,9 +2958,9 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
 		goto recover_ha_init_adapter;
 	}
 
-	/* For the ISP-82xx adapter, issue a stop_firmware if invoked
+	/* For the ISP-8xxx adapter, issue a stop_firmware if invoked
 	 * from eh_host_reset or ioctl module */
-	if (is_qla8022(ha) && !reset_chip &&
+	if (is_qla80XX(ha) && !reset_chip &&
 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
 
 		DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -2980,13 +2983,13 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
 	}
 
 	/* Issue full chip reset if recovering from a catastrophic error,
-	 * or if stop_firmware fails for ISP-82xx.
+	 * or if stop_firmware fails for ISP-8xxx.
 	 * This is the default case for ISP-4xxx */
 	if (is_qla40XX(ha) || reset_chip) {
 		if (is_qla40XX(ha))
 			goto chip_reset;
 
-		/* Check if 82XX firmware is alive or not
+		/* Check if 8XXX firmware is alive or not
 		 * We may have arrived here from NEED_RESET
 		 * detection only */
 		if (test_bit(AF_FW_RECOVERY, &ha->flags))
@@ -3041,7 +3044,7 @@ recover_ha_init_adapter:
 		 * Since we don't want to block the DPC for too long
 		 * with multiple resets in the same thread,
 		 * utilize DPC to retry */
-		if (is_qla8022(ha)) {
+		if (is_qla80XX(ha)) {
 			ha->isp_ops->idc_lock(ha);
 			dev_state = qla4_8xxx_rd_direct(ha,
 							QLA8XXX_CRB_DEV_STATE);
@@ -3386,7 +3389,7 @@ static void qla4xxx_do_dpc(struct work_struct *work)
 	/* post events to application */
 	qla4xxx_do_work(ha);
 
-	if (is_qla8022(ha)) {
+	if (is_qla80XX(ha)) {
 		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
 			ha->isp_ops->idc_lock(ha);
 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
@@ -3404,7 +3407,8 @@ static void qla4xxx_do_dpc(struct work_struct *work)
 	    (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
 	    test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
-		if (ql4xdontresethba) {
+		if ((is_qla8022(ha) && ql4xdontresethba) ||
+		    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
 			DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
 			    ha->host_no, __func__));
 			clear_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -3514,7 +3518,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
 	/* Put firmware in known state */
 	ha->isp_ops->reset_firmware(ha);
 
-	if (is_qla8022(ha)) {
+	if (is_qla80XX(ha)) {
 		ha->isp_ops->idc_lock(ha);
 		qla4_8xxx_clear_drv_active(ha);
 		ha->isp_ops->idc_unlock(ha);
@@ -3564,16 +3568,20 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
 	/* Mapping of IO base pointer, door bell read and write pointer */
 
 	/* mapping of IO base pointer */
-	ha->qla4_82xx_reg =
-	    (struct device_reg_82xx  __iomem *)((uint8_t *)ha->nx_pcibase +
-	    0xbc000 + (ha->pdev->devfn << 11));
+	if (is_qla8022(ha)) {
+		ha->qla4_82xx_reg = (struct device_reg_82xx  __iomem *)
+				    ((uint8_t *)ha->nx_pcibase + 0xbc000 +
+				     (ha->pdev->devfn << 11));
+		ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
+				    QLA82XX_CAM_RAM_DB2);
+	} else if (is_qla8032(ha)) {
+		ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
+				    ((uint8_t *)ha->nx_pcibase);
+	}
 
 	db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
 	db_len = pci_resource_len(pdev, 4);
 
-	ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
-	    QLA82XX_CAM_RAM_DB2);
-
 	return 0;
 iospace_error_exit:
 	return -ENOMEM;
@@ -3693,6 +3701,34 @@ static struct isp_operations qla4_82xx_isp_ops = {
 	.process_mailbox_interrupt = qla4_82xx_process_mbox_intr,
 };
 
+static struct isp_operations qla4_83xx_isp_ops = {
+	.iospace_config		= qla4_8xxx_iospace_config,
+	.pci_config		= qla4_8xxx_pci_config,
+	.disable_intrs		= qla4_83xx_disable_intrs,
+	.enable_intrs		= qla4_83xx_enable_intrs,
+	.start_firmware		= qla4_8xxx_load_risc,
+	.restart_firmware	= qla4_83xx_start_firmware,
+	.intr_handler		= qla4_83xx_intr_handler,
+	.interrupt_service_routine = qla4_83xx_interrupt_service_routine,
+	.need_reset		= qla4_8xxx_need_reset,
+	.reset_chip		= qla4_83xx_isp_reset,
+	.reset_firmware		= qla4_8xxx_stop_firmware,
+	.queue_iocb		= qla4_83xx_queue_iocb,
+	.complete_iocb		= qla4_83xx_complete_iocb,
+	.rd_shdw_req_q_out	= qla4_83xx_rd_shdw_req_q_out,
+	.rd_shdw_rsp_q_in	= qla4_83xx_rd_shdw_rsp_q_in,
+	.get_sys_info		= qla4_8xxx_get_sys_info,
+	.rd_reg_direct		= qla4_83xx_rd_reg,
+	.wr_reg_direct		= qla4_83xx_wr_reg,
+	.rd_reg_indirect	= qla4_83xx_rd_reg_indirect,
+	.wr_reg_indirect	= qla4_83xx_wr_reg_indirect,
+	.idc_lock		= qla4_83xx_drv_lock,
+	.idc_unlock		= qla4_83xx_drv_unlock,
+	.rom_lock_recovery	= qla4_83xx_rom_lock_recovery,
+	.queue_mailbox_command	= qla4_83xx_queue_mbox_cmd,
+	.process_mailbox_interrupt = qla4_83xx_process_mbox_intr,
+};
+
 uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
 {
 	return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
@@ -3703,6 +3739,11 @@ uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
 	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
 }
 
+uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
+{
+	return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->req_q_out));
+}
+
 uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
 {
 	return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
@@ -3713,6 +3754,11 @@ uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
 	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
 }
 
+uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
+{
+	return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->rsp_q_in));
+}
+
 static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
 {
 	struct scsi_qla_host *ha = data;
@@ -5085,6 +5131,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
 	ha->pdev = pdev;
 	ha->host = host;
 	ha->host_no = host->host_no;
+	ha->func_num = PCI_FUNC(ha->pdev->devfn);
 
 	pci_enable_pcie_error_reporting(pdev);
 
@@ -5092,24 +5139,28 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
 	if (is_qla8022(ha)) {
 		ha->isp_ops = &qla4_82xx_isp_ops;
 		ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl;
-		rwlock_init(&ha->hw_lock);
 		ha->qdr_sn_window = -1;
 		ha->ddr_mn_window = -1;
 		ha->curr_window = 255;
-		ha->func_num = PCI_FUNC(ha->pdev->devfn);
 		nx_legacy_intr = &legacy_intr[ha->func_num];
 		ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
 		ha->nx_legacy_intr.tgt_status_reg =
 			nx_legacy_intr->tgt_status_reg;
 		ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
 		ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
+	} else if (is_qla8032(ha)) {
+		ha->isp_ops = &qla4_83xx_isp_ops;
+		ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
 	} else {
 		ha->isp_ops = &qla4xxx_isp_ops;
 	}
 
-	/* Set EEH reset type to fundamental if required by hba */
-	if (is_qla8022(ha))
+	if (is_qla80XX(ha)) {
+		rwlock_init(&ha->hw_lock);
+		ha->pf_bit = ha->func_num << 16;
+		/* Set EEH reset type to fundamental if required by hba */
 		pdev->needs_freset = 1;
+	}
 
 	/* Configure PCI I/O space. */
 	ret = ha->isp_ops->iospace_config(ha);
@@ -5165,8 +5216,20 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
 	if (ret)
 		goto probe_failed;
 
-	if (is_qla8022(ha))
-		(void) qla4_8xxx_get_flash_info(ha);
+	if (is_qla80XX(ha))
+		qla4_8xxx_get_flash_info(ha);
+
+	if (is_qla8032(ha)) {
+		qla4_83xx_read_reset_template(ha);
+		/*
+		 * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
+		 * If DONRESET_BIT0 is set, drivers should not set dev_state
+		 * to NEED_RESET. But if NEED_RESET is set, drivers should
+		 * should honor the reset.
+		 */
+		if (ql4xdontresethba == 1)
+			qla4_83xx_set_idc_dontreset(ha);
+	}
 
 	/*
 	 * Initialize the Host adapter request/response queues and
@@ -5177,7 +5240,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
 	while ((!test_bit(AF_ONLINE, &ha->flags)) &&
 	    init_retry_count++ < MAX_INIT_RETRIES) {
 
-		if (is_qla8022(ha)) {
+		if (is_qla80XX(ha)) {
 			ha->isp_ops->idc_lock(ha);
 			dev_state = qla4_8xxx_rd_direct(ha,
 							QLA82XX_CRB_DEV_STATE);
@@ -5201,7 +5264,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
 	if (!test_bit(AF_ONLINE, &ha->flags)) {
 		ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
 
-		if (is_qla8022(ha) && ql4xdontresethba) {
+		if ((is_qla8022(ha) && ql4xdontresethba) ||
+		    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
 			/* Put the device in failed state. */
 			DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
 			ha->isp_ops->idc_lock(ha);
@@ -5233,7 +5297,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
 		goto remove_host;
 	}
 
-	/* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc
+	/*
+	 * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc
 	 * (which is called indirectly by qla4xxx_initialize_adapter),
 	 * so that irqs will be registered after crbinit but before
 	 * mbx_intr_enable.
@@ -5793,7 +5858,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
 
 	ha = to_qla_host(cmd->device->host);
 
-	if (ql4xdontresethba) {
+	if (is_qla8032(ha) && ql4xdontresethba)
+		qla4_83xx_set_idc_dontreset(ha);
+
+	/*
+	 * For ISP8324, if IDC_CTRL DONTRESET_BIT0 is set by other
+	 * protocol drivers, we should not set device_state to
+	 * NEED_RESET
+	 */
+	if (ql4xdontresethba ||
+	    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
 		DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
 		     ha->host_no, __func__));
 
@@ -5817,7 +5891,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
 	}
 
 	if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
-		if (is_qla8022(ha))
+		if (is_qla80XX(ha))
 			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
 		else
 			set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -5912,7 +5986,7 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
 		break;
 	case SCSI_FIRMWARE_RESET:
 		if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
-			if (is_qla8022(ha))
+			if (is_qla80XX(ha))
 				/* set firmware context reset */
 				set_bit(DPC_RESET_HA_FW_CONTEXT,
 					&ha->dpc_flags);
@@ -6150,7 +6224,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev)
 
 	ha->isp_ops->disable_intrs(ha);
 
-	if (is_qla8022(ha)) {
+	if (is_qla80XX(ha)) {
 		if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
 			ret = PCI_ERS_RESULT_RECOVERED;
 			goto exit_slot_reset;
@@ -6216,6 +6290,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
 		.subvendor      = PCI_ANY_ID,
 		.subdevice      = PCI_ANY_ID,
 	},
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP8324,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
 	{0, 0},
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
-- 
1.7.8.GIT

--
To unsubscribe from this list: 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