scsi: qla2xxx: Secure flash update support for ISP28XX
This patch adds support for Secure flash update with ISP28xx. Signed-off-by: Michael Hernandez <mhernandez@marvell.com> Signed-off-by: Himanshu Madhani <hmadhani@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
5fa8774c7f
commit
3f006ac342
@ -1033,6 +1033,7 @@ struct mbx_cmd_32 {
|
|||||||
#define MBC_GET_FIRMWARE_VERSION 8 /* Get firmware revision. */
|
#define MBC_GET_FIRMWARE_VERSION 8 /* Get firmware revision. */
|
||||||
#define MBC_LOAD_RISC_RAM 9 /* Load RAM command. */
|
#define MBC_LOAD_RISC_RAM 9 /* Load RAM command. */
|
||||||
#define MBC_DUMP_RISC_RAM 0xa /* Dump 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_LOAD_RISC_RAM_EXTENDED 0xb /* Load RAM extended. */
|
||||||
#define MBC_DUMP_RISC_RAM_EXTENDED 0xc /* Dump RAM extended. */
|
#define MBC_DUMP_RISC_RAM_EXTENDED 0xc /* Dump RAM extended. */
|
||||||
#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */
|
#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */
|
||||||
@ -3135,10 +3136,10 @@ struct rsp_que;
|
|||||||
struct isp_operations {
|
struct isp_operations {
|
||||||
|
|
||||||
int (*pci_config) (struct scsi_qla_host *);
|
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 *);
|
int (*chip_diag) (struct scsi_qla_host *);
|
||||||
void (*config_rings) (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 *);
|
int (*nvram_config) (struct scsi_qla_host *);
|
||||||
void (*update_fw_options) (struct scsi_qla_host *);
|
void (*update_fw_options) (struct scsi_qla_host *);
|
||||||
int (*load_risc) (struct scsi_qla_host *, uint32_t *);
|
int (*load_risc) (struct scsi_qla_host *, uint32_t *);
|
||||||
@ -3627,6 +3628,8 @@ struct qla_hw_data {
|
|||||||
uint32_t rida_fmt2:1;
|
uint32_t rida_fmt2:1;
|
||||||
uint32_t purge_mbox:1;
|
uint32_t purge_mbox:1;
|
||||||
uint32_t n2n_bigger:1;
|
uint32_t n2n_bigger:1;
|
||||||
|
uint32_t secure_adapter:1;
|
||||||
|
uint32_t secure_fw:1;
|
||||||
} flags;
|
} flags;
|
||||||
|
|
||||||
uint16_t max_exchg;
|
uint16_t max_exchg;
|
||||||
@ -3915,6 +3918,9 @@ struct qla_hw_data {
|
|||||||
void *sfp_data;
|
void *sfp_data;
|
||||||
dma_addr_t sfp_data_dma;
|
dma_addr_t sfp_data_dma;
|
||||||
|
|
||||||
|
void *flt;
|
||||||
|
dma_addr_t flt_dma;
|
||||||
|
|
||||||
#define XGMAC_DATA_SIZE 4096
|
#define XGMAC_DATA_SIZE 4096
|
||||||
void *xgmac_data;
|
void *xgmac_data;
|
||||||
dma_addr_t xgmac_data_dma;
|
dma_addr_t xgmac_data_dma;
|
||||||
@ -4362,6 +4368,7 @@ typedef struct scsi_qla_host {
|
|||||||
#define N2N_LOGIN_NEEDED 30
|
#define N2N_LOGIN_NEEDED 30
|
||||||
#define IOCB_WORK_ACTIVE 31
|
#define IOCB_WORK_ACTIVE 31
|
||||||
#define SET_ZIO_THRESHOLD_NEEDED 32
|
#define SET_ZIO_THRESHOLD_NEEDED 32
|
||||||
|
#define ISP_ABORT_TO_ROM 33
|
||||||
|
|
||||||
unsigned long pci_flags;
|
unsigned long pci_flags;
|
||||||
#define PFLG_DISCONNECTED 0 /* PCI device removed */
|
#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.
|
* Macros to help code, maintain, etc.
|
||||||
*/
|
*/
|
||||||
@ -4749,6 +4774,8 @@ struct sff_8247_a0 {
|
|||||||
IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \
|
IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \
|
||||||
IS_QLA28XX(_vha->hw)))
|
IS_QLA28XX(_vha->hw)))
|
||||||
|
|
||||||
|
#define FLASH_SEMAPHORE_REGISTER_ADDR 0x00101016
|
||||||
|
|
||||||
#define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \
|
#define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \
|
||||||
(IS_QLA27XX(_ha) || IS_QLA28XX(_ha) || IS_QLA83XX(_ha)))
|
(IS_QLA27XX(_ha) || IS_QLA28XX(_ha) || IS_QLA83XX(_ha)))
|
||||||
|
|
||||||
|
@ -1536,6 +1536,10 @@ struct qla_flt_region {
|
|||||||
uint32_t end;
|
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 ********************************************/
|
/* Flash NPIV Configuration Table ********************************************/
|
||||||
|
|
||||||
struct qla_npiv_header {
|
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_SHIFT (LR_DIST_FW_POS - LR_DIST_NV_POS)
|
||||||
#define LR_DIST_FW_FIELD(x) ((x) << LR_DIST_FW_SHIFT & 0xf000)
|
#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 {
|
struct nvram_81xx {
|
||||||
/* NVRAM header. */
|
/* NVRAM header. */
|
||||||
uint8_t id[4];
|
uint8_t id[4];
|
||||||
|
@ -18,14 +18,14 @@ extern int qla2100_pci_config(struct scsi_qla_host *);
|
|||||||
extern int qla2300_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 qla24xx_pci_config(scsi_qla_host_t *);
|
||||||
extern int qla25xx_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 int qla2x00_reset_chip(struct scsi_qla_host *);
|
||||||
extern void qla24xx_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 qla2x00_chip_diag(struct scsi_qla_host *);
|
||||||
extern int qla24xx_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 qla2x00_config_rings(struct scsi_qla_host *);
|
||||||
extern void qla24xx_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 int qla2x00_reset_adapter(struct scsi_qla_host *);
|
||||||
extern void qla24xx_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 qla2x00_nvram_config(struct scsi_qla_host *);
|
||||||
extern int qla24xx_nvram_config(struct scsi_qla_host *);
|
extern int qla24xx_nvram_config(struct scsi_qla_host *);
|
||||||
extern int qla81xx_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
|
extern int
|
||||||
qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);
|
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
|
extern int
|
||||||
qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *);
|
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);
|
extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t);
|
||||||
int qla24xx_res_count_wait(struct scsi_qla_host *, uint16_t *, int);
|
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.
|
* 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 */
|
/* qlafx00 related functions */
|
||||||
extern int qlafx00_pci_config(struct scsi_qla_host *);
|
extern int qlafx00_pci_config(struct scsi_qla_host *);
|
||||||
extern int qlafx00_initialize_adapter(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 int qlafx00_chip_diag(scsi_qla_host_t *);
|
||||||
extern void qlafx00_config_rings(struct scsi_qla_host *);
|
extern void qlafx00_config_rings(struct scsi_qla_host *);
|
||||||
extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *);
|
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 *);
|
extern int qla82xx_iospace_config(struct qla_hw_data *);
|
||||||
|
|
||||||
/* Initialization related functions */
|
/* 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_config_rings(struct scsi_qla_host *);
|
||||||
extern void qla82xx_watchdog(scsi_qla_host_t *);
|
extern void qla82xx_watchdog(scsi_qla_host_t *);
|
||||||
extern int qla82xx_start_firmware(scsi_qla_host_t *);
|
extern int qla82xx_start_firmware(scsi_qla_host_t *);
|
||||||
|
@ -2102,6 +2102,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
|||||||
int rval;
|
int rval;
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
struct req_que *req = ha->req_q_map[0];
|
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->qla_stats, 0, sizeof(vha->qla_stats));
|
||||||
memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
|
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);
|
ha->isp_ops->reset_chip(vha);
|
||||||
|
|
||||||
|
/* Check for secure flash support */
|
||||||
|
if (IS_QLA28XX(ha)) {
|
||||||
|
if (RD_REG_DWORD(®->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);
|
rval = qla2xxx_get_flash_info(vha);
|
||||||
if (rval) {
|
if (rval) {
|
||||||
ql_log(ql_log_fatal, vha, 0x004f,
|
ql_log(ql_log_fatal, vha, 0x004f,
|
||||||
@ -2452,7 +2462,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
|
|||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
qla2x00_reset_chip(scsi_qla_host_t *vha)
|
qla2x00_reset_chip(scsi_qla_host_t *vha)
|
||||||
{
|
{
|
||||||
unsigned long flags = 0;
|
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;
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
||||||
uint32_t cnt;
|
uint32_t cnt;
|
||||||
uint16_t cmd;
|
uint16_t cmd;
|
||||||
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
if (unlikely(pci_channel_offline(ha->pdev)))
|
if (unlikely(pci_channel_offline(ha->pdev)))
|
||||||
return;
|
return rval;
|
||||||
|
|
||||||
ha->isp_ops->disable_intrs(ha);
|
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);
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||||
|
|
||||||
|
return QLA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2828,14 +2841,15 @@ acquired:
|
|||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
qla24xx_reset_chip(scsi_qla_host_t *vha)
|
qla24xx_reset_chip(scsi_qla_host_t *vha)
|
||||||
{
|
{
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
if (pci_channel_offline(ha->pdev) &&
|
if (pci_channel_offline(ha->pdev) &&
|
||||||
ha->flags.pci_channel_io_perm_failure) {
|
ha->flags.pci_channel_io_perm_failure) {
|
||||||
return;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha->isp_ops->disable_intrs(ha);
|
ha->isp_ops->disable_intrs(ha);
|
||||||
@ -2843,7 +2857,9 @@ qla24xx_reset_chip(scsi_qla_host_t *vha)
|
|||||||
qla25xx_manipulate_risc_semaphore(vha);
|
qla25xx_manipulate_risc_semaphore(vha);
|
||||||
|
|
||||||
/* Perform RISC reset. */
|
/* 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) {
|
if (vha->flags.online) {
|
||||||
qla2x00_abort_isp_cleanup(vha);
|
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)) {
|
if (IS_QLA8031(ha)) {
|
||||||
ql_dbg(ql_dbg_p3p, vha, 0xb05c,
|
ql_dbg(ql_dbg_p3p, vha, 0xb05c,
|
||||||
"Clearing fcoe driver presence.\n");
|
"Clearing fcoe driver presence.\n");
|
||||||
@ -6911,7 +6935,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
|
|||||||
* Input:
|
* Input:
|
||||||
* ha = adapter block pointer.
|
* ha = adapter block pointer.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
qla2x00_reset_adapter(scsi_qla_host_t *vha)
|
qla2x00_reset_adapter(scsi_qla_host_t *vha)
|
||||||
{
|
{
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
@ -6927,17 +6951,20 @@ qla2x00_reset_adapter(scsi_qla_host_t *vha)
|
|||||||
WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC);
|
WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC);
|
||||||
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
||||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||||
|
|
||||||
|
return QLA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
qla24xx_reset_adapter(scsi_qla_host_t *vha)
|
qla24xx_reset_adapter(scsi_qla_host_t *vha)
|
||||||
{
|
{
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||||
|
int rval = QLA_SUCCESS;
|
||||||
|
|
||||||
if (IS_P3P_TYPE(ha))
|
if (IS_P3P_TYPE(ha))
|
||||||
return;
|
return rval;
|
||||||
|
|
||||||
vha->flags.online = 0;
|
vha->flags.online = 0;
|
||||||
ha->isp_ops->disable_intrs(ha);
|
ha->isp_ops->disable_intrs(ha);
|
||||||
@ -6951,6 +6978,8 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)
|
|||||||
|
|
||||||
if (IS_NOPOLLING_TYPE(ha))
|
if (IS_NOPOLLING_TYPE(ha))
|
||||||
ha->isp_ops->enable_intrs(ha);
|
ha->isp_ops->enable_intrs(ha);
|
||||||
|
|
||||||
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On sparc systems, obtain port and node WWN from firmware
|
/* 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))
|
if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
|
||||||
ha->vpd_size = FA_VPD_SIZE_82XX;
|
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);
|
qla28xx_get_aux_images(vha, &active_regions);
|
||||||
|
|
||||||
/* Get VPD data into cache */
|
/* Get VPD data into cache */
|
||||||
|
@ -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_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_start = (mcp->mb[23] << 16) | mcp->mb[22];
|
||||||
ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24];
|
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:
|
failed:
|
||||||
@ -4593,6 +4600,42 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
|
|||||||
return rval;
|
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
|
int
|
||||||
qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
|
qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
|
||||||
{
|
{
|
||||||
@ -6533,3 +6576,101 @@ int qla24xx_res_count_wait(struct scsi_qla_host *vha,
|
|||||||
done:
|
done:
|
||||||
return rval;
|
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;
|
||||||
|
}
|
||||||
|
@ -629,17 +629,20 @@ qlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
|
|||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
qlafx00_soft_reset(scsi_qla_host_t *vha)
|
qlafx00_soft_reset(scsi_qla_host_t *vha)
|
||||||
{
|
{
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
if (unlikely(pci_channel_offline(ha->pdev) &&
|
if (unlikely(pci_channel_offline(ha->pdev) &&
|
||||||
ha->flags.pci_channel_io_perm_failure))
|
ha->flags.pci_channel_io_perm_failure))
|
||||||
return;
|
return rval;
|
||||||
|
|
||||||
ha->isp_ops->disable_intrs(ha);
|
ha->isp_ops->disable_intrs(ha);
|
||||||
qlafx00_soc_cpu_reset(vha);
|
qlafx00_soc_cpu_reset(vha);
|
||||||
|
|
||||||
|
return QLA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1757,11 +1757,13 @@ qla82xx_pci_config(scsi_qla_host_t *vha)
|
|||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
qla82xx_reset_chip(scsi_qla_host_t *vha)
|
qla82xx_reset_chip(scsi_qla_host_t *vha)
|
||||||
{
|
{
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
ha->isp_ops->disable_intrs(ha);
|
ha->isp_ops->disable_intrs(ha);
|
||||||
|
|
||||||
|
return QLA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qla82xx_config_rings(struct scsi_qla_host *vha)
|
void qla82xx_config_rings(struct scsi_qla_host *vha)
|
||||||
|
@ -42,7 +42,7 @@ static struct kmem_cache *ctx_cachep;
|
|||||||
/*
|
/*
|
||||||
* error level for logging
|
* error level for logging
|
||||||
*/
|
*/
|
||||||
uint ql_errlev = ql_log_all;
|
uint ql_errlev = 0x8001;
|
||||||
|
|
||||||
static int ql2xenableclass2;
|
static int ql2xenableclass2;
|
||||||
module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR);
|
module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR);
|
||||||
@ -4310,8 +4310,20 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
|||||||
goto fail_sfp_data;
|
goto fail_sfp_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ha->flt = dma_alloc_coherent(&ha->pdev->dev,
|
||||||
|
sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, &ha->flt_dma,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!ha->flt) {
|
||||||
|
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
|
||||||
|
"Unable to allocate memory for FLT.\n");
|
||||||
|
goto fail_flt_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_flt_buffer:
|
||||||
|
dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
|
||||||
|
ha->sfp_data, ha->sfp_data_dma);
|
||||||
fail_sfp_data:
|
fail_sfp_data:
|
||||||
kfree(ha->loop_id_map);
|
kfree(ha->loop_id_map);
|
||||||
fail_loop_id_map:
|
fail_loop_id_map:
|
||||||
@ -4717,6 +4729,10 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
|||||||
dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data,
|
dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data,
|
||||||
ha->sfp_data_dma);
|
ha->sfp_data_dma);
|
||||||
|
|
||||||
|
if (ha->flt)
|
||||||
|
dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
|
||||||
|
ha->flt, ha->flt_dma);
|
||||||
|
|
||||||
if (ha->ms_iocb)
|
if (ha->ms_iocb)
|
||||||
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
|
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
|
||||||
|
|
||||||
|
@ -634,7 +634,7 @@ end:
|
|||||||
static void
|
static void
|
||||||
qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
||||||
{
|
{
|
||||||
const char *loc, *locations[] = { "DEF", "FLT" };
|
const char *locations[] = { "DEF", "FLT" }, *loc = locations[1];
|
||||||
const uint32_t def_fw[] =
|
const uint32_t def_fw[] =
|
||||||
{ FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 };
|
{ FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 };
|
||||||
const uint32_t def_boot[] =
|
const uint32_t def_boot[] =
|
||||||
@ -664,20 +664,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
|||||||
const uint32_t fcp_prio_cfg1[] =
|
const uint32_t fcp_prio_cfg1[] =
|
||||||
{ FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25,
|
{ FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25,
|
||||||
0 };
|
0 };
|
||||||
uint32_t def;
|
|
||||||
uint16_t *wptr;
|
|
||||||
uint16_t cnt, chksum;
|
|
||||||
uint32_t start;
|
|
||||||
struct qla_flt_header *flt;
|
|
||||||
struct qla_flt_region *region;
|
|
||||||
struct qla_hw_data *ha = vha->hw;
|
|
||||||
struct req_que *req = ha->req_q_map[0];
|
|
||||||
|
|
||||||
def = 0;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
if (IS_QLA25XX(ha))
|
uint32_t def = IS_QLA81XX(ha) ? 2 : IS_QLA25XX(ha) ? 1 : 0;
|
||||||
def = 1;
|
struct qla_flt_header *flt = (void *)ha->flt;
|
||||||
else if (IS_QLA81XX(ha))
|
struct qla_flt_region *region = (void *)&flt[1];
|
||||||
def = 2;
|
uint16_t *wptr, cnt, chksum;
|
||||||
|
uint32_t start;
|
||||||
|
|
||||||
/* Assign FCP prio region since older adapters may not have FLT, or
|
/* Assign FCP prio region since older adapters may not have FLT, or
|
||||||
FCP prio region in it's FLT.
|
FCP prio region in it's FLT.
|
||||||
@ -686,12 +679,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
|||||||
fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
|
fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
|
||||||
|
|
||||||
ha->flt_region_flt = flt_addr;
|
ha->flt_region_flt = flt_addr;
|
||||||
wptr = (uint16_t *)req->ring;
|
wptr = (uint16_t *)ha->flt;
|
||||||
flt = (struct qla_flt_header *)req->ring;
|
qla24xx_read_flash_data(vha, (void *)flt, flt_addr,
|
||||||
region = (struct qla_flt_region *)&flt[1];
|
(sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE) >> 2);
|
||||||
ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring,
|
|
||||||
flt_addr << 2, OPTROM_BURST_SIZE);
|
if (le16_to_cpu(*wptr) == 0xffff)
|
||||||
if (*wptr == cpu_to_le16(0xffff))
|
|
||||||
goto no_flash_data;
|
goto no_flash_data;
|
||||||
if (flt->version != cpu_to_le16(1)) {
|
if (flt->version != cpu_to_le16(1)) {
|
||||||
ql_log(ql_log_warn, vha, 0x0047,
|
ql_log(ql_log_warn, vha, 0x0047,
|
||||||
@ -701,7 +693,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
|||||||
goto no_flash_data;
|
goto no_flash_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
|
cnt = (sizeof(*flt) + le16_to_cpu(flt->length)) / sizeof(*wptr);
|
||||||
for (chksum = 0; cnt--; wptr++)
|
for (chksum = 0; cnt--; wptr++)
|
||||||
chksum += le16_to_cpu(*wptr);
|
chksum += le16_to_cpu(*wptr);
|
||||||
if (chksum) {
|
if (chksum) {
|
||||||
@ -712,16 +704,18 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
|||||||
goto no_flash_data;
|
goto no_flash_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
loc = locations[1];
|
cnt = le16_to_cpu(flt->length) / sizeof(*region);
|
||||||
cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
|
|
||||||
for ( ; cnt; cnt--, region++) {
|
for ( ; cnt; cnt--, region++) {
|
||||||
/* Store addresses as DWORD offsets. */
|
/* Store addresses as DWORD offsets. */
|
||||||
start = le32_to_cpu(region->start) >> 2;
|
start = le32_to_cpu(region->start) >> 2;
|
||||||
ql_dbg(ql_dbg_init, vha, 0x0049,
|
ql_dbg(ql_dbg_init, vha, 0x0049,
|
||||||
"FLT[%#x]: start=%#x end=%#x size=%#x.\n",
|
"FLT[%#x]: start=%#x end=%#x size=%#x.\n",
|
||||||
le16_to_cpu(region->code),
|
le16_to_cpu(region->code), start,
|
||||||
start, le32_to_cpu(region->end) >> 2,
|
le32_to_cpu(region->end) >> 2,
|
||||||
le32_to_cpu(region->size));
|
le32_to_cpu(region->size) >> 2);
|
||||||
|
if (region->attribute)
|
||||||
|
ql_log(ql_dbg_init, vha, 0xffff,
|
||||||
|
"Region %x is secure\n", region->code);
|
||||||
|
|
||||||
switch (le16_to_cpu(region->code)) {
|
switch (le16_to_cpu(region->code)) {
|
||||||
case FLT_REG_FCOE_FW:
|
case FLT_REG_FCOE_FW:
|
||||||
@ -2623,6 +2617,338 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qla28xx_extract_sfub_and_verify(struct scsi_qla_host *vha, uint32_t *buf,
|
||||||
|
uint32_t len, uint32_t buf_size_without_sfub, uint8_t *sfub_buf)
|
||||||
|
{
|
||||||
|
uint32_t *p, check_sum = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
p = buf + buf_size_without_sfub;
|
||||||
|
|
||||||
|
/* Extract SFUB from end of file */
|
||||||
|
memcpy(sfub_buf, (uint8_t *)p,
|
||||||
|
sizeof(struct secure_flash_update_block));
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(struct secure_flash_update_block) >> 2); i++)
|
||||||
|
check_sum += p[i];
|
||||||
|
|
||||||
|
check_sum = (~check_sum) + 1;
|
||||||
|
|
||||||
|
if (check_sum != p[i]) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x7097,
|
||||||
|
"SFUB checksum failed, 0x%x, 0x%x\n",
|
||||||
|
check_sum, p[i]);
|
||||||
|
return QLA_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QLA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qla28xx_get_flash_region(struct scsi_qla_host *vha, uint32_t start,
|
||||||
|
struct qla_flt_region *region)
|
||||||
|
{
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
struct qla_flt_header *flt;
|
||||||
|
struct qla_flt_region *flt_reg;
|
||||||
|
uint16_t cnt;
|
||||||
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
if (!ha->flt)
|
||||||
|
return QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
flt = (struct qla_flt_header *)ha->flt;
|
||||||
|
flt_reg = (struct qla_flt_region *)&flt[1];
|
||||||
|
cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
|
||||||
|
|
||||||
|
for (; cnt; cnt--, flt_reg++) {
|
||||||
|
if (flt_reg->start == start) {
|
||||||
|
memcpy((uint8_t *)region, flt_reg,
|
||||||
|
sizeof(struct qla_flt_region));
|
||||||
|
rval = QLA_SUCCESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
||||||
|
uint32_t dwords)
|
||||||
|
{
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
ulong liter;
|
||||||
|
ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */
|
||||||
|
uint32_t sec_mask, rest_addr, fdata;
|
||||||
|
void *optrom = NULL;
|
||||||
|
dma_addr_t optrom_dma;
|
||||||
|
int rval;
|
||||||
|
struct secure_flash_update_block *sfub;
|
||||||
|
dma_addr_t sfub_dma;
|
||||||
|
uint32_t offset = faddr << 2;
|
||||||
|
uint32_t buf_size_without_sfub = 0;
|
||||||
|
struct qla_flt_region region;
|
||||||
|
bool reset_to_rom = false;
|
||||||
|
uint32_t risc_size, risc_attr = 0;
|
||||||
|
uint32_t *fw_array = NULL;
|
||||||
|
|
||||||
|
/* Retrieve region info - must be a start address passed in */
|
||||||
|
rval = qla28xx_get_flash_region(vha, offset, ®ion);
|
||||||
|
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Invalid address %x - not a region start address\n",
|
||||||
|
offset);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate dma buffer for burst write */
|
||||||
|
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||||
|
&optrom_dma, GFP_KERNEL);
|
||||||
|
if (!optrom) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x7095,
|
||||||
|
"Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE);
|
||||||
|
rval = QLA_COMMAND_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If adapter supports secure flash and region is secure
|
||||||
|
* extract secure flash update block (SFUB) and verify
|
||||||
|
*/
|
||||||
|
if (ha->flags.secure_adapter && region.attribute) {
|
||||||
|
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"Region %x is secure\n", region.code);
|
||||||
|
|
||||||
|
if (region.code == FLT_REG_FW ||
|
||||||
|
region.code == FLT_REG_FW_SEC_27XX) {
|
||||||
|
fw_array = dwptr;
|
||||||
|
|
||||||
|
/* 1st fw array */
|
||||||
|
risc_size = be32_to_cpu(fw_array[3]);
|
||||||
|
risc_attr = be32_to_cpu(fw_array[9]);
|
||||||
|
|
||||||
|
buf_size_without_sfub = risc_size;
|
||||||
|
fw_array += risc_size;
|
||||||
|
|
||||||
|
/* 2nd fw array */
|
||||||
|
risc_size = be32_to_cpu(fw_array[3]);
|
||||||
|
|
||||||
|
buf_size_without_sfub += risc_size;
|
||||||
|
fw_array += risc_size;
|
||||||
|
|
||||||
|
/* 1st dump template */
|
||||||
|
risc_size = be32_to_cpu(fw_array[2]);
|
||||||
|
|
||||||
|
/* skip header and ignore checksum */
|
||||||
|
buf_size_without_sfub += risc_size;
|
||||||
|
fw_array += risc_size;
|
||||||
|
|
||||||
|
if (risc_attr & BIT_9) {
|
||||||
|
/* 2nd dump template */
|
||||||
|
risc_size = be32_to_cpu(fw_array[2]);
|
||||||
|
|
||||||
|
/* skip header and ignore checksum */
|
||||||
|
buf_size_without_sfub += risc_size;
|
||||||
|
fw_array += risc_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"Secure region %x not supported\n",
|
||||||
|
region.code);
|
||||||
|
rval = QLA_COMMAND_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfub = dma_alloc_coherent(&ha->pdev->dev,
|
||||||
|
sizeof(struct secure_flash_update_block), &sfub_dma,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!sfub) {
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Unable to allocate memory for SFUB\n");
|
||||||
|
rval = QLA_COMMAND_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
rval = qla28xx_extract_sfub_and_verify(vha, dwptr, dwords,
|
||||||
|
buf_size_without_sfub, (uint8_t *)sfub);
|
||||||
|
|
||||||
|
if (rval != QLA_SUCCESS)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"SFUB extract and verify successful\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
rest_addr = (ha->fdt_block_size >> 2) - 1;
|
||||||
|
sec_mask = ~rest_addr;
|
||||||
|
|
||||||
|
/* Lock semaphore */
|
||||||
|
rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK);
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Unable to lock flash semaphore.");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
|
||||||
|
"Unprotect flash...\n");
|
||||||
|
rval = qla24xx_unprotect_flash(vha);
|
||||||
|
if (rval) {
|
||||||
|
qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
|
||||||
|
ql_log(ql_log_warn, vha, 0x7096, "Failed unprotect flash\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (liter = 0; liter < dwords; liter++, faddr++) {
|
||||||
|
fdata = (faddr & sec_mask) << 2;
|
||||||
|
|
||||||
|
/* If start of sector */
|
||||||
|
if (!(faddr & rest_addr)) {
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
|
||||||
|
"Erase sector %#x...\n", faddr);
|
||||||
|
rval = qla24xx_erase_sector(vha, fdata);
|
||||||
|
if (rval) {
|
||||||
|
ql_dbg(ql_dbg_user, vha, 0x7007,
|
||||||
|
"Failed erase sector %#x\n", faddr);
|
||||||
|
goto write_protect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ha->flags.secure_adapter) {
|
||||||
|
/*
|
||||||
|
* If adapter supports secure flash but FW doesn't,
|
||||||
|
* disable write protect, release semaphore and reset
|
||||||
|
* chip to execute ROM code in order to update region securely
|
||||||
|
*/
|
||||||
|
if (!ha->flags.secure_fw) {
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"Disable Write and Release Semaphore.");
|
||||||
|
rval = qla24xx_protect_flash(vha);
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
qla81xx_fac_semaphore_access(vha,
|
||||||
|
FAC_SEMAPHORE_UNLOCK);
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Unable to protect flash.");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"Reset chip to ROM.");
|
||||||
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||||
|
set_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags);
|
||||||
|
qla2xxx_wake_dpc(vha);
|
||||||
|
rval = qla2x00_wait_for_chip_reset(vha);
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Unable to reset to ROM code.");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
reset_to_rom = true;
|
||||||
|
ha->flags.fac_supported = 0;
|
||||||
|
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"Lock Semaphore");
|
||||||
|
rval = qla2xxx_write_remote_register(vha,
|
||||||
|
FLASH_SEMAPHORE_REGISTER_ADDR, 0x00020002);
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Unable to lock flash semaphore.");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unprotect flash */
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"Enable Write.");
|
||||||
|
rval = qla2x00_write_ram_word(vha, 0x7ffd0101, 0);
|
||||||
|
if (rval) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x7096,
|
||||||
|
"Failed unprotect flash\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If region is secure, send Secure Flash MB Cmd */
|
||||||
|
if (region.attribute && buf_size_without_sfub) {
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
|
||||||
|
"Sending Secure Flash MB Cmd\n");
|
||||||
|
rval = qla28xx_secure_flash_update(vha, 0, region.code,
|
||||||
|
buf_size_without_sfub, sfub_dma,
|
||||||
|
sizeof(struct secure_flash_update_block));
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Secure Flash MB Cmd failed %x.", rval);
|
||||||
|
goto write_protect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-init flash offset */
|
||||||
|
faddr = offset >> 2;
|
||||||
|
|
||||||
|
for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
|
||||||
|
fdata = (faddr & sec_mask) << 2;
|
||||||
|
|
||||||
|
/* If smaller than a burst remaining */
|
||||||
|
if (dwords - liter < dburst)
|
||||||
|
dburst = dwords - liter;
|
||||||
|
|
||||||
|
/* Copy to dma buffer */
|
||||||
|
memcpy(optrom, dwptr, dburst << 2);
|
||||||
|
|
||||||
|
/* Burst write */
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
|
||||||
|
"Write burst (%#lx dwords)...\n", dburst);
|
||||||
|
rval = qla2x00_load_ram(vha, optrom_dma,
|
||||||
|
flash_data_addr(ha, faddr), dburst);
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x7097,
|
||||||
|
"Failed burst write at %x (%p/%#llx)...\n",
|
||||||
|
flash_data_addr(ha, faddr), optrom,
|
||||||
|
(u64)optrom_dma);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
liter += dburst - 1;
|
||||||
|
faddr += dburst - 1;
|
||||||
|
dwptr += dburst - 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_protect:
|
||||||
|
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
|
||||||
|
"Protect flash...\n");
|
||||||
|
rval = qla24xx_protect_flash(vha);
|
||||||
|
if (rval) {
|
||||||
|
qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
|
||||||
|
ql_log(ql_log_warn, vha, 0x7099,
|
||||||
|
"Failed protect flash\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset_to_rom == true) {
|
||||||
|
/* Schedule DPC to restart the RISC */
|
||||||
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||||
|
qla2xxx_wake_dpc(vha);
|
||||||
|
|
||||||
|
rval = qla2x00_wait_for_hba_online(vha);
|
||||||
|
if (rval != QLA_SUCCESS)
|
||||||
|
ql_log(ql_log_warn, vha, 0xffff,
|
||||||
|
"Adapter did not come out of reset\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (optrom)
|
||||||
|
dma_free_coherent(&ha->pdev->dev,
|
||||||
|
OPTROM_BURST_SIZE, optrom, optrom_dma);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
|
qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
|
||||||
uint32_t offset, uint32_t length)
|
uint32_t offset, uint32_t length)
|
||||||
@ -2635,8 +2961,12 @@ qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
|
|||||||
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
|
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
|
||||||
|
|
||||||
/* Go with write. */
|
/* Go with write. */
|
||||||
rval = qla24xx_write_flash_data(vha, buf, offset >> 2,
|
if (IS_QLA28XX(ha))
|
||||||
length >> 2);
|
rval = qla28xx_write_flash_data(vha, (uint32_t *)buf,
|
||||||
|
offset >> 2, length >> 2);
|
||||||
|
else
|
||||||
|
rval = qla24xx_write_flash_data(vha, (uint32_t *)buf,
|
||||||
|
offset >> 2, length >> 2);
|
||||||
|
|
||||||
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
|
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
|
||||||
scsi_unblock_requests(vha->host);
|
scsi_unblock_requests(vha->host);
|
||||||
@ -3151,6 +3481,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
|||||||
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
|
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
|
||||||
faddr = ha->flt_region_fw;
|
faddr = ha->flt_region_fw;
|
||||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||||
|
qla27xx_get_active_image(vha, &active_regions);
|
||||||
if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
|
if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
|
||||||
faddr = ha->flt_region_fw_sec;
|
faddr = ha->flt_region_fw_sec;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user