mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
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: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
60b3f355c7
@ -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);
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
@ -2462,7 +2466,7 @@ out:
|
||||
}
|
||||
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);
|
||||
|
@ -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)) {
|
||||
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;
|
||||
@ -2379,7 +2395,7 @@ out:
|
||||
}
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user