Blame SOURCES/0041-scsi-scsi-qla2xxx-Secure-flash-update-support-for-IS.patch

3c6e85
From 9131c473f0875bb592df04c7c5c7a3373c65465d Mon Sep 17 00:00:00 2001
3c6e85
From: Himanshu Madhani <hmadhani@redhat.com>
3c6e85
Date: Thu, 1 Aug 2019 15:55:01 -0400
3c6e85
Subject: [PATCH 041/124] [scsi] scsi: qla2xxx: Secure flash update support for
3c6e85
 ISP28XX
3c6e85
3c6e85
Message-id: <20190801155618.12650-42-hmadhani@redhat.com>
3c6e85
Patchwork-id: 267827
3c6e85
O-Subject: [RHEL 7.8 e-stor PATCH 041/118] scsi: qla2xxx: Secure flash update support for ISP28XX
3c6e85
Bugzilla: 1729270
3c6e85
RH-Acked-by: Jarod Wilson <jarod@redhat.com>
3c6e85
RH-Acked-by: Tony Camuso <tcamuso@redhat.com>
3c6e85
3c6e85
From: Michael Hernandez <mhernandez@marvell.com>
3c6e85
3c6e85
Bugzilla 1729270
3c6e85
3c6e85
This patch adds support for Secure flash update with ISP28xx.
3c6e85
3c6e85
Signed-off-by: Michael Hernandez <mhernandez@marvell.com>
3c6e85
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
3c6e85
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
3c6e85
(cherry picked from commit 3f006ac342c033c795aa0ec2d0dde63975e2144b)
3c6e85
Signed-off-by: Himanshu Madhani <hmadhani@redhat.com>
3c6e85
Signed-off-by: Jan Stancek <jstancek@redhat.com>
3c6e85
---
3c6e85
 drivers/scsi/qla2xxx/qla_def.h  |  31 +++-
3c6e85
 drivers/scsi/qla2xxx/qla_fw.h   |   8 +
3c6e85
 drivers/scsi/qla2xxx/qla_gbl.h  |  22 ++-
3c6e85
 drivers/scsi/qla2xxx/qla_init.c |  47 ++++-
3c6e85
 drivers/scsi/qla2xxx/qla_mbx.c  | 141 +++++++++++++++
3c6e85
 drivers/scsi/qla2xxx/qla_mr.c   |   7 +-
3c6e85
 drivers/scsi/qla2xxx/qla_nx.c   |   4 +-
3c6e85
 drivers/scsi/qla2xxx/qla_os.c   |  18 +-
3c6e85
 drivers/scsi/qla2xxx/qla_sup.c  | 387 +++++++++++++++++++++++++++++++++++++---
3c6e85
 9 files changed, 616 insertions(+), 49 deletions(-)
