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

scsi: hisi_sas: Factor out task prep and delivery code

The task prep code is the same between the normal path (in
hisi_sas_task_prep()) and the internal abort path, so factor is out into a
common function.

Link: https://lore.kernel.org/r/1639579061-179473-5-git-send-email-john.garry@huawei.comSigned-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 08c61b5d
...@@ -395,94 +395,20 @@ static int hisi_sas_dif_dma_map(struct hisi_hba *hisi_hba, ...@@ -395,94 +395,20 @@ static int hisi_sas_dif_dma_map(struct hisi_hba *hisi_hba,
return rc; return rc;
} }
static int hisi_sas_task_prep(struct sas_task *task, static
struct hisi_sas_dq **dq_pointer, void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
bool is_tmf, struct hisi_sas_tmf_task *tmf) struct hisi_sas_slot *slot,
struct hisi_sas_dq *dq,
struct hisi_sas_device *sas_dev,
struct hisi_sas_internal_abort *abort,
struct hisi_sas_tmf_task *tmf)
{ {
struct domain_device *device = task->dev;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_sas_port *port;
struct hisi_sas_slot *slot;
struct hisi_sas_cmd_hdr *cmd_hdr_base; struct hisi_sas_cmd_hdr *cmd_hdr_base;
struct asd_sas_port *sas_port = device->port; int dlvry_queue_slot, dlvry_queue;
struct device *dev = hisi_hba->dev; struct sas_task *task = slot->task;
int dlvry_queue_slot, dlvry_queue, rc, slot_idx;
int n_elem = 0, n_elem_dif = 0, n_elem_req = 0;
struct scsi_cmnd *scmd = NULL;
struct hisi_sas_dq *dq;
unsigned long flags; unsigned long flags;
int wr_q_index; int wr_q_index;
if (DEV_IS_GONE(sas_dev)) {
if (sas_dev)
dev_info(dev, "task prep: device %d not ready\n",
sas_dev->device_id);
else
dev_info(dev, "task prep: device %016llx not ready\n",
SAS_ADDR(device->sas_addr));
return -ECOMM;
}
if (task->uldd_task) {
struct ata_queued_cmd *qc;
if (dev_is_sata(device)) {
qc = task->uldd_task;
scmd = qc->scsicmd;
} else {
scmd = task->uldd_task;
}
}
if (scmd) {
unsigned int dq_index;
u32 blk_tag;
blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
dq_index = blk_mq_unique_tag_to_hwq(blk_tag);
*dq_pointer = dq = &hisi_hba->dq[dq_index];
} else {
struct Scsi_Host *shost = hisi_hba->shost;
struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
int queue = qmap->mq_map[raw_smp_processor_id()];
*dq_pointer = dq = &hisi_hba->dq[queue];
}
port = to_hisi_sas_port(sas_port);
if (port && !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);
return -ECOMM;
}
rc = hisi_sas_dma_map(hisi_hba, task, &n_elem,
&n_elem_req);
if (rc < 0)
goto prep_out;
if (!sas_protocol_ata(task->task_proto)) {
rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task);
if (rc < 0)
goto err_out_dma_unmap;
}
if (hisi_hba->hw->slot_index_alloc)
rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
else
rc = hisi_sas_slot_index_alloc(hisi_hba, scmd);
if (rc < 0)
goto err_out_dif_dma_unmap;
slot_idx = rc;
slot = &hisi_hba->slot_info[slot_idx];
spin_lock(&dq->lock); spin_lock(&dq->lock);
wr_q_index = dq->wr_point; wr_q_index = dq->wr_point;
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
...@@ -496,16 +422,13 @@ static int hisi_sas_task_prep(struct sas_task *task, ...@@ -496,16 +422,13 @@ static int hisi_sas_task_prep(struct sas_task *task,
dlvry_queue_slot = wr_q_index; dlvry_queue_slot = wr_q_index;
slot->device_id = sas_dev->device_id; slot->device_id = sas_dev->device_id;
slot->n_elem = n_elem;
slot->n_elem_dif = n_elem_dif;
slot->dlvry_queue = dlvry_queue; slot->dlvry_queue = dlvry_queue;
slot->dlvry_queue_slot = dlvry_queue_slot; slot->dlvry_queue_slot = dlvry_queue_slot;
cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
slot->task = task;
slot->port = port;
slot->tmf = tmf; slot->tmf = tmf;
slot->is_internal = is_tmf; slot->is_internal = tmf;
task->lldd_task = slot; task->lldd_task = slot;
memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
...@@ -525,8 +448,14 @@ static int hisi_sas_task_prep(struct sas_task *task, ...@@ -525,8 +448,14 @@ static int hisi_sas_task_prep(struct sas_task *task,
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
hisi_sas_task_prep_ata(hisi_hba, slot); hisi_sas_task_prep_ata(hisi_hba, slot);
break; break;
case SAS_PROTOCOL_NONE:
if (abort) {
hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id);
break;
}
fallthrough;
default: default:
dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n", dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n",
task->task_proto); task->task_proto);
break; break;
} }
...@@ -540,29 +469,22 @@ static int hisi_sas_task_prep(struct sas_task *task, ...@@ -540,29 +469,22 @@ static int hisi_sas_task_prep(struct sas_task *task,
spin_lock(&dq->lock); spin_lock(&dq->lock);
hisi_hba->hw->start_delivery(dq); hisi_hba->hw->start_delivery(dq);
spin_unlock(&dq->lock); spin_unlock(&dq->lock);
return 0;
err_out_dif_dma_unmap:
if (!sas_protocol_ata(task->task_proto))
hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif);
err_out_dma_unmap:
hisi_sas_dma_unmap(hisi_hba, task, n_elem,
n_elem_req);
prep_out:
dev_err(dev, "task prep: failed[%d]!\n", rc);
return rc;
} }
static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
bool is_tmf, struct hisi_sas_tmf_task *tmf) struct hisi_sas_tmf_task *tmf)
{ {
u32 rc; int n_elem = 0, n_elem_dif = 0, n_elem_req = 0;
struct hisi_hba *hisi_hba;
struct device *dev;
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 scsi_cmnd *scmd = NULL;
struct hisi_sas_dq *dq = NULL; struct hisi_sas_dq *dq = NULL;
struct hisi_sas_port *port;
struct hisi_hba *hisi_hba;
struct hisi_sas_slot *slot;
struct device *dev;
int rc;
if (!sas_port) { if (!sas_port) {
struct task_status_struct *ts = &task->task_status; struct task_status_struct *ts = &task->task_status;
...@@ -589,11 +511,94 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, ...@@ -589,11 +511,94 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
up(&hisi_hba->sem); up(&hisi_hba->sem);
} }
if (DEV_IS_GONE(sas_dev)) {
if (sas_dev)
dev_info(dev, "task prep: device %d not ready\n",
sas_dev->device_id);
else
dev_info(dev, "task prep: device %016llx not ready\n",
SAS_ADDR(device->sas_addr));
return -ECOMM;
}
if (task->uldd_task) {
struct ata_queued_cmd *qc;
if (dev_is_sata(device)) {
qc = task->uldd_task;
scmd = qc->scsicmd;
} else {
scmd = task->uldd_task;
}
}
if (scmd) {
unsigned int dq_index;
u32 blk_tag;
blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
dq_index = blk_mq_unique_tag_to_hwq(blk_tag);
dq = &hisi_hba->dq[dq_index];
} else {
struct Scsi_Host *shost = hisi_hba->shost;
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];
}
port = to_hisi_sas_port(sas_port);
if (port && !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);
return -ECOMM;
}
rc = hisi_sas_dma_map(hisi_hba, task, &n_elem,
&n_elem_req);
if (rc < 0)
goto prep_out;
if (!sas_protocol_ata(task->task_proto)) {
rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task);
if (rc < 0)
goto err_out_dma_unmap;
}
if (hisi_hba->hw->slot_index_alloc)
rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
else
rc = hisi_sas_slot_index_alloc(hisi_hba, scmd);
if (rc < 0)
goto err_out_dif_dma_unmap;
slot = &hisi_hba->slot_info[rc];
slot->n_elem = n_elem;
slot->n_elem_dif = n_elem_dif;
slot->task = task;
slot->port = port;
slot->tmf = tmf;
slot->is_internal = tmf;
/* protect task_prep and start_delivery sequence */ /* protect task_prep and start_delivery sequence */
rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf); hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf);
if (rc)
dev_err(dev, "task exec: failed[%d]!\n", rc);
return 0;
err_out_dif_dma_unmap:
if (!sas_protocol_ata(task->task_proto))
hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif);
err_out_dma_unmap:
hisi_sas_dma_unmap(hisi_hba, task, n_elem,
n_elem_req);
prep_out:
dev_err(dev, "task exec: failed[%d]!\n", rc);
return rc; return rc;
} }
...@@ -1092,7 +1097,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) ...@@ -1092,7 +1097,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
{ {
return hisi_sas_task_exec(task, gfp_flags, 0, NULL); return hisi_sas_task_exec(task, gfp_flags, NULL);
} }
static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no,
...@@ -1246,8 +1251,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, ...@@ -1246,8 +1251,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
task->slow_task->timer.expires = jiffies + TASK_TIMEOUT; task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
add_timer(&task->slow_task->timer); add_timer(&task->slow_task->timer);
res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf); res = hisi_sas_task_exec(task, GFP_KERNEL, tmf);
if (res) { if (res) {
del_timer_sync(&task->slow_task->timer); del_timer_sync(&task->slow_task->timer);
dev_err(dev, "abort tmf: executing internal task failed: %d\n", dev_err(dev, "abort tmf: executing internal task failed: %d\n",
...@@ -2016,12 +2020,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, ...@@ -2016,12 +2020,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_device *sas_dev = device->lldd_dev;
struct device *dev = hisi_hba->dev; struct device *dev = hisi_hba->dev;
struct hisi_sas_port *port; struct hisi_sas_port *port;
struct hisi_sas_slot *slot;
struct asd_sas_port *sas_port = device->port; struct asd_sas_port *sas_port = device->port;
struct hisi_sas_cmd_hdr *cmd_hdr_base; struct hisi_sas_slot *slot;
int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; int slot_idx;
unsigned long flags;
int wr_q_index;
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
return -EINVAL; return -EINVAL;
...@@ -2032,58 +2033,24 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, ...@@ -2032,58 +2033,24 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
port = to_hisi_sas_port(sas_port); port = to_hisi_sas_port(sas_port);
/* simply get a slot and send abort command */ /* simply get a slot and send abort command */
rc = hisi_sas_slot_index_alloc(hisi_hba, NULL); slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL);
if (rc < 0) if (slot_idx < 0)
goto err_out; goto err_out;
slot_idx = rc;
slot = &hisi_hba->slot_info[slot_idx]; slot = &hisi_hba->slot_info[slot_idx];
slot->n_elem = 0;
spin_lock(&dq->lock);
wr_q_index = dq->wr_point;
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
list_add_tail(&slot->delivery, &dq->list);
spin_unlock(&dq->lock);
spin_lock(&sas_dev->lock);
list_add_tail(&slot->entry, &sas_dev->list);
spin_unlock(&sas_dev->lock);
dlvry_queue = dq->id;
dlvry_queue_slot = wr_q_index;
slot->device_id = sas_dev->device_id;
slot->n_elem = n_elem;
slot->dlvry_queue = dlvry_queue;
slot->dlvry_queue_slot = dlvry_queue_slot;
cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
slot->task = task; slot->task = task;
slot->port = port; slot->port = port;
slot->is_internal = true; slot->is_internal = true;
task->lldd_task = slot;
memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL);
memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ);
memset(hisi_sas_status_buf_addr_mem(slot), 0,
sizeof(struct hisi_sas_err_record));
hisi_sas_task_prep_abort(hisi_hba, abort, slot, device_id);
spin_lock_irqsave(&task->task_state_lock, flags);
task->task_state_flags |= SAS_TASK_AT_INITIATOR;
spin_unlock_irqrestore(&task->task_state_lock, flags);
WRITE_ONCE(slot->ready, 1);
/* send abort command to the chip */
spin_lock(&dq->lock);
hisi_hba->hw->start_delivery(dq);
spin_unlock(&dq->lock);
return 0; return 0;
err_out: err_out:
dev_err(dev, "internal abort task prep: failed[%d]!\n", rc); dev_err(dev, "internal abort task prep: failed[%d]!\n", slot_idx);
return rc; return slot_idx;
} }
/** /**
......
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