[PATCH 09/17] qla2xxx: Support for loading Unified ROM Image (URI) format firmware file.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Harish Zunjarrao <harish.zunjarrao@xxxxxxxxxx>

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

Signed-off-by: Giridhar Malavali <giridhar.malavali@xxxxxxxxxx>
---
 drivers/scsi/qla2xxx/qla_def.h |    3 +
 drivers/scsi/qla2xxx/qla_nx.c  |  184 ++++++++++++++++++++++++++++++++++++++--
 drivers/scsi/qla2xxx/qla_nx.h  |   35 ++++++++
 3 files changed, 215 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 2895855..f0e792a 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -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 */
 };
 
 /*
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index eb12bf2..1a9a734 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -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;
@@ -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)
@@ -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]);
@@ -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;
 }
 
@@ -2470,6 +2628,18 @@ try_blob_fw:
 		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 "
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index aa95d38..9a9127e 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -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)
-- 
1.6.2.rc1.30.gd43c

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux