static int
qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
{
	int ret = 0;
	struct qlcnic_adapter *adapter = netdev_priv(netdev);
	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;

	if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) {
		netdev_info(netdev, "Forcing a FW dump\n");
		qlcnic_dev_request_reset(adapter);
	} else {
		if (val->flag > QLCNIC_DUMP_MASK_MAX ||
			val->flag < QLCNIC_DUMP_MASK_MIN) {
				netdev_info(netdev,
				"Invalid dump level: 0x%x\n", val->flag);
				ret = -EINVAL;
				goto out;
		}
		if (qlcnic_api_lock(adapter))
			return -EIO;
		fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
		qlcnic_api_unlock(adapter);
		netdev_info(netdev, "Driver mask changed to: 0x%x\n",
			fw_dump->tmpl_hdr->drv_cap_mask);
	}
out:
	return ret;
}
u32
qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
	u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
{
	u32 rsp;
	u32 signature;
	u32 rcode = QLCNIC_RCODE_SUCCESS;
	struct pci_dev *pdev = adapter->pdev;

	signature = QLCNIC_CDRP_SIGNATURE_MAKE(pci_fn, version);

	/* Acquire semaphore before accessing CRB */
	if (qlcnic_api_lock(adapter))
		return QLCNIC_RCODE_TIMEOUT;

	QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
	QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, arg1);
	QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, arg2);
	QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, arg3);
	QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET, QLCNIC_CDRP_FORM_CMD(cmd));

	rsp = qlcnic_poll_rsp(adapter);

	if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
		dev_err(&pdev->dev, "card response timeout.\n");
		rcode = QLCNIC_RCODE_TIMEOUT;
	} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
		rcode = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
		dev_err(&pdev->dev, "failed card response code:0x%x\n",
				rcode);
	}

	/* Release semaphore */
	qlcnic_api_unlock(adapter);

	return rcode;
}
static int
qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
			void *buffer)
{
	int i, copy_sz;
	u32 *hdr_ptr, *data;
	struct qlcnic_adapter *adapter = netdev_priv(netdev);
	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;

	if (qlcnic_api_lock(adapter))
		return -EIO;
	if (!fw_dump->clr) {
		netdev_info(netdev, "Dump not available\n");
		qlcnic_api_unlock(adapter);
		return -EINVAL;
	}
	/* Copy template header first */
	copy_sz = fw_dump->tmpl_hdr->size;
	hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
	data = (u32 *) buffer;
	for (i = 0; i < copy_sz/sizeof(u32); i++)
		*data++ = cpu_to_le32(*hdr_ptr++);

	/* Copy captured dump data */
	memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
	dump->len = copy_sz + fw_dump->size;
	dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;

	/* Free dump area once data has been captured */
	vfree(fw_dump->data);
	fw_dump->data = NULL;
	fw_dump->clr = 0;
	qlcnic_api_unlock(adapter);

	return 0;
}