Unverified Commit 9895e9ad authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!618 Bugfixes related to SAS error handling, DIF, and low power consumption

Merge Pull Request from: @xia-bing1 
 
Resolve the following issues:
1.SATA devices on an expander may be removed and not be found again when I_T nexus reset and revalidation are processed simultaneously.
2.Currently the driver sets the port invalid if one phy in the port is not enabled, which may cause issues in expander situation. In directly attached situation, if phy up doesn't occur in time when refreshing port id, the port is incorrectly set to invalid which will also cause disk lost.
3.When the current status of the host controller is suspended, enabling a local PHY just after disabling all local PHYs in expander envirnment, a hung as follows occurs.
4.incorrect port id may be configured in hisi_sas_refresh_port_id().As a result, all the internal IOs fail and disk lost,
5.After a HUAWEI disk that supports DIF3 is converted to a common SAS disk in DIF format, an error message is displayed when the FIO command is executed. 
 
Link:https://gitee.com/openeuler/kernel/pulls/618

 

Reviewed-by: default avatarYihang Li <liyihang9@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents a696cb69 6acf8528
Loading
Loading
Loading
Loading
+36 −6
Original line number Diff line number Diff line
@@ -1468,7 +1468,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba)
				device->linkrate = phy->sas_phy.linkrate;

			hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
		} else
		} else if (!port->port_attached)
			port->id = 0xff;
	}
}
@@ -1617,13 +1617,41 @@ void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba)
}
EXPORT_SYMBOL_GPL(hisi_sas_controller_reset_prepare);

static void hisi_sas_async_init_wait_phyup(void *data, async_cookie_t cookie)
{
	struct hisi_sas_phy *phy = data;
	struct hisi_hba *hisi_hba = phy->hisi_hba;
	struct device *dev = hisi_hba->dev;
	DECLARE_COMPLETION_ONSTACK(completion);
	int phy_no = phy->sas_phy.id;

	phy->reset_completion = &completion;
	hisi_sas_phy_enable(hisi_hba, phy_no, 1);
	if (!wait_for_completion_timeout(&completion,
					 HISI_SAS_WAIT_PHYUP_TIMEOUT))
		dev_warn(dev, "phy%d wait phyup timed out\n", phy_no);

	phy->reset_completion = NULL;
}

void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba)
{
	struct Scsi_Host *shost = hisi_hba->shost;
	ASYNC_DOMAIN_EXCLUSIVE(async);
	int phy_no;

	/* Init and wait for PHYs to come up and all libsas event finished. */
	hisi_hba->hw->phys_init(hisi_hba);
	msleep(1000);
	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
		struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];

		if (!(hisi_hba->phy_state & BIT(phy_no)))
			continue;

		async_schedule_domain(hisi_sas_async_init_wait_phyup,
				      phy, &async);
	}

	async_synchronize_full_domain(&async);
	hisi_sas_refresh_port_id(hisi_hba);
	clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);

@@ -1885,13 +1913,15 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
		return rc;
	}

	/* Remote phy */
	if (rc)
		return rc;

	/* Remote phy */
	if (dev_is_sata(device)) {
		rc = sas_ata_wait_after_reset(device,
					HISI_SAS_WAIT_PHYUP_TIMEOUT);
		struct ata_link *link = &device->sata_dev.ap->link;

		rc = ata_wait_after_reset(link, HISI_SAS_WAIT_PHYUP_TIMEOUT,
					  smp_ata_check_ready_type);
	} else {
		msleep(2000);
	}
+56 −17
Original line number Diff line number Diff line
@@ -594,6 +594,27 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
	readl_poll_timeout_atomic(regs, val, cond, delay_us, timeout_us);\
})

static void interrupt_enable_v3_hw(struct hisi_hba *hisi_hba)
{
	int i;

	for (i = 0; i < hisi_hba->queue_count; i++)
		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0);

	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe);
	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe);
	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffc220ff);
	hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0x155555);

	for (i = 0; i < hisi_hba->n_phy; i++) {
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xf2057fff);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffbfe);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
	}
}

static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
{
	int i, j;
@@ -614,20 +635,14 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
	hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
	hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
	hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe);
	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe);
	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffc220ff);
	hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0);
	hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0);
	hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0);
	hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0x155555);
	hisi_sas_write32(hisi_hba, AWQOS_AWCACHE_CFG, 0xf0f0);
	hisi_sas_write32(hisi_hba, ARQOS_ARCACHE_CFG, 0xf0f0);
	for (i = 0; i < hisi_hba->queue_count; i++)
		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0);

	hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);

	interrupt_enable_v3_hw(hisi_hba);
	for (i = 0; i < hisi_hba->n_phy; i++) {
		enum sas_linkrate max;
		struct hisi_sas_phy *phy = &hisi_hba->phy[i];
@@ -650,13 +665,8 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
		hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xf2057fff);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffbfe);
		hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x1);
		hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120);
		hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x2a0a01);
