|
@@ -2291,10 +2291,11 @@ err:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
-int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
|
|
|
|
- u32 data_size, u32 data_offset,
|
|
|
|
- const char *obj_name, u32 *data_written,
|
|
|
|
- u8 *change_status, u8 *addn_status)
|
|
|
|
|
|
+static int lancer_cmd_write_object(struct be_adapter *adapter,
|
|
|
|
+ struct be_dma_mem *cmd, u32 data_size,
|
|
|
|
+ u32 data_offset, const char *obj_name,
|
|
|
|
+ u32 *data_written, u8 *change_status,
|
|
|
|
+ u8 *addn_status)
|
|
{
|
|
{
|
|
struct be_mcc_wrb *wrb;
|
|
struct be_mcc_wrb *wrb;
|
|
struct lancer_cmd_req_write_object *req;
|
|
struct lancer_cmd_req_write_object *req;
|
|
@@ -2410,7 +2411,8 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter)
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
-int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name)
|
|
|
|
|
|
+static int lancer_cmd_delete_object(struct be_adapter *adapter,
|
|
|
|
+ const char *obj_name)
|
|
{
|
|
{
|
|
struct lancer_cmd_req_delete_object *req;
|
|
struct lancer_cmd_req_delete_object *req;
|
|
struct be_mcc_wrb *wrb;
|
|
struct be_mcc_wrb *wrb;
|
|
@@ -2485,9 +2487,9 @@ err_unlock:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
-int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
|
|
|
|
- u32 flash_type, u32 flash_opcode, u32 img_offset,
|
|
|
|
- u32 buf_size)
|
|
|
|
|
|
+static int be_cmd_write_flashrom(struct be_adapter *adapter,
|
|
|
|
+ struct be_dma_mem *cmd, u32 flash_type,
|
|
|
|
+ u32 flash_opcode, u32 img_offset, u32 buf_size)
|
|
{
|
|
{
|
|
struct be_mcc_wrb *wrb;
|
|
struct be_mcc_wrb *wrb;
|
|
struct be_cmd_write_flashrom *req;
|
|
struct be_cmd_write_flashrom *req;
|
|
@@ -2533,8 +2535,8 @@ err_unlock:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
-int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
|
|
|
|
- u16 img_optype, u32 img_offset, u32 crc_offset)
|
|
|
|
|
|
+static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
|
|
|
|
+ u16 img_optype, u32 img_offset, u32 crc_offset)
|
|
{
|
|
{
|
|
struct be_cmd_read_flash_crc *req;
|
|
struct be_cmd_read_flash_crc *req;
|
|
struct be_mcc_wrb *wrb;
|
|
struct be_mcc_wrb *wrb;
|
|
@@ -2571,6 +2573,567 @@ err:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "};
|
|
|
|
+
|
|
|
|
+static bool phy_flashing_required(struct be_adapter *adapter)
|
|
|
|
+{
|
|
|
|
+ return (adapter->phy.phy_type == PHY_TYPE_TN_8022 &&
|
|
|
|
+ adapter->phy.interface_type == PHY_TYPE_BASET_10GB);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool is_comp_in_ufi(struct be_adapter *adapter,
|
|
|
|
+ struct flash_section_info *fsec, int type)
|
|
|
|
+{
|
|
|
|
+ int i = 0, img_type = 0;
|
|
|
|
+ struct flash_section_info_g2 *fsec_g2 = NULL;
|
|
|
|
+
|
|
|
|
+ if (BE2_chip(adapter))
|
|
|
|
+ fsec_g2 = (struct flash_section_info_g2 *)fsec;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < MAX_FLASH_COMP; i++) {
|
|
|
|
+ if (fsec_g2)
|
|
|
|
+ img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type);
|
|
|
|
+ else
|
|
|
|
+ img_type = le32_to_cpu(fsec->fsec_entry[i].type);
|
|
|
|
+
|
|
|
|
+ if (img_type == type)
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct flash_section_info *get_fsec_info(struct be_adapter *adapter,
|
|
|
|
+ int header_size,
|
|
|
|
+ const struct firmware *fw)
|
|
|
|
+{
|
|
|
|
+ struct flash_section_info *fsec = NULL;
|
|
|
|
+ const u8 *p = fw->data;
|
|
|
|
+
|
|
|
|
+ p += header_size;
|
|
|
|
+ while (p < (fw->data + fw->size)) {
|
|
|
|
+ fsec = (struct flash_section_info *)p;
|
|
|
|
+ if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie)))
|
|
|
|
+ return fsec;
|
|
|
|
+ p += 32;
|
|
|
|
+ }
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p,
|
|
|
|
+ u32 img_offset, u32 img_size, int hdr_size,
|
|
|
|
+ u16 img_optype, bool *crc_match)
|
|
|
|
+{
|
|
|
|
+ u32 crc_offset;
|
|
|
|
+ int status;
|
|
|
|
+ u8 crc[4];
|
|
|
|
+
|
|
|
|
+ status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset,
|
|
|
|
+ img_size - 4);
|
|
|
|
+ if (status)
|
|
|
|
+ return status;
|
|
|
|
+
|
|
|
|
+ crc_offset = hdr_size + img_offset + img_size - 4;
|
|
|
|
+
|
|
|
|
+ /* Skip flashing, if crc of flashed region matches */
|
|
|
|
+ if (!memcmp(crc, p + crc_offset, 4))
|
|
|
|
+ *crc_match = true;
|
|
|
|
+ else
|
|
|
|
+ *crc_match = false;
|
|
|
|
+
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int be_flash(struct be_adapter *adapter, const u8 *img,
|
|
|
|
+ struct be_dma_mem *flash_cmd, int optype, int img_size,
|
|
|
|
+ u32 img_offset)
|
|
|
|
+{
|
|
|
|
+ u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0;
|
|
|
|
+ struct be_cmd_write_flashrom *req = flash_cmd->va;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+ while (total_bytes) {
|
|
|
|
+ num_bytes = min_t(u32, 32 * 1024, total_bytes);
|
|
|
|
+
|
|
|
|
+ total_bytes -= num_bytes;
|
|
|
|
+
|
|
|
|
+ if (!total_bytes) {
|
|
|
|
+ if (optype == OPTYPE_PHY_FW)
|
|
|
|
+ flash_op = FLASHROM_OPER_PHY_FLASH;
|
|
|
|
+ else
|
|
|
|
+ flash_op = FLASHROM_OPER_FLASH;
|
|
|
|
+ } else {
|
|
|
|
+ if (optype == OPTYPE_PHY_FW)
|
|
|
|
+ flash_op = FLASHROM_OPER_PHY_SAVE;
|
|
|
|
+ else
|
|
|
|
+ flash_op = FLASHROM_OPER_SAVE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memcpy(req->data_buf, img, num_bytes);
|
|
|
|
+ img += num_bytes;
|
|
|
|
+ status = be_cmd_write_flashrom(adapter, flash_cmd, optype,
|
|
|
|
+ flash_op, img_offset +
|
|
|
|
+ bytes_sent, num_bytes);
|
|
|
|
+ if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST &&
|
|
|
|
+ optype == OPTYPE_PHY_FW)
|
|
|
|
+ break;
|
|
|
|
+ else if (status)
|
|
|
|
+ return status;
|
|
|
|
+
|
|
|
|
+ bytes_sent += num_bytes;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* For BE2, BE3 and BE3-R */
|
|
|
|
+static int be_flash_BEx(struct be_adapter *adapter,
|
|
|
|
+ const struct firmware *fw,
|
|
|
|
+ struct be_dma_mem *flash_cmd, int num_of_images)
|
|
|
|
+{
|
|
|
|
+ int img_hdrs_size = (num_of_images * sizeof(struct image_hdr));
|
|
|
|
+ struct device *dev = &adapter->pdev->dev;
|
|
|
|
+ struct flash_section_info *fsec = NULL;
|
|
|
|
+ int status, i, filehdr_size, num_comp;
|
|
|
|
+ const struct flash_comp *pflashcomp;
|
|
|
|
+ bool crc_match;
|
|
|
|
+ const u8 *p;
|
|
|
|
+
|
|
|
|
+ struct flash_comp gen3_flash_types[] = {
|
|
|
|
+ { BE3_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE,
|
|
|
|
+ BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI},
|
|
|
|
+ { BE3_REDBOOT_START, OPTYPE_REDBOOT,
|
|
|
|
+ BE3_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE},
|
|
|
|
+ { BE3_ISCSI_BIOS_START, OPTYPE_BIOS,
|
|
|
|
+ BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI},
|
|
|
|
+ { BE3_PXE_BIOS_START, OPTYPE_PXE_BIOS,
|
|
|
|
+ BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE},
|
|
|
|
+ { BE3_FCOE_BIOS_START, OPTYPE_FCOE_BIOS,
|
|
|
|
+ BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE},
|
|
|
|
+ { BE3_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP,
|
|
|
|
+ BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI},
|
|
|
|
+ { BE3_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE,
|
|
|
|
+ BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE},
|
|
|
|
+ { BE3_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP,
|
|
|
|
+ BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE},
|
|
|
|
+ { BE3_NCSI_START, OPTYPE_NCSI_FW,
|
|
|
|
+ BE3_NCSI_COMP_MAX_SIZE, IMAGE_NCSI},
|
|
|
|
+ { BE3_PHY_FW_START, OPTYPE_PHY_FW,
|
|
|
|
+ BE3_PHY_FW_COMP_MAX_SIZE, IMAGE_FIRMWARE_PHY}
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ struct flash_comp gen2_flash_types[] = {
|
|
|
|
+ { BE2_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE,
|
|
|
|
+ BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI},
|
|
|
|
+ { BE2_REDBOOT_START, OPTYPE_REDBOOT,
|
|
|
|
+ BE2_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE},
|
|
|
|
+ { BE2_ISCSI_BIOS_START, OPTYPE_BIOS,
|
|
|
|
+ BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI},
|
|
|
|
+ { BE2_PXE_BIOS_START, OPTYPE_PXE_BIOS,
|
|
|
|
+ BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE},
|
|
|
|
+ { BE2_FCOE_BIOS_START, OPTYPE_FCOE_BIOS,
|
|
|
|
+ BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE},
|
|
|
|
+ { BE2_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP,
|
|
|
|
+ BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI},
|
|
|
|
+ { BE2_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE,
|
|
|
|
+ BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE},
|
|
|
|
+ { BE2_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP,
|
|
|
|
+ BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE}
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ if (BE3_chip(adapter)) {
|
|
|
|
+ pflashcomp = gen3_flash_types;
|
|
|
|
+ filehdr_size = sizeof(struct flash_file_hdr_g3);
|
|
|
|
+ num_comp = ARRAY_SIZE(gen3_flash_types);
|
|
|
|
+ } else {
|
|
|
|
+ pflashcomp = gen2_flash_types;
|
|
|
|
+ filehdr_size = sizeof(struct flash_file_hdr_g2);
|
|
|
|
+ num_comp = ARRAY_SIZE(gen2_flash_types);
|
|
|
|
+ img_hdrs_size = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Get flash section info*/
|
|
|
|
+ fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw);
|
|
|
|
+ if (!fsec) {
|
|
|
|
+ dev_err(dev, "Invalid Cookie. FW image may be corrupted\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ for (i = 0; i < num_comp; i++) {
|
|
|
|
+ if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) &&
|
|
|
|
+ memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (pflashcomp[i].optype == OPTYPE_PHY_FW &&
|
|
|
|
+ !phy_flashing_required(adapter))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (pflashcomp[i].optype == OPTYPE_REDBOOT) {
|
|
|
|
+ status = be_check_flash_crc(adapter, fw->data,
|
|
|
|
+ pflashcomp[i].offset,
|
|
|
|
+ pflashcomp[i].size,
|
|
|
|
+ filehdr_size +
|
|
|
|
+ img_hdrs_size,
|
|
|
|
+ OPTYPE_REDBOOT, &crc_match);
|
|
|
|
+ if (status) {
|
|
|
|
+ dev_err(dev,
|
|
|
|
+ "Could not get CRC for 0x%x region\n",
|
|
|
|
+ pflashcomp[i].optype);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (crc_match)
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ p = fw->data + filehdr_size + pflashcomp[i].offset +
|
|
|
|
+ img_hdrs_size;
|
|
|
|
+ if (p + pflashcomp[i].size > fw->data + fw->size)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype,
|
|
|
|
+ pflashcomp[i].size, 0);
|
|
|
|
+ if (status) {
|
|
|
|
+ dev_err(dev, "Flashing section type 0x%x failed\n",
|
|
|
|
+ pflashcomp[i].img_type);
|
|
|
|
+ return status;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u16 be_get_img_optype(struct flash_section_entry fsec_entry)
|
|
|
|
+{
|
|
|
|
+ u32 img_type = le32_to_cpu(fsec_entry.type);
|
|
|
|
+ u16 img_optype = le16_to_cpu(fsec_entry.optype);
|
|
|
|
+
|
|
|
|
+ if (img_optype != 0xFFFF)
|
|
|
|
+ return img_optype;
|
|
|
|
+
|
|
|
|
+ switch (img_type) {
|
|
|
|
+ case IMAGE_FIRMWARE_ISCSI:
|
|
|
|
+ img_optype = OPTYPE_ISCSI_ACTIVE;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_BOOT_CODE:
|
|
|
|
+ img_optype = OPTYPE_REDBOOT;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_OPTION_ROM_ISCSI:
|
|
|
|
+ img_optype = OPTYPE_BIOS;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_OPTION_ROM_PXE:
|
|
|
|
+ img_optype = OPTYPE_PXE_BIOS;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_OPTION_ROM_FCOE:
|
|
|
|
+ img_optype = OPTYPE_FCOE_BIOS;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_FIRMWARE_BACKUP_ISCSI:
|
|
|
|
+ img_optype = OPTYPE_ISCSI_BACKUP;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_NCSI:
|
|
|
|
+ img_optype = OPTYPE_NCSI_FW;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_FLASHISM_JUMPVECTOR:
|
|
|
|
+ img_optype = OPTYPE_FLASHISM_JUMPVECTOR;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_FIRMWARE_PHY:
|
|
|
|
+ img_optype = OPTYPE_SH_PHY_FW;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_REDBOOT_DIR:
|
|
|
|
+ img_optype = OPTYPE_REDBOOT_DIR;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_REDBOOT_CONFIG:
|
|
|
|
+ img_optype = OPTYPE_REDBOOT_CONFIG;
|
|
|
|
+ break;
|
|
|
|
+ case IMAGE_UFI_DIR:
|
|
|
|
+ img_optype = OPTYPE_UFI_DIR;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return img_optype;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int be_flash_skyhawk(struct be_adapter *adapter,
|
|
|
|
+ const struct firmware *fw,
|
|
|
|
+ struct be_dma_mem *flash_cmd, int num_of_images)
|
|
|
|
+{
|
|
|
|
+ int img_hdrs_size = num_of_images * sizeof(struct image_hdr);
|
|
|
|
+ bool crc_match, old_fw_img, flash_offset_support = true;
|
|
|
|
+ struct device *dev = &adapter->pdev->dev;
|
|
|
|
+ struct flash_section_info *fsec = NULL;
|
|
|
|
+ u32 img_offset, img_size, img_type;
|
|
|
|
+ u16 img_optype, flash_optype;
|
|
|
|
+ int status, i, filehdr_size;
|
|
|
|
+ const u8 *p;
|
|
|
|
+
|
|
|
|
+ filehdr_size = sizeof(struct flash_file_hdr_g3);
|
|
|
|
+ fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw);
|
|
|
|
+ if (!fsec) {
|
|
|
|
+ dev_err(dev, "Invalid Cookie. FW image may be corrupted\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+retry_flash:
|
|
|
|
+ for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) {
|
|
|
|
+ img_offset = le32_to_cpu(fsec->fsec_entry[i].offset);
|
|
|
|
+ img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size);
|
|
|
|
+ img_type = le32_to_cpu(fsec->fsec_entry[i].type);
|
|
|
|
+ img_optype = be_get_img_optype(fsec->fsec_entry[i]);
|
|
|
|
+ old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF;
|
|
|
|
+
|
|
|
|
+ if (img_optype == 0xFFFF)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (flash_offset_support)
|
|
|
|
+ flash_optype = OPTYPE_OFFSET_SPECIFIED;
|
|
|
|
+ else
|
|
|
|
+ flash_optype = img_optype;
|
|
|
|
+
|
|
|
|
+ /* Don't bother verifying CRC if an old FW image is being
|
|
|
|
+ * flashed
|
|
|
|
+ */
|
|
|
|
+ if (old_fw_img)
|
|
|
|
+ goto flash;
|
|
|
|
+
|
|
|
|
+ status = be_check_flash_crc(adapter, fw->data, img_offset,
|
|
|
|
+ img_size, filehdr_size +
|
|
|
|
+ img_hdrs_size, flash_optype,
|
|
|
|
+ &crc_match);
|
|
|
|
+ if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST ||
|
|
|
|
+ base_status(status) == MCC_STATUS_ILLEGAL_FIELD) {
|
|
|
|
+ /* The current FW image on the card does not support
|
|
|
|
+ * OFFSET based flashing. Retry using older mechanism
|
|
|
|
+ * of OPTYPE based flashing
|
|
|
|
+ */
|
|
|
|
+ if (flash_optype == OPTYPE_OFFSET_SPECIFIED) {
|
|
|
|
+ flash_offset_support = false;
|
|
|
|
+ goto retry_flash;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* The current FW image on the card does not recognize
|
|
|
|
+ * the new FLASH op_type. The FW download is partially
|
|
|
|
+ * complete. Reboot the server now to enable FW image
|
|
|
|
+ * to recognize the new FLASH op_type. To complete the
|
|
|
|
+ * remaining process, download the same FW again after
|
|
|
|
+ * the reboot.
|
|
|
|
+ */
|
|
|
|
+ dev_err(dev, "Flash incomplete. Reset the server\n");
|
|
|
|
+ dev_err(dev, "Download FW image again after reset\n");
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ } else if (status) {
|
|
|
|
+ dev_err(dev, "Could not get CRC for 0x%x region\n",
|
|
|
|
+ img_optype);
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (crc_match)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+flash:
|
|
|
|
+ p = fw->data + filehdr_size + img_offset + img_hdrs_size;
|
|
|
|
+ if (p + img_size > fw->data + fw->size)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ status = be_flash(adapter, p, flash_cmd, flash_optype, img_size,
|
|
|
|
+ img_offset);
|
|
|
|
+
|
|
|
|
+ /* The current FW image on the card does not support OFFSET
|
|
|
|
+ * based flashing. Retry using older mechanism of OPTYPE based
|
|
|
|
+ * flashing
|
|
|
|
+ */
|
|
|
|
+ if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD &&
|
|
|
|
+ flash_optype == OPTYPE_OFFSET_SPECIFIED) {
|
|
|
|
+ flash_offset_support = false;
|
|
|
|
+ goto retry_flash;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* For old FW images ignore ILLEGAL_FIELD error or errors on
|
|
|
|
+ * UFI_DIR region
|
|
|
|
+ */
|
|
|
|
+ if (old_fw_img &&
|
|
|
|
+ (base_status(status) == MCC_STATUS_ILLEGAL_FIELD ||
|
|
|
|
+ (img_optype == OPTYPE_UFI_DIR &&
|
|
|
|
+ base_status(status) == MCC_STATUS_FAILED))) {
|
|
|
|
+ continue;
|
|
|
|
+ } else if (status) {
|
|
|
|
+ dev_err(dev, "Flashing section type 0x%x failed\n",
|
|
|
|
+ img_type);
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int lancer_fw_download(struct be_adapter *adapter,
|
|
|
|
+ const struct firmware *fw)
|
|
|
|
+{
|
|
|
|
+ struct device *dev = &adapter->pdev->dev;
|
|
|
|
+ struct be_dma_mem flash_cmd;
|
|
|
|
+ const u8 *data_ptr = NULL;
|
|
|
|
+ u8 *dest_image_ptr = NULL;
|
|
|
|
+ size_t image_size = 0;
|
|
|
|
+ u32 chunk_size = 0;
|
|
|
|
+ u32 data_written = 0;
|
|
|
|
+ u32 offset = 0;
|
|
|
|
+ int status = 0;
|
|
|
|
+ u8 add_status = 0;
|
|
|
|
+ u8 change_status;
|
|
|
|
+
|
|
|
|
+ if (!IS_ALIGNED(fw->size, sizeof(u32))) {
|
|
|
|
+ dev_err(dev, "FW image size should be multiple of 4\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
|
|
|
|
+ + LANCER_FW_DOWNLOAD_CHUNK;
|
|
|
|
+ flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size,
|
|
|
|
+ &flash_cmd.dma, GFP_KERNEL);
|
|
|
|
+ if (!flash_cmd.va)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ dest_image_ptr = flash_cmd.va +
|
|
|
|
+ sizeof(struct lancer_cmd_req_write_object);
|
|
|
|
+ image_size = fw->size;
|
|
|
|
+ data_ptr = fw->data;
|
|
|
|
+
|
|
|
|
+ while (image_size) {
|
|
|
|
+ chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK);
|
|
|
|
+
|
|
|
|
+ /* Copy the image chunk content. */
|
|
|
|
+ memcpy(dest_image_ptr, data_ptr, chunk_size);
|
|
|
|
+
|
|
|
|
+ status = lancer_cmd_write_object(adapter, &flash_cmd,
|
|
|
|
+ chunk_size, offset,
|
|
|
|
+ LANCER_FW_DOWNLOAD_LOCATION,
|
|
|
|
+ &data_written, &change_status,
|
|
|
|
+ &add_status);
|
|
|
|
+ if (status)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ offset += data_written;
|
|
|
|
+ data_ptr += data_written;
|
|
|
|
+ image_size -= data_written;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!status) {
|
|
|
|
+ /* Commit the FW written */
|
|
|
|
+ status = lancer_cmd_write_object(adapter, &flash_cmd,
|
|
|
|
+ 0, offset,
|
|
|
|
+ LANCER_FW_DOWNLOAD_LOCATION,
|
|
|
|
+ &data_written, &change_status,
|
|
|
|
+ &add_status);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma);
|
|
|
|
+ if (status) {
|
|
|
|
+ dev_err(dev, "Firmware load error\n");
|
|
|
|
+ return be_cmd_status(status);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dev_info(dev, "Firmware flashed successfully\n");
|
|
|
|
+
|
|
|
|
+ if (change_status == LANCER_FW_RESET_NEEDED) {
|
|
|
|
+ dev_info(dev, "Resetting adapter to activate new FW\n");
|
|
|
|
+ status = lancer_physdev_ctrl(adapter,
|
|
|
|
+ PHYSDEV_CONTROL_FW_RESET_MASK);
|
|
|
|
+ if (status) {
|
|
|
|
+ dev_err(dev, "Adapter busy, could not reset FW\n");
|
|
|
|
+ dev_err(dev, "Reboot server to activate new FW\n");
|
|
|
|
+ }
|
|
|
|
+ } else if (change_status != LANCER_NO_RESET_NEEDED) {
|
|
|
|
+ dev_info(dev, "Reboot server to activate new FW\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Check if the flash image file is compatible with the adapter that
|
|
|
|
+ * is being flashed.
|
|
|
|
+ */
|
|
|
|
+static bool be_check_ufi_compatibility(struct be_adapter *adapter,
|
|
|
|
+ struct flash_file_hdr_g3 *fhdr)
|
|
|
|
+{
|
|
|
|
+ if (!fhdr) {
|
|
|
|
+ dev_err(&adapter->pdev->dev, "Invalid FW UFI file");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* First letter of the build version is used to identify
|
|
|
|
+ * which chip this image file is meant for.
|
|
|
|
+ */
|
|
|
|
+ switch (fhdr->build[0]) {
|
|
|
|
+ case BLD_STR_UFI_TYPE_SH:
|
|
|
|
+ if (!skyhawk_chip(adapter))
|
|
|
|
+ return false;
|
|
|
|
+ break;
|
|
|
|
+ case BLD_STR_UFI_TYPE_BE3:
|
|
|
|
+ if (!BE3_chip(adapter))
|
|
|
|
+ return false;
|
|
|
|
+ break;
|
|
|
|
+ case BLD_STR_UFI_TYPE_BE2:
|
|
|
|
+ if (!BE2_chip(adapter))
|
|
|
|
+ return false;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* In BE3 FW images the "asic_type_rev" field doesn't track the
|
|
|
|
+ * asic_rev of the chips it is compatible with.
|
|
|
|
+ * When asic_type_rev is 0 the image is compatible only with
|
|
|
|
+ * pre-BE3-R chips (asic_rev < 0x10)
|
|
|
|
+ */
|
|
|
|
+ if (BEx_chip(adapter) && fhdr->asic_type_rev == 0)
|
|
|
|
+ return adapter->asic_rev < 0x10;
|
|
|
|
+ else
|
|
|
|
+ return (fhdr->asic_type_rev >= adapter->asic_rev);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int be_fw_download(struct be_adapter *adapter, const struct firmware *fw)
|
|
|
|
+{
|
|
|
|
+ struct device *dev = &adapter->pdev->dev;
|
|
|
|
+ struct flash_file_hdr_g3 *fhdr3;
|
|
|
|
+ struct image_hdr *img_hdr_ptr;
|
|
|
|
+ int status = 0, i, num_imgs;
|
|
|
|
+ struct be_dma_mem flash_cmd;
|
|
|
|
+
|
|
|
|
+ fhdr3 = (struct flash_file_hdr_g3 *)fw->data;
|
|
|
|
+ if (!be_check_ufi_compatibility(adapter, fhdr3)) {
|
|
|
|
+ dev_err(dev, "Flash image is not compatible with adapter\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ flash_cmd.size = sizeof(struct be_cmd_write_flashrom);
|
|
|
|
+ flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, &flash_cmd.dma,
|
|
|
|
+ GFP_KERNEL);
|
|
|
|
+ if (!flash_cmd.va)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ num_imgs = le32_to_cpu(fhdr3->num_imgs);
|
|
|
|
+ for (i = 0; i < num_imgs; i++) {
|
|
|
|
+ img_hdr_ptr = (struct image_hdr *)(fw->data +
|
|
|
|
+ (sizeof(struct flash_file_hdr_g3) +
|
|
|
|
+ i * sizeof(struct image_hdr)));
|
|
|
|
+ if (!BE2_chip(adapter) &&
|
|
|
|
+ le32_to_cpu(img_hdr_ptr->imageid) != 1)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (skyhawk_chip(adapter))
|
|
|
|
+ status = be_flash_skyhawk(adapter, fw, &flash_cmd,
|
|
|
|
+ num_imgs);
|
|
|
|
+ else
|
|
|
|
+ status = be_flash_BEx(adapter, fw, &flash_cmd,
|
|
|
|
+ num_imgs);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma);
|
|
|
|
+ if (!status)
|
|
|
|
+ dev_info(dev, "Firmware flashed successfully\n");
|
|
|
|
+
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+
|
|
int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
|
|
int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
|
|
struct be_dma_mem *nonemb_cmd)
|
|
struct be_dma_mem *nonemb_cmd)
|
|
{
|
|
{
|