Commit 3f006ac3 authored by Michael Hernandez's avatar Michael Hernandez Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Secure flash update support for ISP28XX



This patch adds support for Secure flash update with ISP28xx.

Signed-off-by: default avatarMichael Hernandez <mhernandez@marvell.com>
Signed-off-by: default avatarHimanshu Madhani <hmadhani@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 5fa8774c
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -1033,6 +1033,7 @@ struct mbx_cmd_32 {
#define MBC_GET_FIRMWARE_VERSION	8	/* Get firmware revision. */
#define MBC_LOAD_RISC_RAM		9	/* Load RAM command. */
#define MBC_DUMP_RISC_RAM		0xa	/* Dump RAM command. */
#define MBC_SECURE_FLASH_UPDATE		0xa	/* Secure Flash Update(28xx) */
#define MBC_LOAD_RISC_RAM_EXTENDED	0xb	/* Load RAM extended. */
#define MBC_DUMP_RISC_RAM_EXTENDED	0xc	/* Dump RAM extended. */
#define MBC_WRITE_RAM_WORD_EXTENDED	0xd	/* Write RAM word extended */
@@ -3135,10 +3136,10 @@ struct rsp_que;
struct isp_operations {

	int (*pci_config) (struct scsi_qla_host *);
	void (*reset_chip) (struct scsi_qla_host *);
	int (*reset_chip)(struct scsi_qla_host *);
	int (*chip_diag) (struct scsi_qla_host *);
	void (*config_rings) (struct scsi_qla_host *);
	void (*reset_adapter) (struct scsi_qla_host *);
	int (*reset_adapter)(struct scsi_qla_host *);
	int (*nvram_config) (struct scsi_qla_host *);
	void (*update_fw_options) (struct scsi_qla_host *);
	int (*load_risc) (struct scsi_qla_host *, uint32_t *);
@@ -3627,6 +3628,8 @@ struct qla_hw_data {
		uint32_t	rida_fmt2:1;
		uint32_t	purge_mbox:1;
		uint32_t        n2n_bigger:1;
		uint32_t	secure_adapter:1;
		uint32_t	secure_fw:1;
	} flags;

	uint16_t max_exchg;
@@ -3915,6 +3918,9 @@ struct qla_hw_data {
	void		*sfp_data;
	dma_addr_t	sfp_data_dma;

	void		*flt;
	dma_addr_t	flt_dma;

#define XGMAC_DATA_SIZE	4096
	void		*xgmac_data;
	dma_addr_t	xgmac_data_dma;
@@ -4362,6 +4368,7 @@ typedef struct scsi_qla_host {
#define N2N_LOGIN_NEEDED	30
#define IOCB_WORK_ACTIVE	31
#define SET_ZIO_THRESHOLD_NEEDED 32
#define ISP_ABORT_TO_ROM	33

	unsigned long	pci_flags;
#define PFLG_DISCONNECTED	0	/* PCI device removed */
@@ -4549,6 +4556,24 @@ struct qla2_sgx {
	}					\
}


#define SFUB_CHECKSUM_SIZE	4

struct secure_flash_update_block {
	uint32_t	block_info;
	uint32_t	signature_lo;
	uint32_t	signature_hi;
	uint32_t	signature_upper[0x3e];
};

struct secure_flash_update_block_pk {
	uint32_t	block_info;
	uint32_t	signature_lo;
	uint32_t	signature_hi;
	uint32_t	signature_upper[0x3e];
	uint32_t	public_key[0x41];
};

/*
 * Macros to help code, maintain, etc.
 */
@@ -4749,6 +4774,8 @@ struct sff_8247_a0 {
	IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \
	 IS_QLA28XX(_vha->hw)))

#define FLASH_SEMAPHORE_REGISTER_ADDR   0x00101016

#define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \
	(IS_QLA27XX(_ha) || IS_QLA28XX(_ha) || IS_QLA83XX(_ha)))

+8 −0
Original line number Diff line number Diff line
@@ -1536,6 +1536,10 @@ struct qla_flt_region {
	uint32_t end;
};

#define FLT_REGION_SIZE		16
#define FLT_MAX_REGIONS		0xFF
#define FLT_REGIONS_SIZE	(FLT_REGION_SIZE * FLT_MAX_REGIONS)

/* Flash NPIV Configuration Table ********************************************/

struct qla_npiv_header {
@@ -1725,6 +1729,10 @@ struct access_chip_rsp_84xx {
#define LR_DIST_FW_SHIFT	(LR_DIST_FW_POS - LR_DIST_NV_POS)
#define LR_DIST_FW_FIELD(x)	((x) << LR_DIST_FW_SHIFT & 0xf000)

/* FAC semaphore defines */
#define FAC_SEMAPHORE_UNLOCK    0
#define FAC_SEMAPHORE_LOCK      1

struct nvram_81xx {
	/* NVRAM header. */
	uint8_t id[4];
+16 −6
Original line number Diff line number Diff line
@@ -18,14 +18,14 @@ extern int qla2100_pci_config(struct scsi_qla_host *);
extern int qla2300_pci_config(struct scsi_qla_host *);
extern int qla24xx_pci_config(scsi_qla_host_t *);
extern int qla25xx_pci_config(scsi_qla_host_t *);
extern void qla2x00_reset_chip(struct scsi_qla_host *);
extern void qla24xx_reset_chip(struct scsi_qla_host *);
extern int qla2x00_reset_chip(struct scsi_qla_host *);
extern int qla24xx_reset_chip(struct scsi_qla_host *);
extern int qla2x00_chip_diag(struct scsi_qla_host *);
extern int qla24xx_chip_diag(struct scsi_qla_host *);
extern void qla2x00_config_rings(struct scsi_qla_host *);
extern void qla24xx_config_rings(struct scsi_qla_host *);
extern void qla2x00_reset_adapter(struct scsi_qla_host *);
extern void qla24xx_reset_adapter(struct scsi_qla_host *);
extern int qla2x00_reset_adapter(struct scsi_qla_host *);
extern int qla24xx_reset_adapter(struct scsi_qla_host *);
extern int qla2x00_nvram_config(struct scsi_qla_host *);
extern int qla24xx_nvram_config(struct scsi_qla_host *);
extern int qla81xx_nvram_config(struct scsi_qla_host *);
@@ -471,6 +471,8 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *, int);
extern int
qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);

extern int qla81xx_fac_semaphore_access(scsi_qla_host_t *, int);

extern int
qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *);

@@ -516,6 +518,14 @@ extern int qla27xx_get_zio_threshold(scsi_qla_host_t *, uint16_t *);
extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t);
int qla24xx_res_count_wait(struct scsi_qla_host *, uint16_t *, int);

