[SCSI] qla2xxx: Add ISP82XX support.

Enhanced the driver to support new FCoE host bus adapter.

Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index f318206..b1adeb7 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -29,6 +29,11 @@
  */
 static struct kmem_cache *srb_cachep;
 
+/*
+ * CT6 CTX allocation cache
+ */
+static struct kmem_cache *ctx_cachep;
+
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
@@ -65,6 +70,12 @@
 		"Option to enable extended error logging, "
 		"Default is 0 - no logging. 1 - log errors.");
 
+int ql2xshiftctondsd = 6;
+module_param(ql2xshiftctondsd, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xshiftctondsd,
+		"Set to control shifting of command type processing "
+		"based on total number of SG elements.");
+
 static void qla2x00_free_device(scsi_qla_host_t *);
 
 int ql2xfdmienable=1;
@@ -114,6 +125,21 @@
 		"Enables firmware ETS burst."
 		"Default is 0 - skip ETS enablement.");
 
+int ql2xdbwr;
+module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xdbwr,
+	"Option to specify scheme for request queue posting\n"
+	" 0 -- Regular doorbell.\n"
+	" 1 -- CAMRAM doorbell (faster).\n");
+
+int ql2xdontresethba;
+module_param(ql2xdontresethba, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xdontresethba,
+	"Option to specify reset behaviour\n"
+	" 0 (Default) -- Reset on failure.\n"
+	" 1 -- Do not reset on failure.\n");
+
+
 /*
  * SCSI host template entry points
  */
@@ -183,6 +209,10 @@
 static inline void
 qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval)
 {
+	/* Currently used for 82XX only. */
+	if (vha->device_flags & DFLG_DEV_FAILED)
+		return;
+
 	mod_timer(&vha->timer, jiffies + interval * HZ);
 }
 
@@ -739,7 +769,7 @@
 
 		if (sp == NULL)
 			continue;
-		if (sp->ctx)
+		if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID))
 			continue;
 		if (sp->cmd != cmd)
 			continue;
@@ -834,6 +864,24 @@
 	return status;
 }
 
+void qla82xx_wait_for_pending_commands(scsi_qla_host_t *vha)
+{
+	int cnt;
+	srb_t *sp;
+	struct req_que *req = vha->req;
+
+	DEBUG2(qla_printk(KERN_INFO, vha->hw,
+		"Waiting for pending commands\n"));
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		sp = req->outstanding_cmds[cnt];
+		if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
+			sp, WAIT_HOST) == QLA_SUCCESS) {
+			DEBUG2(qla_printk(KERN_INFO, vha->hw,
+				"Done wait for pending commands\n"));
+		}
+	}
+}
+
 static char *reset_errors[] = {
 	"HBA not online",
 	"HBA not ready",
@@ -1020,11 +1068,19 @@
 		if (qla2x00_vp_abort_isp(vha))
 			goto eh_host_reset_lock;
 	} else {
+		if (IS_QLA82XX(vha->hw)) {
+			if (!qla82xx_fcoe_ctx_reset(vha)) {
+				/* Ctx reset success */
+				ret = SUCCESS;
+				goto eh_host_reset_lock;
+			}
+			/* fall thru if ctx reset failed */
+		}
 		if (ha->wq)
 			flush_workqueue(ha->wq);
 
 		set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-		if (qla2x00_abort_isp(base_vha)) {
+		if (ha->isp_ops->abort_isp(base_vha)) {
 			clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 			/* failed. schedule dpc to try */
 			set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
@@ -1078,7 +1134,7 @@
 		}
 	}
 
-	if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) {
+	if (ha->flags.enable_lip_full_login && !IS_QLA8XXX_TYPE(ha)) {
 		ret = qla2x00_full_login_lip(vha);
 		if (ret != QLA_SUCCESS) {
 			DEBUG2_3(printk("%s(%ld): failed: "
@@ -1125,7 +1181,8 @@
 			sp = req->outstanding_cmds[cnt];
 			if (sp) {
 				req->outstanding_cmds[cnt] = NULL;
-				if (!sp->ctx) {
+				if (!sp->ctx ||
+				(sp->flags & SRB_FCP_CMND_DMA_VALID)) {
 					sp->cmd->result = res;
 					qla2x00_sp_compl(ha, sp);
 				} else {
@@ -1387,6 +1444,7 @@
 	.write_optrom		= qla2x00_write_optrom_data,
 	.get_flash_version	= qla2x00_get_flash_version,
 	.start_scsi		= qla2x00_start_scsi,
+	.abort_isp		= qla2x00_abort_isp,
 };
 
 static struct isp_operations qla2300_isp_ops = {
@@ -1422,6 +1480,7 @@
 	.write_optrom		= qla2x00_write_optrom_data,
 	.get_flash_version	= qla2x00_get_flash_version,
 	.start_scsi		= qla2x00_start_scsi,
+	.abort_isp		= qla2x00_abort_isp,
 };
 
 static struct isp_operations qla24xx_isp_ops = {
@@ -1457,6 +1516,7 @@
 	.write_optrom		= qla24xx_write_optrom_data,
 	.get_flash_version	= qla24xx_get_flash_version,
 	.start_scsi		= qla24xx_start_scsi,
+	.abort_isp		= qla2x00_abort_isp,
 };
 
 static struct isp_operations qla25xx_isp_ops = {
@@ -1492,6 +1552,7 @@
 	.write_optrom		= qla24xx_write_optrom_data,
 	.get_flash_version	= qla24xx_get_flash_version,
 	.start_scsi		= qla24xx_start_scsi,
+	.abort_isp		= qla2x00_abort_isp,
 };
 
 static struct isp_operations qla81xx_isp_ops = {
@@ -1527,6 +1588,43 @@
 	.write_optrom		= qla24xx_write_optrom_data,
 	.get_flash_version	= qla24xx_get_flash_version,
 	.start_scsi		= qla24xx_start_scsi,
+	.abort_isp		= qla2x00_abort_isp,
+};
+
+static struct isp_operations qla82xx_isp_ops = {
+	.pci_config		= qla82xx_pci_config,
+	.reset_chip		= qla82xx_reset_chip,
+	.chip_diag		= qla24xx_chip_diag,
+	.config_rings		= qla82xx_config_rings,
+	.reset_adapter		= qla24xx_reset_adapter,
+	.nvram_config		= qla81xx_nvram_config,
+	.update_fw_options	= qla24xx_update_fw_options,
+	.load_risc		= qla82xx_load_risc,
+	.pci_info_str		= qla82xx_pci_info_str,
+	.fw_version_str		= qla24xx_fw_version_str,
+	.intr_handler		= qla82xx_intr_handler,
+	.enable_intrs		= qla82xx_enable_intrs,
+	.disable_intrs		= qla82xx_disable_intrs,
+	.abort_command		= qla24xx_abort_command,
+	.target_reset		= qla24xx_abort_target,
+	.lun_reset		= qla24xx_lun_reset,
+	.fabric_login		= qla24xx_login_fabric,
+	.fabric_logout		= qla24xx_fabric_logout,
+	.calc_req_entries	= NULL,
+	.build_iocbs		= NULL,
+	.prep_ms_iocb		= qla24xx_prep_ms_iocb,
+	.prep_ms_fdmi_iocb	= qla24xx_prep_ms_fdmi_iocb,
+	.read_nvram		= qla24xx_read_nvram_data,
+	.write_nvram		= qla24xx_write_nvram_data,
+	.fw_dump		= qla24xx_fw_dump,
+	.beacon_on		= qla24xx_beacon_on,
+	.beacon_off		= qla24xx_beacon_off,
+	.beacon_blink		= qla24xx_beacon_blink,
+	.read_optrom		= qla82xx_read_optrom_data,
+	.write_optrom		= qla82xx_write_optrom_data,
+	.get_flash_version	= qla24xx_get_flash_version,
+	.start_scsi             = qla82xx_start_scsi,
+	.abort_isp		= qla82xx_abort_isp,
 };
 
 static inline void
@@ -1615,10 +1713,22 @@
 		ha->device_type |= DT_IIDMA;
 		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
 		break;
+	case PCI_DEVICE_ID_QLOGIC_ISP8021:
+		ha->device_type |= DT_ISP8021;
+		ha->device_type |= DT_ZIO_SUPPORTED;
+		ha->device_type |= DT_FWI2;
+		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+		/* Initialize 82XX ISP flags */
+		qla82xx_init_flags(ha);
+		break;
 	}
 
-	/* Get adapter physical port no from interrupt pin register. */
-	pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+	if (IS_QLA82XX(ha))
+		ha->port_no = !(ha->portnum & 1);
+	else
+		/* Get adapter physical port no from interrupt pin register. */
+		pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+
 	if (ha->port_no & 1)
 		ha->flags.port0 = 1;
 	else
@@ -1632,6 +1742,9 @@
 	uint16_t msix;
 	int cpus;
 
+	if (IS_QLA82XX(ha))
+		return qla82xx_iospace_config(ha);
+
 	if (pci_request_selected_regions(ha->pdev, ha->bars,
 	    QLA2XXX_DRIVER_NAME)) {
 		qla_printk(KERN_WARNING, ha,
@@ -1775,7 +1888,8 @@
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 ||
-	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) {
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021) {
 		bars = pci_select_bars(pdev, IORESOURCE_MEM);
 		mem_only = 1;
 	}
@@ -1905,6 +2019,19 @@
 		ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
 		ha->nvram_conf_off = ~0;
 		ha->nvram_data_off = ~0;
+	} else if (IS_QLA82XX(ha)) {
+		ha->mbx_count = MAILBOX_REGISTER_COUNT;
+		req_length = REQUEST_ENTRY_CNT_82XX;
+		rsp_length = RESPONSE_ENTRY_CNT_82XX;
+		ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
+		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
+		ha->gid_list_info_size = 8;
+		ha->optrom_size = OPTROM_SIZE_82XX;
+		ha->isp_ops = &qla82xx_isp_ops;
+		ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+		ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
+		ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
+		ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
 	}
 
 	mutex_init(&ha->vport_lock);
@@ -1977,6 +2104,7 @@
 		" pointers\n");
 		goto probe_init_failed;
 	}
+
 	ha->rsp_q_map[0] = rsp;
 	ha->req_q_map[0] = req;
 	rsp->req = req;
@@ -1995,6 +2123,12 @@
 		rsp->rsp_q_out =  &ha->mqiobase->isp25mq.rsp_q_out;
 	}
 
+	if (IS_QLA82XX(ha)) {
+		req->req_q_out = &ha->iobase->isp82.req_q_out[0];
+		rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0];
+		rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0];
+	}
+
 	if (qla2x00_initialize_adapter(base_vha)) {
 		qla_printk(KERN_WARNING, ha,
 		    "Failed to initialize adapter\n");
@@ -2003,6 +2137,14 @@
 		    "Adapter flags %x.\n",
 		    base_vha->host_no, base_vha->device_flags));
 