3c6e85
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
3c6e85
index be2699dc5b56..ead433fe0ff4 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_def.h
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_def.h
3c6e85
@@ -1043,6 +1043,7 @@ struct mbx_cmd_32 {
3c6e85
 #define MBC_GET_FIRMWARE_VERSION	8	/* Get firmware revision. */
3c6e85
 #define MBC_LOAD_RISC_RAM		9	/* Load RAM command. */
3c6e85
 #define MBC_DUMP_RISC_RAM		0xa	/* Dump RAM command. */
3c6e85
+#define MBC_SECURE_FLASH_UPDATE		0xa	/* Secure Flash Update(28xx) */
3c6e85
 #define MBC_LOAD_RISC_RAM_EXTENDED	0xb	/* Load RAM extended. */
3c6e85
 #define MBC_DUMP_RISC_RAM_EXTENDED	0xc	/* Dump RAM extended. */
3c6e85
 #define MBC_WRITE_RAM_WORD_EXTENDED	0xd	/* Write RAM word extended */
3c6e85
@@ -3145,10 +3146,10 @@ struct rsp_que;
3c6e85
 struct isp_operations {
3c6e85
 
3c6e85
 	int (*pci_config) (struct scsi_qla_host *);
3c6e85
-	void (*reset_chip) (struct scsi_qla_host *);
3c6e85
+	int (*reset_chip)(struct scsi_qla_host *);
3c6e85
 	int (*chip_diag) (struct scsi_qla_host *);
3c6e85
 	void (*config_rings) (struct scsi_qla_host *);
3c6e85
-	void (*reset_adapter) (struct scsi_qla_host *);
3c6e85
+	int (*reset_adapter)(struct scsi_qla_host *);
3c6e85
 	int (*nvram_config) (struct scsi_qla_host *);
3c6e85
 	void (*update_fw_options) (struct scsi_qla_host *);
3c6e85
 	int (*load_risc) (struct scsi_qla_host *, uint32_t *);
3c6e85
@@ -3634,6 +3635,8 @@ struct qla_hw_data {
3c6e85
 		uint32_t	rida_fmt2:1;
3c6e85
 		uint32_t	purge_mbox:1;
3c6e85
 		uint32_t        n2n_bigger:1;
3c6e85
+		uint32_t	secure_adapter:1;
3c6e85
+		uint32_t	secure_fw:1;
3c6e85
 	} flags;
3c6e85
 
3c6e85
 	uint16_t max_exchg;
3c6e85
@@ -3922,6 +3925,9 @@ struct qla_hw_data {
3c6e85
 	void		*sfp_data;
3c6e85
 	dma_addr_t	sfp_data_dma;
3c6e85
 
3c6e85
+	void		*flt;
3c6e85
+	dma_addr_t	flt_dma;
3c6e85
+
3c6e85
 #define XGMAC_DATA_SIZE	4096
3c6e85
 	void		*xgmac_data;
3c6e85
 	dma_addr_t	xgmac_data_dma;
3c6e85
@@ -4368,6 +4374,7 @@ typedef struct scsi_qla_host {
3c6e85
 #define N2N_LOGIN_NEEDED	30
3c6e85
 #define IOCB_WORK_ACTIVE	31
3c6e85
 #define SET_ZIO_THRESHOLD_NEEDED 32
3c6e85
+#define ISP_ABORT_TO_ROM	33
3c6e85
 
3c6e85
 	unsigned long	pci_flags;
3c6e85
 #define PFLG_DISCONNECTED	0	/* PCI device removed */
3c6e85
@@ -4553,6 +4560,24 @@ struct qla2_sgx {
3c6e85
 	}					\
3c6e85
 }
3c6e85
 
3c6e85
+
3c6e85
+#define SFUB_CHECKSUM_SIZE	4
3c6e85
+
3c6e85
+struct secure_flash_update_block {
3c6e85
+	uint32_t	block_info;
3c6e85
+	uint32_t	signature_lo;
3c6e85
+	uint32_t	signature_hi;
3c6e85
+	uint32_t	signature_upper[0x3e];
3c6e85
+};
3c6e85
+
3c6e85
+struct secure_flash_update_block_pk {
3c6e85
+	uint32_t	block_info;
3c6e85
+	uint32_t	signature_lo;
3c6e85
+	uint32_t	signature_hi;
3c6e85
+	uint32_t	signature_upper[0x3e];
3c6e85
+	uint32_t	public_key[0x41];
3c6e85
+};
3c6e85
+
3c6e85
 /*
3c6e85
  * Macros to help code, maintain, etc.
3c6e85
  */
3c6e85
@@ -4753,6 +4778,8 @@ struct sff_8247_a0 {
3c6e85
 	IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \
3c6e85
 	 IS_QLA28XX(_vha->hw)))
3c6e85
 
3c6e85
+#define FLASH_SEMAPHORE_REGISTER_ADDR   0x00101016
3c6e85
+
3c6e85
 #define SAVE_TOPO(_ha) { \
3c6e85
 	if (_ha->current_topology)				\
3c6e85
 		_ha->prev_topology = _ha->current_topology;     \
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
3c6e85
index 9dbd0dce5a29..d53cd7875a85 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_fw.h
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_fw.h
3c6e85
@@ -1536,6 +1536,10 @@ struct qla_flt_region {
3c6e85
 	uint32_t end;
3c6e85
 };
3c6e85
 
3c6e85
+#define FLT_REGION_SIZE		16
3c6e85
+#define FLT_MAX_REGIONS		0xFF
3c6e85
+#define FLT_REGIONS_SIZE	(FLT_REGION_SIZE * FLT_MAX_REGIONS)
3c6e85
+
3c6e85
 /* Flash NPIV Configuration Table ********************************************/
3c6e85
 
3c6e85
 struct qla_npiv_header {
3c6e85
@@ -1725,6 +1729,10 @@ struct access_chip_rsp_84xx {
3c6e85
 #define LR_DIST_FW_SHIFT	(LR_DIST_FW_POS - LR_DIST_NV_POS)
3c6e85
 #define LR_DIST_FW_FIELD(x)	((x) << LR_DIST_FW_SHIFT & 0xf000)
3c6e85
 
3c6e85
+/* FAC semaphore defines */
3c6e85
+#define FAC_SEMAPHORE_UNLOCK    0
3c6e85
+#define FAC_SEMAPHORE_LOCK      1
3c6e85
+
3c6e85
 struct nvram_81xx {
3c6e85
 	/* NVRAM header. */
3c6e85
 	uint8_t id[4];
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
3c6e85
index d20801e01008..e271e24fce23 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_gbl.h
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
3c6e85
@@ -18,14 +18,14 @@ extern int qla2100_pci_config(struct scsi_qla_host *);
3c6e85
 extern int qla2300_pci_config(struct scsi_qla_host *);
3c6e85
 extern int qla24xx_pci_config(scsi_qla_host_t *);
3c6e85
 extern int qla25xx_pci_config(scsi_qla_host_t *);
3c6e85
-extern void qla2x00_reset_chip(struct scsi_qla_host *);
3c6e85
-extern void qla24xx_reset_chip(struct scsi_qla_host *);
3c6e85
+extern int qla2x00_reset_chip(struct scsi_qla_host *);
3c6e85
+extern int qla24xx_reset_chip(struct scsi_qla_host *);
3c6e85
 extern int qla2x00_chip_diag(struct scsi_qla_host *);
3c6e85
 extern int qla24xx_chip_diag(struct scsi_qla_host *);
3c6e85
 extern void qla2x00_config_rings(struct scsi_qla_host *);
3c6e85
 extern void qla24xx_config_rings(struct scsi_qla_host *);
3c6e85
-extern void qla2x00_reset_adapter(struct scsi_qla_host *);
3c6e85
-extern void qla24xx_reset_adapter(struct scsi_qla_host *);
3c6e85
+extern int qla2x00_reset_adapter(struct scsi_qla_host *);
3c6e85
+extern int qla24xx_reset_adapter(struct scsi_qla_host *);
3c6e85
 extern int qla2x00_nvram_config(struct scsi_qla_host *);
3c6e85
 extern int qla24xx_nvram_config(struct scsi_qla_host *);
3c6e85
 extern int qla81xx_nvram_config(struct scsi_qla_host *);
3c6e85
@@ -470,6 +470,8 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *, int);
3c6e85
 extern int
3c6e85
 qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);
3c6e85
 
3c6e85
+extern int qla81xx_fac_semaphore_access(scsi_qla_host_t *, int);
3c6e85
+
3c6e85
 extern int
3c6e85
 qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *);
3c6e85
 
3c6e85
@@ -515,6 +517,14 @@ extern int qla27xx_get_zio_threshold(scsi_qla_host_t *, uint16_t *);
3c6e85
 extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t);
3c6e85
 int qla24xx_res_count_wait(struct scsi_qla_host *, uint16_t *, int);
3c6e85
 
3c6e85
+extern int qla28xx_secure_flash_update(scsi_qla_host_t *, uint16_t, uint16_t,
3c6e85
+    uint32_t, dma_addr_t, uint32_t);
3c6e85
+
3c6e85
+extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t,
3c6e85
+    uint32_t *);
3c6e85
+extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t,
3c6e85
+    uint32_t);
3c6e85
+
3c6e85
 /*
3c6e85
  * Global Function Prototypes in qla_isr.c source file.
3c6e85
  */
3c6e85
@@ -720,7 +730,7 @@ extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
3c6e85
 /* qlafx00 related functions */
3c6e85
 extern int qlafx00_pci_config(struct scsi_qla_host *);
3c6e85
 extern int qlafx00_initialize_adapter(struct scsi_qla_host *);
3c6e85
-extern void qlafx00_soft_reset(scsi_qla_host_t *);
3c6e85
+extern int qlafx00_soft_reset(scsi_qla_host_t *);
3c6e85
 extern int qlafx00_chip_diag(scsi_qla_host_t *);
3c6e85
 extern void qlafx00_config_rings(struct scsi_qla_host *);
3c6e85
 extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *);
3c6e85
@@ -763,7 +773,7 @@ extern int qla82xx_pci_region_offset(struct pci_dev *, int);
3c6e85
 extern int qla82xx_iospace_config(struct qla_hw_data *);
3c6e85
 
3c6e85
 /* Initialization related functions */
3c6e85
-extern void qla82xx_reset_chip(struct scsi_qla_host *);
3c6e85
+extern int qla82xx_reset_chip(struct scsi_qla_host *);
3c6e85
 extern void qla82xx_config_rings(struct scsi_qla_host *);
3c6e85
 extern void qla82xx_watchdog(scsi_qla_host_t *);
3c6e85
 extern int qla82xx_start_firmware(scsi_qla_host_t *);
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
3c6e85
index 4307556b933b..d4199cd560e2 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_init.c
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_init.c
3c6e85
@@ -2102,6 +2102,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
3c6e85
 	int	rval;
3c6e85
 	struct qla_hw_data *ha = vha->hw;
3c6e85
 	struct req_que *req = ha->req_q_map[0];
3c6e85
+	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
3c6e85
 
3c6e85
 	memset(&vha->qla_stats, 0, sizeof(vha->qla_stats));
3c6e85
 	memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
3c6e85
@@ -2136,6 +2137,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
3c6e85
 
3c6e85
 	ha->isp_ops->reset_chip(vha);
3c6e85
 
3c6e85
+	/* Check for secure flash support */
3c6e85
+	if (IS_QLA28XX(ha)) {
3c6e85
+		if (RD_REG_DWORD(&reg->mailbox12) & BIT_0) {
3c6e85
+			ql_log(ql_log_info, vha, 0xffff, "Adapter is Secure\n");
3c6e85
+			ha->flags.secure_adapter = 1;
3c6e85
+		}
3c6e85
+	}
3c6e85
+
3c6e85
+
3c6e85
 	rval = qla2xxx_get_flash_info(vha);
3c6e85
 	if (rval) {
3c6e85
 		ql_log(ql_log_fatal, vha, 0x004f,
3c6e85
@@ -2452,7 +2462,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
3c6e85
  *
3c6e85
  * Returns 0 on success.
3c6e85
  */
3c6e85
-void
3c6e85
+int
3c6e85
 qla2x00_reset_chip(scsi_qla_host_t *vha)
3c6e85
 {
3c6e85
 	unsigned long   flags = 0;
3c6e85
@@ -2460,9 +2470,10 @@ qla2x00_reset_chip(scsi_qla_host_t *vha)
3c6e85
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
3c6e85
 	uint32_t	cnt;
3c6e85
 	uint16_t	cmd;
3c6e85
+	int rval = QLA_FUNCTION_FAILED;
3c6e85
 
3c6e85
 	if (unlikely(pci_channel_offline(ha->pdev)))
3c6e85
-		return;
3c6e85
+		return rval;
3c6e85
 
3c6e85
 	ha->isp_ops->disable_intrs(ha);
3c6e85
 
3c6e85
@@ -2588,6 +2599,8 @@ qla2x00_reset_chip(scsi_qla_host_t *vha)
3c6e85
 	}
3c6e85
 
3c6e85
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
3c6e85
+
3c6e85
+	return QLA_SUCCESS;
3c6e85
 }
3c6e85
 
3c6e85
 /**
3c6e85
@@ -2828,14 +2841,15 @@ acquired:
3c6e85
  *
3c6e85
  * Returns 0 on success.
3c6e85
  */
3c6e85
-void
3c6e85
+int
3c6e85
 qla24xx_reset_chip(scsi_qla_host_t *vha)
3c6e85
 {
3c6e85
 	struct qla_hw_data *ha = vha->hw;
3c6e85
+	int rval = QLA_FUNCTION_FAILED;
3c6e85
 
3c6e85
 	if (pci_channel_offline(ha->pdev) &&
3c6e85
 	    ha->flags.pci_channel_io_perm_failure) {
3c6e85
-		return;
3c6e85
+		return rval;
3c6e85
 	}
3c6e85
 
3c6e85
 	ha->isp_ops->disable_intrs(ha);
3c6e85
@@ -2843,7 +2857,9 @@ qla24xx_reset_chip(scsi_qla_host_t *vha)
3c6e85
 	qla25xx_manipulate_risc_semaphore(vha);
3c6e85
 
3c6e85
 	/* Perform RISC reset. */
3c6e85
-	qla24xx_reset_risc(vha);
3c6e85
+	rval = qla24xx_reset_risc(vha);
3c6e85
+
3c6e85
+	return rval;
3c6e85
 }
3c6e85
 
3c6e85
 /**
3c6e85
@@ -6685,6 +6701,14 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
3c6e85
 	if (vha->flags.online) {
3c6e85
 		qla2x00_abort_isp_cleanup(vha);
3c6e85
 
3c6e85
+		if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
3c6e85
+			ha->flags.chip_reset_done = 1;
3c6e85
+			vha->flags.online = 1;
3c6e85
+			status = 0;
3c6e85
+			clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
3c6e85
+			return status;
3c6e85
+		}
3c6e85
+
3c6e85
 		if (IS_QLA8031(ha)) {
3c6e85
 			ql_dbg(ql_dbg_p3p, vha, 0xb05c,
3c6e85
 			    "Clearing fcoe driver presence.\n");
3c6e85
@@ -6925,7 +6949,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
3c6e85
 * Input:
3c6e85
 *      ha = adapter block pointer.
3c6e85
 */
3c6e85
-void
3c6e85
+int
3c6e85
 qla2x00_reset_adapter(scsi_qla_host_t *vha)
3c6e85
 {
3c6e85
 	unsigned long flags = 0;
3c6e85
@@ -6941,17 +6965,20 @@ qla2x00_reset_adapter(scsi_qla_host_t *vha)
3c6e85
 	WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
3c6e85
 	RD_REG_WORD(&reg->hccr);			/* PCI Posting. */
3c6e85
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
3c6e85
+
3c6e85
+	return QLA_SUCCESS;
3c6e85
 }
3c6e85
 
3c6e85
-void
3c6e85
+int
3c6e85
 qla24xx_reset_adapter(scsi_qla_host_t *vha)
3c6e85
 {
3c6e85
 	unsigned long flags = 0;
3c6e85
 	struct qla_hw_data *ha = vha->hw;
3c6e85
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
3c6e85
+	int rval = QLA_SUCCESS;
3c6e85
 
3c6e85
 	if (IS_P3P_TYPE(ha))
3c6e85
-		return;
3c6e85
+		return rval;
3c6e85
 
3c6e85
 	vha->flags.online = 0;
3c6e85
 	ha->isp_ops->disable_intrs(ha);
3c6e85
@@ -6965,6 +6992,8 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)
3c6e85
 
3c6e85
 	if (IS_NOPOLLING_TYPE(ha))
3c6e85
 		ha->isp_ops->enable_intrs(ha);
3c6e85
+
3c6e85
+	return rval;
3c6e85
 }
3c6e85
 
3c6e85
 /* On sparc systems, obtain port and node WWN from firmware
3c6e85
@@ -8202,7 +8231,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
3c6e85
 	if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
3c6e85
 		ha->vpd_size = FA_VPD_SIZE_82XX;
3c6e85
 
3c6e85
-	if (IS_QLA28XX(ha))
3c6e85
+	if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
3c6e85
 		qla28xx_get_aux_images(vha, &active_regions);
3c6e85
 
3c6e85
 	/* Get VPD data into cache */
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
3c6e85
index 4fa8b2b08768..2b2678e1b043 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_mbx.c
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
3c6e85
@@ -1145,6 +1145,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
3c6e85
 		ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
3c6e85
 		ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22];
3c6e85
 		ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24];
3c6e85
+		if (IS_QLA28XX(ha)) {
3c6e85
+			if (mcp->mb[16] & BIT_10) {
3c6e85
+				ql_log(ql_log_info, vha, 0xffff,
3c6e85
+				    "FW support secure flash updates\n");
3c6e85
+				ha->flags.secure_fw = 1;
3c6e85
+			}
3c6e85
+		}
3c6e85
 	}
3c6e85
 
3c6e85
 failed:
3c6e85
@@ -4596,6 +4603,42 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
3c6e85
 }
3c6e85
 
3c6e85
 int
3c6e85
+qla81xx_fac_semaphore_access(scsi_qla_host_t *vha, int lock)
3c6e85
+{
3c6e85
+	int rval = QLA_SUCCESS;
3c6e85
+	mbx_cmd_t mc;
3c6e85
+	mbx_cmd_t *mcp = &mc;
3c6e85
+	struct qla_hw_data *ha = vha->hw;
3c6e85
+
3c6e85
+	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
3c6e85
+	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
3c6e85
+		return rval;
3c6e85
+
3c6e85
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2,
3c6e85
+	    "Entered %s.\n", __func__);
3c6e85
+
3c6e85
+	mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
3c6e85
+	mcp->mb[1] = (lock ? FAC_OPT_CMD_LOCK_SEMAPHORE :
3c6e85
+	    FAC_OPT_CMD_UNLOCK_SEMAPHORE);
3c6e85
+	mcp->out_mb = MBX_1|MBX_0;
3c6e85
+	mcp->in_mb = MBX_1|MBX_0;
3c6e85
+	mcp->tov = MBX_TOV_SECONDS;
3c6e85
+	mcp->flags = 0;
3c6e85
+	rval = qla2x00_mailbox_command(vha, mcp);
3c6e85
+
3c6e85
+	if (rval != QLA_SUCCESS) {
3c6e85
+		ql_dbg(ql_dbg_mbx, vha, 0x10e3,
3c6e85
+		    "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
3c6e85
+		    rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
3c6e85
+	} else {
3c6e85
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e4,
3c6e85
+		    "Done %s.\n", __func__);
3c6e85
+	}
3c6e85
+
3c6e85
+	return rval;
3c6e85
+}
3c6e85
+
3c6e85
+int
3c6e85
 qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
3c6e85
 {
3c6e85
 	int rval = 0;
3c6e85
@@ -6534,3 +6577,101 @@ int qla24xx_res_count_wait(struct scsi_qla_host *vha,
3c6e85
 done:
3c6e85
 	return rval;
3c6e85
 }
3c6e85
+
3c6e85
+int qla28xx_secure_flash_update(scsi_qla_host_t *vha, uint16_t opts,
3c6e85
+    uint16_t region, uint32_t len, dma_addr_t sfub_dma_addr,
3c6e85
+    uint32_t sfub_len)
3c6e85
+{
3c6e85
+	int		rval;
3c6e85
+	mbx_cmd_t mc;
3c6e85
+	mbx_cmd_t *mcp = &mc;
3c6e85
+
3c6e85
+	mcp->mb[0] = MBC_SECURE_FLASH_UPDATE;
3c6e85
+	mcp->mb[1] = opts;
3c6e85
+	mcp->mb[2] = region;
3c6e85
+	mcp->mb[3] = MSW(len);
3c6e85
+	mcp->mb[4] = LSW(len);
3c6e85
+	mcp->mb[5] = MSW(sfub_dma_addr);
3c6e85
+	mcp->mb[6] = LSW(sfub_dma_addr);
3c6e85
+	mcp->mb[7] = MSW(MSD(sfub_dma_addr));
3c6e85
+	mcp->mb[8] = LSW(MSD(sfub_dma_addr));
3c6e85
+	mcp->mb[9] = sfub_len;
3c6e85
+	mcp->out_mb =
3c6e85
+	    MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
3c6e85
+	mcp->in_mb = MBX_2|MBX_1|MBX_0;
3c6e85
+	mcp->tov = MBX_TOV_SECONDS;
3c6e85
+	mcp->flags = 0;
3c6e85
+	rval = qla2x00_mailbox_command(vha, mcp);
3c6e85
+
3c6e85
+	if (rval != QLA_SUCCESS) {
3c6e85
+		ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s(%ld): failed rval 0x%x, %x %x %x",
3c6e85
+			__func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1],
3c6e85
+			mcp->mb[2]);
3c6e85
+	}
3c6e85
+
3c6e85
+	return rval;
3c6e85
+}
3c6e85
+
3c6e85
+int qla2xxx_write_remote_register(scsi_qla_host_t *vha, uint32_t addr,
3c6e85
+    uint32_t data)
3c6e85
+{
3c6e85
+	int rval;
3c6e85
+	mbx_cmd_t mc;
3c6e85
+	mbx_cmd_t *mcp = &mc;
3c6e85
+
3c6e85
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8,
3c6e85
+	    "Entered %s.\n", __func__);
3c6e85
+
3c6e85
+	mcp->mb[0] = MBC_WRITE_REMOTE_REG;
3c6e85
+	mcp->mb[1] = LSW(addr);
3c6e85
+	mcp->mb[2] = MSW(addr);
3c6e85
+	mcp->mb[3] = LSW(data);
3c6e85
+	mcp->mb[4] = MSW(data);
3c6e85
+	mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
3c6e85
+	mcp->in_mb = MBX_1|MBX_0;
3c6e85
+	mcp->tov = MBX_TOV_SECONDS;
3c6e85
+	mcp->flags = 0;
3c6e85
+	rval = qla2x00_mailbox_command(vha, mcp);
3c6e85
+
3c6e85
+	if (rval != QLA_SUCCESS) {
3c6e85
+		ql_dbg(ql_dbg_mbx, vha, 0x10e9,
3c6e85
+		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
3c6e85
+	} else {
3c6e85
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
3c6e85
+		    "Done %s.\n", __func__);
3c6e85
+	}
3c6e85
+
3c6e85
+	return rval;
3c6e85
+}
3c6e85
+
3c6e85
+int qla2xxx_read_remote_register(scsi_qla_host_t *vha, uint32_t addr,
3c6e85
+    uint32_t *data)
3c6e85
+{
3c6e85
+	int rval;
3c6e85
+	mbx_cmd_t mc;
3c6e85
+	mbx_cmd_t *mcp = &mc;
3c6e85
+
3c6e85
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8,
3c6e85
+	    "Entered %s.\n", __func__);
3c6e85
+
3c6e85
+	mcp->mb[0] = MBC_READ_REMOTE_REG;
3c6e85
+	mcp->mb[1] = LSW(addr);
3c6e85
+	mcp->mb[2] = MSW(addr);
3c6e85
+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
3c6e85
+	mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
3c6e85
+	mcp->tov = MBX_TOV_SECONDS;
3c6e85
+	mcp->flags = 0;
3c6e85
+	rval = qla2x00_mailbox_command(vha, mcp);
3c6e85
+
3c6e85
+	*data = (uint32_t)((((uint32_t)mcp->mb[4]) << 16) | mcp->mb[3]);
3c6e85
+
3c6e85
+	if (rval != QLA_SUCCESS) {
3c6e85
+		ql_dbg(ql_dbg_mbx, vha, 0x10e9,
3c6e85
+		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
3c6e85
+	} else {
3c6e85
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
3c6e85
+		    "Done %s.\n", __func__);
3c6e85
+	}
3c6e85
+
3c6e85
+	return rval;
3c6e85
+}
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
3c6e85
index 527d255999cd..a3464a76e0b4 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_mr.c
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_mr.c
3c6e85
@@ -627,17 +627,20 @@ qlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
3c6e85
  *
