Skip to content

Commit

Permalink
Merge patch series "scsi: hisi_sas: Some misc changes"
Browse files Browse the repository at this point in the history
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: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Martin K. Petersen committed Apr 3, 2023
2 parents 3d2efb5 + e368d38 commit 60b3f35
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 35 deletions.
3 changes: 2 additions & 1 deletion drivers/scsi/hisi_sas/hisi_sas.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
57 changes: 46 additions & 11 deletions drivers/scsi/hisi_sas/hisi_sas_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -239,9 +239,13 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
}
}

spin_lock(&sas_dev->lock);
list_del_init(&slot->entry);
spin_unlock(&sas_dev->lock);
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));

Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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)
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
8 changes: 6 additions & 2 deletions drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
sas_task_abort(task);
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;
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 6 additions & 2 deletions drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
sas_task_abort(task);
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;
Expand Down Expand Up @@ -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);
Expand Down
83 changes: 64 additions & 19 deletions drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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];
Expand All @@ -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);
Expand Down Expand Up @@ -888,13 +898,15 @@ 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) |
(slot->idx << CFG_SET_ABORTED_IPTT_OFF);
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);
Expand Down Expand Up @@ -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)) {
sas_task_abort(task);
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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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)
Expand Down

0 comments on commit 60b3f35

Please sign in to comment.