Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96c9b2e4 authored by Vasundhara Volam's avatar Vasundhara Volam Committed by David S. Miller
Browse files

be2net: support flashing new regions on Skyhawk-R



Certain new flash regions have been added to Skyhawk-R FW image. The newer
FW images specify op_types for each region. A region is flashed only
when it's CRC doesn't match that of the region on the HW flash. While
upgrading to a new FW image the driver is expected to tolerate certain
errors.

This patch re-factors code under be_flash() to support the above scheme.
Signed-off-by: default avatarVasundhara Volam <vasundhara.volam@emulex.com>
Signed-off-by: default avatarSathya Perla <sathya.perla@emulex.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0f77ba73
Loading
Loading
Loading
Loading
+18 −7
Original line number Diff line number Diff line
@@ -133,6 +133,9 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
	compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
				CQE_STATUS_COMPL_MASK;

	extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
				CQE_STATUS_EXTD_MASK;

	resp_hdr = be_decode_resp_hdr(compl->tag0, compl->tag1);

	if (resp_hdr) {
@@ -173,15 +176,24 @@ static int be_mcc_compl_process(struct be_adapter *adapter,

		if (compl_status == MCC_STATUS_NOT_SUPPORTED ||
		    compl_status == MCC_STATUS_ILLEGAL_REQUEST)
			goto done;
			return compl_status;

		/* Ignore CRC mismatch error during FW download with old FW */
		if (opcode == OPCODE_COMMON_WRITE_FLASHROM &&
		    compl_status == MCC_STATUS_FAILED &&
		    extd_status == MCC_ADDL_STS_FLASH_IMAGE_CRC_MISMATCH)
			return compl_status;

		/* Ignore illegal field error during FW download with old FW */
		if (opcode == OPCODE_COMMON_WRITE_FLASHROM &&
		    compl_status == MCC_STATUS_ILLEGAL_FIELD)
			return compl_status;

		if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) {
			dev_warn(&adapter->pdev->dev,
				 "VF is not privileged to issue opcode %d-%d\n",
				 opcode, subsystem);
		} else {
			extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
					CQE_STATUS_EXTD_MASK;
			dev_err(&adapter->pdev->dev,
				"opcode %d-%d failed:status %d-%d\n",
				opcode, subsystem, compl_status, extd_status);
@@ -190,7 +202,6 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
				return extd_status;
		}
	}
done:
	return compl_status;
}

@@ -2300,7 +2311,7 @@ err_unlock:
}

int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
			 int offset)
			  u16 optype, int offset)
{
	struct be_mcc_wrb *wrb;
	struct be_cmd_read_flash_crc *req;
@@ -2319,7 +2330,7 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
			       OPCODE_COMMON_READ_FLASHROM, sizeof(*req),
			       wrb, NULL);

	req->params.op_type = cpu_to_le32(OPTYPE_REDBOOT);
	req->params.op_type = cpu_to_le32(optype);
	req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
	req->params.offset = cpu_to_le32(offset);
	req->params.data_buf_size = cpu_to_le32(0x4);
+4 −2
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ enum {
};

#define MCC_ADDL_STS_INSUFFICIENT_RESOURCES	0x16
#define MCC_ADDL_STS_FLASH_IMAGE_CRC_MISMATCH	0x4d

#define CQE_STATUS_COMPL_MASK		0xFFFF
#define CQE_STATUS_COMPL_SHIFT		0	/* bits 0 - 15 */
@@ -1186,7 +1187,8 @@ struct be_cmd_read_flash_crc {
	struct flashrom_params params;
	u8 crc[4];
	u8 rsvd[4];
};
} __packed;

/**************** Lancer Firmware Flash ************/
struct amap_lancer_write_obj_context {
	u8 write_length[24];
@@ -2088,7 +2090,7 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
			   u32 data_size, u32 data_offset, const char *obj_name,
			   u32 *data_read, u32 *eof, u8 *addn_status);
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
			 int offset);
			  u16 optype, int offset);
int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
			    struct be_dma_mem *nonemb_cmd);