extern int qla28xx_secure_flash_update(scsi_qla_host_t *, uint16_t, uint16_t,
    uint32_t, dma_addr_t, uint32_t);

extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t,
    uint32_t *);
extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t,
    uint32_t);

/*
 * Global Function Prototypes in qla_isr.c source file.
 */
@@ -721,7 +731,7 @@ extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
/* qlafx00 related functions */
extern int qlafx00_pci_config(struct scsi_qla_host *);
extern int qlafx00_initialize_adapter(struct scsi_qla_host *);
extern void qlafx00_soft_reset(scsi_qla_host_t *);
extern int qlafx00_soft_reset(scsi_qla_host_t *);
extern int qlafx00_chip_diag(scsi_qla_host_t *);
extern void qlafx00_config_rings(struct scsi_qla_host *);
extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *);
@@ -764,7 +774,7 @@ extern int qla82xx_pci_region_offset(struct pci_dev *, int);
extern int qla82xx_iospace_config(struct qla_hw_data *);

/* Initialization related functions */
extern void qla82xx_reset_chip(struct scsi_qla_host *);
extern int qla82xx_reset_chip(struct scsi_qla_host *);
extern void qla82xx_config_rings(struct scsi_qla_host *);
extern void qla82xx_watchdog(scsi_qla_host_t *);
extern int qla82xx_start_firmware(scsi_qla_host_t *);
+38 −9
Original line number Diff line number Diff line
@@ -2102,6 +2102,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
	int	rval;
	struct qla_hw_data *ha = vha->hw;
	struct req_que *req = ha->req_q_map[0];
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

	memset(&vha->qla_stats, 0, sizeof(vha->qla_stats));
	memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
