[SCSI] qla2xxx: Add Flash-Access-Control support for recent ISPs.
Given the low-level interface varies from one flash-part manufacturer to the next, the Flash-Access-Control (FAC) mailbox command makes the specific flash type transparent to the driver by encapsulating a basic set of accessor and update routines. Use these new routines where applicable by querying FAC opcode get-sector-size at init-time. Additional cleanups and Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
Родитель
b997876987
Коммит
1d2874de80
|
@ -2260,7 +2260,7 @@ struct qla_hw_data {
|
|||
uint32_t vsan_enabled :1;
|
||||
uint32_t npiv_supported :1;
|
||||
uint32_t fce_enabled :1;
|
||||
uint32_t hw_event_marker_found:1;
|
||||
uint32_t fac_supported :1;
|
||||
} flags;
|
||||
|
||||
/* This spinlock is used to protect "io transactions", you must
|
||||
|
@ -2382,6 +2382,7 @@ struct qla_hw_data {
|
|||
IS_QLA25XX(ha) || IS_QLA81XX(ha))
|
||||
#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \
|
||||
(ha)->flags.msix_enabled)
|
||||
#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha))
|
||||
|
||||
#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
|
||||
#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)
|
||||
|
|
|
@ -1403,6 +1403,20 @@ struct access_chip_rsp_84xx {
|
|||
#define MBA_IDC_TIME_EXT 0x8102
|
||||
|
||||
#define MBC_IDC_ACK 0x101
|
||||
#define MBC_FLASH_ACCESS_CTRL 0x3e /* Control flash access. */
|
||||
|
||||
/* Flash access control option field bit definitions */
|
||||
#define FAC_OPT_FORCE_SEMAPHORE BIT_15
|
||||
#define FAC_OPT_REQUESTOR_ID BIT_14
|
||||
#define FAC_OPT_CMD_SUBCODE 0xff
|
||||
|
||||
/* Flash access control command subcodes */
|
||||
#define FAC_OPT_CMD_WRITE_PROTECT 0x00
|
||||
#define FAC_OPT_CMD_WRITE_ENABLE 0x01
|
||||
#define FAC_OPT_CMD_ERASE_SECTOR 0x02
|
||||
#define FAC_OPT_CMD_LOCK_SEMAPHORE 0x03
|
||||
#define FAC_OPT_CMD_UNLOCK_SEMAPHORE 0x04
|
||||
#define FAC_OPT_CMD_GET_SECTOR_SIZE 0x05
|
||||
|
||||
struct nvram_81xx {
|
||||
/* NVRAM header. */
|
||||
|
|
|
@ -269,6 +269,15 @@ extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *);
|
|||
|
||||
extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *);
|
||||
|
||||
extern int
|
||||
qla81xx_fac_get_sector_size(scsi_qla_host_t *, uint32_t *);
|
||||
|
||||
extern int
|
||||
qla81xx_fac_do_write_enable(scsi_qla_host_t *, int);
|
||||
|
||||
extern int
|
||||
qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_isr.c source file.
|
||||
*/
|
||||
|
|
|
@ -1032,6 +1032,21 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
|
|||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
|
||||
if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
|
||||
uint32_t size;
|
||||
|
||||
rval = qla81xx_fac_get_sector_size(vha, &size);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
ha->flags.fac_supported = 1;
|
||||
ha->fdt_block_size = size << 2;
|
||||
} else {
|
||||
qla_printk(KERN_ERR, ha,
|
||||
"Unsupported FAC firmware (%d.%02d.%02d).\n",
|
||||
ha->fw_major_version, ha->fw_minor_version,
|
||||
ha->fw_subminor_version);
|
||||
}
|
||||
}
|
||||
|
||||
if (rval) {
|
||||
DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
|
||||
vha->host_no));
|
||||
|
|
|
@ -3228,3 +3228,100 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
|
|||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA81XX(vha->hw))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
|
||||
|
||||
mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
|
||||
mcp->mb[1] = FAC_OPT_CMD_GET_SECTOR_SIZE;
|
||||
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) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
|
||||
__func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
|
||||
} else {
|
||||
DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
|
||||
*sector_size = mcp->mb[1];
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA81XX(vha->hw))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
|
||||
|
||||
mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
|
||||
mcp->mb[1] = enable ? FAC_OPT_CMD_WRITE_ENABLE :
|
||||
FAC_OPT_CMD_WRITE_PROTECT;
|
||||
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) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
|
||||
__func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
|
||||
} else {
|
||||
DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA81XX(vha->hw))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
|
||||
|
||||
mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
|
||||
mcp->mb[1] = FAC_OPT_CMD_ERASE_SECTOR;
|
||||
mcp->mb[2] = LSW(start);
|
||||
mcp->mb[3] = MSW(start);
|
||||
mcp->mb[4] = LSW(finish);
|
||||
mcp->mb[5] = MSW(finish);
|
||||
mcp->out_mb = 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) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
|
||||
"mb[2]=%x.\n", __func__, vha->host_no, rval, mcp->mb[0],
|
||||
mcp->mb[1], mcp->mb[2]));
|
||||
} else {
|
||||
DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
|
|
@ -931,31 +931,41 @@ done:
|
|||
ha->npiv_info = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
qla24xx_unprotect_flash(struct qla_hw_data *ha)
|
||||
static int
|
||||
qla24xx_unprotect_flash(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||
|
||||
if (ha->flags.fac_supported)
|
||||
return qla81xx_fac_do_write_enable(vha, 1);
|
||||
|
||||
/* Enable flash write. */
|
||||
WRT_REG_DWORD(®->ctrl_status,
|
||||
RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE);
|
||||
RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
|
||||
|
||||
if (!ha->fdt_wrt_disable)
|
||||
return;
|
||||
goto done;
|
||||
|
||||
/* Disable flash write-protection, first clear SR protection bit */
|
||||
qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0);
|
||||
/* Then write zero again to clear remaining SR bits.*/
|
||||
qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0);
|
||||
done:
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
qla24xx_protect_flash(struct qla_hw_data *ha)
|
||||
static int
|
||||
qla24xx_protect_flash(scsi_qla_host_t *vha)
|
||||
{
|
||||
uint32_t cnt;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||
|
||||
if (ha->flags.fac_supported)
|
||||
return qla81xx_fac_do_write_enable(vha, 0);
|
||||
|
||||
if (!ha->fdt_wrt_disable)
|
||||
goto skip_wrt_protect;
|
||||
|
||||
|
@ -973,6 +983,26 @@ skip_wrt_protect:
|
|||
WRT_REG_DWORD(®->ctrl_status,
|
||||
RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
|
||||
RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
qla24xx_erase_sector(scsi_qla_host_t *vha, uint32_t fdata)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t start, finish;
|
||||
|
||||
if (ha->flags.fac_supported) {
|
||||
start = fdata >> 2;
|
||||
finish = start + (ha->fdt_block_size >> 2) - 1;
|
||||
return qla81xx_fac_erase_sector(vha, flash_data_addr(ha,
|
||||
start), flash_data_addr(ha, finish));
|
||||
}
|
||||
|
||||
return qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd,
|
||||
(fdata & 0xff00) | ((fdata << 16) & 0xff0000) |
|
||||
((fdata >> 16) & 0xff));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -987,8 +1017,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
|||
void *optrom = NULL;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
ret = QLA_SUCCESS;
|
||||
|
||||
/* Prepare burst-capable write on supported ISPs. */
|
||||
if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && !(faddr & 0xfff) &&
|
||||
dwords > OPTROM_BURST_DWORDS) {
|
||||
|
@ -1004,7 +1032,12 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
|||
rest_addr = (ha->fdt_block_size >> 2) - 1;
|
||||
sec_mask = ~rest_addr;
|
||||
|
||||
qla24xx_unprotect_flash(ha);
|
||||
ret = qla24xx_unprotect_flash(vha);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to unprotect flash for update.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
|
||||
fdata = (faddr & sec_mask) << 2;
|
||||
|
@ -1017,9 +1050,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
|||
ha->fdt_unprotect_sec_cmd,
|
||||
(fdata & 0xff00) | ((fdata << 16) &
|
||||
0xff0000) | ((fdata >> 16) & 0xff));
|
||||
ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd,
|
||||
(fdata & 0xff00) |((fdata << 16) &
|
||||
0xff0000) | ((fdata >> 16) & 0xff));
|
||||
ret = qla24xx_erase_sector(vha, fdata);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
DEBUG9(qla_printk("Unable to erase sector: "
|
||||
"address=%x.\n", faddr));
|
||||
|
@ -1073,8 +1104,11 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
|||
0xff0000) | ((fdata >> 16) & 0xff));
|
||||
}
|
||||
|
||||
qla24xx_protect_flash(ha);
|
||||
|
||||
ret = qla24xx_protect_flash(vha);
|
||||
if (ret != QLA_SUCCESS)
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to protect flash after update.\n");
|
||||
done:
|
||||
if (optrom)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
OPTROM_BURST_SIZE, optrom, optrom_dma);
|
||||
|
|
Загрузка…
Ссылка в новой задаче