int be_cmd_fw_init(struct be_adapter *adapter);
+10 −2
Original line number Diff line number Diff line
@@ -188,10 +188,14 @@
#define OPTYPE_FCOE_FW_ACTIVE		10
#define OPTYPE_FCOE_FW_BACKUP		11
#define OPTYPE_NCSI_FW			13
#define OPTYPE_REDBOOT_DIR		18
#define OPTYPE_REDBOOT_CONFIG		19
#define OPTYPE_SH_PHY_FW		21
#define OPTYPE_FLASHISM_JUMPVECTOR	22
#define OPTYPE_UFI_DIR			23
#define OPTYPE_PHY_FW			99
#define TN_8022				13

#define ILLEGAL_IOCTL_REQ		2
#define FLASHROM_OPER_PHY_FLASH		9
#define FLASHROM_OPER_PHY_SAVE		10
#define FLASHROM_OPER_FLASH		1
@@ -250,6 +254,9 @@
#define IMAGE_FIRMWARE_BACKUP_FCoE	178
#define IMAGE_FIRMWARE_BACKUP_COMP_FCoE 179
#define IMAGE_FIRMWARE_PHY		192
#define IMAGE_REDBOOT_DIR		208
#define IMAGE_REDBOOT_CONFIG		209
#define IMAGE_UFI_DIR			210
#define IMAGE_BOOT_CODE			224

/************* Rx Packet Type Encoding **************/
@@ -534,7 +541,8 @@ struct flash_section_entry {
	u32 image_size;
	u32 cksum;
	u32 entry_point;
	u32 rsvd0;
	u16 optype;
	u16 rsvd0;
	u32 rsvd1;
	u8 ver_data[32];
} __packed;
+156 −96
Original line number Diff line number Diff line
@@ -3630,35 +3630,8 @@ static void be_netpoll(struct net_device *netdev)
}
#endif

#define FW_FILE_HDR_SIGN 	"ServerEngines Corp. "
static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "};

static bool be_flash_redboot(struct be_adapter *adapter,
			     const u8 *p, u32 img_start, int image_size,
			     int hdr_size)
{
	u32 crc_offset;
	u8 flashed_crc[4];
	int status;

	crc_offset = hdr_size + img_start + image_size - 4;

	p += crc_offset;

	status = be_cmd_get_flash_crc(adapter, flashed_crc, (image_size - 4));
	if (status) {
		dev_err(&adapter->pdev->dev,
			"could not get crc from flash, not flashing redboot\n");
		return false;
	}

	/*update redboot only if crc does not match*/
	if (!memcmp(flashed_crc, p, 4))
		return false;
	else
		return true;
}