3c6e85
  * Returns 0 on success.
3c6e85
  */
3c6e85
-void
3c6e85
+int
3c6e85
 qlafx00_soft_reset(scsi_qla_host_t *vha)
3c6e85
 {
3c6e85
 	struct qla_hw_data *ha = vha->hw;
3c6e85
+	int rval = QLA_FUNCTION_FAILED;
3c6e85
 
3c6e85
 	if (unlikely(pci_channel_offline(ha->pdev) &&
3c6e85
 	    ha->flags.pci_channel_io_perm_failure))
3c6e85
-		return;
3c6e85
+		return rval;
3c6e85
 
3c6e85
 	ha->isp_ops->disable_intrs(ha);
3c6e85
 	qlafx00_soc_cpu_reset(vha);
3c6e85
+
3c6e85
+	return QLA_SUCCESS;
3c6e85
 }
3c6e85
 
3c6e85
 /**
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
3c6e85
index ff624c06824e..687c4cb49ecb 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_nx.c
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_nx.c
3c6e85
@@ -1752,11 +1752,13 @@ qla82xx_pci_config(scsi_qla_host_t *vha)
3c6e85
  *
3c6e85
  * Returns 0 on success.
3c6e85
  */
3c6e85
-void
3c6e85
+int
3c6e85
 qla82xx_reset_chip(scsi_qla_host_t *vha)
3c6e85
 {
3c6e85
 	struct qla_hw_data *ha = vha->hw;
3c6e85
 	ha->isp_ops->disable_intrs(ha);
3c6e85
+
3c6e85
+	return QLA_SUCCESS;
3c6e85
 }
3c6e85
 
3c6e85
 void qla82xx_config_rings(struct scsi_qla_host *vha)
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
3c6e85
index 354977d41097..f5933550586d 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_os.c
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_os.c
3c6e85
@@ -41,7 +41,7 @@ static struct kmem_cache *ctx_cachep;
3c6e85
 /*
3c6e85
  * error level for logging
3c6e85
  */
3c6e85
-uint ql_errlev = ql_log_all;
3c6e85
+uint ql_errlev = 0x8001;
3c6e85
 
3c6e85
 static int ql2xenableclass2;
3c6e85
 module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR);
3c6e85
@@ -4395,8 +4395,20 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
3c6e85
 		goto fail_sfp_data;
3c6e85
 	}
3c6e85
 
3c6e85
+	ha->flt = dma_alloc_coherent(&ha->pdev->dev,
3c6e85
+	    sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, &ha->flt_dma,
3c6e85
+	    GFP_KERNEL);
3c6e85
+	if (!ha->flt) {
3c6e85
+		ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
3c6e85
+		    "Unable to allocate memory for FLT.\n");
3c6e85
+		goto fail_flt_buffer;
3c6e85
+	}
3c6e85
+
3c6e85
 	return 0;
3c6e85
 
3c6e85
+fail_flt_buffer:
3c6e85
+	dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
3c6e85
+	    ha->sfp_data, ha->sfp_data_dma);
3c6e85
 fail_sfp_data:
3c6e85
 	kfree(ha->loop_id_map);
3c6e85
 fail_loop_id_map:
3c6e85
@@ -4805,6 +4817,10 @@ qla2x00_mem_free(struct qla_hw_data *ha)
3c6e85
 		dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data,
3c6e85
 		    ha->sfp_data_dma);
3c6e85
 
3c6e85
+	if (ha->flt)
3c6e85
+		dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
3c6e85
+		    ha->flt, ha->flt_dma);
3c6e85
+
3c6e85
 	if (ha->ms_iocb)
3c6e85
 		dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
3c6e85
 
3c6e85
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
3c6e85
index 8191f3599f79..ec14d10bff4c 100644
3c6e85
--- a/drivers/scsi/qla2xxx/qla_sup.c
3c6e85
+++ b/drivers/scsi/qla2xxx/qla_sup.c
3c6e85
@@ -634,7 +634,7 @@ end:
3c6e85
 static void
3c6e85
 qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
3c6e85
 {
3c6e85
-	const char *loc, *locations[] = { "DEF", "FLT" };
3c6e85
+	const char *locations[] = { "DEF", "FLT" }, *loc = locations[1];
3c6e85
 	const uint32_t def_fw[] =
3c6e85
 		{ FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 };
3c6e85
 	const uint32_t def_boot[] =
3c6e85
@@ -664,20 +664,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
3c6e85
 	const uint32_t fcp_prio_cfg1[] =
3c6e85
 		{ FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25,
3c6e85
 			0 };
3c6e85
-	uint32_t def;
3c6e85
-	uint16_t *wptr;
3c6e85
-	uint16_t cnt, chksum;
3c6e85
-	uint32_t start;
3c6e85
-	struct qla_flt_header *flt;
3c6e85
-	struct qla_flt_region *region;
3c6e85
-	struct qla_hw_data *ha = vha->hw;
3c6e85
-	struct req_que *req = ha->req_q_map[0];
3c6e85
 
3c6e85
-	def = 0;
3c6e85
-	if (IS_QLA25XX(ha))
3c6e85
-		def = 1;
3c6e85
-	else if (IS_QLA81XX(ha))
3c6e85
-		def = 2;
3c6e85
+	struct qla_hw_data *ha = vha->hw;
3c6e85
+	uint32_t def = IS_QLA81XX(ha) ? 2 : IS_QLA25XX(ha) ? 1 : 0;
3c6e85
+	struct qla_flt_header *flt = (void *)ha->flt;
3c6e85
+	struct qla_flt_region *region = (void *)&flt[1];
3c6e85
+	uint16_t *wptr, cnt, chksum;
3c6e85
+	uint32_t start;
3c6e85
 
3c6e85
 	/* Assign FCP prio region since older adapters may not have FLT, or
3c6e85
 	   FCP prio region in it's FLT.
3c6e85
@@ -686,12 +679,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
3c6e85
 	    fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
3c6e85
 
3c6e85
 	ha->flt_region_flt = flt_addr;
3c6e85
-	wptr = (uint16_t *)req->ring;
3c6e85
-	flt = (struct qla_flt_header *)req->ring;
3c6e85
-	region = (struct qla_flt_region *)&flt[1];
3c6e85
-	ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring,
3c6e85
-	    flt_addr << 2, OPTROM_BURST_SIZE);
3c6e85
-	if (*wptr == cpu_to_le16(0xffff))
3c6e85
+	wptr = (uint16_t *)ha->flt;
3c6e85
+	qla24xx_read_flash_data(vha, (void *)flt, flt_addr,
3c6e85
+	    (sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE) >> 2);
3c6e85
+
3c6e85
+	if (le16_to_cpu(*wptr) == 0xffff)
3c6e85
 		goto no_flash_data;
3c6e85
 	if (flt->version != cpu_to_le16(1)) {
3c6e85
 		ql_log(ql_log_warn, vha, 0x0047,
3c6e85
@@ -701,7 +693,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
3c6e85
 		goto no_flash_data;
3c6e85
 	}
3c6e85
 
3c6e85
-	cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
3c6e85
+	cnt = (sizeof(*flt) + le16_to_cpu(flt->length)) / sizeof(*wptr);
3c6e85
 	for (chksum = 0; cnt--; wptr++)
3c6e85
 		chksum += le16_to_cpu(*wptr);
3c6e85
 	if (chksum) {
3c6e85
@@ -712,16 +704,18 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
3c6e85
 		goto no_flash_data;
3c6e85
 	}
3c6e85
 
3c6e85
-	loc = locations[1];
3c6e85
-	cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
3c6e85
+	cnt = le16_to_cpu(flt->length) / sizeof(*region);
3c6e85
 	for ( ; cnt; cnt--, region++) {
3c6e85
 		/* Store addresses as DWORD offsets. */
3c6e85
 		start = le32_to_cpu(region->start) >> 2;
3c6e85
 		ql_dbg(ql_dbg_init, vha, 0x0049,
3c6e85
 		    "FLT[%#x]: start=%#x end=%#x size=%#x.\n",
3c6e85
-		    le16_to_cpu(region->code),
3c6e85
-		    start, le32_to_cpu(region->end) >> 2,
3c6e85
-		    le32_to_cpu(region->size));
3c6e85
+		    le16_to_cpu(region->code), start,
3c6e85
+		    le32_to_cpu(region->end) >> 2,
3c6e85
+		    le32_to_cpu(region->size) >> 2);
3c6e85
+		if (region->attribute)
3c6e85
+			ql_log(ql_dbg_init, vha, 0xffff,
3c6e85
+			    "Region %x is secure\n", region->code);
3c6e85
 
3c6e85
 		switch (le16_to_cpu(region->code)) {
3c6e85
 		case FLT_REG_FCOE_FW:
3c6e85
@@ -2623,6 +2617,338 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
3c6e85
 	return buf;
3c6e85
 }
3c6e85
 
3c6e85
+static int
3c6e85
+qla28xx_extract_sfub_and_verify(struct scsi_qla_host *vha, uint32_t *buf,
3c6e85
+    uint32_t len, uint32_t buf_size_without_sfub, uint8_t *sfub_buf)
3c6e85
+{
3c6e85
+	uint32_t *p, check_sum = 0;
3c6e85
+	int i;
3c6e85
+
3c6e85
+	p = buf + buf_size_without_sfub;
3c6e85
+
3c6e85
+	/* Extract SFUB from end of file */
3c6e85
+	memcpy(sfub_buf, (uint8_t *)p,
3c6e85
+	    sizeof(struct secure_flash_update_block));
3c6e85
+
3c6e85
+	for (i = 0; i < (sizeof(struct secure_flash_update_block) >> 2); i++)
3c6e85
+		check_sum += p[i];
3c6e85
+
3c6e85
+	check_sum = (~check_sum) + 1;
3c6e85
+
3c6e85
+	if (check_sum != p[i]) {
3c6e85
+		ql_log(ql_log_warn, vha, 0x7097,
3c6e85
+		    "SFUB checksum failed, 0x%x, 0x%x\n",
3c6e85
+		    check_sum, p[i]);
3c6e85
+		return QLA_COMMAND_ERROR;
3c6e85
+	}
3c6e85
+
3c6e85
+	return QLA_SUCCESS;
3c6e85
+}
3c6e85
+
3c6e85
+static int
3c6e85
+qla28xx_get_flash_region(struct scsi_qla_host *vha, uint32_t start,
3c6e85
+    struct qla_flt_region *region)
3c6e85
+{
3c6e85
+	struct qla_hw_data *ha = vha->hw;
3c6e85
+	struct qla_flt_header *flt;
3c6e85
+	struct qla_flt_region *flt_reg;
3c6e85
+	uint16_t cnt;
3c6e85
+	int rval = QLA_FUNCTION_FAILED;
3c6e85
+
3c6e85
+	if (!ha->flt)
3c6e85
+		return QLA_FUNCTION_FAILED;
3c6e85
+
3c6e85
+	flt = (struct qla_flt_header *)ha->flt;
3c6e85
+	flt_reg = (struct qla_flt_region *)&flt[1];
3c6e85
+	cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
3c6e85
+
3c6e85
+	for (; cnt; cnt--, flt_reg++) {
3c6e85
+		if (flt_reg->start == start) {
3c6e85
+			memcpy((uint8_t *)region, flt_reg,
3c6e85
+			    sizeof(struct qla_flt_region));
3c6e85
+			rval = QLA_SUCCESS;
3c6e85
+			break;
3c6e85
+		}
3c6e85
+	}
3c6e85
+
3c6e85
+	return rval;
3c6e85
+}
3c6e85
+
3c6e85
+static int
3c6e85
+qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
3c6e85
+    uint32_t dwords)
3c6e85
+{
3c6e85
+	struct qla_hw_data *ha = vha->hw;
3c6e85
+	ulong liter;
3c6e85
+	ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */
3c6e85
+	uint32_t sec_mask, rest_addr, fdata;
3c6e85
+	void *optrom = NULL;
3c6e85
+	dma_addr_t optrom_dma;
3c6e85
+	int rval;
3c6e85
+	struct secure_flash_update_block *sfub;
3c6e85
+	dma_addr_t sfub_dma;
3c6e85
+	uint32_t offset = faddr << 2;
3c6e85
+	uint32_t buf_size_without_sfub = 0;
3c6e85
+	struct qla_flt_region region;
3c6e85
+	bool reset_to_rom = false;
3c6e85
+	uint32_t risc_size, risc_attr = 0;
3c6e85
+	uint32_t *fw_array = NULL;
3c6e85
+
3c6e85
+	/* Retrieve region info - must be a start address passed in */
3c6e85
+	rval = qla28xx_get_flash_region(vha, offset, &region);
3c6e85
+
3c6e85
+	if (rval != QLA_SUCCESS) {
3c6e85
+		ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+		    "Invalid address %x - not a region start address\n",
3c6e85
+		    offset);
3c6e85
+		goto done;
3c6e85
+	}
3c6e85
+
3c6e85
+	/* Allocate dma buffer for burst write */
3c6e85
+	optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
3c6e85
+	    &optrom_dma, GFP_KERNEL);
3c6e85
+	if (!optrom) {
3c6e85
+		ql_log(ql_log_warn, vha, 0x7095,
3c6e85
+		    "Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE);
3c6e85
+		rval = QLA_COMMAND_ERROR;
3c6e85
+		goto done;
3c6e85
+	}
3c6e85
+
3c6e85
+	/*
3c6e85
+	 * If adapter supports secure flash and region is secure
3c6e85
+	 * extract secure flash update block (SFUB) and verify
3c6e85
+	 */
3c6e85
+	if (ha->flags.secure_adapter && region.attribute) {
3c6e85
+
3c6e85
+		ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+		    "Region %x is secure\n", region.code);
3c6e85
+
3c6e85
+		if (region.code == FLT_REG_FW ||
3c6e85
+		    region.code == FLT_REG_FW_SEC_27XX) {
3c6e85
+			fw_array = dwptr;
3c6e85
+
3c6e85
+			/* 1st fw array */
3c6e85
+			risc_size = be32_to_cpu(fw_array[3]);
3c6e85
+			risc_attr = be32_to_cpu(fw_array[9]);
3c6e85
+
3c6e85
+			buf_size_without_sfub = risc_size;
3c6e85
+			fw_array += risc_size;
3c6e85
+
3c6e85
+			/* 2nd fw array */
3c6e85
+			risc_size = be32_to_cpu(fw_array[3]);
3c6e85
+
3c6e85
+			buf_size_without_sfub += risc_size;
3c6e85
+			fw_array += risc_size;
3c6e85
+
3c6e85
+			/* 1st dump template */
3c6e85
+			risc_size = be32_to_cpu(fw_array[2]);
3c6e85
+
3c6e85
+			/* skip header and ignore checksum */
3c6e85
+			buf_size_without_sfub += risc_size;
3c6e85
+			fw_array += risc_size;
3c6e85
+
3c6e85
+			if (risc_attr & BIT_9) {
3c6e85
+				/* 2nd dump template */
3c6e85
+				risc_size = be32_to_cpu(fw_array[2]);
3c6e85
+
3c6e85
+				/* skip header and ignore checksum */
3c6e85
+				buf_size_without_sfub += risc_size;
3c6e85
+				fw_array += risc_size;
3c6e85
+			}
3c6e85
+		} else {
3c6e85
+			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+			    "Secure region %x not supported\n",
3c6e85
+			    region.code);
3c6e85
+			rval = QLA_COMMAND_ERROR;
3c6e85
+			goto done;
3c6e85
+		}
3c6e85
+
3c6e85
+		sfub = dma_alloc_coherent(&ha->pdev->dev,
3c6e85
+			sizeof(struct secure_flash_update_block), &sfub_dma,
3c6e85
+			GFP_KERNEL);
3c6e85
+		if (!sfub) {
3c6e85
+			ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+			    "Unable to allocate memory for SFUB\n");
3c6e85
+			rval = QLA_COMMAND_ERROR;
3c6e85
+			goto done;
3c6e85
+		}
3c6e85
+
3c6e85
+		rval = qla28xx_extract_sfub_and_verify(vha, dwptr, dwords,
3c6e85
+			buf_size_without_sfub, (uint8_t *)sfub);
3c6e85
+
3c6e85
+		if (rval != QLA_SUCCESS)
3c6e85
+			goto done;
3c6e85
+
3c6e85
+		ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+		    "SFUB extract and verify successful\n");
3c6e85
+	}
3c6e85
+
3c6e85
+	rest_addr = (ha->fdt_block_size >> 2) - 1;
3c6e85
+	sec_mask = ~rest_addr;
3c6e85
+
3c6e85
+	/* Lock semaphore */
3c6e85
+	rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK);
3c6e85
+	if (rval != QLA_SUCCESS) {
3c6e85
+		ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+		    "Unable to lock flash semaphore.");
3c6e85
+		goto done;
3c6e85
+	}
3c6e85
+
3c6e85
+	ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
3c6e85
+	    "Unprotect flash...\n");
3c6e85
+	rval = qla24xx_unprotect_flash(vha);
3c6e85
+	if (rval) {
3c6e85
+		qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
3c6e85
+		ql_log(ql_log_warn, vha, 0x7096, "Failed unprotect flash\n");
3c6e85
+		goto done;
3c6e85
+	}
3c6e85
+
3c6e85
+	for (liter = 0; liter < dwords; liter++, faddr++) {
3c6e85
+		fdata = (faddr & sec_mask) << 2;
3c6e85
+
3c6e85
+		/* If start of sector */
3c6e85
+		if (!(faddr & rest_addr)) {
3c6e85
+			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
3c6e85
+			    "Erase sector %#x...\n", faddr);
3c6e85
+			rval = qla24xx_erase_sector(vha, fdata);
3c6e85
+			if (rval) {
3c6e85
+				ql_dbg(ql_dbg_user, vha, 0x7007,
3c6e85
+				    "Failed erase sector %#x\n", faddr);
3c6e85
+				goto write_protect;
3c6e85
+			}
3c6e85
+		}
3c6e85
+	}
3c6e85
+
3c6e85
+	if (ha->flags.secure_adapter) {
3c6e85
+		/*
3c6e85
+		 * If adapter supports secure flash but FW doesn't,
3c6e85
+		 * disable write protect, release semaphore and reset
3c6e85
+		 * chip to execute ROM code in order to update region securely
3c6e85
+		 */
3c6e85
+		if (!ha->flags.secure_fw) {
3c6e85
+			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+			    "Disable Write and Release Semaphore.");
3c6e85
+			rval = qla24xx_protect_flash(vha);
3c6e85
+			if (rval != QLA_SUCCESS) {
3c6e85
+				qla81xx_fac_semaphore_access(vha,
3c6e85
+					FAC_SEMAPHORE_UNLOCK);
3c6e85
+				ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+				    "Unable to protect flash.");
3c6e85
+				goto done;
3c6e85
+			}
3c6e85
+
3c6e85
+			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+			    "Reset chip to ROM.");
3c6e85
+			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
3c6e85
+			set_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags);
3c6e85
+			qla2xxx_wake_dpc(vha);
3c6e85
+			rval = qla2x00_wait_for_chip_reset(vha);
3c6e85
+			if (rval != QLA_SUCCESS) {
3c6e85
+				ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+				    "Unable to reset to ROM code.");
3c6e85
+				goto done;
3c6e85
+			}
3c6e85
+			reset_to_rom = true;
3c6e85
+			ha->flags.fac_supported = 0;
3c6e85
+
3c6e85
+			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+			    "Lock Semaphore");
3c6e85
+			rval = qla2xxx_write_remote_register(vha,
3c6e85
+			    FLASH_SEMAPHORE_REGISTER_ADDR, 0x00020002);
3c6e85
+			if (rval != QLA_SUCCESS) {
3c6e85
+				ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+				    "Unable to lock flash semaphore.");
3c6e85
+				goto done;
3c6e85
+			}
3c6e85
+
3c6e85
+			/* Unprotect flash */
3c6e85
+			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+			    "Enable Write.");
3c6e85
+			rval = qla2x00_write_ram_word(vha, 0x7ffd0101, 0);
3c6e85
+			if (rval) {
3c6e85
+				ql_log(ql_log_warn, vha, 0x7096,
3c6e85
+				    "Failed unprotect flash\n");
3c6e85
+				goto done;
3c6e85
+			}
3c6e85
+		}
3c6e85
+
3c6e85
+		/* If region is secure, send Secure Flash MB Cmd */
3c6e85
+		if (region.attribute && buf_size_without_sfub) {
3c6e85
+			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
3c6e85
+			    "Sending Secure Flash MB Cmd\n");
3c6e85
+			rval = qla28xx_secure_flash_update(vha, 0, region.code,
3c6e85
+				buf_size_without_sfub, sfub_dma,
3c6e85
+				sizeof(struct secure_flash_update_block));
3c6e85
+			if (rval != QLA_SUCCESS) {
3c6e85
+				ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+				    "Secure Flash MB Cmd failed %x.", rval);
3c6e85
+				goto write_protect;
3c6e85
+			}
3c6e85
+		}
3c6e85
+
3c6e85
+	}
3c6e85
+
3c6e85
+	/* re-init flash offset */
3c6e85
+	faddr = offset >> 2;
3c6e85
+
3c6e85
+	for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
3c6e85
+		fdata = (faddr & sec_mask) << 2;
3c6e85
+
3c6e85
+		/* If smaller than a burst remaining */
3c6e85
+		if (dwords - liter < dburst)
3c6e85
+			dburst = dwords - liter;
3c6e85
+
3c6e85
+		/* Copy to dma buffer */
3c6e85
+		memcpy(optrom, dwptr, dburst << 2);
3c6e85
+
3c6e85
+		/* Burst write */
3c6e85
+		ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
3c6e85
+		    "Write burst (%#lx dwords)...\n", dburst);
3c6e85
+		rval = qla2x00_load_ram(vha, optrom_dma,
3c6e85
+		    flash_data_addr(ha, faddr), dburst);
3c6e85
+		if (rval != QLA_SUCCESS) {
3c6e85
+			ql_log(ql_log_warn, vha, 0x7097,
3c6e85
+			    "Failed burst write at %x (%p/%#llx)...\n",
3c6e85
+			    flash_data_addr(ha, faddr), optrom,
3c6e85
+			    (u64)optrom_dma);
3c6e85
+			break;
3c6e85
+		}
3c6e85
+
3c6e85
+		liter += dburst - 1;
3c6e85
+		faddr += dburst - 1;
3c6e85
+		dwptr += dburst - 1;
3c6e85
+		continue;
3c6e85
+	}
3c6e85
+
3c6e85
+write_protect:
3c6e85
+	ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
3c6e85
+	    "Protect flash...\n");
3c6e85
+	rval = qla24xx_protect_flash(vha);
3c6e85
+	if (rval) {
3c6e85
+		qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
3c6e85
+		ql_log(ql_log_warn, vha, 0x7099,
3c6e85
+		    "Failed protect flash\n");
3c6e85
+	}
3c6e85
+
3c6e85
+	if (reset_to_rom == true) {
3c6e85
+		/* Schedule DPC to restart the RISC */
3c6e85
+		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
3c6e85
+		qla2xxx_wake_dpc(vha);
3c6e85
+
3c6e85
+		rval = qla2x00_wait_for_hba_online(vha);
3c6e85
+		if (rval != QLA_SUCCESS)
3c6e85
+			ql_log(ql_log_warn, vha, 0xffff,
3c6e85
+			    "Adapter did not come out of reset\n");
3c6e85
+	}
3c6e85
+
3c6e85
+done:
3c6e85
+	if (optrom)
3c6e85
+		dma_free_coherent(&ha->pdev->dev,
3c6e85
+		    OPTROM_BURST_SIZE, optrom, optrom_dma);
3c6e85
+
3c6e85
+	return rval;
3c6e85
+}
3c6e85
+
3c6e85
 int
