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.com Signed-off-by: John Garry <john.garry@huawei.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
08c61b5d90
commit
dc313f6b12
1 changed files with 131 additions and 164 deletions
|
@ -395,25 +395,122 @@ err_out_dif_dma_unmap:
|
||||||
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_sas_cmd_hdr *cmd_hdr_base;
|
||||||
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
|
int dlvry_queue_slot, dlvry_queue;
|
||||||
struct hisi_sas_device *sas_dev = device->lldd_dev;
|
struct sas_task *task = slot->task;
|
||||||
struct hisi_sas_port *port;
|
|
||||||
struct hisi_sas_slot *slot;
|
|
||||||
struct hisi_sas_cmd_hdr *cmd_hdr_base;
|
|
||||||
struct asd_sas_port *sas_port = device->port;
|
|
||||||
struct device *dev = hisi_hba->dev;
|
|
||||||
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;
|
||||||
|
|
||||||
|
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->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->tmf = tmf;
|
||||||
|
slot->is_internal = tmf;
|
||||||
|
task->lldd_task = slot;
|
||||||
|
|
||||||
|
memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
|
||||||
|
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));
|
||||||
|
|
||||||
|
switch (task->task_proto) {
|
||||||
|
case SAS_PROTOCOL_SMP:
|
||||||
|
hisi_sas_task_prep_smp(hisi_hba, slot);
|
||||||
|
break;
|
||||||
|
case SAS_PROTOCOL_SSP:
|
||||||
|
hisi_sas_task_prep_ssp(hisi_hba, slot);
|
||||||
|
break;
|
||||||
|
case SAS_PROTOCOL_SATA:
|
||||||
|
case SAS_PROTOCOL_STP:
|
||||||
|
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
|
||||||
|
hisi_sas_task_prep_ata(hisi_hba, slot);
|
||||||
|
break;
|
||||||
|
case SAS_PROTOCOL_NONE:
|
||||||
|
if (abort) {
|
||||||
|
hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n",
|
||||||
|
task->task_proto);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
spin_lock(&dq->lock);
|
||||||
|
hisi_hba->hw->start_delivery(dq);
|
||||||
|
spin_unlock(&dq->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
|
||||||
|
struct hisi_sas_tmf_task *tmf)
|
||||||
|
{
|
||||||
|
int n_elem = 0, n_elem_dif = 0, n_elem_req = 0;
|
||||||
|
struct domain_device *device = task->dev;
|
||||||
|
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_port *port;
|
||||||
|
struct hisi_hba *hisi_hba;
|
||||||
|
struct hisi_sas_slot *slot;
|
||||||
|
struct device *dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!sas_port) {
|
||||||
|
struct task_status_struct *ts = &task->task_status;
|
||||||
|
|
||||||
|
ts->resp = SAS_TASK_UNDELIVERED;
|
||||||
|
ts->stat = SAS_PHY_DOWN;
|
||||||
|
/*
|
||||||
|
* libsas will use dev->port, should
|
||||||
|
* not call task_done for sata
|
||||||
|
*/
|
||||||
|
if (device->dev_type != SAS_SATA_DEV)
|
||||||
|
task->task_done(task);
|
||||||
|
return -ECOMM;
|
||||||
|
}
|
||||||
|
|
||||||
|
hisi_hba = dev_to_hisi_hba(device);
|
||||||
|
dev = hisi_hba->dev;
|
||||||
|
|
||||||
|
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
|
||||||
|
if (!gfpflags_allow_blocking(gfp_flags))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
down(&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",
|
||||||
|
@ -442,13 +539,13 @@ static int hisi_sas_task_prep(struct sas_task *task,
|
||||||
|
|
||||||
blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
|
blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
|
||||||
dq_index = blk_mq_unique_tag_to_hwq(blk_tag);
|
dq_index = blk_mq_unique_tag_to_hwq(blk_tag);
|
||||||
*dq_pointer = dq = &hisi_hba->dq[dq_index];
|
dq = &hisi_hba->dq[dq_index];
|
||||||
} else {
|
} else {
|
||||||
struct Scsi_Host *shost = hisi_hba->shost;
|
struct Scsi_Host *shost = hisi_hba->shost;
|
||||||
struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
|
struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
|
||||||
int queue = qmap->mq_map[raw_smp_processor_id()];
|
int queue = qmap->mq_map[raw_smp_processor_id()];
|
||||||
|
|
||||||
*dq_pointer = dq = &hisi_hba->dq[queue];
|
dq = &hisi_hba->dq[queue];
|
||||||
}
|
}
|
||||||
|
|
||||||
port = to_hisi_sas_port(sas_port);
|
port = to_hisi_sas_port(sas_port);
|
||||||
|
@ -480,66 +577,17 @@ static int hisi_sas_task_prep(struct sas_task *task,
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto err_out_dif_dma_unmap;
|
goto err_out_dif_dma_unmap;
|
||||||
|
|
||||||
slot_idx = rc;
|
slot = &hisi_hba->slot_info[rc];
|
||||||
slot = &hisi_hba->slot_info[slot_idx];
|
|
||||||
|
|
||||||
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->n_elem = n_elem;
|
||||||
slot->n_elem_dif = n_elem_dif;
|
slot->n_elem_dif = n_elem_dif;
|
||||||
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->tmf = tmf;
|
slot->tmf = tmf;
|
||||||
slot->is_internal = is_tmf;
|
slot->is_internal = tmf;
|
||||||
task->lldd_task = slot;
|
|
||||||
|
|
||||||
memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
|
/* protect task_prep and start_delivery sequence */
|
||||||
memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ);
|
hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf);
|
||||||
memset(hisi_sas_status_buf_addr_mem(slot), 0,
|
|
||||||
sizeof(struct hisi_sas_err_record));
|
|
||||||
|
|
||||||
switch (task->task_proto) {
|
|
||||||
case SAS_PROTOCOL_SMP:
|
|
||||||
hisi_sas_task_prep_smp(hisi_hba, slot);
|
|
||||||
break;
|
|
||||||
case SAS_PROTOCOL_SSP:
|
|
||||||
hisi_sas_task_prep_ssp(hisi_hba, slot);
|
|
||||||
break;
|
|
||||||
case SAS_PROTOCOL_SATA:
|
|
||||||
case SAS_PROTOCOL_STP:
|
|
||||||
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
|
|
||||||
hisi_sas_task_prep_ata(hisi_hba, slot);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n",
|
|
||||||
task->task_proto);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
spin_lock(&dq->lock);
|
|
||||||
hisi_hba->hw->start_delivery(dq);
|
|
||||||
spin_unlock(&dq->lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -548,52 +596,9 @@ err_out_dif_dma_unmap:
|
||||||
hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif);
|
hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif);
|
||||||
err_out_dma_unmap:
|
err_out_dma_unmap:
|
||||||
hisi_sas_dma_unmap(hisi_hba, task, n_elem,
|
hisi_sas_dma_unmap(hisi_hba, task, n_elem,
|
||||||
n_elem_req);
|
n_elem_req);
|
||||||
prep_out:
|
prep_out:
|
||||||
dev_err(dev, "task prep: failed[%d]!\n", rc);
|
dev_err(dev, "task exec: failed[%d]!\n", rc);
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
|
|
||||||
bool is_tmf, struct hisi_sas_tmf_task *tmf)
|
|
||||||
{
|
|
||||||
u32 rc;
|
|
||||||
struct hisi_hba *hisi_hba;
|
|
||||||
struct device *dev;
|
|
||||||
struct domain_device *device = task->dev;
|
|
||||||
struct asd_sas_port *sas_port = device->port;
|
|
||||||
struct hisi_sas_dq *dq = NULL;
|
|
||||||
|
|
||||||
if (!sas_port) {
|
|
||||||
struct task_status_struct *ts = &task->task_status;
|
|
||||||
|
|
||||||
ts->resp = SAS_TASK_UNDELIVERED;
|
|
||||||
ts->stat = SAS_PHY_DOWN;
|
|
||||||
/*
|
|
||||||
* libsas will use dev->port, should
|
|
||||||
* not call task_done for sata
|
|
||||||
*/
|
|
||||||
if (device->dev_type != SAS_SATA_DEV)
|
|
||||||
task->task_done(task);
|
|
||||||
return -ECOMM;
|
|
||||||
}
|
|
||||||
|
|
||||||
hisi_hba = dev_to_hisi_hba(device);
|
|
||||||
dev = hisi_hba->dev;
|
|
||||||
|
|
||||||
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
|
|
||||||
if (!gfpflags_allow_blocking(gfp_flags))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
down(&hisi_hba->sem);
|
|
||||||
up(&hisi_hba->sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* protect task_prep and start_delivery sequence */
|
|
||||||
rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf);
|
|
||||||
if (rc)
|
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue