Commit 60b3f355 authored by Martin K. Petersen's avatar Martin K. Petersen
Browse files

Merge patch series "scsi: hisi_sas: Some misc changes"

chenxiang <chenxiang66@hisilicon.com> says:

This series contain some fixes including:

 - Grab sas_dev lock when traversing sas_dev list to avoid NULL
   pointer

 - Handle NCQ error when IPTT is valid

 - Ensure all enabled PHYs up during controller reset

 - Exit suspend state when usage count of runtime PM is greater than 0

https://lore.kernel.org/r/1679283265-115066-1-git-send-email-chenxiang66@hisilicon.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parents 3d2efb54 e368d38c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -656,7 +656,8 @@ extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy,
extern void hisi_sas_phy_bcast(struct hisi_sas_phy *phy);
extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
				    struct sas_task *task,
				    struct hisi_sas_slot *slot);
				    struct hisi_sas_slot *slot,
				    bool need_lock);
extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
extern void hisi_sas_rst_work_handler(struct work_struct *work);
extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
+46 −11
Original line number Diff line number Diff line
@@ -205,7 +205,7 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba,
}

void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
			     struct hisi_sas_slot *slot)
			     struct hisi_sas_slot *slot, bool need_lock)
{
	int device_id = slot->device_id;
	struct hisi_sas_device *sas_dev = &hisi_hba->devices[device_id];
@@ -239,9 +239,13 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
		}
	}

	if (need_lock) {
		spin_lock(&sas_dev->lock);
		list_del_init(&slot->entry);
		spin_unlock(&sas_dev->lock);
	} else {
		list_del_init(&slot->entry);
	}

	memset(slot, 0, offsetof(struct hisi_sas_slot, buf));

@@ -1081,7 +1085,7 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
}

static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task *task,
				     struct hisi_sas_slot *slot)
				     struct hisi_sas_slot *slot, bool need_lock)
{
	if (task) {
		unsigned long flags;
@@ -1098,7 +1102,7 @@ static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task
		spin_unlock_irqrestore(&task->task_state_lock, flags);
	}

	hisi_sas_slot_task_free(hisi_hba, task, slot);
	hisi_sas_slot_task_free(hisi_hba, task, slot, need_lock);
}

static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
@@ -1107,8 +1111,11 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
	struct hisi_sas_slot *slot, *slot2;
	struct hisi_sas_device *sas_dev = device->lldd_dev;

	spin_lock(&sas_dev->lock);
	list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry)
		hisi_sas_do_release_task(hisi_hba, slot->task, slot);
		hisi_sas_do_release_task(hisi_hba, slot->task, slot, false);

	spin_unlock(&sas_dev->lock);
}

void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
@@ -1513,13 +1520,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);