@@ -2632,7 +2642,6 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba)
	u32 status, reg_val;
	int rc;

	interrupt_disable_v3_hw(hisi_hba);
	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);

	hisi_sas_stop_phys(hisi_hba);
@@ -2662,6 +2671,7 @@ static int soft_reset_v3_hw(struct hisi_hba *hisi_hba)
	struct device *dev = hisi_hba->dev;
	int rc;

	interrupt_disable_v3_hw(hisi_hba);
	rc = disable_host_v3_hw(hisi_hba);
	if (rc) {
		dev_err(dev, "soft reset: disable host failed rc=%d\n", rc);
@@ -4994,6 +5004,7 @@ static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev)
	set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
	hisi_sas_controller_reset_prepare(hisi_hba);

	interrupt_disable_v3_hw(hisi_hba);
	rc = disable_host_v3_hw(hisi_hba);
	if (rc)
		dev_err(dev, "FLR: disable host failed rc=%d\n", rc);
@@ -5023,6 +5034,21 @@ enum {
	hip08,
};

static void enable_host_v3_hw(struct hisi_hba *hisi_hba)
{
	u32 reg_val;

	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
			 (u32)((1ULL << hisi_hba->queue_count) - 1));

	phys_init_v3_hw(hisi_hba);
	reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE +
				  AM_CTRL_GLOBAL);
	reg_val &= ~AM_CTRL_SHUTDOWN_REQ_MSK;
	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE +
			 AM_CTRL_GLOBAL, reg_val);
}

static int _suspend_v3_hw(struct device *device)
{
	struct pci_dev *pdev = to_pci_dev(device);
@@ -5045,14 +5071,18 @@ static int _suspend_v3_hw(struct device *device)
	scsi_block_requests(shost);
	set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
	flush_workqueue(hisi_hba->wq);
	interrupt_disable_v3_hw(hisi_hba);

	if (atomic_read(&device->power.usage_count)) {
		dev_err(dev, "PM suspend: host status cannot be suspended\n");
		rc = -EBUSY;
		goto err_out;
	}

	rc = disable_host_v3_hw(hisi_hba);
	if (rc) {
		dev_err(dev, "PM suspend: disable host failed rc=%d\n", rc);
		clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
		clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
		scsi_unblock_requests(shost);
		return rc;
		goto err_out_recover_host;
	}

	hisi_sas_init_mem(hisi_hba);
@@ -5063,6 +5093,15 @@ static int _suspend_v3_hw(struct device *device)

	dev_warn(dev, "end of suspending controller\n");
	return 0;

err_out_recover_host:
	enable_host_v3_hw(hisi_hba);
err_out:
	interrupt_enable_v3_hw(hisi_hba);
	clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
	clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
	scsi_unblock_requests(shost);
	return rc;
}

static int _resume_v3_hw(struct device *device)
+26 −2
Original line number Diff line number Diff line
@@ -301,6 +301,31 @@ static int sas_ata_clear_pending(struct domain_device *dev, struct ex_phy *phy)
		return 1;
}

int smp_ata_check_ready_type(struct ata_link *link)
{
	struct domain_device *dev = link->ap->private_data;
	struct sas_phy *phy = sas_get_local_phy(dev);
	struct domain_device *ex_dev = dev->parent;
	enum sas_device_type type = SAS_PHY_UNUSED;
	u8 sas_addr[SAS_ADDR_SIZE];
	int res;

	res = sas_get_phy_attached_dev(ex_dev, phy->number, sas_addr, &type);
	sas_put_local_phy(phy);
	if (res)
		return res;

	switch (type) {
	case SAS_SATA_PENDING:
		return 0;
	case SAS_END_DEVICE:
		return 1;
	default:
		return -ENODEV;
	}
}
EXPORT_SYMBOL_GPL(smp_ata_check_ready_type);

static int smp_ata_check_ready(struct ata_link *link)
{
	int res;
@@ -372,7 +397,7 @@ static int sas_ata_printk(const char *level, const struct domain_device *ddev,
	return r;
}

int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline)
static int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline)
{
	struct sata_device *sata_dev = &dev->sata_dev;
	int (*check_ready)(struct ata_link *link);
@@ -394,7 +419,6 @@ int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline)

	return ret;
}
EXPORT_SYMBOL_GPL(sas_ata_wait_after_reset);

static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
			      unsigned long deadline)
+2 −2
Original line number Diff line number Diff line
@@ -1719,7 +1719,7 @@ static int sas_get_phy_change_count(struct domain_device *dev,
	return res;
}

static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
			     u8 *sas_addr, enum sas_device_type *type)
{
	int res;
+2 −0
Original line number Diff line number Diff line
@@ -86,6 +86,8 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
int sas_ex_phy_discover(struct domain_device *dev, int single);
int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
			    struct smp_resp *rps_resp);
int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
			     u8 *sas_addr, enum sas_device_type *type);
int sas_try_ata_reset(struct asd_sas_phy *phy);
void sas_hae_reset(struct work_struct *work);

Loading