@@ -2136,6 +2137,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)

	ha->isp_ops->reset_chip(vha);

	/* Check for secure flash support */
	if (IS_QLA28XX(ha)) {
		if (RD_REG_DWORD(&reg->mailbox12) & BIT_0) {
			ql_log(ql_log_info, vha, 0xffff, "Adapter is Secure\n");
			ha->flags.secure_adapter = 1;
		}
	}


	rval = qla2xxx_get_flash_info(vha);
	if (rval) {
		ql_log(ql_log_fatal, vha, 0x004f,
@@ -2452,7 +2462,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
 *
 * Returns 0 on success.
 */
void
int
qla2x00_reset_chip(scsi_qla_host_t *vha)
{
	unsigned long   flags = 0;
@@ -2460,9 +2470,10 @@ qla2x00_reset_chip(scsi_qla_host_t *vha)
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
	uint32_t	cnt;
	uint16_t	cmd;
	int rval = QLA_FUNCTION_FAILED;

	if (unlikely(pci_channel_offline(ha->pdev)))
		return;
		return rval;

	ha->isp_ops->disable_intrs(ha);

@@ -2588,6 +2599,8 @@ qla2x00_reset_chip(scsi_qla_host_t *vha)
	}

	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return QLA_SUCCESS;
}

/**
@@ -2828,14 +2841,15 @@ acquired:
 *
 * Returns 0 on success.
 */
void
int
qla24xx_reset_chip(scsi_qla_host_t *vha)
{
	struct qla_hw_data *ha = vha->hw;
	int rval = QLA_FUNCTION_FAILED;

	if (pci_channel_offline(ha->pdev) &&
	    ha->flags.pci_channel_io_perm_failure) {
		return;
		return rval;
	}

	ha->isp_ops->disable_intrs(ha);
@@ -2843,7 +2857,9 @@ qla24xx_reset_chip(scsi_qla_host_t *vha)
	qla25xx_manipulate_risc_semaphore(vha);

	/* Perform RISC reset. */
	qla24xx_reset_risc(vha);
	rval = qla24xx_reset_risc(vha);

	return rval;
}

/**
@@ -6671,6 +6687,14 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
	if (vha->flags.online) {
		qla2x00_abort_isp_cleanup(vha);

		if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
			ha->flags.chip_reset_done = 1;
			vha->flags.online = 1;
			status = 0;
			clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
			return status;
		}

		if (IS_QLA8031(ha)) {
			ql_dbg(ql_dbg_p3p, vha, 0xb05c,
			    "Clearing fcoe driver presence.\n");
@@ -6911,7 +6935,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
* Input:
*      ha = adapter block pointer.
*/
void
int
qla2x00_reset_adapter(scsi_qla_host_t *vha)
{
	unsigned long flags = 0;
@@ -6927,17 +6951,20 @@ qla2x00_reset_adapter(scsi_qla_host_t *vha)
	WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
	RD_REG_WORD(&reg->hccr);			/* PCI Posting. */
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return QLA_SUCCESS;
}

void
int
qla24xx_reset_adapter(scsi_qla_host_t *vha)
{
	unsigned long flags = 0;
	struct qla_hw_data *ha = vha->hw;
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
	int rval = QLA_SUCCESS;

	if (IS_P3P_TYPE(ha))
		return;
		return rval;

	vha->flags.online = 0;
	ha->isp_ops->disable_intrs(ha);
@@ -6951,6 +6978,8 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)

	if (IS_NOPOLLING_TYPE(ha))
		ha->isp_ops->enable_intrs(ha);

	return rval;
}

/* On sparc systems, obtain port and node WWN from firmware
@@ -8188,7 +8217,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
	if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
		ha->vpd_size = FA_VPD_SIZE_82XX;

	if (IS_QLA28XX(ha))
	if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
		qla28xx_get_aux_images(vha, &active_regions);

	/* Get VPD data into cache */
+141 −0
Original line number Diff line number Diff line
@@ -1143,6 +1143,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
		ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
		ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22];
		ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24];
		if (IS_QLA28XX(ha)) {
			if (mcp->mb[16] & BIT_10) {
				ql_log(ql_log_info, vha, 0xffff,
				    "FW support secure flash updates\n");
				ha->flags.secure_fw = 1;
			}
		}
	}

failed:
@@ -4593,6 +4600,42 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
	return rval;
}

int
qla81xx_fac_semaphore_access(scsi_qla_host_t *vha, int lock)
{
	int rval = QLA_SUCCESS;
	mbx_cmd_t mc;
	mbx_cmd_t *mcp = &mc;
	struct qla_hw_data *ha = vha->hw;

	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
		return rval;

	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2,
	    "Entered %s.\n", __func__);

	mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
	mcp->mb[1] = (lock ? FAC_OPT_CMD_LOCK_SEMAPHORE :
	    FAC_OPT_CMD_UNLOCK_SEMAPHORE);
	mcp->out_mb = MBX_1|MBX_0;
	mcp->in_mb = MBX_1|MBX_0;
	mcp->tov = MBX_TOV_SECONDS;
	mcp->flags = 0;
	rval = qla2x00_mailbox_command(vha, mcp);

	if (rval != QLA_SUCCESS) {
		ql_dbg(ql_dbg_mbx, vha, 0x10e3,
		    "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
		    rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
	} else {
		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e4,
		    "Done %s.\n", __func__);
	}

	return rval;
}

int
qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
{
@@ -6533,3 +6576,101 @@ int qla24xx_res_count_wait(struct scsi_qla_host *vha,
done:
	return rval;
}

int qla28xx_secure_flash_update(scsi_qla_host_t *vha, uint16_t opts,
    uint16_t region, uint32_t len, dma_addr_t sfub_dma_addr,
    uint32_t sfub_len)
{
	int		rval;
	mbx_cmd_t mc;
	mbx_cmd_t *mcp = &mc;

	mcp->mb[0] = MBC_SECURE_FLASH_UPDATE;
	mcp->mb[1] = opts;
	mcp->mb[2] = region;
	mcp->mb[3] = MSW(len);
	mcp->mb[4] = LSW(len);
	mcp->mb[5] = MSW(sfub_dma_addr);
	mcp->mb[6] = LSW(sfub_dma_addr);
	mcp->mb[7] = MSW(MSD(sfub_dma_addr));
	mcp->mb[8] = LSW(MSD(sfub_dma_addr));
	mcp->mb[9] = sfub_len;
	mcp->out_mb =
	    MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
	mcp->in_mb = MBX_2|MBX_1|MBX_0;
	mcp->tov = MBX_TOV_SECONDS;
	mcp->flags = 0;
	rval = qla2x00_mailbox_command(vha, mcp);

	if (rval != QLA_SUCCESS) {
		ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s(%ld): failed rval 0x%x, %x %x %x",
			__func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1],
			mcp->mb[2]);
	}

	return rval;
}

int qla2xxx_write_remote_register(scsi_qla_host_t *vha, uint32_t addr,
    uint32_t data)
{
	int rval;
	mbx_cmd_t mc;
	mbx_cmd_t *mcp = &mc;

	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8,
	    "Entered %s.\n", __func__);

	mcp->mb[0] = MBC_WRITE_REMOTE_REG;
	mcp->mb[1] = LSW(addr);
	mcp->mb[2] = MSW(addr);
	mcp->mb[3] = LSW(data);
	mcp->mb[4] = MSW(data);
	mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
	mcp->in_mb = MBX_1|MBX_0;
	mcp->tov = MBX_TOV_SECONDS;
	mcp->flags = 0;
	rval = qla2x00_mailbox_command(vha, mcp);

	if (rval != QLA_SUCCESS) {
		ql_dbg(ql_dbg_mbx, vha, 0x10e9,
		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
	} else {
		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
		    "Done %s.\n", __func__);
	}

	return rval;
}

int qla2xxx_read_remote_register(scsi_qla_host_t *vha, uint32_t addr,
    uint32_t *data)
{
	int rval;
	mbx_cmd_t mc;
	mbx_cmd_t *mcp = &mc;

	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8,
	    "Entered %s.\n", __func__);

	mcp->mb[0] = MBC_READ_REMOTE_REG;
	mcp->mb[1] = LSW(addr);
	mcp->mb[2] = MSW(addr);
	mcp->out_mb = MBX_2|MBX_1|MBX_0;
	mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
	mcp->tov = MBX_TOV_SECONDS;
	mcp->flags = 0;
	rval = qla2x00_mailbox_command(vha, mcp);

	*data = (uint32_t)((((uint32_t)mcp->mb[4]) << 16) | mcp->mb[3]);

	if (rval != QLA_SUCCESS) {
		ql_dbg(ql_dbg_mbx, vha, 0x10e9,
		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
	} else {
		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
		    "Done %s.\n", __func__);
	}

	return rval;
}
Loading