mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
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
@ -395,25 +395,122 @@ err_out_dif_dma_unmap:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hisi_sas_task_prep(struct sas_task *task,
|
||||
struct hisi_sas_dq **dq_pointer,
|
||||
bool is_tmf, struct hisi_sas_tmf_task *tmf)
|
||||
static
|
||||
void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
|
||||
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 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;
|
||||
struct hisi_sas_cmd_hdr *cmd_hdr_base;
|
||||
int dlvry_queue_slot, dlvry_queue;
|
||||
struct sas_task *task = slot->task;
|
||||
unsigned long flags;
|
||||
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 (sas_dev)
|
||||
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));
|
||||
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 {
|
||||
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];
|
||||
dq = &hisi_hba->dq[queue];
|
||||
}
|
||||
|
||||
port = to_hisi_sas_port(sas_port);
|
||||
@ -480,66 +577,17 @@ static int hisi_sas_task_prep(struct sas_task *task,
|
||||
if (rc < 0)
|
||||
goto err_out_dif_dma_unmap;
|
||||
|
||||
slot_idx = 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 = &hisi_hba->slot_info[rc];
|
||||
slot->n_elem = n_elem;
|
||||
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->port = port;
|
||||
|
||||
slot->tmf = tmf;
|
||||
slot->is_internal = is_tmf;
|
||||
task->lldd_task = slot;
|
||||
slot->is_internal = tmf;
|
||||
|
||||
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;
|
||||
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);
|
||||
/* protect task_prep and start_delivery sequence */
|
||||
hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -548,52 +596,9 @@ err_out_dif_dma_unmap:
|
||||
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);
|
||||
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,
|
||||
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);
|
||||
|
||||
dev_err(dev, "task exec: failed[%d]!\n", 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)
|
||||
{
|
||||
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,
|
||||
@ -1246,8 +1251,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
|
||||
task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
|
||||
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) {
|
||||
del_timer_sync(&task->slow_task->timer);
|
||||
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 device *dev = hisi_hba->dev;
|
||||
struct hisi_sas_port *port;
|
||||
struct hisi_sas_slot *slot;
|
||||
struct asd_sas_port *sas_port = device->port;
|
||||
struct hisi_sas_cmd_hdr *cmd_hdr_base;
|
||||
int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
|
||||
unsigned long flags;
|
||||
int wr_q_index;
|
||||
struct hisi_sas_slot *slot;
|
||||
int slot_idx;
|
||||
|
||||
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
|
||||
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);
|
||||
|
||||
/* simply get a slot and send abort command */
|
||||
rc = hisi_sas_slot_index_alloc(hisi_hba, NULL);
|
||||
if (rc < 0)
|
||||
slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL);
|
||||
if (slot_idx < 0)
|
||||
goto err_out;
|
||||
|
||||
slot_idx = 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->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->n_elem = 0;
|
||||
slot->task = task;
|
||||
slot->port = port;
|
||||
slot->is_internal = true;
|
||||
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));
|
||||
|
||||
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);
|
||||
hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
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…
Reference in New Issue
Block a user