diff options
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_main.c')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 104 |
1 files changed, 71 insertions, 33 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 14bac4966c87..8a7feb8ed8d6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -10,7 +10,6 @@ */ #include "hisi_sas.h" -#include "../libsas/sas_internal.h" #define DRV_NAME "hisi_sas" #define DEV_IS_GONE(dev) \ @@ -171,7 +170,7 @@ void hisi_sas_stop_phys(struct hisi_hba *hisi_hba) int phy_no; for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); } EXPORT_SYMBOL_GPL(hisi_sas_stop_phys); @@ -684,7 +683,7 @@ static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no) id->initiator_bits = SAS_PROTOCOL_ALL; id->target_bits = phy->identify.target_port_protocols; } else if (phy->phy_type & PORT_TYPE_SATA) { - /*Nothing*/ + /* Nothing */ } sas_phy->frame_rcvd_size = phy->frame_rcvd_size; @@ -755,7 +754,8 @@ static int hisi_sas_init_device(struct domain_device *device) * STP target port */ local_phy = sas_get_local_phy(device); - if (!scsi_is_sas_phy_local(local_phy)) { + if (!scsi_is_sas_phy_local(local_phy) && + !test_bit(HISI_SAS_RESET_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; @@ -770,8 +770,7 @@ static int hisi_sas_init_device(struct domain_device *device) } sas_put_local_phy(local_phy); if (rc) { - dev_warn(dev, "SATA disk hardreset fail: 0x%x\n", - rc); + dev_warn(dev, "SATA disk hardreset fail: %d\n", rc); return rc; } @@ -976,6 +975,30 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no) timer_setup(&phy->timer, hisi_sas_wait_phyup_timedout, 0); } +/* Wrapper to ensure we track hisi_sas_phy.enable properly */ +void hisi_sas_phy_enable(struct hisi_hba *hisi_hba, int phy_no, int enable) +{ + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *aphy = &phy->sas_phy; + struct sas_phy *sphy = aphy->phy; + unsigned long flags; + + spin_lock_irqsave(&phy->lock, flags); + + if (enable) { + /* We may have been enabled already; if so, don't touch */ + if (!phy->enable) + sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; + hisi_hba->hw->phy_start(hisi_hba, phy_no); + } else { + sphy->negotiated_linkrate = SAS_PHY_DISABLED; + hisi_hba->hw->phy_disable(hisi_hba, phy_no); + } + phy->enable = enable; + spin_unlock_irqrestore(&phy->lock, flags); +} +EXPORT_SYMBOL_GPL(hisi_sas_phy_enable); + static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) { struct sas_ha_struct *sas_ha = sas_phy->ha; @@ -1112,10 +1135,10 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, sas_phy->phy->maximum_linkrate = max; sas_phy->phy->minimum_linkrate = min; - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); msleep(100); hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r); - hisi_hba->hw->phy_start(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 1); return 0; } @@ -1133,13 +1156,13 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, break; case PHY_FUNC_LINK_RESET: - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); msleep(100); - hisi_hba->hw->phy_start(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 1); break; case PHY_FUNC_DISABLE: - hisi_hba->hw->phy_disable(hisi_hba, phy_no); + hisi_sas_phy_enable(hisi_hba, phy_no, 0); break; case PHY_FUNC_SET_LINK_RATE: @@ -1264,8 +1287,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, /* no error, but return the number of bytes of * underrun */ - dev_warn(dev, "abort tmf: task to dev %016llx " - "resp: 0x%x sts 0x%x underrun\n", + dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x sts 0x%x underrun\n", SAS_ADDR(device->sas_addr), task->task_status.resp, task->task_status.stat); @@ -1280,10 +1302,16 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, break; } - dev_warn(dev, "abort tmf: task to dev " - "%016llx resp: 0x%x status 0x%x\n", - SAS_ADDR(device->sas_addr), task->task_status.resp, - task->task_status.stat); + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_OPEN_REJECT) { + dev_warn(dev, "abort tmf: open reject failed\n"); + res = -EIO; + } else { + dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x status 0x%x\n", + SAS_ADDR(device->sas_addr), + task->task_status.resp, + task->task_status.stat); + } sas_free_task(task); task = NULL; } @@ -1427,9 +1455,9 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); } - } else if (old_state & (1 << phy_no)) - /* PHY down but was up before */ + } else { hisi_sas_phy_down(hisi_hba, phy_no, 0); + } } } @@ -1711,7 +1739,7 @@ static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; struct hisi_sas_tmf_task tmf_task; - int rc = TMF_RESP_FUNC_FAILED; + int rc; rc = hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_DEV, 0); @@ -1803,7 +1831,7 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) if (dev_is_sata(device)) { rc = hisi_sas_softreset_ata_disk(device); - if (rc) + if (rc == TMF_RESP_FUNC_FAILED) return TMF_RESP_FUNC_FAILED; } @@ -2100,10 +2128,8 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, } exit: - dev_dbg(dev, "internal task abort: task to dev %016llx task=%p " - "resp: 0x%x sts 0x%x\n", - SAS_ADDR(device->sas_addr), - task, + dev_dbg(dev, "internal task abort: task to dev %016llx task=%p resp: 0x%x sts 0x%x\n", + SAS_ADDR(device->sas_addr), task, task->task_status.resp, /* 0 is complete, -1 is undelivered */ task->task_status.stat); sas_free_task(task); @@ -2172,16 +2198,18 @@ static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) { struct asd_sas_phy *sas_phy = &phy->sas_phy; struct sas_phy *sphy = sas_phy->phy; - struct sas_phy_data *d = sphy->hostdata; + unsigned long flags; phy->phy_attached = 0; phy->phy_type = 0; phy->port = NULL; - if (d->enable) + spin_lock_irqsave(&phy->lock, flags); + if (phy->enable) sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; else sphy->negotiated_linkrate = SAS_PHY_DISABLED; + spin_unlock_irqrestore(&phy->lock, flags); } void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) @@ -2234,6 +2262,19 @@ void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba) } EXPORT_SYMBOL_GPL(hisi_sas_kill_tasklets); +int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type) +{ + struct hisi_hba *hisi_hba = shost_priv(shost); + + if (reset_type != SCSI_ADAPTER_RESET) + return -EOPNOTSUPP; + + queue_work(hisi_hba->wq, &hisi_hba->rst_work); + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_sas_host_reset); + struct scsi_transport_template *hisi_sas_stt; EXPORT_SYMBOL_GPL(hisi_sas_stt); @@ -2491,22 +2532,19 @@ int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba) if (device_property_read_u32(dev, "ctrl-reset-reg", &hisi_hba->ctrl_reset_reg)) { - dev_err(dev, - "could not get property ctrl-reset-reg\n"); + dev_err(dev, "could not get property ctrl-reset-reg\n"); return -ENOENT; } if (device_property_read_u32(dev, "ctrl-reset-sts-reg", &hisi_hba->ctrl_reset_sts_reg)) { - dev_err(dev, - "could not get property ctrl-reset-sts-reg\n"); + dev_err(dev, "could not get property ctrl-reset-sts-reg\n"); return -ENOENT; } if (device_property_read_u32(dev, "ctrl-clock-ena-reg", &hisi_hba->ctrl_clock_ena_reg)) { - dev_err(dev, - "could not get property ctrl-clock-ena-reg\n"); + dev_err(dev, "could not get property ctrl-clock-ena-reg\n"); return -ENOENT; } } |