Commit 29e2bac8 authored by Xiang Chen's avatar Xiang Chen Committed by Martin K. Petersen
Browse files

scsi: hisi_sas: Fix some issues related to asd_sas_port->phy_list

Most places that use asd_sas_port->phy_list are protected by spinlock
asd_sas_port->phy_list_lock, however there are still some places which miss
grabbing the lock. Add it in function hisi_sas_refresh_port_id() when
accessing asd_sas_port->phy_list. This carries a risk that list mutates
while at the same time dropping the lock in function
hisi_sas_send_ata_reset_each_phy(). Read asd_sas_port->phy_mask instead of
accessing asd_sas_port->phy_list to avoid this risk.

Link: https://lore.kernel.org/r/1639999298-244569-6-git-send-email-chenxiang66@hisilicon.com


Acked-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 42159d3c
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -1428,11 +1428,13 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba)
		sas_port = device->port;
		port = to_hisi_sas_port(sas_port);

		spin_lock(&sas_port->phy_list_lock);
		list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el)
			if (state & BIT(sas_phy->id)) {
				phy = sas_phy->lldd_phy;
				break;
			}
		spin_unlock(&sas_port->phy_list_lock);

		if (phy) {
			port->id = phy->port_id;
@@ -1509,22 +1511,25 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba,
	struct ata_link *link;
	u8 fis[20] = {0};
	u32 state;
	int i;

	state = hisi_hba->hw->get_phys_state(hisi_hba);
	list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) {
	for (i = 0; i < hisi_hba->n_phy; i++) {
		if (!(state & BIT(sas_phy->id)))
			continue;
		if (!(sas_port->phy_mask & BIT(i)))
			continue;

		ata_for_each_link(link, ap, EDGE) {
			int pmp = sata_srst_pmp(link);

			tmf_task.phy_id = sas_phy->id;
			tmf_task.phy_id = i;
			hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
			rc = hisi_sas_exec_internal_tmf_task(device, fis, s,
							     &tmf_task);
			if (rc != TMF_RESP_FUNC_COMPLETE) {
				dev_err(dev, "phy%d ata reset failed rc=%d\n",
					sas_phy->id, rc);
					i, rc);
				break;
			}
		}