+		if (IS_QLA82XX(ha)) {
+			qla82xx_idc_lock(ha);
+			qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+				QLA82XX_DEV_FAILED);
+			qla82xx_idc_unlock(ha);
+			qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+		}
+
 		ret = -ENODEV;
 		goto probe_failed;
 	}
@@ -2041,6 +2183,8 @@
 	DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
 	    base_vha->host_no, ha));
 
+	ha->isp_ops->enable_intrs(ha);
+
 	ret = scsi_add_host(host, &pdev->dev);
 	if (ret)
 		goto probe_failed;
@@ -2048,8 +2192,6 @@
 	base_vha->flags.init_done = 1;
 	base_vha->flags.online = 1;
 
-	ha->isp_ops->enable_intrs(ha);
-
 	scsi_scan_host(host);
 
 	qla2x00_alloc_sysfs_attr(base_vha);
@@ -2091,9 +2233,17 @@
 	scsi_host_put(base_vha->host);
 
 probe_hw_failed:
-	if (ha->iobase)
-		iounmap(ha->iobase);
-
+	if (IS_QLA82XX(ha)) {
+		qla82xx_idc_lock(ha);
+		qla82xx_clear_drv_active(ha);
+		qla82xx_idc_unlock(ha);
+		iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+		if (!ql2xdbwr)
+			iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+	} else {
+		if (ha->iobase)
+			iounmap(ha->iobase);
+	}
 	pci_release_selected_regions(ha->pdev, ha->bars);
 	kfree(ha);
 	ha = NULL;
@@ -2160,11 +2310,17 @@
 
 	scsi_host_put(base_vha->host);
 
-	if (ha->iobase)
-		iounmap(ha->iobase);
+	if (IS_QLA82XX(ha)) {
+		iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+		if (!ql2xdbwr)
+			iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+	} else {
+		if (ha->iobase)
+			iounmap(ha->iobase);
 
-	if (ha->mqiobase)
-		iounmap(ha->mqiobase);
+		if (ha->mqiobase)
+			iounmap(ha->mqiobase);
+	}
 
 	pci_release_selected_regions(ha->pdev, ha->bars);
 	kfree(ha);
@@ -2213,8 +2369,10 @@
 	vha->flags.online = 0;
 
 	/* turn-off interrupts on the card */
-	if (ha->interrupts_on)
+	if (ha->interrupts_on) {
+		vha->flags.init_done = 0;
 		ha->isp_ops->disable_intrs(ha);
+	}
 
 	qla2x00_free_irqs(vha);
 
@@ -2359,10 +2517,25 @@
 	if (!ha->srb_mempool)
 		goto fail_free_gid_list;
 
+	if (IS_QLA82XX(ha)) {
+		/* Allocate cache for CT6 Ctx. */
+		if (!ctx_cachep) {
+			ctx_cachep = kmem_cache_create("qla2xxx_ctx",
+				sizeof(struct ct6_dsd), 0,
+				SLAB_HWCACHE_ALIGN, NULL);
+			if (!ctx_cachep)
+				goto fail_free_gid_list;
+		}
+		ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ,
+			ctx_cachep);
+		if (!ha->ctx_mempool)
+			goto fail_free_srb_mempool;
+	}
+
 	/* Get memory for cached NVRAM */
 	ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
 	if (!ha->nvram)
-		goto fail_free_srb_mempool;
+		goto fail_free_ctx_mempool;
 
 	snprintf(name, sizeof(name), "%s_%d", QLA2XXX_DRIVER_NAME,
 		ha->pdev->device);
@@ -2371,6 +2544,24 @@
 	if (!ha->s_dma_pool)
 		goto fail_free_nvram;
 
+	if (IS_QLA82XX(ha)) {
+		ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+			DSD_LIST_DMA_POOL_SIZE, 8, 0);
+		if (!ha->dl_dma_pool) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - dl_dma_pool\n");
+			goto fail_s_dma_pool;
+		}
+
+		ha->fcp_cmnd_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+			FCP_CMND_DMA_POOL_SIZE, 8, 0);
+		if (!ha->fcp_cmnd_dma_pool) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - fcp_cmnd_dma_pool\n");
+			goto fail_dl_dma_pool;
+		}
+	}
+
 	/* Allocate memory for SNS commands */
 	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
 	/* Get consistent memory allocated for SNS commands */
@@ -2437,13 +2628,15 @@
 		ha->npiv_info = NULL;
 
 	/* Get consistent memory allocated for EX-INIT-CB. */
-	if (IS_QLA81XX(ha)) {
+	if (IS_QLA8XXX_TYPE(ha)) {
 		ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
 		    &ha->ex_init_cb_dma);
 		if (!ha->ex_init_cb)
 			goto fail_ex_init_cb;
 	}
 
+	INIT_LIST_HEAD(&ha->gbl_dsd_list);
+
 	INIT_LIST_HEAD(&ha->vp_list);
 	return 1;
 
@@ -2473,11 +2666,24 @@
 	ha->ms_iocb = NULL;
 	ha->ms_iocb_dma = 0;
 fail_dma_pool:
+	if (IS_QLA82XX(ha)) {
+		dma_pool_destroy(ha->fcp_cmnd_dma_pool);
+		ha->fcp_cmnd_dma_pool = NULL;
+	}
+fail_dl_dma_pool:
+	if (IS_QLA82XX(ha)) {
+		dma_pool_destroy(ha->dl_dma_pool);
+		ha->dl_dma_pool = NULL;
+	}
+fail_s_dma_pool:
 	dma_pool_destroy(ha->s_dma_pool);
 	ha->s_dma_pool = NULL;
 fail_free_nvram:
 	kfree(ha->nvram);
 	ha->nvram = NULL;
+fail_free_ctx_mempool:
+	mempool_destroy(ha->ctx_mempool);
+	ha->ctx_mempool = NULL;
 fail_free_srb_mempool:
 	mempool_destroy(ha->srb_mempool);
 	ha->srb_mempool = NULL;
@@ -2546,7 +2752,8 @@
 		dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 
 	if (ha->ex_init_cb)
-		dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
+		dma_pool_free(ha->s_dma_pool,
+			ha->ex_init_cb, ha->ex_init_cb_dma);
 
 	if (ha->s_dma_pool)
 		dma_pool_destroy(ha->s_dma_pool);
@@ -2555,14 +2762,39 @@
 		dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
 		ha->gid_list_dma);
 
+	if (IS_QLA82XX(ha)) {
+		if (!list_empty(&ha->gbl_dsd_list)) {
+			struct dsd_dma *dsd_ptr, *tdsd_ptr;
+
+			/* clean up allocated prev pool */
+			list_for_each_entry_safe(dsd_ptr,
+				tdsd_ptr, &ha->gbl_dsd_list, list) {
+				dma_pool_free(ha->dl_dma_pool,
+				dsd_ptr->dsd_addr, dsd_ptr->dsd_list_dma);
+				list_del(&dsd_ptr->list);
+				kfree(dsd_ptr);
+			}
+		}
+	}
+
+	if (ha->dl_dma_pool)
+		dma_pool_destroy(ha->dl_dma_pool);
+
+	if (ha->fcp_cmnd_dma_pool)
+		dma_pool_destroy(ha->fcp_cmnd_dma_pool);
+
+	if (ha->ctx_mempool)
+		mempool_destroy(ha->ctx_mempool);
+
 	if (ha->init_cb)
 		dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
-		ha->init_cb, ha->init_cb_dma);
+			ha->init_cb, ha->init_cb_dma);
 	vfree(ha->optrom_buffer);
 	kfree(ha->nvram);
 	kfree(ha->npiv_info);
 
 	ha->srb_mempool = NULL;
+	ha->ctx_mempool = NULL;
 	ha->eft = NULL;
 	ha->eft_dma = 0;
 	ha->sns_cmd = NULL;
@@ -2577,6 +2809,8 @@
 	ha->ex_init_cb_dma = 0;
 
 	ha->s_dma_pool = NULL;
+	ha->dl_dma_pool = NULL;
+	ha->fcp_cmnd_dma_pool = NULL;
 
 	ha->gid_list = NULL;
 	ha->gid_list_dma = 0;
@@ -2904,6 +3138,45 @@
 
 		qla2x00_do_work(base_vha);
 
+		if (IS_QLA82XX(ha)) {
+			if (test_and_clear_bit(ISP_UNRECOVERABLE,
+				&base_vha->dpc_flags)) {
+				qla82xx_idc_lock(ha);
+				qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+					QLA82XX_DEV_FAILED);
+				qla82xx_idc_unlock(ha);
+				qla_printk(KERN_INFO, ha,
+					"HW State: FAILED\n");
+				qla82xx_device_state_handler(base_vha);
+				continue;
+			}
+
+			if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED,
+				&base_vha->dpc_flags)) {
+
+				DEBUG(printk(KERN_INFO
+					"scsi(%ld): dpc: sched "
+					"qla82xx_fcoe_ctx_reset ha = %p\n",
+					base_vha->host_no, ha));
+				if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
+					&base_vha->dpc_flags))) {
+					if (qla82xx_fcoe_ctx_reset(base_vha)) {
+						/* FCoE-ctx reset failed.
+						 * Escalate to chip-reset
+						 */
+						set_bit(ISP_ABORT_NEEDED,
+							&base_vha->dpc_flags);
+					}
+					clear_bit(ABORT_ISP_ACTIVE,
+						&base_vha->dpc_flags);
+				}
+
+				DEBUG(printk("scsi(%ld): dpc:"
+					" qla82xx_fcoe_ctx_reset end\n",
+					base_vha->host_no));
+			}
+		}
+
 		if (test_and_clear_bit(ISP_ABORT_NEEDED,
 						&base_vha->dpc_flags)) {
 
@@ -2913,7 +3186,7 @@
 			if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
 			    &base_vha->dpc_flags))) {
 
-				if (qla2x00_abort_isp(base_vha)) {
+				if (ha->isp_ops->abort_isp(base_vha)) {
 					/* failed. retry later */
 					set_bit(ISP_ABORT_NEEDED,
 					    &base_vha->dpc_flags);
@@ -3061,8 +3334,18 @@
 
 	qla2x00_sp_free_dma(sp);
 
-	mempool_free(sp, ha->srb_mempool);
+	if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
+		struct ct6_dsd *ctx = sp->ctx;
+		dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd,
+			ctx->fcp_cmnd_dma);
+		list_splice(&ctx->dsd_list, &ha->gbl_dsd_list);
+		ha->gbl_dsd_inuse -= ctx->dsd_use_cnt;
+		ha->gbl_dsd_avail += ctx->dsd_use_cnt;
+		mempool_free(sp->ctx, ha->ctx_mempool);
+		sp->ctx = NULL;
+	}
 
+	mempool_free(sp, ha->srb_mempool);
 	cmd->scsi_done(cmd);
 }
 