@@ -1634,7 +1669,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
		 */
		if (rc == TMF_RESP_FUNC_COMPLETE && rc2 != TMF_RESP_FUNC_SUCC) {
			if (task->lldd_task)
				hisi_sas_do_release_task(hisi_hba, task, slot);
				hisi_sas_do_release_task(hisi_hba, task, slot, true);
		}
	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
		task->task_proto & SAS_PROTOCOL_STP) {
@@ -1654,7 +1689,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
			 */
			if ((sas_dev->dev_status == HISI_SAS_DEV_NCQ_ERR) &&
			    qc && qc->scsicmd) {
				hisi_sas_do_release_task(hisi_hba, task, slot);
				hisi_sas_do_release_task(hisi_hba, task, slot, true);
				rc = TMF_RESP_FUNC_COMPLETE;
			} else {
				rc = hisi_sas_softreset_ata_disk(device);
+6 −2
Original line number Diff line number Diff line
@@ -1258,7 +1258,11 @@ static void slot_complete_v1_hw(struct hisi_hba *hisi_hba,

		slot_err_v1_hw(hisi_hba, task, slot);
		if (unlikely(slot->abort)) {
			if (dev_is_sata(device) && task->ata_task.use_ncq)
				sas_ata_device_link_abort(device, true);
			else
				sas_task_abort(task);

			return;
		}
		goto out;
@@ -1306,7 +1310,7 @@ static void slot_complete_v1_hw(struct hisi_hba *hisi_hba,
	}

out:
	hisi_sas_slot_task_free(hisi_hba, task, slot);
	hisi_sas_slot_task_free(hisi_hba, task, slot, true);

	if (task->task_done)
		task->task_done(task);
+6 −2
Original line number Diff line number Diff line
@@ -2404,7 +2404,11 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba,
				 error_info[2], error_info[3]);

		if (unlikely(slot->abort)) {
			if (dev_is_sata(device) && task->ata_task.use_ncq)
				sas_ata_device_link_abort(device, true);
			else
				sas_task_abort(task);

			return;
		}
		goto out;
@@ -2462,7 +2466,7 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba,
	}
	task->task_state_flags |= SAS_TASK_STATE_DONE;
	spin_unlock_irqrestore(&task->task_state_lock, flags);
	hisi_sas_slot_task_free(hisi_hba, task, slot);
	hisi_sas_slot_task_free(hisi_hba, task, slot, true);

	if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
		spin_lock_irqsave(&device->done_lock, flags);
+64 −19
Original line number Diff line number Diff line
@@ -604,6 +604,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;
@@ -624,20 +645,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];
@@ -660,13 +675,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);
@@ -888,6 +898,7 @@ static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,

	cfg_abt_set_query_iptt = hisi_sas_read32(hisi_hba,
		CFG_ABT_SET_QUERY_IPTT);
	spin_lock(&sas_dev->lock);
	list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry) {
		cfg_abt_set_query_iptt &= ~CFG_SET_ABORTED_IPTT_MSK;
		cfg_abt_set_query_iptt |= (1 << CFG_SET_ABORTED_EN_OFF) |
@@ -895,6 +906,7 @@ static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,
		hisi_sas_write32(hisi_hba, CFG_ABT_SET_QUERY_IPTT,
			cfg_abt_set_query_iptt);
	}
	spin_unlock(&sas_dev->lock);
	cfg_abt_set_query_iptt &= ~(1 << CFG_SET_ABORTED_EN_OFF);
	hisi_sas_write32(hisi_hba, CFG_ABT_SET_QUERY_IPTT,
		cfg_abt_set_query_iptt);
@@ -2325,7 +2337,11 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
					error_info[0], error_info[1],
					error_info[2], error_info[3]);
			if (unlikely(slot->abort)) {
				if (dev_is_sata(device) && task->ata_task.use_ncq)
					sas_ata_device_link_abort(device, true);
				else
					sas_task_abort(task);

				return;
			}
			goto out;
@@ -2379,7 +2395,7 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
	}
	task->task_state_flags |= SAS_TASK_STATE_DONE;
	spin_unlock_irqrestore(&task->task_state_lock, flags);
	hisi_sas_slot_task_free(hisi_hba, task, slot);
	hisi_sas_slot_task_free(hisi_hba, task, slot, true);

	if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
		spin_lock_irqsave(&device->done_lock, flags);
@@ -2655,7 +2671,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_sync_poll_cqs(hisi_hba);
	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);

@@ -2686,6 +2701,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);
@@ -5054,6 +5070,7 @@ static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev)
	set_bit(HISI_SAS_RESETTING_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);
@@ -5083,6 +5100,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);
@@ -5105,14 +5137,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_RESETTING_BIT, &hisi_hba->flags);
		scsi_unblock_requests(shost);
		return rc;
		goto err_out_recover_host;
	}

	hisi_sas_init_mem(hisi_hba);
@@ -5123,6 +5159,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_RESETTING_BIT, &hisi_hba->flags);
	scsi_unblock_requests(shost);
	return rc;
}

static int _resume_v3_hw(struct device *device)