Commit 095478a6 authored by John Garry's avatar John Garry Committed by Martin K. Petersen

scsi: hisi_sas: Use libsas internal abort support

Use the common libsas internal abort functionality.

In addition, this driver has special handling for internal abort timeouts -
specifically whether to reset the controller in that instance, so extend
the API for that.

Timeout is now increased to 20 * Hz from 6 * Hz.

We also retry for failure now, but this should not make a difference.

Link: https://lore.kernel.org/r/1647001432-239276-5-git-send-email-john.garry@huawei.comTested-by: default avatarDamien Le Moal <damien.lemoal@opensource.wdc.com>
Acked-by: default avatarJack Wang <jinpu.wang@ionos.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 2cbbf489
...@@ -133,11 +133,6 @@ struct hisi_sas_rst { ...@@ -133,11 +133,6 @@ struct hisi_sas_rst {
bool done; bool done;
}; };
struct hisi_sas_internal_abort {
unsigned int flag;
unsigned int tag;
};
#define HISI_SAS_RST_WORK_INIT(r, c) \ #define HISI_SAS_RST_WORK_INIT(r, c) \
{ .hisi_hba = hisi_hba, \ { .hisi_hba = hisi_hba, \
.completion = &c, \ .completion = &c, \
...@@ -325,8 +320,7 @@ struct hisi_sas_hw { ...@@ -325,8 +320,7 @@ struct hisi_sas_hw {
void (*prep_stp)(struct hisi_hba *hisi_hba, void (*prep_stp)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot); struct hisi_sas_slot *slot);
void (*prep_abort)(struct hisi_hba *hisi_hba, void (*prep_abort)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot, struct hisi_sas_slot *slot);
int device_id, int abort_flag, int tag_to_abort);
void (*phys_init)(struct hisi_hba *hisi_hba); void (*phys_init)(struct hisi_hba *hisi_hba);
void (*phy_start)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_start)(struct hisi_hba *hisi_hba, int phy_no);
void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
......
...@@ -10,10 +10,6 @@ ...@@ -10,10 +10,6 @@
#define DEV_IS_GONE(dev) \ #define DEV_IS_GONE(dev) \
((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) ((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
static int
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
struct domain_device *device,
int abort_flag, int tag, bool rst_to_recover);
static int hisi_sas_softreset_ata_disk(struct domain_device *device); static int hisi_sas_softreset_ata_disk(struct domain_device *device);
static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
void *funcdata); void *funcdata);
...@@ -21,6 +17,10 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba, ...@@ -21,6 +17,10 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
struct domain_device *device); struct domain_device *device);
static void hisi_sas_dev_gone(struct domain_device *device); static void hisi_sas_dev_gone(struct domain_device *device);
struct hisi_sas_internal_abort_data {
bool rst_ha_timeout; /* reset the HA for timeout */
};
u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction)
{ {
switch (fis->command) { switch (fis->command) {
...@@ -263,11 +263,9 @@ static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, ...@@ -263,11 +263,9 @@ static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
} }
static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
struct hisi_sas_internal_abort *abort, struct hisi_sas_slot *slot)
struct hisi_sas_slot *slot, int device_id)
{ {
hisi_hba->hw->prep_abort(hisi_hba, slot, hisi_hba->hw->prep_abort(hisi_hba, slot);
device_id, abort->flag, abort->tag);
} }
static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba,
...@@ -397,8 +395,7 @@ static ...@@ -397,8 +395,7 @@ static
void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot, struct hisi_sas_slot *slot,
struct hisi_sas_dq *dq, struct hisi_sas_dq *dq,
struct hisi_sas_device *sas_dev, struct hisi_sas_device *sas_dev)
struct hisi_sas_internal_abort *abort)
{ {
struct hisi_sas_cmd_hdr *cmd_hdr_base; struct hisi_sas_cmd_hdr *cmd_hdr_base;
int dlvry_queue_slot, dlvry_queue; int dlvry_queue_slot, dlvry_queue;
...@@ -439,19 +436,15 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, ...@@ -439,19 +436,15 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
break; break;
case SAS_PROTOCOL_SATA: case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP: case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: case SAS_PROTOCOL_STP_ALL:
hisi_sas_task_prep_ata(hisi_hba, slot); hisi_sas_task_prep_ata(hisi_hba, slot);
break; break;
case SAS_PROTOCOL_NONE: case SAS_PROTOCOL_INTERNAL_ABORT:
if (abort) { hisi_sas_task_prep_abort(hisi_hba, slot);
hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id); break;
break;
}
fallthrough; fallthrough;
default: default:
dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n", return;
task->task_proto);
break;
} }
WRITE_ONCE(slot->ready, 1); WRITE_ONCE(slot->ready, 1);
...@@ -467,6 +460,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) ...@@ -467,6 +460,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
struct domain_device *device = task->dev; struct domain_device *device = task->dev;
struct asd_sas_port *sas_port = device->port; struct asd_sas_port *sas_port = device->port;
struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_device *sas_dev = device->lldd_dev;
bool internal_abort = sas_is_internal_abort(task);
struct scsi_cmnd *scmd = NULL; struct scsi_cmnd *scmd = NULL;
struct hisi_sas_dq *dq = NULL; struct hisi_sas_dq *dq = NULL;
struct hisi_sas_port *port; struct hisi_sas_port *port;
...@@ -484,7 +478,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) ...@@ -484,7 +478,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
* libsas will use dev->port, should * libsas will use dev->port, should
* not call task_done for sata * not call task_done for sata
*/ */
if (device->dev_type != SAS_SATA_DEV) if (device->dev_type != SAS_SATA_DEV && !internal_abort)
task->task_done(task); task->task_done(task);
return -ECOMM; return -ECOMM;
} }
...@@ -492,59 +486,85 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) ...@@ -492,59 +486,85 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
hisi_hba = dev_to_hisi_hba(device); hisi_hba = dev_to_hisi_hba(device);
dev = hisi_hba->dev; dev = hisi_hba->dev;
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { switch (task->task_proto) {
if (!gfpflags_allow_blocking(gfp_flags)) case SAS_PROTOCOL_SSP:
return -EINVAL; case SAS_PROTOCOL_SMP:
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_STP_ALL:
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
if (!gfpflags_allow_blocking(gfp_flags))
return -EINVAL;
down(&hisi_hba->sem); down(&hisi_hba->sem);
up(&hisi_hba->sem); up(&hisi_hba->sem);
} }
if (DEV_IS_GONE(sas_dev)) { if (DEV_IS_GONE(sas_dev)) {
if (sas_dev) if (sas_dev)
dev_info(dev, "task prep: device %d not ready\n", dev_info(dev, "task prep: device %d not ready\n",
sas_dev->device_id); sas_dev->device_id);
else else
dev_info(dev, "task prep: device %016llx not ready\n", dev_info(dev, "task prep: device %016llx not ready\n",
SAS_ADDR(device->sas_addr)); SAS_ADDR(device->sas_addr));
return -ECOMM; return -ECOMM;
} }
if (task->uldd_task) { port = to_hisi_sas_port(sas_port);
struct ata_queued_cmd *qc; if (!port->port_attached) {
dev_info(dev, "task prep: %s port%d not attach device\n",
dev_is_sata(device) ? "SATA/STP" : "SAS",
device->port->id);
if (dev_is_sata(device)) { return -ECOMM;
qc = task->uldd_task;
scmd = qc->scsicmd;
} else {
scmd = task->uldd_task;
} }
}
if (scmd) { if (task->uldd_task) {
unsigned int dq_index; struct ata_queued_cmd *qc;
u32 blk_tag;
blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); if (dev_is_sata(device)) {
dq_index = blk_mq_unique_tag_to_hwq(blk_tag); qc = task->uldd_task;
dq = &hisi_hba->dq[dq_index]; scmd = qc->scsicmd;
} else { } else {
struct Scsi_Host *shost = hisi_hba->shost; scmd = task->uldd_task;
struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; }
int queue = qmap->mq_map[raw_smp_processor_id()]; }
dq = &hisi_hba->dq[queue]; if (scmd) {
} unsigned int dq_index;
u32 blk_tag;
port = to_hisi_sas_port(sas_port); blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
if (port && !port->port_attached) { dq_index = blk_mq_unique_tag_to_hwq(blk_tag);
dev_info(dev, "task prep: %s port%d not attach device\n", dq = &hisi_hba->dq[dq_index];
(dev_is_sata(device)) ? } else {
"SATA/STP" : "SAS", struct Scsi_Host *shost = hisi_hba->shost;
device->port->id); struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
int queue = qmap->mq_map[raw_smp_processor_id()];
return -ECOMM; dq = &hisi_hba->dq[queue];
}
break;
case SAS_PROTOCOL_INTERNAL_ABORT:
if (!hisi_hba->hw->prep_abort)
return TMF_RESP_FUNC_FAILED;
if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags))
return -EIO;
hisi_hba = dev_to_hisi_hba(device);
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
return -EINVAL;
port = to_hisi_sas_port(sas_port);
dq = &hisi_hba->dq[task->abort_task.qid];
break;
default:
dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n",
task->task_proto);
return -EINVAL;
} }
rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, rc = hisi_sas_dma_map(hisi_hba, task, &n_elem,
...@@ -558,7 +578,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) ...@@ -558,7 +578,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
goto err_out_dma_unmap; goto err_out_dma_unmap;
} }
if (hisi_hba->hw->slot_index_alloc) if (!internal_abort && hisi_hba->hw->slot_index_alloc)
rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
else else
rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); rc = hisi_sas_slot_index_alloc(hisi_hba, scmd);
...@@ -573,10 +593,10 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) ...@@ -573,10 +593,10 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
slot->port = port; slot->port = port;
slot->tmf = task->tmf; slot->tmf = task->tmf;
slot->is_internal = task->tmf; slot->is_internal = !!task->tmf || internal_abort;
/* protect task_prep and start_delivery sequence */ /* protect task_prep and start_delivery sequence */
hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL); hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev);
return 0; return 0;
...@@ -1088,6 +1108,29 @@ static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba, ...@@ -1088,6 +1108,29 @@ static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
hisi_hba->hw->dereg_device(hisi_hba, device); hisi_hba->hw->dereg_device(hisi_hba, device);
} }
static int
hisi_sas_internal_task_abort_dev(struct hisi_sas_device *sas_dev,
bool rst_ha_timeout)
{
struct hisi_sas_internal_abort_data data = { rst_ha_timeout };
struct domain_device *device = sas_dev->sas_device;
struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
int i, rc;
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
const struct cpumask *mask = cq->irq_mask;
if (mask && !cpumask_intersects(cpu_online_mask, mask))
continue;
rc = sas_execute_internal_abort_dev(device, i, &data);
if (rc)
return rc;
}
return 0;
}
static void hisi_sas_dev_gone(struct domain_device *device) static void hisi_sas_dev_gone(struct domain_device *device)
{ {
struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_device *sas_dev = device->lldd_dev;
...@@ -1100,8 +1143,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) ...@@ -1100,8 +1143,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
down(&hisi_hba->sem); down(&hisi_hba->sem);
if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) {
hisi_sas_internal_task_abort(hisi_hba, device, hisi_sas_internal_task_abort_dev(sas_dev, true);
HISI_SAS_INT_ABT_DEV, 0, true);
hisi_sas_dereg_device(hisi_hba, device); hisi_sas_dereg_device(hisi_hba, device);
...@@ -1216,32 +1258,6 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, ...@@ -1216,32 +1258,6 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
return ret; return ret;
} }
static void hisi_sas_task_done(struct sas_task *task)
{
del_timer_sync(&task->slow_task->timer);
complete(&task->slow_task->completion);
}
static void hisi_sas_tmf_timedout(struct timer_list *t)
{
struct sas_task_slow *slow = from_timer(slow, t, timer);
struct sas_task *task = slow->task;
unsigned long flags;
bool is_completed = true;
spin_lock_irqsave(&task->task_state_lock, flags);
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
is_completed = false;
}
spin_unlock_irqrestore(&task->task_state_lock, flags);
if (!is_completed)
complete(&task->slow_task->completion);
}
#define INTERNAL_ABORT_TIMEOUT (6 * HZ)
static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev,
bool reset, int pmp, u8 *fis) bool reset, int pmp, u8 *fis)
{ {
...@@ -1426,9 +1442,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) ...@@ -1426,9 +1442,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device) if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device)
continue; continue;
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
HISI_SAS_INT_ABT_DEV, 0,
false);
if (rc < 0) if (rc < 0)
dev_err(dev, "STP reject: abort dev failed %d\n", rc); dev_err(dev, "STP reject: abort dev failed %d\n", rc);
} }
...@@ -1536,6 +1550,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) ...@@ -1536,6 +1550,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
static int hisi_sas_abort_task(struct sas_task *task) static int hisi_sas_abort_task(struct sas_task *task)
{ {
struct hisi_sas_internal_abort_data internal_abort_data = { false };
struct domain_device *device = task->dev; struct domain_device *device = task->dev;
struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_hba *hisi_hba; struct hisi_hba *hisi_hba;
...@@ -1575,9 +1590,8 @@ static int hisi_sas_abort_task(struct sas_task *task) ...@@ -1575,9 +1590,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
int rc2; int rc2;
rc = sas_abort_task(task, tag); rc = sas_abort_task(task, tag);
rc2 = hisi_sas_internal_task_abort(hisi_hba, device, rc2 = sas_execute_internal_abort_single(device, tag,
HISI_SAS_INT_ABT_CMD, tag, slot->dlvry_queue, &internal_abort_data);
false);
if (rc2 < 0) { if (rc2 < 0) {
dev_err(dev, "abort task: internal abort (%d)\n", rc2); dev_err(dev, "abort task: internal abort (%d)\n", rc2);
return TMF_RESP_FUNC_FAILED; return TMF_RESP_FUNC_FAILED;
...@@ -1597,9 +1611,7 @@ static int hisi_sas_abort_task(struct sas_task *task) ...@@ -1597,9 +1611,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
} else if (task->task_proto & SAS_PROTOCOL_SATA || } else if (task->task_proto & SAS_PROTOCOL_SATA ||
task->task_proto & SAS_PROTOCOL_STP) { task->task_proto & SAS_PROTOCOL_STP) {
if (task->dev->dev_type == SAS_SATA_DEV) { if (task->dev->dev_type == SAS_SATA_DEV) {
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
HISI_SAS_INT_ABT_DEV,
0, false);
if (rc < 0) { if (rc < 0) {
dev_err(dev, "abort task: internal abort failed\n"); dev_err(dev, "abort task: internal abort failed\n");
goto out; goto out;
...@@ -1613,9 +1625,9 @@ static int hisi_sas_abort_task(struct sas_task *task) ...@@ -1613,9 +1625,9 @@ static int hisi_sas_abort_task(struct sas_task *task)
u32 tag = slot->idx; u32 tag = slot->idx;
struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = sas_execute_internal_abort_single(device,
HISI_SAS_INT_ABT_CMD, tag, tag, slot->dlvry_queue,
false); &internal_abort_data);
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) && if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
task->lldd_task) { task->lldd_task) {
/* /*
...@@ -1635,12 +1647,12 @@ static int hisi_sas_abort_task(struct sas_task *task) ...@@ -1635,12 +1647,12 @@ static int hisi_sas_abort_task(struct sas_task *task)
static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
{ {
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct device *dev = hisi_hba->dev; struct device *dev = hisi_hba->dev;
int rc; int rc;
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
HISI_SAS_INT_ABT_DEV, 0, false);
if (rc < 0) { if (rc < 0) {
dev_err(dev, "abort task set: internal abort rc=%d\n", rc); dev_err(dev, "abort task set: internal abort rc=%d\n", rc);
return TMF_RESP_FUNC_FAILED; return TMF_RESP_FUNC_FAILED;
...@@ -1713,12 +1725,12 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) ...@@ -1713,12 +1725,12 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
static int hisi_sas_I_T_nexus_reset(struct domain_device *device) static int hisi_sas_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 hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct device *dev = hisi_hba->dev; struct device *dev = hisi_hba->dev;
int rc; int rc;
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
HISI_SAS_INT_ABT_DEV, 0, false);
if (rc < 0) { if (rc < 0) {
dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc); dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc);
return TMF_RESP_FUNC_FAILED; return TMF_RESP_FUNC_FAILED;
...@@ -1766,8 +1778,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) ...@@ -1766,8 +1778,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
int rc = TMF_RESP_FUNC_FAILED; int rc = TMF_RESP_FUNC_FAILED;
/* Clear internal IO and then lu reset */ /* Clear internal IO and then lu reset */
rc = hisi_sas_internal_task_abort(hisi_hba, device, rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
HISI_SAS_INT_ABT_DEV, 0, false);
if (rc < 0) { if (rc < 0) {
dev_err(dev, "lu_reset: internal abort failed\n"); dev_err(dev, "lu_reset: internal abort failed\n");
goto out; goto out;
...@@ -1862,203 +1873,48 @@ static int hisi_sas_query_task(struct sas_task *task) ...@@ -1862,203 +1873,48 @@ static int hisi_sas_query_task(struct sas_task *task)
return rc; return rc;
} }
static int static bool hisi_sas_internal_abort_timeout(struct sas_task *task,
hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, void *data)
struct hisi_sas_internal_abort *abort,
struct sas_task *task,
struct hisi_sas_dq *dq)
{ {
struct domain_device *device = task->dev; struct domain_device *device = task->dev;
struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct device *dev = hisi_hba->dev; struct hisi_sas_internal_abort_data *timeout = data;
struct hisi_sas_port *port;
struct asd_sas_port *sas_port = device->port;
struct hisi_sas_slot *slot;
int slot_idx;
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
return -EINVAL;
if (!device->port)
return -1;
port = to_hisi_sas_port(sas_port);
/* simply get a slot and send abort command */
slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL);
if (slot_idx < 0)
goto err_out;
slot = &hisi_hba->slot_info[slot_idx];
slot->n_elem = 0;
slot->task = task;
slot->port = port;
slot->is_internal = true;
hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort);
return 0;
err_out:
dev_err(dev, "internal abort task prep: failed[%d]!\n", slot_idx);
return slot_idx;
}
/**
* _hisi_sas_internal_task_abort -- execute an internal
* abort command for single IO command or a device
* @hisi_hba: host controller struct
* @device: domain device
* @abort_flag: mode of operation, device or single IO
* @tag: tag of IO to be aborted (only relevant to single
* IO mode)
* @dq: delivery queue for this internal abort command
* @rst_to_recover: If rst_to_recover set, queue a controller
* reset if an internal abort times out.
*/
static int
_hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
struct domain_device *device, int abort_flag,
int tag, struct hisi_sas_dq *dq, bool rst_to_recover)
{
struct sas_task *task;
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_sas_internal_abort abort = {
.flag = abort_flag,
.tag = tag,
};
struct device *dev = hisi_hba->dev;
int res;
/*
* The interface is not realized means this HW don't support internal
* abort, or don't need to do internal abort. Then here, we return
* TMF_RESP_FUNC_FAILED and let other steps go on, which depends that
* the internal abort has been executed and returned CQ.
*/
if (!hisi_hba->hw->prep_abort)
return TMF_RESP_FUNC_FAILED;
if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags))
return -EIO;
task = sas_alloc_slow_task(GFP_KERNEL);
if (!task)
return -ENOMEM;
task->dev = device;
task->task_proto = SAS_PROTOCOL_NONE;
task->task_done = hisi_sas_task_done;
task->slow_task->timer.function = hisi_sas_tmf_timedout;
task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT;
add_timer(&task->slow_task->timer);
res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
&abort, task, dq);
if (res) {
del_timer_sync(&task->slow_task->timer);
dev_err(dev, "internal task abort: executing internal task failed: %d\n",
res);
goto exit;
}
wait_for_completion(&task->slow_task->completion);
res = TMF_RESP_FUNC_FAILED;
/* Internal abort timed out */
if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
struct hisi_sas_slot *slot = task->lldd_task;
set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags);
if (slot) {
struct hisi_sas_cq *cq =
&hisi_hba->cq[slot->dlvry_queue];
/*
* sync irq to avoid free'ing task
* before using task in IO completion
*/
synchronize_irq(cq->irq_no);
slot->task = NULL;
}
if (rst_to_recover) {
dev_err(dev, "internal task abort: timeout and not done. Queuing reset.\n");
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
} else {
dev_err(dev, "internal task abort: timeout and not done.\n");
}
res = -EIO;
goto exit;
} else
dev_err(dev, "internal task abort: timeout.\n");
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
res = TMF_RESP_FUNC_COMPLETE;
goto exit;
}
if (task->task_status.resp == SAS_TASK_COMPLETE && if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
task->task_status.stat == TMF_RESP_FUNC_SUCC) { queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
res = TMF_RESP_FUNC_SUCC;
goto exit;
}
exit: if (task->task_state_flags & SAS_TASK_STATE_DONE) {
dev_dbg(dev, "internal task abort: task to dev %016llx task=%pK resp: 0x%x sts 0x%x\n", pr_err("Internal abort: timeout %016llx\n",
SAS_ADDR(device->sas_addr), task, SAS_ADDR(device->sas_addr));
task->task_status.resp, /* 0 is complete, -1 is undelivered */ } else {
task->task_status.stat); struct hisi_sas_slot *slot = task->lldd_task;
sas_free_task(task);
return res; set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags);
}
static int if (slot) {
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, struct hisi_sas_cq *cq =
struct domain_device *device, &hisi_hba->cq[slot->dlvry_queue];
int abort_flag, int tag, bool rst_to_recover) /*
{ * sync irq to avoid free'ing task
struct hisi_sas_slot *slot; * before using task in IO completion
struct device *dev = hisi_hba->dev; */
struct hisi_sas_dq *dq; synchronize_irq(cq->irq_no);
int i, rc; slot->task = NULL;
}
switch (abort_flag) { if (timeout->rst_ha_timeout) {
case HISI_SAS_INT_ABT_CMD: pr_err("Internal abort: timeout and not done %016llx. Queuing reset.\n",
slot = &hisi_hba->slot_info[tag]; SAS_ADDR(device->sas_addr));
dq = &hisi_hba->dq[slot->dlvry_queue]; queue_work(hisi_hba->wq, &hisi_hba->rst_work);
return _hisi_sas_internal_task_abort(hisi_hba, device, } else {
abort_flag, tag, dq, pr_err("Internal abort: timeout and not done %016llx.\n",
rst_to_recover); SAS_ADDR(device->sas_addr));
case HISI_SAS_INT_ABT_DEV:
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
const struct cpumask *mask = cq->irq_mask;
if (mask && !cpumask_intersects(cpu_online_mask, mask))
continue;
dq = &hisi_hba->dq[i];
rc = _hisi_sas_internal_task_abort(hisi_hba, device,
abort_flag, tag,
dq, rst_to_recover);
if (rc)
return rc;
} }
break;
default: return true;
dev_err(dev, "Unrecognised internal abort flag (%d)\n",
abort_flag);
return -EINVAL;
} }
return 0; return false;
} }
static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
...@@ -2176,6 +2032,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { ...@@ -2176,6 +2032,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = {
.lldd_port_formed = hisi_sas_port_formed, .lldd_port_formed = hisi_sas_port_formed,
.lldd_write_gpio = hisi_sas_write_gpio, .lldd_write_gpio = hisi_sas_write_gpio,
.lldd_tmf_aborted = hisi_sas_tmf_aborted, .lldd_tmf_aborted = hisi_sas_tmf_aborted,
.lldd_abort_timeout = hisi_sas_internal_abort_timeout,
}; };
void hisi_sas_init_mem(struct hisi_hba *hisi_hba) void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
......
...@@ -2603,14 +2603,15 @@ static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t) ...@@ -2603,14 +2603,15 @@ static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t)
} }
static void prep_abort_v2_hw(struct hisi_hba *hisi_hba, static void prep_abort_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot, struct hisi_sas_slot *slot)
int device_id, int abort_flag, int tag_to_abort)
{ {
struct sas_task *task = slot->task; struct sas_task *task = slot->task;
struct sas_internal_abort_task *abort = &task->abort_task;
struct domain_device *dev = task->dev; struct domain_device *dev = task->dev;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct hisi_sas_port *port = slot->port; struct hisi_sas_port *port = slot->port;
struct timer_list *timer = &slot->internal_abort_timer; struct timer_list *timer = &slot->internal_abort_timer;
struct hisi_sas_device *sas_dev = dev->lldd_dev;
/* setup the quirk timer */ /* setup the quirk timer */
timer_setup(timer, hisi_sas_internal_abort_quirk_timeout, 0); timer_setup(timer, hisi_sas_internal_abort_quirk_timeout, 0);
...@@ -2622,13 +2623,13 @@ static void prep_abort_v2_hw(struct hisi_hba *hisi_hba, ...@@ -2622,13 +2623,13 @@ static void prep_abort_v2_hw(struct hisi_hba *hisi_hba,
(port->id << CMD_HDR_PORT_OFF) | (port->id << CMD_HDR_PORT_OFF) |
(dev_is_sata(dev) << (dev_is_sata(dev) <<
CMD_HDR_ABORT_DEVICE_TYPE_OFF) | CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
(abort_flag << CMD_HDR_ABORT_FLAG_OFF)); (abort->type << CMD_HDR_ABORT_FLAG_OFF));
/* dw1 */ /* dw1 */
hdr->dw1 = cpu_to_le32(device_id << CMD_HDR_DEV_ID_OFF); hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEV_ID_OFF);
/* dw7 */ /* dw7 */
hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF); hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF);
hdr->transfer_tags = cpu_to_le32(slot->idx); hdr->transfer_tags = cpu_to_le32(slot->idx);
} }
......
...@@ -1452,28 +1452,28 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, ...@@ -1452,28 +1452,28 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
} }
static void prep_abort_v3_hw(struct hisi_hba *hisi_hba, static void prep_abort_v3_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot, struct hisi_sas_slot *slot)
int device_id, int abort_flag, int tag_to_abort)
{ {
struct sas_task *task = slot->task; struct sas_task *task = slot->task;
struct sas_internal_abort_task *abort = &task->abort_task;
struct domain_device *dev = task->dev; struct domain_device *dev = task->dev;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct hisi_sas_port *port = slot->port; struct hisi_sas_port *port = slot->port;
struct hisi_sas_device *sas_dev = dev->lldd_dev;
bool sata = dev_is_sata(dev);
/* dw0 */ /* dw0 */
hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /*abort*/ hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /* abort */
(port->id << CMD_HDR_PORT_OFF) | (port->id << CMD_HDR_PORT_OFF) |
(dev_is_sata(dev) (sata << CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
<< CMD_HDR_ABORT_DEVICE_TYPE_OFF) | (abort->type << CMD_HDR_ABORT_FLAG_OFF));
(abort_flag
<< CMD_HDR_ABORT_FLAG_OFF));
/* dw1 */ /* dw1 */
hdr->dw1 = cpu_to_le32(device_id hdr->dw1 = cpu_to_le32(sas_dev->device_id
<< CMD_HDR_DEV_ID_OFF); << CMD_HDR_DEV_ID_OFF);
/* dw7 */ /* dw7 */
hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF); hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF);
hdr->transfer_tags = cpu_to_le32(slot->idx); hdr->transfer_tags = cpu_to_le32(slot->idx);
} }
......
...@@ -943,6 +943,7 @@ static int sas_execute_internal_abort(struct domain_device *device, ...@@ -943,6 +943,7 @@ static int sas_execute_internal_abort(struct domain_device *device,
task->abort_task.tag = tag; task->abort_task.tag = tag;
task->abort_task.type = type; task->abort_task.type = type;
task->abort_task.qid = qid;
res = i->dft->lldd_execute_task(task, GFP_KERNEL); res = i->dft->lldd_execute_task(task, GFP_KERNEL);
if (res) { if (res) {
...@@ -957,10 +958,16 @@ static int sas_execute_internal_abort(struct domain_device *device, ...@@ -957,10 +958,16 @@ static int sas_execute_internal_abort(struct domain_device *device,
/* Even if the internal abort timed out, return direct. */ /* Even if the internal abort timed out, return direct. */
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
pr_err("Internal abort: timeout %016llx\n", bool quit = true;
SAS_ADDR(device->sas_addr));
if (i->dft->lldd_abort_timeout)
quit = i->dft->lldd_abort_timeout(task, data);
else
pr_err("Internal abort: timeout %016llx\n",
SAS_ADDR(device->sas_addr));
res = -EIO; res = -EIO;
break; if (quit)
break;
} }
if (task->task_status.resp == SAS_TASK_COMPLETE && if (task->task_status.resp == SAS_TASK_COMPLETE &&
......
...@@ -565,6 +565,7 @@ enum sas_internal_abort { ...@@ -565,6 +565,7 @@ enum sas_internal_abort {
struct sas_internal_abort_task { struct sas_internal_abort_task {
enum sas_internal_abort type; enum sas_internal_abort type;
unsigned int qid;
u16 tag; u16 tag;
}; };
...@@ -671,6 +672,7 @@ struct sas_domain_function_template { ...@@ -671,6 +672,7 @@ struct sas_domain_function_template {
/* Special TMF callbacks */ /* Special TMF callbacks */
void (*lldd_tmf_exec_complete)(struct domain_device *dev); void (*lldd_tmf_exec_complete)(struct domain_device *dev);
void (*lldd_tmf_aborted)(struct sas_task *task); void (*lldd_tmf_aborted)(struct sas_task *task);
bool (*lldd_abort_timeout)(struct sas_task *task, void *data);
/* Port and Adapter management */ /* Port and Adapter management */
int (*lldd_clear_nexus_port)(struct asd_sas_port *); int (*lldd_clear_nexus_port)(struct asd_sas_port *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment