summaryrefslogtreecommitdiff
path: root/drivers/scsi/hisi_sas/hisi_sas_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_main.c')
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c113
1 files changed, 81 insertions, 32 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 9515c45affa5..f206c433de32 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -724,7 +724,7 @@ static int hisi_sas_init_device(struct domain_device *device)
*/
local_phy = sas_get_local_phy(device);
if (!scsi_is_sas_phy_local(local_phy) &&
- !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
+ !test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) {
unsigned long deadline = ata_deadline(jiffies, 20000);
struct sata_device *sata_dev = &device->sata_dev;
struct ata_host *ata_host = sata_dev->ata_host;
@@ -756,6 +756,20 @@ static int hisi_sas_init_device(struct domain_device *device)
return rc;
}
+int hisi_sas_slave_alloc(struct scsi_device *sdev)
+{
+ struct domain_device *ddev;
+ int rc;
+
+ rc = sas_slave_alloc(sdev);
+ if (rc)
+ return rc;
+ ddev = sdev_to_domain_dev(sdev);
+
+ return hisi_sas_init_device(ddev);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_slave_alloc);
+
static int hisi_sas_dev_found(struct domain_device *device)
{
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
@@ -802,9 +816,6 @@ static int hisi_sas_dev_found(struct domain_device *device)
dev_info(dev, "dev[%d:%x] found\n",
sas_dev->device_id, sas_dev->dev_type);
- rc = hisi_sas_init_device(device);
- if (rc)
- goto err_out;
sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
return 0;
@@ -1072,7 +1083,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
sas_dev->device_id, sas_dev->dev_type);
down(&hisi_hba->sem);
- if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
+ if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) {
hisi_sas_internal_task_abort(hisi_hba, device,
HISI_SAS_INT_ABT_DEV, 0, true);
@@ -1135,9 +1146,17 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no,
static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
void *funcdata)
{
+ struct hisi_sas_phy *phy = container_of(sas_phy,
+ struct hisi_sas_phy, sas_phy);
struct sas_ha_struct *sas_ha = sas_phy->ha;
struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+ struct device *dev = hisi_hba->dev;
+ DECLARE_COMPLETION_ONSTACK(completion);
int phy_no = sas_phy->id;
+ u8 sts = phy->phy_attached;
+ int ret = 0;
+
+ phy->reset_completion = &completion;
switch (func) {
case PHY_FUNC_HARD_RESET:
@@ -1152,26 +1171,40 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
case PHY_FUNC_DISABLE:
hisi_sas_phy_enable(hisi_hba, phy_no, 0);
- break;
+ goto out;
case PHY_FUNC_SET_LINK_RATE:
- return hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata);
+ ret = hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata);
+ break;
+
case PHY_FUNC_GET_EVENTS:
if (hisi_hba->hw->get_events) {
hisi_hba->hw->get_events(hisi_hba, phy_no);
- break;
+ goto out;
}
fallthrough;
case PHY_FUNC_RELEASE_SPINUP_HOLD:
default:
- return -EOPNOTSUPP;
+ ret = -EOPNOTSUPP;
+ goto out;
}
- return 0;
+
+ if (sts && !wait_for_completion_timeout(&completion, 2 * HZ)) {
+ dev_warn(dev, "phy%d wait phyup timed out for func %d\n",
+ phy_no, func);
+ if (phy->in_reset)
+ ret = -ETIMEDOUT;
+ }
+
+out:
+ phy->reset_completion = NULL;
+
+ return ret;
}
static void hisi_sas_task_done(struct sas_task *task)
{
- del_timer(&task->slow_task->timer);
+ del_timer_sync(&task->slow_task->timer);
complete(&task->slow_task->completion);
}
@@ -1229,7 +1262,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf);
if (res) {
- del_timer(&task->slow_task->timer);
+ del_timer_sync(&task->slow_task->timer);
dev_err(dev, "abort tmf: executing internal task failed: %d\n",
res);
goto ex_err;
@@ -1554,8 +1587,7 @@ void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba)
scsi_block_requests(shost);
hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000);
- if (timer_pending(&hisi_hba->timer))
- del_timer_sync(&hisi_hba->timer);
+ del_timer_sync(&hisi_hba->timer);
set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
}
@@ -1576,7 +1608,7 @@ void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba)
hisi_sas_reset_init_all_devices(hisi_hba);
up(&hisi_hba->sem);
scsi_unblock_requests(shost);
- clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+ clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags);
hisi_sas_rescan_topology(hisi_hba, hisi_hba->phy_state);
}
@@ -1587,7 +1619,7 @@ static int hisi_sas_controller_prereset(struct hisi_hba *hisi_hba)
if (!hisi_hba->hw->soft_reset)
return -1;
- if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))
+ if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags))
return -1;
if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
@@ -1611,7 +1643,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
up(&hisi_hba->sem);
scsi_unblock_requests(shost);
- clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+ clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags);
return rc;
}
@@ -1773,7 +1805,6 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct sas_ha_struct *sas_ha = &hisi_hba->sha;
- DECLARE_COMPLETION_ONSTACK(phyreset);
int rc, reset_type;
if (!local_phy->enabled) {
@@ -1786,8 +1817,11 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
sas_ha->sas_phy[local_phy->number];
struct hisi_sas_phy *phy =
container_of(sas_phy, struct hisi_sas_phy, sas_phy);
+ unsigned long flags;
+
+ spin_lock_irqsave(&phy->lock, flags);
phy->in_reset = 1;
- phy->reset_completion = &phyreset;
+ spin_unlock_irqrestore(&phy->lock, flags);
}
reset_type = (sas_dev->dev_status == HISI_SAS_DEV_INIT ||
@@ -1801,17 +1835,14 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
sas_ha->sas_phy[local_phy->number];
struct hisi_sas_phy *phy =
container_of(sas_phy, struct hisi_sas_phy, sas_phy);
- int ret = wait_for_completion_timeout(&phyreset,
- I_T_NEXUS_RESET_PHYUP_TIMEOUT);
unsigned long flags;
spin_lock_irqsave(&phy->lock, flags);
- phy->reset_completion = NULL;
phy->in_reset = 0;
spin_unlock_irqrestore(&phy->lock, flags);
/* report PHY down if timed out */
- if (!ret)
+ if (rc == -ETIMEDOUT)
hisi_sas_phy_down(hisi_hba, sas_phy->id, 0, GFP_KERNEL);
} else if (sas_dev->dev_status != HISI_SAS_DEV_INIT) {
/*
@@ -1839,14 +1870,33 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
}
hisi_sas_dereg_device(hisi_hba, device);
- if (dev_is_sata(device)) {
+ rc = hisi_sas_debug_I_T_nexus_reset(device);
+ if (rc == TMF_RESP_FUNC_COMPLETE && dev_is_sata(device)) {
+ struct sas_phy *local_phy;
+
rc = hisi_sas_softreset_ata_disk(device);
- if (rc == TMF_RESP_FUNC_FAILED)
- return TMF_RESP_FUNC_FAILED;
+ switch (rc) {
+ case -ECOMM:
+ rc = -ENODEV;
+ break;
+ case TMF_RESP_FUNC_FAILED:
+ case -EMSGSIZE:
+ case -EIO:
+ local_phy = sas_get_local_phy(device);
+ rc = sas_phy_enable(local_phy, 0);
+ if (!rc) {
+ local_phy->enabled = 0;
+ dev_err(dev, "Disabled local phy of ATA disk %016llx due to softreset fail (%d)\n",
+ SAS_ADDR(device->sas_addr), rc);
+ rc = -ENODEV;
+ }
+ sas_put_local_phy(local_phy);
+ break;
+ default:
+ break;
+ }
}
- rc = hisi_sas_debug_I_T_nexus_reset(device);
-
if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV))
hisi_sas_release_task(hisi_hba, device);
@@ -2097,7 +2147,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
task, abort_flag, tag, dq);
if (res) {
- del_timer(&task->slow_task->timer);
+ del_timer_sync(&task->slow_task->timer);
dev_err(dev, "internal task abort: executing internal task failed: %d\n",
res);
goto exit;
@@ -2251,7 +2301,7 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy,
} else {
struct hisi_sas_port *port = phy->port;
- if (test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags) ||
+ if (test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) ||
phy->in_reset) {
dev_info(dev, "ignore flutter phy%d down\n", phy_no);
return;
@@ -2769,8 +2819,7 @@ int hisi_sas_remove(struct platform_device *pdev)
struct hisi_hba *hisi_hba = sha->lldd_ha;
struct Scsi_Host *shost = sha->core.shost;
- if (timer_pending(&hisi_hba->timer))
- del_timer(&hisi_hba->timer);
+ del_timer_sync(&hisi_hba->timer);
sas_unregister_ha(sha);
sas_remove_host(sha->core.shost);