3c6e85
 qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
3c6e85
     uint32_t offset, uint32_t length)
3c6e85
@@ -2635,8 +2961,12 @@ qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
3c6e85
 	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
3c6e85
 
3c6e85
 	/* Go with write. */
3c6e85
-	rval = qla24xx_write_flash_data(vha, buf, offset >> 2,
3c6e85
-	    length >> 2);
3c6e85
+	if (IS_QLA28XX(ha))
3c6e85
+		rval = qla28xx_write_flash_data(vha, (uint32_t *)buf,
3c6e85
+		    offset >> 2, length >> 2);
3c6e85
+	else
3c6e85
+		rval = qla24xx_write_flash_data(vha, (uint32_t *)buf,
3c6e85
+		    offset >> 2, length >> 2);
3c6e85
 
3c6e85
 	clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
3c6e85
 	scsi_unblock_requests(vha->host);
3c6e85
@@ -3151,6 +3481,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
3c6e85
 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
3c6e85
 	faddr = ha->flt_region_fw;
3c6e85
 	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
3c6e85
+		qla27xx_get_active_image(vha, &active_regions);
3c6e85
 		if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
3c6e85
 			faddr = ha->flt_region_fw_sec;
3c6e85
 	}
3c6e85
-- 
3c6e85
2.13.6
3c6e85