Skip to content

Commit

Permalink
[SCSI] qla2xxx: Support for loading Unified ROM Image (URI) format fi…
Browse files Browse the repository at this point in the history
…rmware file.

Used bootloder address from FLT while loading FW from flash as well.

Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Harish Zunjarrao authored and James Bottomley committed Jul 27, 2010
1 parent b0cd579 commit 9c2b297
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 7 deletions.
3 changes: 3 additions & 0 deletions drivers/scsi/qla2xxx/qla_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -2788,6 +2788,9 @@ struct qla_hw_data {
uint16_t gbl_dsd_avail;
struct list_head gbl_dsd_list;
#define NUM_DSD_CHAIN 4096

uint8_t fw_type;
__le32 file_prd_off; /* File firmware product offset */
};

/*
Expand Down
184 changes: 177 additions & 7 deletions drivers/scsi/qla2xxx/qla_nx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1407,7 +1407,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
{
int i;
long size = 0;
long flashaddr = BOOTLD_START, memaddr = BOOTLD_START;
long flashaddr = ha->flt_region_bootload << 2;
long memaddr = BOOTLD_START;
u64 data;
u32 high, low;
size = (IMAGE_START - BOOTLD_START) / 8;
Expand Down Expand Up @@ -1677,6 +1678,94 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
return ret;
}

static struct qla82xx_uri_table_desc *
qla82xx_get_table_desc(const u8 *unirom, int section)
{
uint32_t i;
struct qla82xx_uri_table_desc *directory =
(struct qla82xx_uri_table_desc *)&unirom[0];
__le32 offset;
__le32 tab_type;
__le32 entries = cpu_to_le32(directory->num_entries);

for (i = 0; i < entries; i++) {
offset = cpu_to_le32(directory->findex) +
(i * cpu_to_le32(directory->entry_size));
tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8));

if (tab_type == section)
return (struct qla82xx_uri_table_desc *)&unirom[offset];
}

return NULL;
}

static struct qla82xx_uri_data_desc *
qla82xx_get_data_desc(struct qla_hw_data *ha,
u32 section, u32 idx_offset)
{
const u8 *unirom = ha->hablob->fw->data;
int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset));
struct qla82xx_uri_table_desc *tab_desc = NULL;
__le32 offset;

tab_desc = qla82xx_get_table_desc(unirom, section);
if (!tab_desc)
return NULL;

offset = cpu_to_le32(tab_desc->findex) +
(cpu_to_le32(tab_desc->entry_size) * idx);

return (struct qla82xx_uri_data_desc *)&unirom[offset];
}

static u8 *
qla82xx_get_bootld_offset(struct qla_hw_data *ha)
{
u32 offset = BOOTLD_START;
struct qla82xx_uri_data_desc *uri_desc = NULL;

if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
uri_desc = qla82xx_get_data_desc(ha,
QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF);
if (uri_desc)
offset = cpu_to_le32(uri_desc->findex);
}

return (u8 *)&ha->hablob->fw->data[offset];
}

static __le32
qla82xx_get_fw_size(struct qla_hw_data *ha)
{
struct qla82xx_uri_data_desc *uri_desc = NULL;

if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
QLA82XX_URI_FIRMWARE_IDX_OFF);
if (uri_desc)
return cpu_to_le32(uri_desc->size);
}

return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]);
}

static u8 *
qla82xx_get_fw_offs(struct qla_hw_data *ha)
{
u32 offset = IMAGE_START;
struct qla82xx_uri_data_desc *uri_desc = NULL;

if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
QLA82XX_URI_FIRMWARE_IDX_OFF);
if (uri_desc)
offset = cpu_to_le32(uri_desc->findex);
}

return (u8 *)&ha->hablob->fw->data[offset];
}

/* PCI related functions */
char *
qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str)
Expand Down Expand Up @@ -1878,19 +1967,19 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)

size = (IMAGE_START - BOOTLD_START) / 8;

ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START];
ptr64 = (u64 *)qla82xx_get_bootld_offset(ha);
flashaddr = BOOTLD_START;

for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8);
if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
return -EIO;
flashaddr += 8;
}

size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET];
size = (__force u32)cpu_to_le32(size) / 8;
ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START];
flashaddr = FLASH_ADDR_START;
size = (__force u32)qla82xx_get_fw_size(ha) / 8;
ptr64 = (u64 *)qla82xx_get_fw_offs(ha);

for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
Expand All @@ -1899,19 +1988,88 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
return -EIO;
flashaddr += 8;
}
udelay(100);

/* Write a magic value to CAMRAM register
* at a specified offset to indicate
* that all data is written and
* ready for firmware to initialize.
*/
qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678);
qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC);

read_lock(&ha->hw_lock);
if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
} else
qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
read_unlock(&ha->hw_lock);
return 0;
}

static int
qla82xx_set_product_offset(struct qla_hw_data *ha)
{
struct qla82xx_uri_table_desc *ptab_desc = NULL;
const uint8_t *unirom = ha->hablob->fw->data;
uint32_t i;
__le32 entries;
__le32 flags, file_chiprev, offset;
uint8_t chiprev = ha->chip_revision;
/* Hardcoding mn_present flag for P3P */
int mn_present = 0;
uint32_t flagbit;

ptab_desc = qla82xx_get_table_desc(unirom,
QLA82XX_URI_DIR_SECT_PRODUCT_TBL);
if (!ptab_desc)
return -1;

entries = cpu_to_le32(ptab_desc->num_entries);

for (i = 0; i < entries; i++) {
offset = cpu_to_le32(ptab_desc->findex) +
(i * cpu_to_le32(ptab_desc->entry_size));
flags = cpu_to_le32(*((int *)&unirom[offset] +
QLA82XX_URI_FLAGS_OFF));
file_chiprev = cpu_to_le32(*((int *)&unirom[offset] +
QLA82XX_URI_CHIP_REV_OFF));

flagbit = mn_present ? 1 : 2;

if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) {
ha->file_prd_off = offset;
return 0;
}
}
return -1;
}

int
qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type)
{
__le32 val;
uint32_t min_size;
struct qla_hw_data *ha = vha->hw;
const struct firmware *fw = ha->hablob->fw;

ha->fw_type = fw_type;

if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
if (qla82xx_set_product_offset(ha))
return -EINVAL;

min_size = QLA82XX_URI_FW_MIN_SIZE;
} else {
val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]);
if ((__force u32)val != QLA82XX_BDINFO_MAGIC)
return -EINVAL;

min_size = QLA82XX_FW_MIN_SIZE;
}

if (fw->size < min_size)
return -EINVAL;
return 0;
}

Expand Down Expand Up @@ -2470,6 +2628,18 @@ int qla82xx_load_fw(scsi_qla_host_t *vha)
goto fw_load_failed;
}

/* Validating firmware blob */
if (qla82xx_validate_firmware_blob(vha,
QLA82XX_FLASH_ROMIMAGE)) {
/* Fallback to URI format */
if (qla82xx_validate_firmware_blob(vha,
QLA82XX_UNIFIED_ROMIMAGE)) {
qla_printk(KERN_ERR, ha,
"No valid firmware image found!!!");
return QLA_FUNCTION_FAILED;
}
}

if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
qla_printk(KERN_ERR, ha,
"%s: Firmware loaded successfully "
Expand Down
35 changes: 35 additions & 0 deletions drivers/scsi/qla2xxx/qla_nx.h
Original file line number Diff line number Diff line change
Expand Up @@ -773,13 +773,48 @@ struct qla82xx_legacy_intr_set {
.pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \
}

#define BRDCFG_START 0x4000
#define BOOTLD_START 0x10000
#define IMAGE_START 0x100000
#define FLASH_ADDR_START 0x43000

/* Magic number to let user know flash is programmed */
#define QLA82XX_BDINFO_MAGIC 0x12345678
#define QLA82XX_FW_MAGIC_OFFSET (BRDCFG_START + 0x128)
#define FW_SIZE_OFFSET (0x3e840c)
#define QLA82XX_FW_MIN_SIZE 0x3fffff

/* UNIFIED ROMIMAGE START */
#define QLA82XX_URI_FW_MIN_SIZE 0xc8000
#define QLA82XX_URI_DIR_SECT_PRODUCT_TBL 0x0
#define QLA82XX_URI_DIR_SECT_BOOTLD 0x6
#define QLA82XX_URI_DIR_SECT_FW 0x7

/* Offsets */
#define QLA82XX_URI_CHIP_REV_OFF 10
#define QLA82XX_URI_FLAGS_OFF 11
#define QLA82XX_URI_BIOS_VERSION_OFF 12
#define QLA82XX_URI_BOOTLD_IDX_OFF 27
#define QLA82XX_URI_FIRMWARE_IDX_OFF 29

struct qla82xx_uri_table_desc{
uint32_t findex;
uint32_t num_entries;
uint32_t entry_size;
uint32_t reserved[5];
};

struct qla82xx_uri_data_desc{
uint32_t findex;
uint32_t size;
uint32_t reserved[5];
};

/* UNIFIED ROMIMAGE END */

#define QLA82XX_UNIFIED_ROMIMAGE 3
#define QLA82XX_FLASH_ROMIMAGE 4
#define QLA82XX_UNKNOWN_ROMIMAGE 0xff

#define QLA82XX_IS_REVISION_P3PLUS(_rev_) ((_rev_) >= 0x50)
#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0)
Expand Down

0 comments on commit 9c2b297

Please sign in to comment.