static bool phy_flashing_required(struct be_adapter *adapter)
{
	return (adapter->phy.phy_type == TN_8022 &&
@@ -3704,12 +3677,35 @@ static struct flash_section_info *get_fsec_info(struct be_adapter *adapter,
	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_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 total_bytes = 0, flash_op, num_bytes = 0;
	int status = 0;
	struct be_cmd_write_flashrom *req = flash_cmd->va;
	u32 total_bytes, flash_op, num_bytes;
	int status;

	total_bytes = img_size;
	while (total_bytes) {
@@ -3733,15 +3729,12 @@ static int be_flash(struct be_adapter *adapter, const u8 *img,
		img += num_bytes;
		status = be_cmd_write_flashrom(adapter, flash_cmd, optype,
					       flash_op, num_bytes);
		if (status) {
			if (status == ILLEGAL_IOCTL_REQ &&
		if (status == MCC_STATUS_ILLEGAL_REQUEST &&
		    optype == OPTYPE_PHY_FW)
			break;
			dev_err(&adapter->pdev->dev,
				"cmd to write to flash rom failed.\n");
		else if (status)
			return status;
	}
	}
	return 0;
}

@@ -3750,12 +3743,13 @@ static int be_flash_BEx(struct be_adapter *adapter,
			const struct firmware *fw,
			struct be_dma_mem *flash_cmd, int num_of_images)
{
	int status = 0, i, filehdr_size = 0;
	int img_hdrs_size = (num_of_images * sizeof(struct image_hdr));
	const u8 *p = fw->data;
	const struct flash_comp *pflashcomp;
	int num_comp, redboot;
	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[] = {
		{ FLASH_iSCSI_PRIMARY_IMAGE_START_g3, OPTYPE_ISCSI_ACTIVE,
@@ -3812,8 +3806,7 @@ static int be_flash_BEx(struct be_adapter *adapter,
	/* Get flash section info*/
	fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw);
	if (!fsec) {
		dev_err(&adapter->pdev->dev,
			"Invalid Cookie. UFI corrupted ?\n");
		dev_err(dev, "Invalid Cookie. FW image may be corrupted\n");
		return -1;
	}
	for (i = 0; i < num_comp; i++) {
@@ -3829,25 +3822,32 @@ static int be_flash_BEx(struct be_adapter *adapter,
				continue;

		if (pflashcomp[i].optype == OPTYPE_REDBOOT) {
			redboot = be_flash_redboot(adapter, fw->data,
			status = be_check_flash_crc(adapter, fw->data,
						    pflashcomp[i].offset,
						    pflashcomp[i].size,
						    filehdr_size +
						   img_hdrs_size);
			if (!redboot)
						    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;
			}

		p = fw->data;
		p += filehdr_size + pflashcomp[i].offset + img_hdrs_size;
			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);
		if (status) {
			dev_err(&adapter->pdev->dev,
				"Flashing section type %d failed.\n",
			dev_err(dev, "Flashing section type 0x%x failed\n",
				pflashcomp[i].img_type);
			return status;
		}
@@ -3855,29 +3855,15 @@ static int be_flash_BEx(struct be_adapter *adapter,
	return 0;
}

static int be_flash_skyhawk(struct be_adapter *adapter,
			    const struct firmware *fw,
			    struct be_dma_mem *flash_cmd, int num_of_images)
static u16 be_get_img_optype(struct flash_section_entry fsec_entry)
{
	int status = 0, i, filehdr_size = 0;
	int img_offset, img_size, img_optype, redboot;
	int img_hdrs_size = num_of_images * sizeof(struct image_hdr);
	const u8 *p = fw->data;
	struct flash_section_info *fsec = NULL;
	u32 img_type = le32_to_cpu(fsec_entry.type);
	u16 img_optype = le16_to_cpu(fsec_entry.optype);

	filehdr_size = sizeof(struct flash_file_hdr_g3);
	fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw);
	if (!fsec) {
		dev_err(&adapter->pdev->dev,
			"Invalid Cookie. UFI corrupted ?\n");
		return -1;
	}
	if (img_optype != 0xFFFF)
		return img_optype;

	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);

		switch (le32_to_cpu(fsec->fsec_entry[i].type)) {
	switch (img_type) {
	case IMAGE_FIRMWARE_iSCSI:
		img_optype = OPTYPE_ISCSI_ACTIVE;
		break;
@@ -3899,30 +3885,104 @@ static int be_flash_skyhawk(struct be_adapter *adapter,
	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:
			continue;
		break;
	}

		if (img_optype == OPTYPE_REDBOOT) {
			redboot = be_flash_redboot(adapter, fw->data,
						   img_offset, img_size,
						   filehdr_size +
						   img_hdrs_size);
			if (!redboot)
				continue;
	return img_optype;
}

		p = fw->data;
		p += filehdr_size + img_offset + img_hdrs_size;
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);
	struct device *dev = &adapter->pdev->dev;
	struct flash_section_info *fsec = NULL;
	u32 img_offset, img_size, img_type;
	int status, i, filehdr_size;
	bool crc_match, old_fw_img;
	u16 img_optype;
	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 -1;
	}

	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;
		/* 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, img_optype,
					    &crc_match);
		/* 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.
		 */
		if (status == MCC_STATUS_ILLEGAL_REQUEST ||
		    status == MCC_STATUS_ILLEGAL_FIELD) {
			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, img_optype, img_size);
		if (status) {
			dev_err(&adapter->pdev->dev,
				"Flashing section type %d failed.\n",
				fsec->fsec_entry[i].type);
			return status;
		/* For old FW images ignore ILLEGAL_FIELD error or errors on
		 * UFI_DIR region
		 */
		if (old_fw_img && (status == MCC_STATUS_ILLEGAL_FIELD ||
				   (img_optype == OPTYPE_UFI_DIR &&
				    status == MCC_STATUS_FAILED))) {
			continue;
		} else if (status) {
			dev_err(dev, "Flashing section type 0x%x failed\n",
				img_type);
			return -EFAULT;
		}
	}
	return 0;