@@ -3087,6 +3370,9 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req;
 
+	if (IS_QLA82XX(ha))
+		qla82xx_watchdog(vha);
+
 	/* Hardware read to raise pending EEH errors during mailbox waits. */
 	if (!pci_channel_offline(ha->pdev))
 		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
@@ -3201,6 +3487,8 @@
 	    start_dpc ||
 	    test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) ||
 	    test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags) ||
+	    test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) ||
+	    test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
 	    test_bit(VP_DPC_NEEDED, &vha->dpc_flags) ||
 	    test_bit(RELOGIN_NEEDED, &vha->dpc_flags)))
 		qla2xxx_wake_dpc(vha);
@@ -3210,7 +3498,7 @@
 
 /* Firmware interface routines. */
 
-#define FW_BLOBS	7
+#define FW_BLOBS	8
 #define FW_ISP21XX	0
 #define FW_ISP22XX	1
 #define FW_ISP2300	2
@@ -3218,6 +3506,7 @@
 #define FW_ISP24XX	4
 #define FW_ISP25XX	5
 #define FW_ISP81XX	6
+#define FW_ISP82XX	7
 
 #define FW_FILE_ISP21XX	"ql2100_fw.bin"
 #define FW_FILE_ISP22XX	"ql2200_fw.bin"
@@ -3226,6 +3515,7 @@
 #define FW_FILE_ISP24XX	"ql2400_fw.bin"
 #define FW_FILE_ISP25XX	"ql2500_fw.bin"
 #define FW_FILE_ISP81XX	"ql8100_fw.bin"
+#define FW_FILE_ISP82XX	"ql8200_fw.bin"
 
 static DEFINE_MUTEX(qla_fw_lock);
 
@@ -3237,6 +3527,7 @@
 	{ .name = FW_FILE_ISP24XX, },
 	{ .name = FW_FILE_ISP25XX, },
 	{ .name = FW_FILE_ISP81XX, },
+	{ .name = FW_FILE_ISP82XX, },
 };
 
 struct fw_blob *
@@ -3260,6 +3551,8 @@
 		blob = &qla_fw_blobs[FW_ISP25XX];
 	} else if (IS_QLA81XX(ha)) {
 		blob = &qla_fw_blobs[FW_ISP81XX];
+	} else if (IS_QLA82XX(ha)) {
+		blob = &qla_fw_blobs[FW_ISP82XX];
 	}
 
 	mutex_lock(&qla_fw_lock);
@@ -3400,7 +3693,7 @@
 		msleep(1000);
 
 	set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-	if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS)
+	if (ha->isp_ops->abort_isp(base_vha) == QLA_SUCCESS)
 		ret =  PCI_ERS_RESULT_RECOVERED;
 	clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 
@@ -3453,6 +3746,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -3524,6 +3818,8 @@
 	pci_unregister_driver(&qla2xxx_pci_driver);
 	qla2x00_release_firmware();
 	kmem_cache_destroy(srb_cachep);
+	if (ctx_cachep)
+		kmem_cache_destroy(ctx_cachep);
 	fc_release_transport(qla2xxx_transport_template);
 	fc_release_transport(qla2xxx_transport_vport_template);
 }